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    git_store::{GitStoreEvent, RepositoryEvent},
  138    project_settings::DiagnosticSeverity,
  139};
  140
  141pub use git::blame::BlameRenderer;
  142pub use proposed_changes_editor::{
  143    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  144};
  145use std::{cell::OnceCell, iter::Peekable, ops::Not};
  146use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  147
  148pub use lsp::CompletionContext;
  149use lsp::{
  150    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  151    LanguageServerId, LanguageServerName,
  152};
  153
  154use language::BufferSnapshot;
  155pub use lsp_ext::lsp_tasks;
  156use movement::TextLayoutDetails;
  157pub use multi_buffer::{
  158    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  159    RowInfo, ToOffset, ToPoint,
  160};
  161use multi_buffer::{
  162    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  163    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  164};
  165use parking_lot::Mutex;
  166use project::{
  167    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  168    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  169    TaskSourceKind,
  170    debugger::breakpoint_store::Breakpoint,
  171    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  172    project_settings::{GitGutterSetting, ProjectSettings},
  173};
  174use rand::prelude::*;
  175use rpc::{ErrorExt, proto::*};
  176use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  177use selections_collection::{
  178    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  179};
  180use serde::{Deserialize, Serialize};
  181use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  182use smallvec::{SmallVec, smallvec};
  183use snippet::Snippet;
  184use std::sync::Arc;
  185use std::{
  186    any::TypeId,
  187    borrow::Cow,
  188    cell::RefCell,
  189    cmp::{self, Ordering, Reverse},
  190    mem,
  191    num::NonZeroU32,
  192    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  193    path::{Path, PathBuf},
  194    rc::Rc,
  195    time::{Duration, Instant},
  196};
  197pub use sum_tree::Bias;
  198use sum_tree::TreeMap;
  199use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  200use theme::{
  201    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  202    observe_buffer_font_size_adjustment,
  203};
  204use ui::{
  205    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  206    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  207};
  208use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  209use workspace::{
  210    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  211    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  212    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  213    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  214    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  215    searchable::SearchEvent,
  216};
  217
  218use crate::{
  219    code_context_menus::CompletionsMenuSource,
  220    hover_links::{find_url, find_url_from_range},
  221};
  222use crate::{
  223    editor_settings::MultiCursorModifier,
  224    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  225};
  226
  227pub const FILE_HEADER_HEIGHT: u32 = 2;
  228pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  229pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  230const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  231const MAX_LINE_LEN: usize = 1024;
  232const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  233const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  234pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  235#[doc(hidden)]
  236pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  237const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  238
  239pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  241pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  242
  243pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  244pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  245pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  246
  247pub type RenderDiffHunkControlsFn = Arc<
  248    dyn Fn(
  249        u32,
  250        &DiffHunkStatus,
  251        Range<Anchor>,
  252        bool,
  253        Pixels,
  254        &Entity<Editor>,
  255        &mut Window,
  256        &mut App,
  257    ) -> AnyElement,
  258>;
  259
  260struct InlineValueCache {
  261    enabled: bool,
  262    inlays: Vec<InlayId>,
  263    refresh_task: Task<Option<()>>,
  264}
  265
  266impl InlineValueCache {
  267    fn new(enabled: bool) -> Self {
  268        Self {
  269            enabled,
  270            inlays: Vec::new(),
  271            refresh_task: Task::ready(None),
  272        }
  273    }
  274}
  275
  276#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  277pub enum InlayId {
  278    InlineCompletion(usize),
  279    DebuggerValue(usize),
  280    // LSP
  281    Hint(usize),
  282    Color(usize),
  283}
  284
  285impl InlayId {
  286    fn id(&self) -> usize {
  287        match self {
  288            Self::InlineCompletion(id) => *id,
  289            Self::DebuggerValue(id) => *id,
  290            Self::Hint(id) => *id,
  291            Self::Color(id) => *id,
  292        }
  293    }
  294}
  295
  296pub enum ActiveDebugLine {}
  297pub enum DebugStackFrameLine {}
  298enum DocumentHighlightRead {}
  299enum DocumentHighlightWrite {}
  300enum InputComposition {}
  301pub enum PendingInput {}
  302enum SelectedTextHighlight {}
  303
  304pub enum ConflictsOuter {}
  305pub enum ConflictsOurs {}
  306pub enum ConflictsTheirs {}
  307pub enum ConflictsOursMarker {}
  308pub enum ConflictsTheirsMarker {}
  309
  310#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  311pub enum Navigated {
  312    Yes,
  313    No,
  314}
  315
  316impl Navigated {
  317    pub fn from_bool(yes: bool) -> Navigated {
  318        if yes { Navigated::Yes } else { Navigated::No }
  319    }
  320}
  321
  322#[derive(Debug, Clone, PartialEq, Eq)]
  323enum DisplayDiffHunk {
  324    Folded {
  325        display_row: DisplayRow,
  326    },
  327    Unfolded {
  328        is_created_file: bool,
  329        diff_base_byte_range: Range<usize>,
  330        display_row_range: Range<DisplayRow>,
  331        multi_buffer_range: Range<Anchor>,
  332        status: DiffHunkStatus,
  333    },
  334}
  335
  336pub enum HideMouseCursorOrigin {
  337    TypingAction,
  338    MovementAction,
  339}
  340
  341pub fn init_settings(cx: &mut App) {
  342    EditorSettings::register(cx);
  343}
  344
  345pub fn init(cx: &mut App) {
  346    init_settings(cx);
  347
  348    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  349
  350    workspace::register_project_item::<Editor>(cx);
  351    workspace::FollowableViewRegistry::register::<Editor>(cx);
  352    workspace::register_serializable_item::<Editor>(cx);
  353
  354    cx.observe_new(
  355        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  356            workspace.register_action(Editor::new_file);
  357            workspace.register_action(Editor::new_file_vertical);
  358            workspace.register_action(Editor::new_file_horizontal);
  359            workspace.register_action(Editor::cancel_language_server_work);
  360        },
  361    )
  362    .detach();
  363
  364    cx.on_action(move |_: &workspace::NewFile, cx| {
  365        let app_state = workspace::AppState::global(cx);
  366        if let Some(app_state) = app_state.upgrade() {
  367            workspace::open_new(
  368                Default::default(),
  369                app_state,
  370                cx,
  371                |workspace, window, cx| {
  372                    Editor::new_file(workspace, &Default::default(), window, cx)
  373                },
  374            )
  375            .detach();
  376        }
  377    });
  378    cx.on_action(move |_: &workspace::NewWindow, cx| {
  379        let app_state = workspace::AppState::global(cx);
  380        if let Some(app_state) = app_state.upgrade() {
  381            workspace::open_new(
  382                Default::default(),
  383                app_state,
  384                cx,
  385                |workspace, window, cx| {
  386                    cx.activate(true);
  387                    Editor::new_file(workspace, &Default::default(), window, cx)
  388                },
  389            )
  390            .detach();
  391        }
  392    });
  393}
  394
  395pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  396    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  397}
  398
  399pub trait DiagnosticRenderer {
  400    fn render_group(
  401        &self,
  402        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  403        buffer_id: BufferId,
  404        snapshot: EditorSnapshot,
  405        editor: WeakEntity<Editor>,
  406        cx: &mut App,
  407    ) -> Vec<BlockProperties<Anchor>>;
  408
  409    fn render_hover(
  410        &self,
  411        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  412        range: Range<Point>,
  413        buffer_id: BufferId,
  414        cx: &mut App,
  415    ) -> Option<Entity<markdown::Markdown>>;
  416
  417    fn open_link(
  418        &self,
  419        editor: &mut Editor,
  420        link: SharedString,
  421        window: &mut Window,
  422        cx: &mut Context<Editor>,
  423    );
  424}
  425
  426pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  427
  428impl GlobalDiagnosticRenderer {
  429    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  430        cx.try_global::<Self>().map(|g| g.0.clone())
  431    }
  432}
  433
  434impl gpui::Global for GlobalDiagnosticRenderer {}
  435pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  436    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  437}
  438
  439pub struct SearchWithinRange;
  440
  441trait InvalidationRegion {
  442    fn ranges(&self) -> &[Range<Anchor>];
  443}
  444
  445#[derive(Clone, Debug, PartialEq)]
  446pub enum SelectPhase {
  447    Begin {
  448        position: DisplayPoint,
  449        add: bool,
  450        click_count: usize,
  451    },
  452    BeginColumnar {
  453        position: DisplayPoint,
  454        reset: bool,
  455        mode: ColumnarMode,
  456        goal_column: u32,
  457    },
  458    Extend {
  459        position: DisplayPoint,
  460        click_count: usize,
  461    },
  462    Update {
  463        position: DisplayPoint,
  464        goal_column: u32,
  465        scroll_delta: gpui::Point<f32>,
  466    },
  467    End,
  468}
  469
  470#[derive(Clone, Debug, PartialEq)]
  471pub enum ColumnarMode {
  472    FromMouse,
  473    FromSelection,
  474}
  475
  476#[derive(Clone, Debug)]
  477pub enum SelectMode {
  478    Character,
  479    Word(Range<Anchor>),
  480    Line(Range<Anchor>),
  481    All,
  482}
  483
  484#[derive(Clone, PartialEq, Eq, Debug)]
  485pub enum EditorMode {
  486    SingleLine {
  487        auto_width: bool,
  488    },
  489    AutoHeight {
  490        min_lines: usize,
  491        max_lines: usize,
  492    },
  493    Full {
  494        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  495        scale_ui_elements_with_buffer_font_size: bool,
  496        /// When set to `true`, the editor will render a background for the active line.
  497        show_active_line_background: bool,
  498        /// When set to `true`, the editor's height will be determined by its content.
  499        sized_by_content: bool,
  500    },
  501    Minimap {
  502        parent: WeakEntity<Editor>,
  503    },
  504}
  505
  506impl EditorMode {
  507    pub fn full() -> Self {
  508        Self::Full {
  509            scale_ui_elements_with_buffer_font_size: true,
  510            show_active_line_background: true,
  511            sized_by_content: false,
  512        }
  513    }
  514
  515    pub fn is_full(&self) -> bool {
  516        matches!(self, Self::Full { .. })
  517    }
  518
  519    fn is_minimap(&self) -> bool {
  520        matches!(self, Self::Minimap { .. })
  521    }
  522}
  523
  524#[derive(Copy, Clone, Debug)]
  525pub enum SoftWrap {
  526    /// Prefer not to wrap at all.
  527    ///
  528    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  529    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  530    GitDiff,
  531    /// Prefer a single line generally, unless an overly long line is encountered.
  532    None,
  533    /// Soft wrap lines that exceed the editor width.
  534    EditorWidth,
  535    /// Soft wrap lines at the preferred line length.
  536    Column(u32),
  537    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  538    Bounded(u32),
  539}
  540
  541#[derive(Clone)]
  542pub struct EditorStyle {
  543    pub background: Hsla,
  544    pub local_player: PlayerColor,
  545    pub text: TextStyle,
  546    pub scrollbar_width: Pixels,
  547    pub syntax: Arc<SyntaxTheme>,
  548    pub status: StatusColors,
  549    pub inlay_hints_style: HighlightStyle,
  550    pub inline_completion_styles: InlineCompletionStyles,
  551    pub unnecessary_code_fade: f32,
  552    pub show_underlines: bool,
  553}
  554
  555impl Default for EditorStyle {
  556    fn default() -> Self {
  557        Self {
  558            background: Hsla::default(),
  559            local_player: PlayerColor::default(),
  560            text: TextStyle::default(),
  561            scrollbar_width: Pixels::default(),
  562            syntax: Default::default(),
  563            // HACK: Status colors don't have a real default.
  564            // We should look into removing the status colors from the editor
  565            // style and retrieve them directly from the theme.
  566            status: StatusColors::dark(),
  567            inlay_hints_style: HighlightStyle::default(),
  568            inline_completion_styles: InlineCompletionStyles {
  569                insertion: HighlightStyle::default(),
  570                whitespace: HighlightStyle::default(),
  571            },
  572            unnecessary_code_fade: Default::default(),
  573            show_underlines: true,
  574        }
  575    }
  576}
  577
  578pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  579    let show_background = language_settings::language_settings(None, None, cx)
  580        .inlay_hints
  581        .show_background;
  582
  583    HighlightStyle {
  584        color: Some(cx.theme().status().hint),
  585        background_color: show_background.then(|| cx.theme().status().hint_background),
  586        ..HighlightStyle::default()
  587    }
  588}
  589
  590pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  591    InlineCompletionStyles {
  592        insertion: HighlightStyle {
  593            color: Some(cx.theme().status().predictive),
  594            ..HighlightStyle::default()
  595        },
  596        whitespace: HighlightStyle {
  597            background_color: Some(cx.theme().status().created_background),
  598            ..HighlightStyle::default()
  599        },
  600    }
  601}
  602
  603type CompletionId = usize;
  604
  605pub(crate) enum EditDisplayMode {
  606    TabAccept,
  607    DiffPopover,
  608    Inline,
  609}
  610
  611enum InlineCompletion {
  612    Edit {
  613        edits: Vec<(Range<Anchor>, String)>,
  614        edit_preview: Option<EditPreview>,
  615        display_mode: EditDisplayMode,
  616        snapshot: BufferSnapshot,
  617    },
  618    Move {
  619        target: Anchor,
  620        snapshot: BufferSnapshot,
  621    },
  622}
  623
  624struct InlineCompletionState {
  625    inlay_ids: Vec<InlayId>,
  626    completion: InlineCompletion,
  627    completion_id: Option<SharedString>,
  628    invalidation_range: Range<Anchor>,
  629}
  630
  631enum EditPredictionSettings {
  632    Disabled,
  633    Enabled {
  634        show_in_menu: bool,
  635        preview_requires_modifier: bool,
  636    },
  637}
  638
  639enum InlineCompletionHighlight {}
  640
  641#[derive(Debug, Clone)]
  642struct InlineDiagnostic {
  643    message: SharedString,
  644    group_id: usize,
  645    is_primary: bool,
  646    start: Point,
  647    severity: lsp::DiagnosticSeverity,
  648}
  649
  650pub enum MenuInlineCompletionsPolicy {
  651    Never,
  652    ByProvider,
  653}
  654
  655pub enum EditPredictionPreview {
  656    /// Modifier is not pressed
  657    Inactive { released_too_fast: bool },
  658    /// Modifier pressed
  659    Active {
  660        since: Instant,
  661        previous_scroll_position: Option<ScrollAnchor>,
  662    },
  663}
  664
  665impl EditPredictionPreview {
  666    pub fn released_too_fast(&self) -> bool {
  667        match self {
  668            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  669            EditPredictionPreview::Active { .. } => false,
  670        }
  671    }
  672
  673    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  674        if let EditPredictionPreview::Active {
  675            previous_scroll_position,
  676            ..
  677        } = self
  678        {
  679            *previous_scroll_position = scroll_position;
  680        }
  681    }
  682}
  683
  684pub struct ContextMenuOptions {
  685    pub min_entries_visible: usize,
  686    pub max_entries_visible: usize,
  687    pub placement: Option<ContextMenuPlacement>,
  688}
  689
  690#[derive(Debug, Clone, PartialEq, Eq)]
  691pub enum ContextMenuPlacement {
  692    Above,
  693    Below,
  694}
  695
  696#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  697struct EditorActionId(usize);
  698
  699impl EditorActionId {
  700    pub fn post_inc(&mut self) -> Self {
  701        let answer = self.0;
  702
  703        *self = Self(answer + 1);
  704
  705        Self(answer)
  706    }
  707}
  708
  709// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  710// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  711
  712#[derive(Clone)]
  713pub struct BackgroundHighlight {
  714    pub range: Range<Anchor>,
  715    pub color_fetcher: fn(&Theme) -> Hsla,
  716}
  717
  718type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  719
  720#[derive(Default)]
  721struct ScrollbarMarkerState {
  722    scrollbar_size: Size<Pixels>,
  723    dirty: bool,
  724    markers: Arc<[PaintQuad]>,
  725    pending_refresh: Option<Task<Result<()>>>,
  726}
  727
  728impl ScrollbarMarkerState {
  729    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  730        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  731    }
  732}
  733
  734#[derive(Clone, Copy, PartialEq, Eq)]
  735pub enum MinimapVisibility {
  736    Disabled,
  737    Enabled {
  738        /// The configuration currently present in the users settings.
  739        setting_configuration: bool,
  740        /// Whether to override the currently set visibility from the users setting.
  741        toggle_override: bool,
  742    },
  743}
  744
  745impl MinimapVisibility {
  746    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  747        if mode.is_full() {
  748            Self::Enabled {
  749                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  750                toggle_override: false,
  751            }
  752        } else {
  753            Self::Disabled
  754        }
  755    }
  756
  757    fn hidden(&self) -> Self {
  758        match *self {
  759            Self::Enabled {
  760                setting_configuration,
  761                ..
  762            } => Self::Enabled {
  763                setting_configuration,
  764                toggle_override: setting_configuration,
  765            },
  766            Self::Disabled => Self::Disabled,
  767        }
  768    }
  769
  770    fn disabled(&self) -> bool {
  771        match *self {
  772            Self::Disabled => true,
  773            _ => false,
  774        }
  775    }
  776
  777    fn settings_visibility(&self) -> bool {
  778        match *self {
  779            Self::Enabled {
  780                setting_configuration,
  781                ..
  782            } => setting_configuration,
  783            _ => false,
  784        }
  785    }
  786
  787    fn visible(&self) -> bool {
  788        match *self {
  789            Self::Enabled {
  790                setting_configuration,
  791                toggle_override,
  792            } => setting_configuration ^ toggle_override,
  793            _ => false,
  794        }
  795    }
  796
  797    fn toggle_visibility(&self) -> Self {
  798        match *self {
  799            Self::Enabled {
  800                toggle_override,
  801                setting_configuration,
  802            } => Self::Enabled {
  803                setting_configuration,
  804                toggle_override: !toggle_override,
  805            },
  806            Self::Disabled => Self::Disabled,
  807        }
  808    }
  809}
  810
  811#[derive(Clone, Debug)]
  812struct RunnableTasks {
  813    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  814    offset: multi_buffer::Anchor,
  815    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  816    column: u32,
  817    // Values of all named captures, including those starting with '_'
  818    extra_variables: HashMap<String, String>,
  819    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  820    context_range: Range<BufferOffset>,
  821}
  822
  823impl RunnableTasks {
  824    fn resolve<'a>(
  825        &'a self,
  826        cx: &'a task::TaskContext,
  827    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  828        self.templates.iter().filter_map(|(kind, template)| {
  829            template
  830                .resolve_task(&kind.to_id_base(), cx)
  831                .map(|task| (kind.clone(), task))
  832        })
  833    }
  834}
  835
  836#[derive(Clone)]
  837pub struct ResolvedTasks {
  838    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  839    position: Anchor,
  840}
  841
  842#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  843struct BufferOffset(usize);
  844
  845// Addons allow storing per-editor state in other crates (e.g. Vim)
  846pub trait Addon: 'static {
  847    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  848
  849    fn render_buffer_header_controls(
  850        &self,
  851        _: &ExcerptInfo,
  852        _: &Window,
  853        _: &App,
  854    ) -> Option<AnyElement> {
  855        None
  856    }
  857
  858    fn to_any(&self) -> &dyn std::any::Any;
  859
  860    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  861        None
  862    }
  863}
  864
  865/// A set of caret positions, registered when the editor was edited.
  866pub struct ChangeList {
  867    changes: Vec<Vec<Anchor>>,
  868    /// Currently "selected" change.
  869    position: Option<usize>,
  870}
  871
  872impl ChangeList {
  873    pub fn new() -> Self {
  874        Self {
  875            changes: Vec::new(),
  876            position: None,
  877        }
  878    }
  879
  880    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  881    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  882    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  883        if self.changes.is_empty() {
  884            return None;
  885        }
  886
  887        let prev = self.position.unwrap_or(self.changes.len());
  888        let next = if direction == Direction::Prev {
  889            prev.saturating_sub(count)
  890        } else {
  891            (prev + count).min(self.changes.len() - 1)
  892        };
  893        self.position = Some(next);
  894        self.changes.get(next).map(|anchors| anchors.as_slice())
  895    }
  896
  897    /// Adds a new change to the list, resetting the change list position.
  898    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  899        self.position.take();
  900        if pop_state {
  901            self.changes.pop();
  902        }
  903        self.changes.push(new_positions.clone());
  904    }
  905
  906    pub fn last(&self) -> Option<&[Anchor]> {
  907        self.changes.last().map(|anchors| anchors.as_slice())
  908    }
  909}
  910
  911#[derive(Clone)]
  912struct InlineBlamePopoverState {
  913    scroll_handle: ScrollHandle,
  914    commit_message: Option<ParsedCommitMessage>,
  915    markdown: Entity<Markdown>,
  916}
  917
  918struct InlineBlamePopover {
  919    position: gpui::Point<Pixels>,
  920    hide_task: Option<Task<()>>,
  921    popover_bounds: Option<Bounds<Pixels>>,
  922    popover_state: InlineBlamePopoverState,
  923}
  924
  925enum SelectionDragState {
  926    /// State when no drag related activity is detected.
  927    None,
  928    /// State when the mouse is down on a selection that is about to be dragged.
  929    ReadyToDrag {
  930        selection: Selection<Anchor>,
  931        click_position: gpui::Point<Pixels>,
  932        mouse_down_time: Instant,
  933    },
  934    /// State when the mouse is dragging the selection in the editor.
  935    Dragging {
  936        selection: Selection<Anchor>,
  937        drop_cursor: Selection<Anchor>,
  938        hide_drop_cursor: bool,
  939    },
  940}
  941
  942enum ColumnarSelectionState {
  943    FromMouse {
  944        selection_tail: Anchor,
  945        display_point: Option<DisplayPoint>,
  946    },
  947    FromSelection {
  948        selection_tail: Anchor,
  949    },
  950}
  951
  952/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  953/// a breakpoint on them.
  954#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  955struct PhantomBreakpointIndicator {
  956    display_row: DisplayRow,
  957    /// There's a small debounce between hovering over the line and showing the indicator.
  958    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  959    is_active: bool,
  960    collides_with_existing_breakpoint: bool,
  961}
  962
  963/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  964///
  965/// See the [module level documentation](self) for more information.
  966pub struct Editor {
  967    focus_handle: FocusHandle,
  968    last_focused_descendant: Option<WeakFocusHandle>,
  969    /// The text buffer being edited
  970    buffer: Entity<MultiBuffer>,
  971    /// Map of how text in the buffer should be displayed.
  972    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  973    pub display_map: Entity<DisplayMap>,
  974    pub selections: SelectionsCollection,
  975    pub scroll_manager: ScrollManager,
  976    /// When inline assist editors are linked, they all render cursors because
  977    /// typing enters text into each of them, even the ones that aren't focused.
  978    pub(crate) show_cursor_when_unfocused: bool,
  979    columnar_selection_state: Option<ColumnarSelectionState>,
  980    add_selections_state: Option<AddSelectionsState>,
  981    select_next_state: Option<SelectNextState>,
  982    select_prev_state: Option<SelectNextState>,
  983    selection_history: SelectionHistory,
  984    defer_selection_effects: bool,
  985    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  986    autoclose_regions: Vec<AutocloseRegion>,
  987    snippet_stack: InvalidationStack<SnippetState>,
  988    select_syntax_node_history: SelectSyntaxNodeHistory,
  989    ime_transaction: Option<TransactionId>,
  990    pub diagnostics_max_severity: DiagnosticSeverity,
  991    active_diagnostics: ActiveDiagnostic,
  992    show_inline_diagnostics: bool,
  993    inline_diagnostics_update: Task<()>,
  994    inline_diagnostics_enabled: bool,
  995    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  996    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  997    hard_wrap: Option<usize>,
  998
  999    // TODO: make this a access method
 1000    pub project: Option<Entity<Project>>,
 1001    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1002    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1003    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1004    blink_manager: Entity<BlinkManager>,
 1005    show_cursor_names: bool,
 1006    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1007    pub show_local_selections: bool,
 1008    mode: EditorMode,
 1009    show_breadcrumbs: bool,
 1010    show_gutter: bool,
 1011    show_scrollbars: ScrollbarAxes,
 1012    minimap_visibility: MinimapVisibility,
 1013    offset_content: bool,
 1014    disable_expand_excerpt_buttons: bool,
 1015    show_line_numbers: Option<bool>,
 1016    use_relative_line_numbers: Option<bool>,
 1017    show_git_diff_gutter: Option<bool>,
 1018    show_code_actions: Option<bool>,
 1019    show_runnables: Option<bool>,
 1020    show_breakpoints: Option<bool>,
 1021    show_wrap_guides: Option<bool>,
 1022    show_indent_guides: Option<bool>,
 1023    placeholder_text: Option<Arc<str>>,
 1024    highlight_order: usize,
 1025    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1026    background_highlights: TreeMap<TypeId, Vec<BackgroundHighlight>>,
 1027    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1028    scrollbar_marker_state: ScrollbarMarkerState,
 1029    active_indent_guides_state: ActiveIndentGuidesState,
 1030    nav_history: Option<ItemNavHistory>,
 1031    context_menu: RefCell<Option<CodeContextMenu>>,
 1032    context_menu_options: Option<ContextMenuOptions>,
 1033    mouse_context_menu: Option<MouseContextMenu>,
 1034    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1035    inline_blame_popover: Option<InlineBlamePopover>,
 1036    inline_blame_popover_show_task: Option<Task<()>>,
 1037    signature_help_state: SignatureHelpState,
 1038    auto_signature_help: Option<bool>,
 1039    find_all_references_task_sources: Vec<Anchor>,
 1040    next_completion_id: CompletionId,
 1041    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1042    code_actions_task: Option<Task<Result<()>>>,
 1043    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1044    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1045    document_highlights_task: Option<Task<()>>,
 1046    linked_editing_range_task: Option<Task<Option<()>>>,
 1047    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1048    pending_rename: Option<RenameState>,
 1049    searchable: bool,
 1050    cursor_shape: CursorShape,
 1051    current_line_highlight: Option<CurrentLineHighlight>,
 1052    collapse_matches: bool,
 1053    autoindent_mode: Option<AutoindentMode>,
 1054    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1055    input_enabled: bool,
 1056    use_modal_editing: bool,
 1057    read_only: bool,
 1058    leader_id: Option<CollaboratorId>,
 1059    remote_id: Option<ViewId>,
 1060    pub hover_state: HoverState,
 1061    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1062    gutter_hovered: bool,
 1063    hovered_link_state: Option<HoveredLinkState>,
 1064    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1065    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1066    active_inline_completion: Option<InlineCompletionState>,
 1067    /// Used to prevent flickering as the user types while the menu is open
 1068    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1069    edit_prediction_settings: EditPredictionSettings,
 1070    inline_completions_hidden_for_vim_mode: bool,
 1071    show_inline_completions_override: Option<bool>,
 1072    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1073    edit_prediction_preview: EditPredictionPreview,
 1074    edit_prediction_indent_conflict: bool,
 1075    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1076    inlay_hint_cache: InlayHintCache,
 1077    next_inlay_id: usize,
 1078    _subscriptions: Vec<Subscription>,
 1079    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1080    gutter_dimensions: GutterDimensions,
 1081    style: Option<EditorStyle>,
 1082    text_style_refinement: Option<TextStyleRefinement>,
 1083    next_editor_action_id: EditorActionId,
 1084    editor_actions: Rc<
 1085        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1086    >,
 1087    use_autoclose: bool,
 1088    use_auto_surround: bool,
 1089    auto_replace_emoji_shortcode: bool,
 1090    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1091    show_git_blame_gutter: bool,
 1092    show_git_blame_inline: bool,
 1093    show_git_blame_inline_delay_task: Option<Task<()>>,
 1094    git_blame_inline_enabled: bool,
 1095    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1096    serialize_dirty_buffers: bool,
 1097    show_selection_menu: Option<bool>,
 1098    blame: Option<Entity<GitBlame>>,
 1099    blame_subscription: Option<Subscription>,
 1100    custom_context_menu: Option<
 1101        Box<
 1102            dyn 'static
 1103                + Fn(
 1104                    &mut Self,
 1105                    DisplayPoint,
 1106                    &mut Window,
 1107                    &mut Context<Self>,
 1108                ) -> Option<Entity<ui::ContextMenu>>,
 1109        >,
 1110    >,
 1111    last_bounds: Option<Bounds<Pixels>>,
 1112    last_position_map: Option<Rc<PositionMap>>,
 1113    expect_bounds_change: Option<Bounds<Pixels>>,
 1114    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1115    tasks_update_task: Option<Task<()>>,
 1116    breakpoint_store: Option<Entity<BreakpointStore>>,
 1117    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1118    hovered_diff_hunk_row: Option<DisplayRow>,
 1119    pull_diagnostics_task: Task<()>,
 1120    in_project_search: bool,
 1121    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1122    breadcrumb_header: Option<String>,
 1123    focused_block: Option<FocusedBlock>,
 1124    next_scroll_position: NextScrollCursorCenterTopBottom,
 1125    addons: HashMap<TypeId, Box<dyn Addon>>,
 1126    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1127    load_diff_task: Option<Shared<Task<()>>>,
 1128    /// Whether we are temporarily displaying a diff other than git's
 1129    temporary_diff_override: bool,
 1130    selection_mark_mode: bool,
 1131    toggle_fold_multiple_buffers: Task<()>,
 1132    _scroll_cursor_center_top_bottom_task: Task<()>,
 1133    serialize_selections: Task<()>,
 1134    serialize_folds: Task<()>,
 1135    mouse_cursor_hidden: bool,
 1136    minimap: Option<Entity<Self>>,
 1137    hide_mouse_mode: HideMouseMode,
 1138    pub change_list: ChangeList,
 1139    inline_value_cache: InlineValueCache,
 1140    selection_drag_state: SelectionDragState,
 1141    drag_and_drop_selection_enabled: bool,
 1142    next_color_inlay_id: usize,
 1143    colors: Option<LspColorData>,
 1144}
 1145
 1146#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1147enum NextScrollCursorCenterTopBottom {
 1148    #[default]
 1149    Center,
 1150    Top,
 1151    Bottom,
 1152}
 1153
 1154impl NextScrollCursorCenterTopBottom {
 1155    fn next(&self) -> Self {
 1156        match self {
 1157            Self::Center => Self::Top,
 1158            Self::Top => Self::Bottom,
 1159            Self::Bottom => Self::Center,
 1160        }
 1161    }
 1162}
 1163
 1164#[derive(Clone)]
 1165pub struct EditorSnapshot {
 1166    pub mode: EditorMode,
 1167    show_gutter: bool,
 1168    show_line_numbers: Option<bool>,
 1169    show_git_diff_gutter: Option<bool>,
 1170    show_code_actions: Option<bool>,
 1171    show_runnables: Option<bool>,
 1172    show_breakpoints: Option<bool>,
 1173    git_blame_gutter_max_author_length: Option<usize>,
 1174    pub display_snapshot: DisplaySnapshot,
 1175    pub placeholder_text: Option<Arc<str>>,
 1176    is_focused: bool,
 1177    scroll_anchor: ScrollAnchor,
 1178    ongoing_scroll: OngoingScroll,
 1179    current_line_highlight: CurrentLineHighlight,
 1180    gutter_hovered: bool,
 1181}
 1182
 1183#[derive(Default, Debug, Clone, Copy)]
 1184pub struct GutterDimensions {
 1185    pub left_padding: Pixels,
 1186    pub right_padding: Pixels,
 1187    pub width: Pixels,
 1188    pub margin: Pixels,
 1189    pub git_blame_entries_width: Option<Pixels>,
 1190}
 1191
 1192impl GutterDimensions {
 1193    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1194        Self {
 1195            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1196            ..Default::default()
 1197        }
 1198    }
 1199
 1200    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1201        -cx.text_system().descent(font_id, font_size)
 1202    }
 1203    /// The full width of the space taken up by the gutter.
 1204    pub fn full_width(&self) -> Pixels {
 1205        self.margin + self.width
 1206    }
 1207
 1208    /// The width of the space reserved for the fold indicators,
 1209    /// use alongside 'justify_end' and `gutter_width` to
 1210    /// right align content with the line numbers
 1211    pub fn fold_area_width(&self) -> Pixels {
 1212        self.margin + self.right_padding
 1213    }
 1214}
 1215
 1216#[derive(Debug)]
 1217pub struct RemoteSelection {
 1218    pub replica_id: ReplicaId,
 1219    pub selection: Selection<Anchor>,
 1220    pub cursor_shape: CursorShape,
 1221    pub collaborator_id: CollaboratorId,
 1222    pub line_mode: bool,
 1223    pub user_name: Option<SharedString>,
 1224    pub color: PlayerColor,
 1225}
 1226
 1227#[derive(Clone, Debug)]
 1228struct SelectionHistoryEntry {
 1229    selections: Arc<[Selection<Anchor>]>,
 1230    select_next_state: Option<SelectNextState>,
 1231    select_prev_state: Option<SelectNextState>,
 1232    add_selections_state: Option<AddSelectionsState>,
 1233}
 1234
 1235#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1236enum SelectionHistoryMode {
 1237    Normal,
 1238    Undoing,
 1239    Redoing,
 1240    Skipping,
 1241}
 1242
 1243#[derive(Clone, PartialEq, Eq, Hash)]
 1244struct HoveredCursor {
 1245    replica_id: u16,
 1246    selection_id: usize,
 1247}
 1248
 1249impl Default for SelectionHistoryMode {
 1250    fn default() -> Self {
 1251        Self::Normal
 1252    }
 1253}
 1254
 1255#[derive(Debug)]
 1256pub struct SelectionEffects {
 1257    nav_history: bool,
 1258    completions: bool,
 1259    scroll: Option<Autoscroll>,
 1260}
 1261
 1262impl Default for SelectionEffects {
 1263    fn default() -> Self {
 1264        Self {
 1265            nav_history: true,
 1266            completions: true,
 1267            scroll: Some(Autoscroll::fit()),
 1268        }
 1269    }
 1270}
 1271impl SelectionEffects {
 1272    pub fn scroll(scroll: Autoscroll) -> Self {
 1273        Self {
 1274            scroll: Some(scroll),
 1275            ..Default::default()
 1276        }
 1277    }
 1278
 1279    pub fn no_scroll() -> Self {
 1280        Self {
 1281            scroll: None,
 1282            ..Default::default()
 1283        }
 1284    }
 1285
 1286    pub fn completions(self, completions: bool) -> Self {
 1287        Self {
 1288            completions,
 1289            ..self
 1290        }
 1291    }
 1292
 1293    pub fn nav_history(self, nav_history: bool) -> Self {
 1294        Self {
 1295            nav_history,
 1296            ..self
 1297        }
 1298    }
 1299}
 1300
 1301struct DeferredSelectionEffectsState {
 1302    changed: bool,
 1303    effects: SelectionEffects,
 1304    old_cursor_position: Anchor,
 1305    history_entry: SelectionHistoryEntry,
 1306}
 1307
 1308#[derive(Default)]
 1309struct SelectionHistory {
 1310    #[allow(clippy::type_complexity)]
 1311    selections_by_transaction:
 1312        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1313    mode: SelectionHistoryMode,
 1314    undo_stack: VecDeque<SelectionHistoryEntry>,
 1315    redo_stack: VecDeque<SelectionHistoryEntry>,
 1316}
 1317
 1318impl SelectionHistory {
 1319    #[track_caller]
 1320    fn insert_transaction(
 1321        &mut self,
 1322        transaction_id: TransactionId,
 1323        selections: Arc<[Selection<Anchor>]>,
 1324    ) {
 1325        if selections.is_empty() {
 1326            log::error!(
 1327                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1328                std::panic::Location::caller()
 1329            );
 1330            return;
 1331        }
 1332        self.selections_by_transaction
 1333            .insert(transaction_id, (selections, None));
 1334    }
 1335
 1336    #[allow(clippy::type_complexity)]
 1337    fn transaction(
 1338        &self,
 1339        transaction_id: TransactionId,
 1340    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1341        self.selections_by_transaction.get(&transaction_id)
 1342    }
 1343
 1344    #[allow(clippy::type_complexity)]
 1345    fn transaction_mut(
 1346        &mut self,
 1347        transaction_id: TransactionId,
 1348    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1349        self.selections_by_transaction.get_mut(&transaction_id)
 1350    }
 1351
 1352    fn push(&mut self, entry: SelectionHistoryEntry) {
 1353        if !entry.selections.is_empty() {
 1354            match self.mode {
 1355                SelectionHistoryMode::Normal => {
 1356                    self.push_undo(entry);
 1357                    self.redo_stack.clear();
 1358                }
 1359                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1360                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1361                SelectionHistoryMode::Skipping => {}
 1362            }
 1363        }
 1364    }
 1365
 1366    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1367        if self
 1368            .undo_stack
 1369            .back()
 1370            .map_or(true, |e| e.selections != entry.selections)
 1371        {
 1372            self.undo_stack.push_back(entry);
 1373            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1374                self.undo_stack.pop_front();
 1375            }
 1376        }
 1377    }
 1378
 1379    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1380        if self
 1381            .redo_stack
 1382            .back()
 1383            .map_or(true, |e| e.selections != entry.selections)
 1384        {
 1385            self.redo_stack.push_back(entry);
 1386            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1387                self.redo_stack.pop_front();
 1388            }
 1389        }
 1390    }
 1391}
 1392
 1393#[derive(Clone, Copy)]
 1394pub struct RowHighlightOptions {
 1395    pub autoscroll: bool,
 1396    pub include_gutter: bool,
 1397}
 1398
 1399impl Default for RowHighlightOptions {
 1400    fn default() -> Self {
 1401        Self {
 1402            autoscroll: Default::default(),
 1403            include_gutter: true,
 1404        }
 1405    }
 1406}
 1407
 1408struct RowHighlight {
 1409    index: usize,
 1410    range: Range<Anchor>,
 1411    color: Hsla,
 1412    options: RowHighlightOptions,
 1413    type_id: TypeId,
 1414}
 1415
 1416#[derive(Clone, Debug)]
 1417struct AddSelectionsState {
 1418    groups: Vec<AddSelectionsGroup>,
 1419}
 1420
 1421#[derive(Clone, Debug)]
 1422struct AddSelectionsGroup {
 1423    above: bool,
 1424    stack: Vec<usize>,
 1425}
 1426
 1427#[derive(Clone)]
 1428struct SelectNextState {
 1429    query: AhoCorasick,
 1430    wordwise: bool,
 1431    done: bool,
 1432}
 1433
 1434impl std::fmt::Debug for SelectNextState {
 1435    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1436        f.debug_struct(std::any::type_name::<Self>())
 1437            .field("wordwise", &self.wordwise)
 1438            .field("done", &self.done)
 1439            .finish()
 1440    }
 1441}
 1442
 1443#[derive(Debug)]
 1444struct AutocloseRegion {
 1445    selection_id: usize,
 1446    range: Range<Anchor>,
 1447    pair: BracketPair,
 1448}
 1449
 1450#[derive(Debug)]
 1451struct SnippetState {
 1452    ranges: Vec<Vec<Range<Anchor>>>,
 1453    active_index: usize,
 1454    choices: Vec<Option<Vec<String>>>,
 1455}
 1456
 1457#[doc(hidden)]
 1458pub struct RenameState {
 1459    pub range: Range<Anchor>,
 1460    pub old_name: Arc<str>,
 1461    pub editor: Entity<Editor>,
 1462    block_id: CustomBlockId,
 1463}
 1464
 1465struct InvalidationStack<T>(Vec<T>);
 1466
 1467struct RegisteredInlineCompletionProvider {
 1468    provider: Arc<dyn InlineCompletionProviderHandle>,
 1469    _subscription: Subscription,
 1470}
 1471
 1472#[derive(Debug, PartialEq, Eq)]
 1473pub struct ActiveDiagnosticGroup {
 1474    pub active_range: Range<Anchor>,
 1475    pub active_message: String,
 1476    pub group_id: usize,
 1477    pub blocks: HashSet<CustomBlockId>,
 1478}
 1479
 1480#[derive(Debug, PartialEq, Eq)]
 1481
 1482pub(crate) enum ActiveDiagnostic {
 1483    None,
 1484    All,
 1485    Group(ActiveDiagnosticGroup),
 1486}
 1487
 1488#[derive(Serialize, Deserialize, Clone, Debug)]
 1489pub struct ClipboardSelection {
 1490    /// The number of bytes in this selection.
 1491    pub len: usize,
 1492    /// Whether this was a full-line selection.
 1493    pub is_entire_line: bool,
 1494    /// The indentation of the first line when this content was originally copied.
 1495    pub first_line_indent: u32,
 1496}
 1497
 1498// selections, scroll behavior, was newest selection reversed
 1499type SelectSyntaxNodeHistoryState = (
 1500    Box<[Selection<usize>]>,
 1501    SelectSyntaxNodeScrollBehavior,
 1502    bool,
 1503);
 1504
 1505#[derive(Default)]
 1506struct SelectSyntaxNodeHistory {
 1507    stack: Vec<SelectSyntaxNodeHistoryState>,
 1508    // disable temporarily to allow changing selections without losing the stack
 1509    pub disable_clearing: bool,
 1510}
 1511
 1512impl SelectSyntaxNodeHistory {
 1513    pub fn try_clear(&mut self) {
 1514        if !self.disable_clearing {
 1515            self.stack.clear();
 1516        }
 1517    }
 1518
 1519    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1520        self.stack.push(selection);
 1521    }
 1522
 1523    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1524        self.stack.pop()
 1525    }
 1526}
 1527
 1528enum SelectSyntaxNodeScrollBehavior {
 1529    CursorTop,
 1530    FitSelection,
 1531    CursorBottom,
 1532}
 1533
 1534#[derive(Debug)]
 1535pub(crate) struct NavigationData {
 1536    cursor_anchor: Anchor,
 1537    cursor_position: Point,
 1538    scroll_anchor: ScrollAnchor,
 1539    scroll_top_row: u32,
 1540}
 1541
 1542#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1543pub enum GotoDefinitionKind {
 1544    Symbol,
 1545    Declaration,
 1546    Type,
 1547    Implementation,
 1548}
 1549
 1550#[derive(Debug, Clone)]
 1551enum InlayHintRefreshReason {
 1552    ModifiersChanged(bool),
 1553    Toggle(bool),
 1554    SettingsChange(InlayHintSettings),
 1555    NewLinesShown,
 1556    BufferEdited(HashSet<Arc<Language>>),
 1557    RefreshRequested,
 1558    ExcerptsRemoved(Vec<ExcerptId>),
 1559}
 1560
 1561impl InlayHintRefreshReason {
 1562    fn description(&self) -> &'static str {
 1563        match self {
 1564            Self::ModifiersChanged(_) => "modifiers changed",
 1565            Self::Toggle(_) => "toggle",
 1566            Self::SettingsChange(_) => "settings change",
 1567            Self::NewLinesShown => "new lines shown",
 1568            Self::BufferEdited(_) => "buffer edited",
 1569            Self::RefreshRequested => "refresh requested",
 1570            Self::ExcerptsRemoved(_) => "excerpts removed",
 1571        }
 1572    }
 1573}
 1574
 1575pub enum FormatTarget {
 1576    Buffers(HashSet<Entity<Buffer>>),
 1577    Ranges(Vec<Range<MultiBufferPoint>>),
 1578}
 1579
 1580pub(crate) struct FocusedBlock {
 1581    id: BlockId,
 1582    focus_handle: WeakFocusHandle,
 1583}
 1584
 1585#[derive(Clone)]
 1586enum JumpData {
 1587    MultiBufferRow {
 1588        row: MultiBufferRow,
 1589        line_offset_from_top: u32,
 1590    },
 1591    MultiBufferPoint {
 1592        excerpt_id: ExcerptId,
 1593        position: Point,
 1594        anchor: text::Anchor,
 1595        line_offset_from_top: u32,
 1596    },
 1597}
 1598
 1599pub enum MultibufferSelectionMode {
 1600    First,
 1601    All,
 1602}
 1603
 1604#[derive(Clone, Copy, Debug, Default)]
 1605pub struct RewrapOptions {
 1606    pub override_language_settings: bool,
 1607    pub preserve_existing_whitespace: bool,
 1608}
 1609
 1610impl Editor {
 1611    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1612        let buffer = cx.new(|cx| Buffer::local("", cx));
 1613        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1614        Self::new(
 1615            EditorMode::SingleLine { auto_width: false },
 1616            buffer,
 1617            None,
 1618            window,
 1619            cx,
 1620        )
 1621    }
 1622
 1623    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1624        let buffer = cx.new(|cx| Buffer::local("", cx));
 1625        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1626        Self::new(EditorMode::full(), buffer, None, window, cx)
 1627    }
 1628
 1629    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1630        let buffer = cx.new(|cx| Buffer::local("", cx));
 1631        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1632        Self::new(
 1633            EditorMode::SingleLine { auto_width: true },
 1634            buffer,
 1635            None,
 1636            window,
 1637            cx,
 1638        )
 1639    }
 1640
 1641    pub fn auto_height(
 1642        min_lines: usize,
 1643        max_lines: usize,
 1644        window: &mut Window,
 1645        cx: &mut Context<Self>,
 1646    ) -> Self {
 1647        let buffer = cx.new(|cx| Buffer::local("", cx));
 1648        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1649        Self::new(
 1650            EditorMode::AutoHeight {
 1651                min_lines,
 1652                max_lines,
 1653            },
 1654            buffer,
 1655            None,
 1656            window,
 1657            cx,
 1658        )
 1659    }
 1660
 1661    pub fn for_buffer(
 1662        buffer: Entity<Buffer>,
 1663        project: Option<Entity<Project>>,
 1664        window: &mut Window,
 1665        cx: &mut Context<Self>,
 1666    ) -> Self {
 1667        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1668        Self::new(EditorMode::full(), buffer, project, window, cx)
 1669    }
 1670
 1671    pub fn for_multibuffer(
 1672        buffer: Entity<MultiBuffer>,
 1673        project: Option<Entity<Project>>,
 1674        window: &mut Window,
 1675        cx: &mut Context<Self>,
 1676    ) -> Self {
 1677        Self::new(EditorMode::full(), buffer, project, window, cx)
 1678    }
 1679
 1680    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1681        let mut clone = Self::new(
 1682            self.mode.clone(),
 1683            self.buffer.clone(),
 1684            self.project.clone(),
 1685            window,
 1686            cx,
 1687        );
 1688        self.display_map.update(cx, |display_map, cx| {
 1689            let snapshot = display_map.snapshot(cx);
 1690            clone.display_map.update(cx, |display_map, cx| {
 1691                display_map.set_state(&snapshot, cx);
 1692            });
 1693        });
 1694        clone.folds_did_change(cx);
 1695        clone.selections.clone_state(&self.selections);
 1696        clone.scroll_manager.clone_state(&self.scroll_manager);
 1697        clone.searchable = self.searchable;
 1698        clone.read_only = self.read_only;
 1699        clone
 1700    }
 1701
 1702    pub fn new(
 1703        mode: EditorMode,
 1704        buffer: Entity<MultiBuffer>,
 1705        project: Option<Entity<Project>>,
 1706        window: &mut Window,
 1707        cx: &mut Context<Self>,
 1708    ) -> Self {
 1709        Editor::new_internal(mode, buffer, project, None, window, cx)
 1710    }
 1711
 1712    fn new_internal(
 1713        mode: EditorMode,
 1714        buffer: Entity<MultiBuffer>,
 1715        project: Option<Entity<Project>>,
 1716        display_map: Option<Entity<DisplayMap>>,
 1717        window: &mut Window,
 1718        cx: &mut Context<Self>,
 1719    ) -> Self {
 1720        debug_assert!(
 1721            display_map.is_none() || mode.is_minimap(),
 1722            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1723        );
 1724
 1725        let full_mode = mode.is_full();
 1726        let diagnostics_max_severity = if full_mode {
 1727            EditorSettings::get_global(cx)
 1728                .diagnostics_max_severity
 1729                .unwrap_or(DiagnosticSeverity::Hint)
 1730        } else {
 1731            DiagnosticSeverity::Off
 1732        };
 1733        let style = window.text_style();
 1734        let font_size = style.font_size.to_pixels(window.rem_size());
 1735        let editor = cx.entity().downgrade();
 1736        let fold_placeholder = FoldPlaceholder {
 1737            constrain_width: true,
 1738            render: Arc::new(move |fold_id, fold_range, cx| {
 1739                let editor = editor.clone();
 1740                div()
 1741                    .id(fold_id)
 1742                    .bg(cx.theme().colors().ghost_element_background)
 1743                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1744                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1745                    .rounded_xs()
 1746                    .size_full()
 1747                    .cursor_pointer()
 1748                    .child("")
 1749                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1750                    .on_click(move |_, _window, cx| {
 1751                        editor
 1752                            .update(cx, |editor, cx| {
 1753                                editor.unfold_ranges(
 1754                                    &[fold_range.start..fold_range.end],
 1755                                    true,
 1756                                    false,
 1757                                    cx,
 1758                                );
 1759                                cx.stop_propagation();
 1760                            })
 1761                            .ok();
 1762                    })
 1763                    .into_any()
 1764            }),
 1765            merge_adjacent: true,
 1766            ..FoldPlaceholder::default()
 1767        };
 1768        let display_map = display_map.unwrap_or_else(|| {
 1769            cx.new(|cx| {
 1770                DisplayMap::new(
 1771                    buffer.clone(),
 1772                    style.font(),
 1773                    font_size,
 1774                    None,
 1775                    FILE_HEADER_HEIGHT,
 1776                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1777                    fold_placeholder,
 1778                    diagnostics_max_severity,
 1779                    cx,
 1780                )
 1781            })
 1782        });
 1783
 1784        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1785
 1786        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1787
 1788        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1789            .then(|| language_settings::SoftWrap::None);
 1790
 1791        let mut project_subscriptions = Vec::new();
 1792        if mode.is_full() {
 1793            if let Some(project) = project.as_ref() {
 1794                project_subscriptions.push(cx.subscribe_in(
 1795                    project,
 1796                    window,
 1797                    |editor, _, event, window, cx| match event {
 1798                        project::Event::RefreshCodeLens => {
 1799                            // we always query lens with actions, without storing them, always refreshing them
 1800                        }
 1801                        project::Event::RefreshInlayHints => {
 1802                            editor
 1803                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1804                        }
 1805                        project::Event::LanguageServerAdded(server_id, ..)
 1806                        | project::Event::LanguageServerRemoved(server_id) => {
 1807                            if editor.tasks_update_task.is_none() {
 1808                                editor.tasks_update_task =
 1809                                    Some(editor.refresh_runnables(window, cx));
 1810                            }
 1811                            editor.update_lsp_data(false, Some(*server_id), None, window, cx);
 1812                        }
 1813                        project::Event::SnippetEdit(id, snippet_edits) => {
 1814                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1815                                let focus_handle = editor.focus_handle(cx);
 1816                                if focus_handle.is_focused(window) {
 1817                                    let snapshot = buffer.read(cx).snapshot();
 1818                                    for (range, snippet) in snippet_edits {
 1819                                        let editor_range =
 1820                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1821                                        editor
 1822                                            .insert_snippet(
 1823                                                &[editor_range],
 1824                                                snippet.clone(),
 1825                                                window,
 1826                                                cx,
 1827                                            )
 1828                                            .ok();
 1829                                    }
 1830                                }
 1831                            }
 1832                        }
 1833                        _ => {}
 1834                    },
 1835                ));
 1836                if let Some(task_inventory) = project
 1837                    .read(cx)
 1838                    .task_store()
 1839                    .read(cx)
 1840                    .task_inventory()
 1841                    .cloned()
 1842                {
 1843                    project_subscriptions.push(cx.observe_in(
 1844                        &task_inventory,
 1845                        window,
 1846                        |editor, _, window, cx| {
 1847                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1848                        },
 1849                    ));
 1850                };
 1851
 1852                project_subscriptions.push(cx.subscribe_in(
 1853                    &project.read(cx).breakpoint_store(),
 1854                    window,
 1855                    |editor, _, event, window, cx| match event {
 1856                        BreakpointStoreEvent::ClearDebugLines => {
 1857                            editor.clear_row_highlights::<ActiveDebugLine>();
 1858                            editor.refresh_inline_values(cx);
 1859                        }
 1860                        BreakpointStoreEvent::SetDebugLine => {
 1861                            if editor.go_to_active_debug_line(window, cx) {
 1862                                cx.stop_propagation();
 1863                            }
 1864
 1865                            editor.refresh_inline_values(cx);
 1866                        }
 1867                        _ => {}
 1868                    },
 1869                ));
 1870                let git_store = project.read(cx).git_store().clone();
 1871                let project = project.clone();
 1872                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1873                    match event {
 1874                        GitStoreEvent::RepositoryUpdated(
 1875                            _,
 1876                            RepositoryEvent::Updated {
 1877                                new_instance: true, ..
 1878                            },
 1879                            _,
 1880                        ) => {
 1881                            this.load_diff_task = Some(
 1882                                update_uncommitted_diff_for_buffer(
 1883                                    cx.entity(),
 1884                                    &project,
 1885                                    this.buffer.read(cx).all_buffers(),
 1886                                    this.buffer.clone(),
 1887                                    cx,
 1888                                )
 1889                                .shared(),
 1890                            );
 1891                        }
 1892                        _ => {}
 1893                    }
 1894                }));
 1895            }
 1896        }
 1897
 1898        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1899
 1900        let inlay_hint_settings =
 1901            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1902        let focus_handle = cx.focus_handle();
 1903        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1904            .detach();
 1905        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1906            .detach();
 1907        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1908            .detach();
 1909        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1910            .detach();
 1911        cx.observe_pending_input(window, Self::observe_pending_input)
 1912            .detach();
 1913
 1914        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1915            Some(false)
 1916        } else {
 1917            None
 1918        };
 1919
 1920        let breakpoint_store = match (&mode, project.as_ref()) {
 1921            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1922            _ => None,
 1923        };
 1924
 1925        let mut code_action_providers = Vec::new();
 1926        let mut load_uncommitted_diff = None;
 1927        if let Some(project) = project.clone() {
 1928            load_uncommitted_diff = Some(
 1929                update_uncommitted_diff_for_buffer(
 1930                    cx.entity(),
 1931                    &project,
 1932                    buffer.read(cx).all_buffers(),
 1933                    buffer.clone(),
 1934                    cx,
 1935                )
 1936                .shared(),
 1937            );
 1938            code_action_providers.push(Rc::new(project) as Rc<_>);
 1939        }
 1940
 1941        let mut editor = Self {
 1942            focus_handle,
 1943            show_cursor_when_unfocused: false,
 1944            last_focused_descendant: None,
 1945            buffer: buffer.clone(),
 1946            display_map: display_map.clone(),
 1947            selections,
 1948            scroll_manager: ScrollManager::new(cx),
 1949            columnar_selection_state: None,
 1950            add_selections_state: None,
 1951            select_next_state: None,
 1952            select_prev_state: None,
 1953            selection_history: SelectionHistory::default(),
 1954            defer_selection_effects: false,
 1955            deferred_selection_effects_state: None,
 1956            autoclose_regions: Vec::new(),
 1957            snippet_stack: InvalidationStack::default(),
 1958            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1959            ime_transaction: None,
 1960            active_diagnostics: ActiveDiagnostic::None,
 1961            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1962            inline_diagnostics_update: Task::ready(()),
 1963            inline_diagnostics: Vec::new(),
 1964            soft_wrap_mode_override,
 1965            diagnostics_max_severity,
 1966            hard_wrap: None,
 1967            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1968            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1969            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1970            project,
 1971            blink_manager: blink_manager.clone(),
 1972            show_local_selections: true,
 1973            show_scrollbars: ScrollbarAxes {
 1974                horizontal: full_mode,
 1975                vertical: full_mode,
 1976            },
 1977            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1978            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1979            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1980            show_gutter: mode.is_full(),
 1981            show_line_numbers: None,
 1982            use_relative_line_numbers: None,
 1983            disable_expand_excerpt_buttons: false,
 1984            show_git_diff_gutter: None,
 1985            show_code_actions: None,
 1986            show_runnables: None,
 1987            show_breakpoints: None,
 1988            show_wrap_guides: None,
 1989            show_indent_guides,
 1990            placeholder_text: None,
 1991            highlight_order: 0,
 1992            highlighted_rows: HashMap::default(),
 1993            background_highlights: TreeMap::default(),
 1994            gutter_highlights: TreeMap::default(),
 1995            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1996            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1997            nav_history: None,
 1998            context_menu: RefCell::new(None),
 1999            context_menu_options: None,
 2000            mouse_context_menu: None,
 2001            completion_tasks: Vec::new(),
 2002            inline_blame_popover: None,
 2003            inline_blame_popover_show_task: None,
 2004            signature_help_state: SignatureHelpState::default(),
 2005            auto_signature_help: None,
 2006            find_all_references_task_sources: Vec::new(),
 2007            next_completion_id: 0,
 2008            next_inlay_id: 0,
 2009            code_action_providers,
 2010            available_code_actions: None,
 2011            code_actions_task: None,
 2012            quick_selection_highlight_task: None,
 2013            debounced_selection_highlight_task: None,
 2014            document_highlights_task: None,
 2015            linked_editing_range_task: None,
 2016            pending_rename: None,
 2017            searchable: true,
 2018            cursor_shape: EditorSettings::get_global(cx)
 2019                .cursor_shape
 2020                .unwrap_or_default(),
 2021            current_line_highlight: None,
 2022            autoindent_mode: Some(AutoindentMode::EachLine),
 2023            collapse_matches: false,
 2024            workspace: None,
 2025            input_enabled: true,
 2026            use_modal_editing: mode.is_full(),
 2027            read_only: mode.is_minimap(),
 2028            use_autoclose: true,
 2029            use_auto_surround: true,
 2030            auto_replace_emoji_shortcode: false,
 2031            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2032            leader_id: None,
 2033            remote_id: None,
 2034            hover_state: HoverState::default(),
 2035            pending_mouse_down: None,
 2036            hovered_link_state: None,
 2037            edit_prediction_provider: None,
 2038            active_inline_completion: None,
 2039            stale_inline_completion_in_menu: None,
 2040            edit_prediction_preview: EditPredictionPreview::Inactive {
 2041                released_too_fast: false,
 2042            },
 2043            inline_diagnostics_enabled: mode.is_full(),
 2044            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2045            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2046
 2047            gutter_hovered: false,
 2048            pixel_position_of_newest_cursor: None,
 2049            last_bounds: None,
 2050            last_position_map: None,
 2051            expect_bounds_change: None,
 2052            gutter_dimensions: GutterDimensions::default(),
 2053            style: None,
 2054            show_cursor_names: false,
 2055            hovered_cursors: HashMap::default(),
 2056            next_editor_action_id: EditorActionId::default(),
 2057            editor_actions: Rc::default(),
 2058            inline_completions_hidden_for_vim_mode: false,
 2059            show_inline_completions_override: None,
 2060            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2061            edit_prediction_settings: EditPredictionSettings::Disabled,
 2062            edit_prediction_indent_conflict: false,
 2063            edit_prediction_requires_modifier_in_indent_conflict: true,
 2064            custom_context_menu: None,
 2065            show_git_blame_gutter: false,
 2066            show_git_blame_inline: false,
 2067            show_selection_menu: None,
 2068            show_git_blame_inline_delay_task: None,
 2069            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2070            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2071            serialize_dirty_buffers: !mode.is_minimap()
 2072                && ProjectSettings::get_global(cx)
 2073                    .session
 2074                    .restore_unsaved_buffers,
 2075            blame: None,
 2076            blame_subscription: None,
 2077            tasks: BTreeMap::default(),
 2078
 2079            breakpoint_store,
 2080            gutter_breakpoint_indicator: (None, None),
 2081            hovered_diff_hunk_row: None,
 2082            _subscriptions: vec![
 2083                cx.observe(&buffer, Self::on_buffer_changed),
 2084                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2085                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2086                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2087                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2088                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2089                cx.observe_window_activation(window, |editor, window, cx| {
 2090                    let active = window.is_window_active();
 2091                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2092                        if active {
 2093                            blink_manager.enable(cx);
 2094                        } else {
 2095                            blink_manager.disable(cx);
 2096                        }
 2097                    });
 2098                    if active {
 2099                        editor.show_mouse_cursor(cx);
 2100                    }
 2101                }),
 2102            ],
 2103            tasks_update_task: None,
 2104            pull_diagnostics_task: Task::ready(()),
 2105            colors: None,
 2106            next_color_inlay_id: 0,
 2107            linked_edit_ranges: Default::default(),
 2108            in_project_search: false,
 2109            previous_search_ranges: None,
 2110            breadcrumb_header: None,
 2111            focused_block: None,
 2112            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2113            addons: HashMap::default(),
 2114            registered_buffers: HashMap::default(),
 2115            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2116            selection_mark_mode: false,
 2117            toggle_fold_multiple_buffers: Task::ready(()),
 2118            serialize_selections: Task::ready(()),
 2119            serialize_folds: Task::ready(()),
 2120            text_style_refinement: None,
 2121            load_diff_task: load_uncommitted_diff,
 2122            temporary_diff_override: false,
 2123            mouse_cursor_hidden: false,
 2124            minimap: None,
 2125            hide_mouse_mode: EditorSettings::get_global(cx)
 2126                .hide_mouse
 2127                .unwrap_or_default(),
 2128            change_list: ChangeList::new(),
 2129            mode,
 2130            selection_drag_state: SelectionDragState::None,
 2131            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2132        };
 2133        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2134            editor
 2135                ._subscriptions
 2136                .push(cx.observe(breakpoints, |_, _, cx| {
 2137                    cx.notify();
 2138                }));
 2139        }
 2140        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2141        editor._subscriptions.extend(project_subscriptions);
 2142
 2143        editor._subscriptions.push(cx.subscribe_in(
 2144            &cx.entity(),
 2145            window,
 2146            |editor, _, e: &EditorEvent, window, cx| match e {
 2147                EditorEvent::ScrollPositionChanged { local, .. } => {
 2148                    if *local {
 2149                        let new_anchor = editor.scroll_manager.anchor();
 2150                        let snapshot = editor.snapshot(window, cx);
 2151                        editor.update_restoration_data(cx, move |data| {
 2152                            data.scroll_position = (
 2153                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2154                                new_anchor.offset,
 2155                            );
 2156                        });
 2157                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2158                        editor.inline_blame_popover.take();
 2159                    }
 2160                }
 2161                EditorEvent::Edited { .. } => {
 2162                    if !vim_enabled(cx) {
 2163                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2164                        let pop_state = editor
 2165                            .change_list
 2166                            .last()
 2167                            .map(|previous| {
 2168                                previous.len() == selections.len()
 2169                                    && previous.iter().enumerate().all(|(ix, p)| {
 2170                                        p.to_display_point(&map).row()
 2171                                            == selections[ix].head().row()
 2172                                    })
 2173                            })
 2174                            .unwrap_or(false);
 2175                        let new_positions = selections
 2176                            .into_iter()
 2177                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2178                            .collect();
 2179                        editor
 2180                            .change_list
 2181                            .push_to_change_list(pop_state, new_positions);
 2182                    }
 2183                }
 2184                _ => (),
 2185            },
 2186        ));
 2187
 2188        if let Some(dap_store) = editor
 2189            .project
 2190            .as_ref()
 2191            .map(|project| project.read(cx).dap_store())
 2192        {
 2193            let weak_editor = cx.weak_entity();
 2194
 2195            editor
 2196                ._subscriptions
 2197                .push(
 2198                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2199                        let session_entity = cx.entity();
 2200                        weak_editor
 2201                            .update(cx, |editor, cx| {
 2202                                editor._subscriptions.push(
 2203                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2204                                );
 2205                            })
 2206                            .ok();
 2207                    }),
 2208                );
 2209
 2210            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2211                editor
 2212                    ._subscriptions
 2213                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2214            }
 2215        }
 2216
 2217        // skip adding the initial selection to selection history
 2218        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2219        editor.end_selection(window, cx);
 2220        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2221
 2222        editor.scroll_manager.show_scrollbars(window, cx);
 2223        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2224
 2225        if full_mode {
 2226            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2227            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2228
 2229            if editor.git_blame_inline_enabled {
 2230                editor.start_git_blame_inline(false, window, cx);
 2231            }
 2232
 2233            editor.go_to_active_debug_line(window, cx);
 2234
 2235            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2236                if let Some(project) = editor.project.as_ref() {
 2237                    let handle = project.update(cx, |project, cx| {
 2238                        project.register_buffer_with_language_servers(&buffer, cx)
 2239                    });
 2240                    editor
 2241                        .registered_buffers
 2242                        .insert(buffer.read(cx).remote_id(), handle);
 2243                }
 2244            }
 2245
 2246            editor.minimap =
 2247                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2248            editor.colors = Some(LspColorData::new(cx));
 2249            editor.update_lsp_data(false, None, None, window, cx);
 2250        }
 2251
 2252        editor.report_editor_event("Editor Opened", None, cx);
 2253        editor
 2254    }
 2255
 2256    pub fn deploy_mouse_context_menu(
 2257        &mut self,
 2258        position: gpui::Point<Pixels>,
 2259        context_menu: Entity<ContextMenu>,
 2260        window: &mut Window,
 2261        cx: &mut Context<Self>,
 2262    ) {
 2263        self.mouse_context_menu = Some(MouseContextMenu::new(
 2264            self,
 2265            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2266            context_menu,
 2267            window,
 2268            cx,
 2269        ));
 2270    }
 2271
 2272    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2273        self.mouse_context_menu
 2274            .as_ref()
 2275            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2276    }
 2277
 2278    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2279        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2280    }
 2281
 2282    fn key_context_internal(
 2283        &self,
 2284        has_active_edit_prediction: bool,
 2285        window: &Window,
 2286        cx: &App,
 2287    ) -> KeyContext {
 2288        let mut key_context = KeyContext::new_with_defaults();
 2289        key_context.add("Editor");
 2290        let mode = match self.mode {
 2291            EditorMode::SingleLine { .. } => "single_line",
 2292            EditorMode::AutoHeight { .. } => "auto_height",
 2293            EditorMode::Minimap { .. } => "minimap",
 2294            EditorMode::Full { .. } => "full",
 2295        };
 2296
 2297        if EditorSettings::jupyter_enabled(cx) {
 2298            key_context.add("jupyter");
 2299        }
 2300
 2301        key_context.set("mode", mode);
 2302        if self.pending_rename.is_some() {
 2303            key_context.add("renaming");
 2304        }
 2305
 2306        match self.context_menu.borrow().as_ref() {
 2307            Some(CodeContextMenu::Completions(_)) => {
 2308                key_context.add("menu");
 2309                key_context.add("showing_completions");
 2310            }
 2311            Some(CodeContextMenu::CodeActions(_)) => {
 2312                key_context.add("menu");
 2313                key_context.add("showing_code_actions")
 2314            }
 2315            None => {}
 2316        }
 2317
 2318        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2319        if !self.focus_handle(cx).contains_focused(window, cx)
 2320            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2321        {
 2322            for addon in self.addons.values() {
 2323                addon.extend_key_context(&mut key_context, cx)
 2324            }
 2325        }
 2326
 2327        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2328            if let Some(extension) = singleton_buffer
 2329                .read(cx)
 2330                .file()
 2331                .and_then(|file| file.path().extension()?.to_str())
 2332            {
 2333                key_context.set("extension", extension.to_string());
 2334            }
 2335        } else {
 2336            key_context.add("multibuffer");
 2337        }
 2338
 2339        if has_active_edit_prediction {
 2340            if self.edit_prediction_in_conflict() {
 2341                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2342            } else {
 2343                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2344                key_context.add("copilot_suggestion");
 2345            }
 2346        }
 2347
 2348        if self.selection_mark_mode {
 2349            key_context.add("selection_mode");
 2350        }
 2351
 2352        key_context
 2353    }
 2354
 2355    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2356        if self.mouse_cursor_hidden {
 2357            self.mouse_cursor_hidden = false;
 2358            cx.notify();
 2359        }
 2360    }
 2361
 2362    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2363        let hide_mouse_cursor = match origin {
 2364            HideMouseCursorOrigin::TypingAction => {
 2365                matches!(
 2366                    self.hide_mouse_mode,
 2367                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2368                )
 2369            }
 2370            HideMouseCursorOrigin::MovementAction => {
 2371                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2372            }
 2373        };
 2374        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2375            self.mouse_cursor_hidden = hide_mouse_cursor;
 2376            cx.notify();
 2377        }
 2378    }
 2379
 2380    pub fn edit_prediction_in_conflict(&self) -> bool {
 2381        if !self.show_edit_predictions_in_menu() {
 2382            return false;
 2383        }
 2384
 2385        let showing_completions = self
 2386            .context_menu
 2387            .borrow()
 2388            .as_ref()
 2389            .map_or(false, |context| {
 2390                matches!(context, CodeContextMenu::Completions(_))
 2391            });
 2392
 2393        showing_completions
 2394            || self.edit_prediction_requires_modifier()
 2395            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2396            // bindings to insert tab characters.
 2397            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2398    }
 2399
 2400    pub fn accept_edit_prediction_keybind(
 2401        &self,
 2402        accept_partial: bool,
 2403        window: &Window,
 2404        cx: &App,
 2405    ) -> AcceptEditPredictionBinding {
 2406        let key_context = self.key_context_internal(true, window, cx);
 2407        let in_conflict = self.edit_prediction_in_conflict();
 2408
 2409        let bindings = if accept_partial {
 2410            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2411        } else {
 2412            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2413        };
 2414
 2415        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2416        // just the first one.
 2417        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2418            !in_conflict
 2419                || binding
 2420                    .keystrokes()
 2421                    .first()
 2422                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2423        }))
 2424    }
 2425
 2426    pub fn new_file(
 2427        workspace: &mut Workspace,
 2428        _: &workspace::NewFile,
 2429        window: &mut Window,
 2430        cx: &mut Context<Workspace>,
 2431    ) {
 2432        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2433            "Failed to create buffer",
 2434            window,
 2435            cx,
 2436            |e, _, _| match e.error_code() {
 2437                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2438                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2439                e.error_tag("required").unwrap_or("the latest version")
 2440            )),
 2441                _ => None,
 2442            },
 2443        );
 2444    }
 2445
 2446    pub fn new_in_workspace(
 2447        workspace: &mut Workspace,
 2448        window: &mut Window,
 2449        cx: &mut Context<Workspace>,
 2450    ) -> Task<Result<Entity<Editor>>> {
 2451        let project = workspace.project().clone();
 2452        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2453
 2454        cx.spawn_in(window, async move |workspace, cx| {
 2455            let buffer = create.await?;
 2456            workspace.update_in(cx, |workspace, window, cx| {
 2457                let editor =
 2458                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2459                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2460                editor
 2461            })
 2462        })
 2463    }
 2464
 2465    fn new_file_vertical(
 2466        workspace: &mut Workspace,
 2467        _: &workspace::NewFileSplitVertical,
 2468        window: &mut Window,
 2469        cx: &mut Context<Workspace>,
 2470    ) {
 2471        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2472    }
 2473
 2474    fn new_file_horizontal(
 2475        workspace: &mut Workspace,
 2476        _: &workspace::NewFileSplitHorizontal,
 2477        window: &mut Window,
 2478        cx: &mut Context<Workspace>,
 2479    ) {
 2480        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2481    }
 2482
 2483    fn new_file_in_direction(
 2484        workspace: &mut Workspace,
 2485        direction: SplitDirection,
 2486        window: &mut Window,
 2487        cx: &mut Context<Workspace>,
 2488    ) {
 2489        let project = workspace.project().clone();
 2490        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2491
 2492        cx.spawn_in(window, async move |workspace, cx| {
 2493            let buffer = create.await?;
 2494            workspace.update_in(cx, move |workspace, window, cx| {
 2495                workspace.split_item(
 2496                    direction,
 2497                    Box::new(
 2498                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2499                    ),
 2500                    window,
 2501                    cx,
 2502                )
 2503            })?;
 2504            anyhow::Ok(())
 2505        })
 2506        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2507            match e.error_code() {
 2508                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2509                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2510                e.error_tag("required").unwrap_or("the latest version")
 2511            )),
 2512                _ => None,
 2513            }
 2514        });
 2515    }
 2516
 2517    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2518        self.leader_id
 2519    }
 2520
 2521    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2522        &self.buffer
 2523    }
 2524
 2525    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2526        self.workspace.as_ref()?.0.upgrade()
 2527    }
 2528
 2529    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2530        self.buffer().read(cx).title(cx)
 2531    }
 2532
 2533    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2534        let git_blame_gutter_max_author_length = self
 2535            .render_git_blame_gutter(cx)
 2536            .then(|| {
 2537                if let Some(blame) = self.blame.as_ref() {
 2538                    let max_author_length =
 2539                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2540                    Some(max_author_length)
 2541                } else {
 2542                    None
 2543                }
 2544            })
 2545            .flatten();
 2546
 2547        EditorSnapshot {
 2548            mode: self.mode.clone(),
 2549            show_gutter: self.show_gutter,
 2550            show_line_numbers: self.show_line_numbers,
 2551            show_git_diff_gutter: self.show_git_diff_gutter,
 2552            show_code_actions: self.show_code_actions,
 2553            show_runnables: self.show_runnables,
 2554            show_breakpoints: self.show_breakpoints,
 2555            git_blame_gutter_max_author_length,
 2556            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2557            scroll_anchor: self.scroll_manager.anchor(),
 2558            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2559            placeholder_text: self.placeholder_text.clone(),
 2560            is_focused: self.focus_handle.is_focused(window),
 2561            current_line_highlight: self
 2562                .current_line_highlight
 2563                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2564            gutter_hovered: self.gutter_hovered,
 2565        }
 2566    }
 2567
 2568    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2569        self.buffer.read(cx).language_at(point, cx)
 2570    }
 2571
 2572    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2573        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2574    }
 2575
 2576    pub fn active_excerpt(
 2577        &self,
 2578        cx: &App,
 2579    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2580        self.buffer
 2581            .read(cx)
 2582            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2583    }
 2584
 2585    pub fn mode(&self) -> &EditorMode {
 2586        &self.mode
 2587    }
 2588
 2589    pub fn set_mode(&mut self, mode: EditorMode) {
 2590        self.mode = mode;
 2591    }
 2592
 2593    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2594        self.collaboration_hub.as_deref()
 2595    }
 2596
 2597    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2598        self.collaboration_hub = Some(hub);
 2599    }
 2600
 2601    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2602        self.in_project_search = in_project_search;
 2603    }
 2604
 2605    pub fn set_custom_context_menu(
 2606        &mut self,
 2607        f: impl 'static
 2608        + Fn(
 2609            &mut Self,
 2610            DisplayPoint,
 2611            &mut Window,
 2612            &mut Context<Self>,
 2613        ) -> Option<Entity<ui::ContextMenu>>,
 2614    ) {
 2615        self.custom_context_menu = Some(Box::new(f))
 2616    }
 2617
 2618    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2619        self.completion_provider = provider;
 2620    }
 2621
 2622    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2623        self.semantics_provider.clone()
 2624    }
 2625
 2626    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2627        self.semantics_provider = provider;
 2628    }
 2629
 2630    pub fn set_edit_prediction_provider<T>(
 2631        &mut self,
 2632        provider: Option<Entity<T>>,
 2633        window: &mut Window,
 2634        cx: &mut Context<Self>,
 2635    ) where
 2636        T: EditPredictionProvider,
 2637    {
 2638        self.edit_prediction_provider =
 2639            provider.map(|provider| RegisteredInlineCompletionProvider {
 2640                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2641                    if this.focus_handle.is_focused(window) {
 2642                        this.update_visible_inline_completion(window, cx);
 2643                    }
 2644                }),
 2645                provider: Arc::new(provider),
 2646            });
 2647        self.update_edit_prediction_settings(cx);
 2648        self.refresh_inline_completion(false, false, window, cx);
 2649    }
 2650
 2651    pub fn placeholder_text(&self) -> Option<&str> {
 2652        self.placeholder_text.as_deref()
 2653    }
 2654
 2655    pub fn set_placeholder_text(
 2656        &mut self,
 2657        placeholder_text: impl Into<Arc<str>>,
 2658        cx: &mut Context<Self>,
 2659    ) {
 2660        let placeholder_text = Some(placeholder_text.into());
 2661        if self.placeholder_text != placeholder_text {
 2662            self.placeholder_text = placeholder_text;
 2663            cx.notify();
 2664        }
 2665    }
 2666
 2667    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2668        self.cursor_shape = cursor_shape;
 2669
 2670        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2671        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2672
 2673        cx.notify();
 2674    }
 2675
 2676    pub fn set_current_line_highlight(
 2677        &mut self,
 2678        current_line_highlight: Option<CurrentLineHighlight>,
 2679    ) {
 2680        self.current_line_highlight = current_line_highlight;
 2681    }
 2682
 2683    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2684        self.collapse_matches = collapse_matches;
 2685    }
 2686
 2687    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2688        let buffers = self.buffer.read(cx).all_buffers();
 2689        let Some(project) = self.project.as_ref() else {
 2690            return;
 2691        };
 2692        project.update(cx, |project, cx| {
 2693            for buffer in buffers {
 2694                self.registered_buffers
 2695                    .entry(buffer.read(cx).remote_id())
 2696                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2697            }
 2698        })
 2699    }
 2700
 2701    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2702        if self.collapse_matches {
 2703            return range.start..range.start;
 2704        }
 2705        range.clone()
 2706    }
 2707
 2708    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2709        if self.display_map.read(cx).clip_at_line_ends != clip {
 2710            self.display_map
 2711                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2712        }
 2713    }
 2714
 2715    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2716        self.input_enabled = input_enabled;
 2717    }
 2718
 2719    pub fn set_inline_completions_hidden_for_vim_mode(
 2720        &mut self,
 2721        hidden: bool,
 2722        window: &mut Window,
 2723        cx: &mut Context<Self>,
 2724    ) {
 2725        if hidden != self.inline_completions_hidden_for_vim_mode {
 2726            self.inline_completions_hidden_for_vim_mode = hidden;
 2727            if hidden {
 2728                self.update_visible_inline_completion(window, cx);
 2729            } else {
 2730                self.refresh_inline_completion(true, false, window, cx);
 2731            }
 2732        }
 2733    }
 2734
 2735    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2736        self.menu_inline_completions_policy = value;
 2737    }
 2738
 2739    pub fn set_autoindent(&mut self, autoindent: bool) {
 2740        if autoindent {
 2741            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2742        } else {
 2743            self.autoindent_mode = None;
 2744        }
 2745    }
 2746
 2747    pub fn read_only(&self, cx: &App) -> bool {
 2748        self.read_only || self.buffer.read(cx).read_only()
 2749    }
 2750
 2751    pub fn set_read_only(&mut self, read_only: bool) {
 2752        self.read_only = read_only;
 2753    }
 2754
 2755    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2756        self.use_autoclose = autoclose;
 2757    }
 2758
 2759    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2760        self.use_auto_surround = auto_surround;
 2761    }
 2762
 2763    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2764        self.auto_replace_emoji_shortcode = auto_replace;
 2765    }
 2766
 2767    pub fn toggle_edit_predictions(
 2768        &mut self,
 2769        _: &ToggleEditPrediction,
 2770        window: &mut Window,
 2771        cx: &mut Context<Self>,
 2772    ) {
 2773        if self.show_inline_completions_override.is_some() {
 2774            self.set_show_edit_predictions(None, window, cx);
 2775        } else {
 2776            let show_edit_predictions = !self.edit_predictions_enabled();
 2777            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2778        }
 2779    }
 2780
 2781    pub fn set_show_edit_predictions(
 2782        &mut self,
 2783        show_edit_predictions: Option<bool>,
 2784        window: &mut Window,
 2785        cx: &mut Context<Self>,
 2786    ) {
 2787        self.show_inline_completions_override = show_edit_predictions;
 2788        self.update_edit_prediction_settings(cx);
 2789
 2790        if let Some(false) = show_edit_predictions {
 2791            self.discard_inline_completion(false, cx);
 2792        } else {
 2793            self.refresh_inline_completion(false, true, window, cx);
 2794        }
 2795    }
 2796
 2797    fn inline_completions_disabled_in_scope(
 2798        &self,
 2799        buffer: &Entity<Buffer>,
 2800        buffer_position: language::Anchor,
 2801        cx: &App,
 2802    ) -> bool {
 2803        let snapshot = buffer.read(cx).snapshot();
 2804        let settings = snapshot.settings_at(buffer_position, cx);
 2805
 2806        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2807            return false;
 2808        };
 2809
 2810        scope.override_name().map_or(false, |scope_name| {
 2811            settings
 2812                .edit_predictions_disabled_in
 2813                .iter()
 2814                .any(|s| s == scope_name)
 2815        })
 2816    }
 2817
 2818    pub fn set_use_modal_editing(&mut self, to: bool) {
 2819        self.use_modal_editing = to;
 2820    }
 2821
 2822    pub fn use_modal_editing(&self) -> bool {
 2823        self.use_modal_editing
 2824    }
 2825
 2826    fn selections_did_change(
 2827        &mut self,
 2828        local: bool,
 2829        old_cursor_position: &Anchor,
 2830        effects: SelectionEffects,
 2831        window: &mut Window,
 2832        cx: &mut Context<Self>,
 2833    ) {
 2834        window.invalidate_character_coordinates();
 2835
 2836        // Copy selections to primary selection buffer
 2837        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2838        if local {
 2839            let selections = self.selections.all::<usize>(cx);
 2840            let buffer_handle = self.buffer.read(cx).read(cx);
 2841
 2842            let mut text = String::new();
 2843            for (index, selection) in selections.iter().enumerate() {
 2844                let text_for_selection = buffer_handle
 2845                    .text_for_range(selection.start..selection.end)
 2846                    .collect::<String>();
 2847
 2848                text.push_str(&text_for_selection);
 2849                if index != selections.len() - 1 {
 2850                    text.push('\n');
 2851                }
 2852            }
 2853
 2854            if !text.is_empty() {
 2855                cx.write_to_primary(ClipboardItem::new_string(text));
 2856            }
 2857        }
 2858
 2859        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2860            self.buffer.update(cx, |buffer, cx| {
 2861                buffer.set_active_selections(
 2862                    &self.selections.disjoint_anchors(),
 2863                    self.selections.line_mode,
 2864                    self.cursor_shape,
 2865                    cx,
 2866                )
 2867            });
 2868        }
 2869        let display_map = self
 2870            .display_map
 2871            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2872        let buffer = &display_map.buffer_snapshot;
 2873        if self.selections.count() == 1 {
 2874            self.add_selections_state = None;
 2875        }
 2876        self.select_next_state = None;
 2877        self.select_prev_state = None;
 2878        self.select_syntax_node_history.try_clear();
 2879        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2880        self.snippet_stack
 2881            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2882        self.take_rename(false, window, cx);
 2883
 2884        let newest_selection = self.selections.newest_anchor();
 2885        let new_cursor_position = newest_selection.head();
 2886        let selection_start = newest_selection.start;
 2887
 2888        if effects.nav_history {
 2889            self.push_to_nav_history(
 2890                *old_cursor_position,
 2891                Some(new_cursor_position.to_point(buffer)),
 2892                false,
 2893                cx,
 2894            );
 2895        }
 2896
 2897        if local {
 2898            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2899                if !self.registered_buffers.contains_key(&buffer_id) {
 2900                    if let Some(project) = self.project.as_ref() {
 2901                        project.update(cx, |project, cx| {
 2902                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2903                                return;
 2904                            };
 2905                            self.registered_buffers.insert(
 2906                                buffer_id,
 2907                                project.register_buffer_with_language_servers(&buffer, cx),
 2908                            );
 2909                        })
 2910                    }
 2911                }
 2912            }
 2913
 2914            let mut context_menu = self.context_menu.borrow_mut();
 2915            let completion_menu = match context_menu.as_ref() {
 2916                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2917                Some(CodeContextMenu::CodeActions(_)) => {
 2918                    *context_menu = None;
 2919                    None
 2920                }
 2921                None => None,
 2922            };
 2923            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2924            drop(context_menu);
 2925
 2926            if effects.completions {
 2927                if let Some(completion_position) = completion_position {
 2928                    let start_offset = selection_start.to_offset(buffer);
 2929                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2930                    let continue_showing = if position_matches {
 2931                        if self.snippet_stack.is_empty() {
 2932                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2933                        } else {
 2934                            // Snippet choices can be shown even when the cursor is in whitespace.
 2935                            // Dismissing the menu with actions like backspace is handled by
 2936                            // invalidation regions.
 2937                            true
 2938                        }
 2939                    } else {
 2940                        false
 2941                    };
 2942
 2943                    if continue_showing {
 2944                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2945                    } else {
 2946                        self.hide_context_menu(window, cx);
 2947                    }
 2948                }
 2949            }
 2950
 2951            hide_hover(self, cx);
 2952
 2953            if old_cursor_position.to_display_point(&display_map).row()
 2954                != new_cursor_position.to_display_point(&display_map).row()
 2955            {
 2956                self.available_code_actions.take();
 2957            }
 2958            self.refresh_code_actions(window, cx);
 2959            self.refresh_document_highlights(cx);
 2960            self.refresh_selected_text_highlights(false, window, cx);
 2961            refresh_matching_bracket_highlights(self, window, cx);
 2962            self.update_visible_inline_completion(window, cx);
 2963            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2964            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2965            self.inline_blame_popover.take();
 2966            if self.git_blame_inline_enabled {
 2967                self.start_inline_blame_timer(window, cx);
 2968            }
 2969        }
 2970
 2971        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2972        cx.emit(EditorEvent::SelectionsChanged { local });
 2973
 2974        let selections = &self.selections.disjoint;
 2975        if selections.len() == 1 {
 2976            cx.emit(SearchEvent::ActiveMatchChanged)
 2977        }
 2978        if local {
 2979            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2980                let inmemory_selections = selections
 2981                    .iter()
 2982                    .map(|s| {
 2983                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2984                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2985                    })
 2986                    .collect();
 2987                self.update_restoration_data(cx, |data| {
 2988                    data.selections = inmemory_selections;
 2989                });
 2990
 2991                if WorkspaceSettings::get(None, cx).restore_on_startup
 2992                    != RestoreOnStartupBehavior::None
 2993                {
 2994                    if let Some(workspace_id) =
 2995                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2996                    {
 2997                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2998                        let selections = selections.clone();
 2999                        let background_executor = cx.background_executor().clone();
 3000                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3001                        self.serialize_selections = cx.background_spawn(async move {
 3002                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3003                            let db_selections = selections
 3004                                .iter()
 3005                                .map(|selection| {
 3006                                    (
 3007                                        selection.start.to_offset(&snapshot),
 3008                                        selection.end.to_offset(&snapshot),
 3009                                    )
 3010                                })
 3011                                .collect();
 3012
 3013                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3014                                .await
 3015                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3016                                .log_err();
 3017                        });
 3018                    }
 3019                }
 3020            }
 3021        }
 3022
 3023        cx.notify();
 3024    }
 3025
 3026    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3027        use text::ToOffset as _;
 3028        use text::ToPoint as _;
 3029
 3030        if self.mode.is_minimap()
 3031            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3032        {
 3033            return;
 3034        }
 3035
 3036        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3037            return;
 3038        };
 3039
 3040        let snapshot = singleton.read(cx).snapshot();
 3041        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3042            let display_snapshot = display_map.snapshot(cx);
 3043
 3044            display_snapshot
 3045                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3046                .map(|fold| {
 3047                    fold.range.start.text_anchor.to_point(&snapshot)
 3048                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3049                })
 3050                .collect()
 3051        });
 3052        self.update_restoration_data(cx, |data| {
 3053            data.folds = inmemory_folds;
 3054        });
 3055
 3056        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3057            return;
 3058        };
 3059        let background_executor = cx.background_executor().clone();
 3060        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3061        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3062            display_map
 3063                .snapshot(cx)
 3064                .folds_in_range(0..snapshot.len())
 3065                .map(|fold| {
 3066                    (
 3067                        fold.range.start.text_anchor.to_offset(&snapshot),
 3068                        fold.range.end.text_anchor.to_offset(&snapshot),
 3069                    )
 3070                })
 3071                .collect()
 3072        });
 3073        self.serialize_folds = cx.background_spawn(async move {
 3074            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3075            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3076                .await
 3077                .with_context(|| {
 3078                    format!(
 3079                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3080                    )
 3081                })
 3082                .log_err();
 3083        });
 3084    }
 3085
 3086    pub fn sync_selections(
 3087        &mut self,
 3088        other: Entity<Editor>,
 3089        cx: &mut Context<Self>,
 3090    ) -> gpui::Subscription {
 3091        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3092        self.selections.change_with(cx, |selections| {
 3093            selections.select_anchors(other_selections);
 3094        });
 3095
 3096        let other_subscription =
 3097            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3098                EditorEvent::SelectionsChanged { local: true } => {
 3099                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3100                    if other_selections.is_empty() {
 3101                        return;
 3102                    }
 3103                    this.selections.change_with(cx, |selections| {
 3104                        selections.select_anchors(other_selections);
 3105                    });
 3106                }
 3107                _ => {}
 3108            });
 3109
 3110        let this_subscription =
 3111            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3112                EditorEvent::SelectionsChanged { local: true } => {
 3113                    let these_selections = this.selections.disjoint.to_vec();
 3114                    if these_selections.is_empty() {
 3115                        return;
 3116                    }
 3117                    other.update(cx, |other_editor, cx| {
 3118                        other_editor.selections.change_with(cx, |selections| {
 3119                            selections.select_anchors(these_selections);
 3120                        })
 3121                    });
 3122                }
 3123                _ => {}
 3124            });
 3125
 3126        Subscription::join(other_subscription, this_subscription)
 3127    }
 3128
 3129    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3130    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3131    /// effects of selection change occur at the end of the transaction.
 3132    pub fn change_selections<R>(
 3133        &mut self,
 3134        effects: impl Into<SelectionEffects>,
 3135        window: &mut Window,
 3136        cx: &mut Context<Self>,
 3137        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3138    ) -> R {
 3139        let effects = effects.into();
 3140        if let Some(state) = &mut self.deferred_selection_effects_state {
 3141            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3142            state.effects.completions = effects.completions;
 3143            state.effects.nav_history |= effects.nav_history;
 3144            let (changed, result) = self.selections.change_with(cx, change);
 3145            state.changed |= changed;
 3146            return result;
 3147        }
 3148        let mut state = DeferredSelectionEffectsState {
 3149            changed: false,
 3150            effects,
 3151            old_cursor_position: self.selections.newest_anchor().head(),
 3152            history_entry: SelectionHistoryEntry {
 3153                selections: self.selections.disjoint_anchors(),
 3154                select_next_state: self.select_next_state.clone(),
 3155                select_prev_state: self.select_prev_state.clone(),
 3156                add_selections_state: self.add_selections_state.clone(),
 3157            },
 3158        };
 3159        let (changed, result) = self.selections.change_with(cx, change);
 3160        state.changed = state.changed || changed;
 3161        if self.defer_selection_effects {
 3162            self.deferred_selection_effects_state = Some(state);
 3163        } else {
 3164            self.apply_selection_effects(state, window, cx);
 3165        }
 3166        result
 3167    }
 3168
 3169    /// Defers the effects of selection change, so that the effects of multiple calls to
 3170    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3171    /// to selection history and the state of popovers based on selection position aren't
 3172    /// erroneously updated.
 3173    pub fn with_selection_effects_deferred<R>(
 3174        &mut self,
 3175        window: &mut Window,
 3176        cx: &mut Context<Self>,
 3177        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3178    ) -> R {
 3179        let already_deferred = self.defer_selection_effects;
 3180        self.defer_selection_effects = true;
 3181        let result = update(self, window, cx);
 3182        if !already_deferred {
 3183            self.defer_selection_effects = false;
 3184            if let Some(state) = self.deferred_selection_effects_state.take() {
 3185                self.apply_selection_effects(state, window, cx);
 3186            }
 3187        }
 3188        result
 3189    }
 3190
 3191    fn apply_selection_effects(
 3192        &mut self,
 3193        state: DeferredSelectionEffectsState,
 3194        window: &mut Window,
 3195        cx: &mut Context<Self>,
 3196    ) {
 3197        if state.changed {
 3198            self.selection_history.push(state.history_entry);
 3199
 3200            if let Some(autoscroll) = state.effects.scroll {
 3201                self.request_autoscroll(autoscroll, cx);
 3202            }
 3203
 3204            let old_cursor_position = &state.old_cursor_position;
 3205
 3206            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3207
 3208            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3209                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3210            }
 3211        }
 3212    }
 3213
 3214    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3215    where
 3216        I: IntoIterator<Item = (Range<S>, T)>,
 3217        S: ToOffset,
 3218        T: Into<Arc<str>>,
 3219    {
 3220        if self.read_only(cx) {
 3221            return;
 3222        }
 3223
 3224        self.buffer
 3225            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3226    }
 3227
 3228    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3229    where
 3230        I: IntoIterator<Item = (Range<S>, T)>,
 3231        S: ToOffset,
 3232        T: Into<Arc<str>>,
 3233    {
 3234        if self.read_only(cx) {
 3235            return;
 3236        }
 3237
 3238        self.buffer.update(cx, |buffer, cx| {
 3239            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3240        });
 3241    }
 3242
 3243    pub fn edit_with_block_indent<I, S, T>(
 3244        &mut self,
 3245        edits: I,
 3246        original_indent_columns: Vec<Option<u32>>,
 3247        cx: &mut Context<Self>,
 3248    ) where
 3249        I: IntoIterator<Item = (Range<S>, T)>,
 3250        S: ToOffset,
 3251        T: Into<Arc<str>>,
 3252    {
 3253        if self.read_only(cx) {
 3254            return;
 3255        }
 3256
 3257        self.buffer.update(cx, |buffer, cx| {
 3258            buffer.edit(
 3259                edits,
 3260                Some(AutoindentMode::Block {
 3261                    original_indent_columns,
 3262                }),
 3263                cx,
 3264            )
 3265        });
 3266    }
 3267
 3268    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3269        self.hide_context_menu(window, cx);
 3270
 3271        match phase {
 3272            SelectPhase::Begin {
 3273                position,
 3274                add,
 3275                click_count,
 3276            } => self.begin_selection(position, add, click_count, window, cx),
 3277            SelectPhase::BeginColumnar {
 3278                position,
 3279                goal_column,
 3280                reset,
 3281                mode,
 3282            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3283            SelectPhase::Extend {
 3284                position,
 3285                click_count,
 3286            } => self.extend_selection(position, click_count, window, cx),
 3287            SelectPhase::Update {
 3288                position,
 3289                goal_column,
 3290                scroll_delta,
 3291            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3292            SelectPhase::End => self.end_selection(window, cx),
 3293        }
 3294    }
 3295
 3296    fn extend_selection(
 3297        &mut self,
 3298        position: DisplayPoint,
 3299        click_count: usize,
 3300        window: &mut Window,
 3301        cx: &mut Context<Self>,
 3302    ) {
 3303        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3304        let tail = self.selections.newest::<usize>(cx).tail();
 3305        self.begin_selection(position, false, click_count, window, cx);
 3306
 3307        let position = position.to_offset(&display_map, Bias::Left);
 3308        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3309
 3310        let mut pending_selection = self
 3311            .selections
 3312            .pending_anchor()
 3313            .expect("extend_selection not called with pending selection");
 3314        if position >= tail {
 3315            pending_selection.start = tail_anchor;
 3316        } else {
 3317            pending_selection.end = tail_anchor;
 3318            pending_selection.reversed = true;
 3319        }
 3320
 3321        let mut pending_mode = self.selections.pending_mode().unwrap();
 3322        match &mut pending_mode {
 3323            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3324            _ => {}
 3325        }
 3326
 3327        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3328            SelectionEffects::scroll(Autoscroll::fit())
 3329        } else {
 3330            SelectionEffects::no_scroll()
 3331        };
 3332
 3333        self.change_selections(effects, window, cx, |s| {
 3334            s.set_pending(pending_selection, pending_mode)
 3335        });
 3336    }
 3337
 3338    fn begin_selection(
 3339        &mut self,
 3340        position: DisplayPoint,
 3341        add: bool,
 3342        click_count: usize,
 3343        window: &mut Window,
 3344        cx: &mut Context<Self>,
 3345    ) {
 3346        if !self.focus_handle.is_focused(window) {
 3347            self.last_focused_descendant = None;
 3348            window.focus(&self.focus_handle);
 3349        }
 3350
 3351        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3352        let buffer = &display_map.buffer_snapshot;
 3353        let position = display_map.clip_point(position, Bias::Left);
 3354
 3355        let start;
 3356        let end;
 3357        let mode;
 3358        let mut auto_scroll;
 3359        match click_count {
 3360            1 => {
 3361                start = buffer.anchor_before(position.to_point(&display_map));
 3362                end = start;
 3363                mode = SelectMode::Character;
 3364                auto_scroll = true;
 3365            }
 3366            2 => {
 3367                let range = movement::surrounding_word(&display_map, position);
 3368                start = buffer.anchor_before(range.start.to_point(&display_map));
 3369                end = buffer.anchor_before(range.end.to_point(&display_map));
 3370                mode = SelectMode::Word(start..end);
 3371                auto_scroll = true;
 3372            }
 3373            3 => {
 3374                let position = display_map
 3375                    .clip_point(position, Bias::Left)
 3376                    .to_point(&display_map);
 3377                let line_start = display_map.prev_line_boundary(position).0;
 3378                let next_line_start = buffer.clip_point(
 3379                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3380                    Bias::Left,
 3381                );
 3382                start = buffer.anchor_before(line_start);
 3383                end = buffer.anchor_before(next_line_start);
 3384                mode = SelectMode::Line(start..end);
 3385                auto_scroll = true;
 3386            }
 3387            _ => {
 3388                start = buffer.anchor_before(0);
 3389                end = buffer.anchor_before(buffer.len());
 3390                mode = SelectMode::All;
 3391                auto_scroll = false;
 3392            }
 3393        }
 3394        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3395
 3396        let point_to_delete: Option<usize> = {
 3397            let selected_points: Vec<Selection<Point>> =
 3398                self.selections.disjoint_in_range(start..end, cx);
 3399
 3400            if !add || click_count > 1 {
 3401                None
 3402            } else if !selected_points.is_empty() {
 3403                Some(selected_points[0].id)
 3404            } else {
 3405                let clicked_point_already_selected =
 3406                    self.selections.disjoint.iter().find(|selection| {
 3407                        selection.start.to_point(buffer) == start.to_point(buffer)
 3408                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3409                    });
 3410
 3411                clicked_point_already_selected.map(|selection| selection.id)
 3412            }
 3413        };
 3414
 3415        let selections_count = self.selections.count();
 3416
 3417        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3418            if let Some(point_to_delete) = point_to_delete {
 3419                s.delete(point_to_delete);
 3420
 3421                if selections_count == 1 {
 3422                    s.set_pending_anchor_range(start..end, mode);
 3423                }
 3424            } else {
 3425                if !add {
 3426                    s.clear_disjoint();
 3427                }
 3428
 3429                s.set_pending_anchor_range(start..end, mode);
 3430            }
 3431        });
 3432    }
 3433
 3434    fn begin_columnar_selection(
 3435        &mut self,
 3436        position: DisplayPoint,
 3437        goal_column: u32,
 3438        reset: bool,
 3439        mode: ColumnarMode,
 3440        window: &mut Window,
 3441        cx: &mut Context<Self>,
 3442    ) {
 3443        if !self.focus_handle.is_focused(window) {
 3444            self.last_focused_descendant = None;
 3445            window.focus(&self.focus_handle);
 3446        }
 3447
 3448        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3449
 3450        if reset {
 3451            let pointer_position = display_map
 3452                .buffer_snapshot
 3453                .anchor_before(position.to_point(&display_map));
 3454
 3455            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3456                s.clear_disjoint();
 3457                s.set_pending_anchor_range(
 3458                    pointer_position..pointer_position,
 3459                    SelectMode::Character,
 3460                );
 3461            });
 3462        };
 3463
 3464        let tail = self.selections.newest::<Point>(cx).tail();
 3465        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3466        self.columnar_selection_state = match mode {
 3467            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3468                selection_tail: selection_anchor,
 3469                display_point: if reset {
 3470                    if position.column() != goal_column {
 3471                        Some(DisplayPoint::new(position.row(), goal_column))
 3472                    } else {
 3473                        None
 3474                    }
 3475                } else {
 3476                    None
 3477                },
 3478            }),
 3479            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3480                selection_tail: selection_anchor,
 3481            }),
 3482        };
 3483
 3484        if !reset {
 3485            self.select_columns(position, goal_column, &display_map, window, cx);
 3486        }
 3487    }
 3488
 3489    fn update_selection(
 3490        &mut self,
 3491        position: DisplayPoint,
 3492        goal_column: u32,
 3493        scroll_delta: gpui::Point<f32>,
 3494        window: &mut Window,
 3495        cx: &mut Context<Self>,
 3496    ) {
 3497        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3498
 3499        if self.columnar_selection_state.is_some() {
 3500            self.select_columns(position, goal_column, &display_map, window, cx);
 3501        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3502            let buffer = self.buffer.read(cx).snapshot(cx);
 3503            let head;
 3504            let tail;
 3505            let mode = self.selections.pending_mode().unwrap();
 3506            match &mode {
 3507                SelectMode::Character => {
 3508                    head = position.to_point(&display_map);
 3509                    tail = pending.tail().to_point(&buffer);
 3510                }
 3511                SelectMode::Word(original_range) => {
 3512                    let original_display_range = original_range.start.to_display_point(&display_map)
 3513                        ..original_range.end.to_display_point(&display_map);
 3514                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3515                        ..original_display_range.end.to_point(&display_map);
 3516                    if movement::is_inside_word(&display_map, position)
 3517                        || original_display_range.contains(&position)
 3518                    {
 3519                        let word_range = movement::surrounding_word(&display_map, position);
 3520                        if word_range.start < original_display_range.start {
 3521                            head = word_range.start.to_point(&display_map);
 3522                        } else {
 3523                            head = word_range.end.to_point(&display_map);
 3524                        }
 3525                    } else {
 3526                        head = position.to_point(&display_map);
 3527                    }
 3528
 3529                    if head <= original_buffer_range.start {
 3530                        tail = original_buffer_range.end;
 3531                    } else {
 3532                        tail = original_buffer_range.start;
 3533                    }
 3534                }
 3535                SelectMode::Line(original_range) => {
 3536                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3537
 3538                    let position = display_map
 3539                        .clip_point(position, Bias::Left)
 3540                        .to_point(&display_map);
 3541                    let line_start = display_map.prev_line_boundary(position).0;
 3542                    let next_line_start = buffer.clip_point(
 3543                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3544                        Bias::Left,
 3545                    );
 3546
 3547                    if line_start < original_range.start {
 3548                        head = line_start
 3549                    } else {
 3550                        head = next_line_start
 3551                    }
 3552
 3553                    if head <= original_range.start {
 3554                        tail = original_range.end;
 3555                    } else {
 3556                        tail = original_range.start;
 3557                    }
 3558                }
 3559                SelectMode::All => {
 3560                    return;
 3561                }
 3562            };
 3563
 3564            if head < tail {
 3565                pending.start = buffer.anchor_before(head);
 3566                pending.end = buffer.anchor_before(tail);
 3567                pending.reversed = true;
 3568            } else {
 3569                pending.start = buffer.anchor_before(tail);
 3570                pending.end = buffer.anchor_before(head);
 3571                pending.reversed = false;
 3572            }
 3573
 3574            self.change_selections(None, window, cx, |s| {
 3575                s.set_pending(pending, mode);
 3576            });
 3577        } else {
 3578            log::error!("update_selection dispatched with no pending selection");
 3579            return;
 3580        }
 3581
 3582        self.apply_scroll_delta(scroll_delta, window, cx);
 3583        cx.notify();
 3584    }
 3585
 3586    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3587        self.columnar_selection_state.take();
 3588        if self.selections.pending_anchor().is_some() {
 3589            let selections = self.selections.all::<usize>(cx);
 3590            self.change_selections(None, window, cx, |s| {
 3591                s.select(selections);
 3592                s.clear_pending();
 3593            });
 3594        }
 3595    }
 3596
 3597    fn select_columns(
 3598        &mut self,
 3599        head: DisplayPoint,
 3600        goal_column: u32,
 3601        display_map: &DisplaySnapshot,
 3602        window: &mut Window,
 3603        cx: &mut Context<Self>,
 3604    ) {
 3605        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3606            return;
 3607        };
 3608
 3609        let tail = match columnar_state {
 3610            ColumnarSelectionState::FromMouse {
 3611                selection_tail,
 3612                display_point,
 3613            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3614            ColumnarSelectionState::FromSelection { selection_tail } => {
 3615                selection_tail.to_display_point(&display_map)
 3616            }
 3617        };
 3618
 3619        let start_row = cmp::min(tail.row(), head.row());
 3620        let end_row = cmp::max(tail.row(), head.row());
 3621        let start_column = cmp::min(tail.column(), goal_column);
 3622        let end_column = cmp::max(tail.column(), goal_column);
 3623        let reversed = start_column < tail.column();
 3624
 3625        let selection_ranges = (start_row.0..=end_row.0)
 3626            .map(DisplayRow)
 3627            .filter_map(|row| {
 3628                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3629                    || start_column <= display_map.line_len(row))
 3630                    && !display_map.is_block_line(row)
 3631                {
 3632                    let start = display_map
 3633                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3634                        .to_point(display_map);
 3635                    let end = display_map
 3636                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3637                        .to_point(display_map);
 3638                    if reversed {
 3639                        Some(end..start)
 3640                    } else {
 3641                        Some(start..end)
 3642                    }
 3643                } else {
 3644                    None
 3645                }
 3646            })
 3647            .collect::<Vec<_>>();
 3648
 3649        let ranges = match columnar_state {
 3650            ColumnarSelectionState::FromMouse { .. } => {
 3651                let mut non_empty_ranges = selection_ranges
 3652                    .iter()
 3653                    .filter(|selection_range| selection_range.start != selection_range.end)
 3654                    .peekable();
 3655                if non_empty_ranges.peek().is_some() {
 3656                    non_empty_ranges.cloned().collect()
 3657                } else {
 3658                    selection_ranges
 3659                }
 3660            }
 3661            _ => selection_ranges,
 3662        };
 3663
 3664        self.change_selections(None, window, cx, |s| {
 3665            s.select_ranges(ranges);
 3666        });
 3667        cx.notify();
 3668    }
 3669
 3670    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3671        self.selections
 3672            .all_adjusted(cx)
 3673            .iter()
 3674            .any(|selection| !selection.is_empty())
 3675    }
 3676
 3677    pub fn has_pending_nonempty_selection(&self) -> bool {
 3678        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3679            Some(Selection { start, end, .. }) => start != end,
 3680            None => false,
 3681        };
 3682
 3683        pending_nonempty_selection
 3684            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3685    }
 3686
 3687    pub fn has_pending_selection(&self) -> bool {
 3688        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3689    }
 3690
 3691    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3692        self.selection_mark_mode = false;
 3693        self.selection_drag_state = SelectionDragState::None;
 3694
 3695        if self.clear_expanded_diff_hunks(cx) {
 3696            cx.notify();
 3697            return;
 3698        }
 3699        if self.dismiss_menus_and_popups(true, window, cx) {
 3700            return;
 3701        }
 3702
 3703        if self.mode.is_full()
 3704            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3705        {
 3706            return;
 3707        }
 3708
 3709        cx.propagate();
 3710    }
 3711
 3712    pub fn dismiss_menus_and_popups(
 3713        &mut self,
 3714        is_user_requested: bool,
 3715        window: &mut Window,
 3716        cx: &mut Context<Self>,
 3717    ) -> bool {
 3718        if self.take_rename(false, window, cx).is_some() {
 3719            return true;
 3720        }
 3721
 3722        if hide_hover(self, cx) {
 3723            return true;
 3724        }
 3725
 3726        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3727            return true;
 3728        }
 3729
 3730        if self.hide_context_menu(window, cx).is_some() {
 3731            return true;
 3732        }
 3733
 3734        if self.mouse_context_menu.take().is_some() {
 3735            return true;
 3736        }
 3737
 3738        if is_user_requested && self.discard_inline_completion(true, cx) {
 3739            return true;
 3740        }
 3741
 3742        if self.snippet_stack.pop().is_some() {
 3743            return true;
 3744        }
 3745
 3746        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3747            self.dismiss_diagnostics(cx);
 3748            return true;
 3749        }
 3750
 3751        false
 3752    }
 3753
 3754    fn linked_editing_ranges_for(
 3755        &self,
 3756        selection: Range<text::Anchor>,
 3757        cx: &App,
 3758    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3759        if self.linked_edit_ranges.is_empty() {
 3760            return None;
 3761        }
 3762        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3763            selection.end.buffer_id.and_then(|end_buffer_id| {
 3764                if selection.start.buffer_id != Some(end_buffer_id) {
 3765                    return None;
 3766                }
 3767                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3768                let snapshot = buffer.read(cx).snapshot();
 3769                self.linked_edit_ranges
 3770                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3771                    .map(|ranges| (ranges, snapshot, buffer))
 3772            })?;
 3773        use text::ToOffset as TO;
 3774        // find offset from the start of current range to current cursor position
 3775        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3776
 3777        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3778        let start_difference = start_offset - start_byte_offset;
 3779        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3780        let end_difference = end_offset - start_byte_offset;
 3781        // Current range has associated linked ranges.
 3782        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3783        for range in linked_ranges.iter() {
 3784            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3785            let end_offset = start_offset + end_difference;
 3786            let start_offset = start_offset + start_difference;
 3787            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3788                continue;
 3789            }
 3790            if self.selections.disjoint_anchor_ranges().any(|s| {
 3791                if s.start.buffer_id != selection.start.buffer_id
 3792                    || s.end.buffer_id != selection.end.buffer_id
 3793                {
 3794                    return false;
 3795                }
 3796                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3797                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3798            }) {
 3799                continue;
 3800            }
 3801            let start = buffer_snapshot.anchor_after(start_offset);
 3802            let end = buffer_snapshot.anchor_after(end_offset);
 3803            linked_edits
 3804                .entry(buffer.clone())
 3805                .or_default()
 3806                .push(start..end);
 3807        }
 3808        Some(linked_edits)
 3809    }
 3810
 3811    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3812        let text: Arc<str> = text.into();
 3813
 3814        if self.read_only(cx) {
 3815            return;
 3816        }
 3817
 3818        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3819
 3820        let selections = self.selections.all_adjusted(cx);
 3821        let mut bracket_inserted = false;
 3822        let mut edits = Vec::new();
 3823        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3824        let mut new_selections = Vec::with_capacity(selections.len());
 3825        let mut new_autoclose_regions = Vec::new();
 3826        let snapshot = self.buffer.read(cx).read(cx);
 3827        let mut clear_linked_edit_ranges = false;
 3828
 3829        for (selection, autoclose_region) in
 3830            self.selections_with_autoclose_regions(selections, &snapshot)
 3831        {
 3832            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3833                // Determine if the inserted text matches the opening or closing
 3834                // bracket of any of this language's bracket pairs.
 3835                let mut bracket_pair = None;
 3836                let mut is_bracket_pair_start = false;
 3837                let mut is_bracket_pair_end = false;
 3838                if !text.is_empty() {
 3839                    let mut bracket_pair_matching_end = None;
 3840                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3841                    //  and they are removing the character that triggered IME popup.
 3842                    for (pair, enabled) in scope.brackets() {
 3843                        if !pair.close && !pair.surround {
 3844                            continue;
 3845                        }
 3846
 3847                        if enabled && pair.start.ends_with(text.as_ref()) {
 3848                            let prefix_len = pair.start.len() - text.len();
 3849                            let preceding_text_matches_prefix = prefix_len == 0
 3850                                || (selection.start.column >= (prefix_len as u32)
 3851                                    && snapshot.contains_str_at(
 3852                                        Point::new(
 3853                                            selection.start.row,
 3854                                            selection.start.column - (prefix_len as u32),
 3855                                        ),
 3856                                        &pair.start[..prefix_len],
 3857                                    ));
 3858                            if preceding_text_matches_prefix {
 3859                                bracket_pair = Some(pair.clone());
 3860                                is_bracket_pair_start = true;
 3861                                break;
 3862                            }
 3863                        }
 3864                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3865                        {
 3866                            // take first bracket pair matching end, but don't break in case a later bracket
 3867                            // pair matches start
 3868                            bracket_pair_matching_end = Some(pair.clone());
 3869                        }
 3870                    }
 3871                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3872                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3873                        is_bracket_pair_end = true;
 3874                    }
 3875                }
 3876
 3877                if let Some(bracket_pair) = bracket_pair {
 3878                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3879                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3880                    let auto_surround =
 3881                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3882                    if selection.is_empty() {
 3883                        if is_bracket_pair_start {
 3884                            // If the inserted text is a suffix of an opening bracket and the
 3885                            // selection is preceded by the rest of the opening bracket, then
 3886                            // insert the closing bracket.
 3887                            let following_text_allows_autoclose = snapshot
 3888                                .chars_at(selection.start)
 3889                                .next()
 3890                                .map_or(true, |c| scope.should_autoclose_before(c));
 3891
 3892                            let preceding_text_allows_autoclose = selection.start.column == 0
 3893                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3894                                    true,
 3895                                    |c| {
 3896                                        bracket_pair.start != bracket_pair.end
 3897                                            || !snapshot
 3898                                                .char_classifier_at(selection.start)
 3899                                                .is_word(c)
 3900                                    },
 3901                                );
 3902
 3903                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3904                                && bracket_pair.start.len() == 1
 3905                            {
 3906                                let target = bracket_pair.start.chars().next().unwrap();
 3907                                let current_line_count = snapshot
 3908                                    .reversed_chars_at(selection.start)
 3909                                    .take_while(|&c| c != '\n')
 3910                                    .filter(|&c| c == target)
 3911                                    .count();
 3912                                current_line_count % 2 == 1
 3913                            } else {
 3914                                false
 3915                            };
 3916
 3917                            if autoclose
 3918                                && bracket_pair.close
 3919                                && following_text_allows_autoclose
 3920                                && preceding_text_allows_autoclose
 3921                                && !is_closing_quote
 3922                            {
 3923                                let anchor = snapshot.anchor_before(selection.end);
 3924                                new_selections.push((selection.map(|_| anchor), text.len()));
 3925                                new_autoclose_regions.push((
 3926                                    anchor,
 3927                                    text.len(),
 3928                                    selection.id,
 3929                                    bracket_pair.clone(),
 3930                                ));
 3931                                edits.push((
 3932                                    selection.range(),
 3933                                    format!("{}{}", text, bracket_pair.end).into(),
 3934                                ));
 3935                                bracket_inserted = true;
 3936                                continue;
 3937                            }
 3938                        }
 3939
 3940                        if let Some(region) = autoclose_region {
 3941                            // If the selection is followed by an auto-inserted closing bracket,
 3942                            // then don't insert that closing bracket again; just move the selection
 3943                            // past the closing bracket.
 3944                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3945                                && text.as_ref() == region.pair.end.as_str();
 3946                            if should_skip {
 3947                                let anchor = snapshot.anchor_after(selection.end);
 3948                                new_selections
 3949                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3950                                continue;
 3951                            }
 3952                        }
 3953
 3954                        let always_treat_brackets_as_autoclosed = snapshot
 3955                            .language_settings_at(selection.start, cx)
 3956                            .always_treat_brackets_as_autoclosed;
 3957                        if always_treat_brackets_as_autoclosed
 3958                            && is_bracket_pair_end
 3959                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3960                        {
 3961                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3962                            // and the inserted text is a closing bracket and the selection is followed
 3963                            // by the closing bracket then move the selection past the closing bracket.
 3964                            let anchor = snapshot.anchor_after(selection.end);
 3965                            new_selections.push((selection.map(|_| anchor), text.len()));
 3966                            continue;
 3967                        }
 3968                    }
 3969                    // If an opening bracket is 1 character long and is typed while
 3970                    // text is selected, then surround that text with the bracket pair.
 3971                    else if auto_surround
 3972                        && bracket_pair.surround
 3973                        && is_bracket_pair_start
 3974                        && bracket_pair.start.chars().count() == 1
 3975                    {
 3976                        edits.push((selection.start..selection.start, text.clone()));
 3977                        edits.push((
 3978                            selection.end..selection.end,
 3979                            bracket_pair.end.as_str().into(),
 3980                        ));
 3981                        bracket_inserted = true;
 3982                        new_selections.push((
 3983                            Selection {
 3984                                id: selection.id,
 3985                                start: snapshot.anchor_after(selection.start),
 3986                                end: snapshot.anchor_before(selection.end),
 3987                                reversed: selection.reversed,
 3988                                goal: selection.goal,
 3989                            },
 3990                            0,
 3991                        ));
 3992                        continue;
 3993                    }
 3994                }
 3995            }
 3996
 3997            if self.auto_replace_emoji_shortcode
 3998                && selection.is_empty()
 3999                && text.as_ref().ends_with(':')
 4000            {
 4001                if let Some(possible_emoji_short_code) =
 4002                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4003                {
 4004                    if !possible_emoji_short_code.is_empty() {
 4005                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4006                            let emoji_shortcode_start = Point::new(
 4007                                selection.start.row,
 4008                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4009                            );
 4010
 4011                            // Remove shortcode from buffer
 4012                            edits.push((
 4013                                emoji_shortcode_start..selection.start,
 4014                                "".to_string().into(),
 4015                            ));
 4016                            new_selections.push((
 4017                                Selection {
 4018                                    id: selection.id,
 4019                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4020                                    end: snapshot.anchor_before(selection.start),
 4021                                    reversed: selection.reversed,
 4022                                    goal: selection.goal,
 4023                                },
 4024                                0,
 4025                            ));
 4026
 4027                            // Insert emoji
 4028                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4029                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4030                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4031
 4032                            continue;
 4033                        }
 4034                    }
 4035                }
 4036            }
 4037
 4038            // If not handling any auto-close operation, then just replace the selected
 4039            // text with the given input and move the selection to the end of the
 4040            // newly inserted text.
 4041            let anchor = snapshot.anchor_after(selection.end);
 4042            if !self.linked_edit_ranges.is_empty() {
 4043                let start_anchor = snapshot.anchor_before(selection.start);
 4044
 4045                let is_word_char = text.chars().next().map_or(true, |char| {
 4046                    let classifier = snapshot
 4047                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4048                        .ignore_punctuation(true);
 4049                    classifier.is_word(char)
 4050                });
 4051
 4052                if is_word_char {
 4053                    if let Some(ranges) = self
 4054                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4055                    {
 4056                        for (buffer, edits) in ranges {
 4057                            linked_edits
 4058                                .entry(buffer.clone())
 4059                                .or_default()
 4060                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4061                        }
 4062                    }
 4063                } else {
 4064                    clear_linked_edit_ranges = true;
 4065                }
 4066            }
 4067
 4068            new_selections.push((selection.map(|_| anchor), 0));
 4069            edits.push((selection.start..selection.end, text.clone()));
 4070        }
 4071
 4072        drop(snapshot);
 4073
 4074        self.transact(window, cx, |this, window, cx| {
 4075            if clear_linked_edit_ranges {
 4076                this.linked_edit_ranges.clear();
 4077            }
 4078            let initial_buffer_versions =
 4079                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4080
 4081            this.buffer.update(cx, |buffer, cx| {
 4082                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4083            });
 4084            for (buffer, edits) in linked_edits {
 4085                buffer.update(cx, |buffer, cx| {
 4086                    let snapshot = buffer.snapshot();
 4087                    let edits = edits
 4088                        .into_iter()
 4089                        .map(|(range, text)| {
 4090                            use text::ToPoint as TP;
 4091                            let end_point = TP::to_point(&range.end, &snapshot);
 4092                            let start_point = TP::to_point(&range.start, &snapshot);
 4093                            (start_point..end_point, text)
 4094                        })
 4095                        .sorted_by_key(|(range, _)| range.start);
 4096                    buffer.edit(edits, None, cx);
 4097                })
 4098            }
 4099            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4100            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4101            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4102            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4103                .zip(new_selection_deltas)
 4104                .map(|(selection, delta)| Selection {
 4105                    id: selection.id,
 4106                    start: selection.start + delta,
 4107                    end: selection.end + delta,
 4108                    reversed: selection.reversed,
 4109                    goal: SelectionGoal::None,
 4110                })
 4111                .collect::<Vec<_>>();
 4112
 4113            let mut i = 0;
 4114            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4115                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4116                let start = map.buffer_snapshot.anchor_before(position);
 4117                let end = map.buffer_snapshot.anchor_after(position);
 4118                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4119                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4120                        Ordering::Less => i += 1,
 4121                        Ordering::Greater => break,
 4122                        Ordering::Equal => {
 4123                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4124                                Ordering::Less => i += 1,
 4125                                Ordering::Equal => break,
 4126                                Ordering::Greater => break,
 4127                            }
 4128                        }
 4129                    }
 4130                }
 4131                this.autoclose_regions.insert(
 4132                    i,
 4133                    AutocloseRegion {
 4134                        selection_id,
 4135                        range: start..end,
 4136                        pair,
 4137                    },
 4138                );
 4139            }
 4140
 4141            let had_active_inline_completion = this.has_active_inline_completion();
 4142            this.change_selections(
 4143                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4144                window,
 4145                cx,
 4146                |s| s.select(new_selections),
 4147            );
 4148
 4149            if !bracket_inserted {
 4150                if let Some(on_type_format_task) =
 4151                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4152                {
 4153                    on_type_format_task.detach_and_log_err(cx);
 4154                }
 4155            }
 4156
 4157            let editor_settings = EditorSettings::get_global(cx);
 4158            if bracket_inserted
 4159                && (editor_settings.auto_signature_help
 4160                    || editor_settings.show_signature_help_after_edits)
 4161            {
 4162                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4163            }
 4164
 4165            let trigger_in_words =
 4166                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4167            if this.hard_wrap.is_some() {
 4168                let latest: Range<Point> = this.selections.newest(cx).range();
 4169                if latest.is_empty()
 4170                    && this
 4171                        .buffer()
 4172                        .read(cx)
 4173                        .snapshot(cx)
 4174                        .line_len(MultiBufferRow(latest.start.row))
 4175                        == latest.start.column
 4176                {
 4177                    this.rewrap_impl(
 4178                        RewrapOptions {
 4179                            override_language_settings: true,
 4180                            preserve_existing_whitespace: true,
 4181                        },
 4182                        cx,
 4183                    )
 4184                }
 4185            }
 4186            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4187            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4188            this.refresh_inline_completion(true, false, window, cx);
 4189            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4190        });
 4191    }
 4192
 4193    fn find_possible_emoji_shortcode_at_position(
 4194        snapshot: &MultiBufferSnapshot,
 4195        position: Point,
 4196    ) -> Option<String> {
 4197        let mut chars = Vec::new();
 4198        let mut found_colon = false;
 4199        for char in snapshot.reversed_chars_at(position).take(100) {
 4200            // Found a possible emoji shortcode in the middle of the buffer
 4201            if found_colon {
 4202                if char.is_whitespace() {
 4203                    chars.reverse();
 4204                    return Some(chars.iter().collect());
 4205                }
 4206                // If the previous character is not a whitespace, we are in the middle of a word
 4207                // and we only want to complete the shortcode if the word is made up of other emojis
 4208                let mut containing_word = String::new();
 4209                for ch in snapshot
 4210                    .reversed_chars_at(position)
 4211                    .skip(chars.len() + 1)
 4212                    .take(100)
 4213                {
 4214                    if ch.is_whitespace() {
 4215                        break;
 4216                    }
 4217                    containing_word.push(ch);
 4218                }
 4219                let containing_word = containing_word.chars().rev().collect::<String>();
 4220                if util::word_consists_of_emojis(containing_word.as_str()) {
 4221                    chars.reverse();
 4222                    return Some(chars.iter().collect());
 4223                }
 4224            }
 4225
 4226            if char.is_whitespace() || !char.is_ascii() {
 4227                return None;
 4228            }
 4229            if char == ':' {
 4230                found_colon = true;
 4231            } else {
 4232                chars.push(char);
 4233            }
 4234        }
 4235        // Found a possible emoji shortcode at the beginning of the buffer
 4236        chars.reverse();
 4237        Some(chars.iter().collect())
 4238    }
 4239
 4240    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4241        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4242        self.transact(window, cx, |this, window, cx| {
 4243            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4244                let selections = this.selections.all::<usize>(cx);
 4245                let multi_buffer = this.buffer.read(cx);
 4246                let buffer = multi_buffer.snapshot(cx);
 4247                selections
 4248                    .iter()
 4249                    .map(|selection| {
 4250                        let start_point = selection.start.to_point(&buffer);
 4251                        let mut existing_indent =
 4252                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4253                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4254                        let start = selection.start;
 4255                        let end = selection.end;
 4256                        let selection_is_empty = start == end;
 4257                        let language_scope = buffer.language_scope_at(start);
 4258                        let (
 4259                            comment_delimiter,
 4260                            doc_delimiter,
 4261                            insert_extra_newline,
 4262                            indent_on_newline,
 4263                            indent_on_extra_newline,
 4264                        ) = if let Some(language) = &language_scope {
 4265                            let mut insert_extra_newline =
 4266                                insert_extra_newline_brackets(&buffer, start..end, language)
 4267                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4268
 4269                            // Comment extension on newline is allowed only for cursor selections
 4270                            let comment_delimiter = maybe!({
 4271                                if !selection_is_empty {
 4272                                    return None;
 4273                                }
 4274
 4275                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4276                                    return None;
 4277                                }
 4278
 4279                                let delimiters = language.line_comment_prefixes();
 4280                                let max_len_of_delimiter =
 4281                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4282                                let (snapshot, range) =
 4283                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4284
 4285                                let num_of_whitespaces = snapshot
 4286                                    .chars_for_range(range.clone())
 4287                                    .take_while(|c| c.is_whitespace())
 4288                                    .count();
 4289                                let comment_candidate = snapshot
 4290                                    .chars_for_range(range)
 4291                                    .skip(num_of_whitespaces)
 4292                                    .take(max_len_of_delimiter)
 4293                                    .collect::<String>();
 4294                                let (delimiter, trimmed_len) = delimiters
 4295                                    .iter()
 4296                                    .filter_map(|delimiter| {
 4297                                        let prefix = delimiter.trim_end();
 4298                                        if comment_candidate.starts_with(prefix) {
 4299                                            Some((delimiter, prefix.len()))
 4300                                        } else {
 4301                                            None
 4302                                        }
 4303                                    })
 4304                                    .max_by_key(|(_, len)| *len)?;
 4305
 4306                                let cursor_is_placed_after_comment_marker =
 4307                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4308                                if cursor_is_placed_after_comment_marker {
 4309                                    Some(delimiter.clone())
 4310                                } else {
 4311                                    None
 4312                                }
 4313                            });
 4314
 4315                            let mut indent_on_newline = IndentSize::spaces(0);
 4316                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4317
 4318                            let doc_delimiter = maybe!({
 4319                                if !selection_is_empty {
 4320                                    return None;
 4321                                }
 4322
 4323                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4324                                    return None;
 4325                                }
 4326
 4327                                let DocumentationConfig {
 4328                                    start: start_tag,
 4329                                    end: end_tag,
 4330                                    prefix: delimiter,
 4331                                    tab_size: len,
 4332                                } = language.documentation()?;
 4333
 4334                                let is_within_block_comment = buffer
 4335                                    .language_scope_at(start_point)
 4336                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4337                                if !is_within_block_comment {
 4338                                    return None;
 4339                                }
 4340
 4341                                let (snapshot, range) =
 4342                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4343
 4344                                let num_of_whitespaces = snapshot
 4345                                    .chars_for_range(range.clone())
 4346                                    .take_while(|c| c.is_whitespace())
 4347                                    .count();
 4348
 4349                                // 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.
 4350                                let column = start_point.column;
 4351                                let cursor_is_after_start_tag = {
 4352                                    let start_tag_len = start_tag.len();
 4353                                    let start_tag_line = snapshot
 4354                                        .chars_for_range(range.clone())
 4355                                        .skip(num_of_whitespaces)
 4356                                        .take(start_tag_len)
 4357                                        .collect::<String>();
 4358                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4359                                        num_of_whitespaces + start_tag_len <= column as usize
 4360                                    } else {
 4361                                        false
 4362                                    }
 4363                                };
 4364
 4365                                let cursor_is_after_delimiter = {
 4366                                    let delimiter_trim = delimiter.trim_end();
 4367                                    let delimiter_line = snapshot
 4368                                        .chars_for_range(range.clone())
 4369                                        .skip(num_of_whitespaces)
 4370                                        .take(delimiter_trim.len())
 4371                                        .collect::<String>();
 4372                                    if delimiter_line.starts_with(delimiter_trim) {
 4373                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4374                                    } else {
 4375                                        false
 4376                                    }
 4377                                };
 4378
 4379                                let cursor_is_before_end_tag_if_exists = {
 4380                                    let mut char_position = 0u32;
 4381                                    let mut end_tag_offset = None;
 4382
 4383                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4384                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4385                                            let chars_before_match =
 4386                                                chunk[..byte_pos].chars().count() as u32;
 4387                                            end_tag_offset =
 4388                                                Some(char_position + chars_before_match);
 4389                                            break 'outer;
 4390                                        }
 4391                                        char_position += chunk.chars().count() as u32;
 4392                                    }
 4393
 4394                                    if let Some(end_tag_offset) = end_tag_offset {
 4395                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4396                                        if cursor_is_after_start_tag {
 4397                                            if cursor_is_before_end_tag {
 4398                                                insert_extra_newline = true;
 4399                                            }
 4400                                            let cursor_is_at_start_of_end_tag =
 4401                                                column == end_tag_offset;
 4402                                            if cursor_is_at_start_of_end_tag {
 4403                                                indent_on_extra_newline.len = (*len).into();
 4404                                            }
 4405                                        }
 4406                                        cursor_is_before_end_tag
 4407                                    } else {
 4408                                        true
 4409                                    }
 4410                                };
 4411
 4412                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4413                                    && cursor_is_before_end_tag_if_exists
 4414                                {
 4415                                    if cursor_is_after_start_tag {
 4416                                        indent_on_newline.len = (*len).into();
 4417                                    }
 4418                                    Some(delimiter.clone())
 4419                                } else {
 4420                                    None
 4421                                }
 4422                            });
 4423
 4424                            (
 4425                                comment_delimiter,
 4426                                doc_delimiter,
 4427                                insert_extra_newline,
 4428                                indent_on_newline,
 4429                                indent_on_extra_newline,
 4430                            )
 4431                        } else {
 4432                            (
 4433                                None,
 4434                                None,
 4435                                false,
 4436                                IndentSize::default(),
 4437                                IndentSize::default(),
 4438                            )
 4439                        };
 4440
 4441                        let prevent_auto_indent = doc_delimiter.is_some();
 4442                        let delimiter = comment_delimiter.or(doc_delimiter);
 4443
 4444                        let capacity_for_delimiter =
 4445                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4446                        let mut new_text = String::with_capacity(
 4447                            1 + capacity_for_delimiter
 4448                                + existing_indent.len as usize
 4449                                + indent_on_newline.len as usize
 4450                                + indent_on_extra_newline.len as usize,
 4451                        );
 4452                        new_text.push('\n');
 4453                        new_text.extend(existing_indent.chars());
 4454                        new_text.extend(indent_on_newline.chars());
 4455
 4456                        if let Some(delimiter) = &delimiter {
 4457                            new_text.push_str(delimiter);
 4458                        }
 4459
 4460                        if insert_extra_newline {
 4461                            new_text.push('\n');
 4462                            new_text.extend(existing_indent.chars());
 4463                            new_text.extend(indent_on_extra_newline.chars());
 4464                        }
 4465
 4466                        let anchor = buffer.anchor_after(end);
 4467                        let new_selection = selection.map(|_| anchor);
 4468                        (
 4469                            ((start..end, new_text), prevent_auto_indent),
 4470                            (insert_extra_newline, new_selection),
 4471                        )
 4472                    })
 4473                    .unzip()
 4474            };
 4475
 4476            let mut auto_indent_edits = Vec::new();
 4477            let mut edits = Vec::new();
 4478            for (edit, prevent_auto_indent) in edits_with_flags {
 4479                if prevent_auto_indent {
 4480                    edits.push(edit);
 4481                } else {
 4482                    auto_indent_edits.push(edit);
 4483                }
 4484            }
 4485            if !edits.is_empty() {
 4486                this.edit(edits, cx);
 4487            }
 4488            if !auto_indent_edits.is_empty() {
 4489                this.edit_with_autoindent(auto_indent_edits, cx);
 4490            }
 4491
 4492            let buffer = this.buffer.read(cx).snapshot(cx);
 4493            let new_selections = selection_info
 4494                .into_iter()
 4495                .map(|(extra_newline_inserted, new_selection)| {
 4496                    let mut cursor = new_selection.end.to_point(&buffer);
 4497                    if extra_newline_inserted {
 4498                        cursor.row -= 1;
 4499                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4500                    }
 4501                    new_selection.map(|_| cursor)
 4502                })
 4503                .collect();
 4504
 4505            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4506                s.select(new_selections)
 4507            });
 4508            this.refresh_inline_completion(true, false, window, cx);
 4509        });
 4510    }
 4511
 4512    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4513        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4514
 4515        let buffer = self.buffer.read(cx);
 4516        let snapshot = buffer.snapshot(cx);
 4517
 4518        let mut edits = Vec::new();
 4519        let mut rows = Vec::new();
 4520
 4521        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4522            let cursor = selection.head();
 4523            let row = cursor.row;
 4524
 4525            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4526
 4527            let newline = "\n".to_string();
 4528            edits.push((start_of_line..start_of_line, newline));
 4529
 4530            rows.push(row + rows_inserted as u32);
 4531        }
 4532
 4533        self.transact(window, cx, |editor, window, cx| {
 4534            editor.edit(edits, cx);
 4535
 4536            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4537                let mut index = 0;
 4538                s.move_cursors_with(|map, _, _| {
 4539                    let row = rows[index];
 4540                    index += 1;
 4541
 4542                    let point = Point::new(row, 0);
 4543                    let boundary = map.next_line_boundary(point).1;
 4544                    let clipped = map.clip_point(boundary, Bias::Left);
 4545
 4546                    (clipped, SelectionGoal::None)
 4547                });
 4548            });
 4549
 4550            let mut indent_edits = Vec::new();
 4551            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4552            for row in rows {
 4553                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4554                for (row, indent) in indents {
 4555                    if indent.len == 0 {
 4556                        continue;
 4557                    }
 4558
 4559                    let text = match indent.kind {
 4560                        IndentKind::Space => " ".repeat(indent.len as usize),
 4561                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4562                    };
 4563                    let point = Point::new(row.0, 0);
 4564                    indent_edits.push((point..point, text));
 4565                }
 4566            }
 4567            editor.edit(indent_edits, cx);
 4568        });
 4569    }
 4570
 4571    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4572        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4573
 4574        let buffer = self.buffer.read(cx);
 4575        let snapshot = buffer.snapshot(cx);
 4576
 4577        let mut edits = Vec::new();
 4578        let mut rows = Vec::new();
 4579        let mut rows_inserted = 0;
 4580
 4581        for selection in self.selections.all_adjusted(cx) {
 4582            let cursor = selection.head();
 4583            let row = cursor.row;
 4584
 4585            let point = Point::new(row + 1, 0);
 4586            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4587
 4588            let newline = "\n".to_string();
 4589            edits.push((start_of_line..start_of_line, newline));
 4590
 4591            rows_inserted += 1;
 4592            rows.push(row + rows_inserted);
 4593        }
 4594
 4595        self.transact(window, cx, |editor, window, cx| {
 4596            editor.edit(edits, cx);
 4597
 4598            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4599                let mut index = 0;
 4600                s.move_cursors_with(|map, _, _| {
 4601                    let row = rows[index];
 4602                    index += 1;
 4603
 4604                    let point = Point::new(row, 0);
 4605                    let boundary = map.next_line_boundary(point).1;
 4606                    let clipped = map.clip_point(boundary, Bias::Left);
 4607
 4608                    (clipped, SelectionGoal::None)
 4609                });
 4610            });
 4611
 4612            let mut indent_edits = Vec::new();
 4613            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4614            for row in rows {
 4615                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4616                for (row, indent) in indents {
 4617                    if indent.len == 0 {
 4618                        continue;
 4619                    }
 4620
 4621                    let text = match indent.kind {
 4622                        IndentKind::Space => " ".repeat(indent.len as usize),
 4623                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4624                    };
 4625                    let point = Point::new(row.0, 0);
 4626                    indent_edits.push((point..point, text));
 4627                }
 4628            }
 4629            editor.edit(indent_edits, cx);
 4630        });
 4631    }
 4632
 4633    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4634        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4635            original_indent_columns: Vec::new(),
 4636        });
 4637        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4638    }
 4639
 4640    fn insert_with_autoindent_mode(
 4641        &mut self,
 4642        text: &str,
 4643        autoindent_mode: Option<AutoindentMode>,
 4644        window: &mut Window,
 4645        cx: &mut Context<Self>,
 4646    ) {
 4647        if self.read_only(cx) {
 4648            return;
 4649        }
 4650
 4651        let text: Arc<str> = text.into();
 4652        self.transact(window, cx, |this, window, cx| {
 4653            let old_selections = this.selections.all_adjusted(cx);
 4654            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4655                let anchors = {
 4656                    let snapshot = buffer.read(cx);
 4657                    old_selections
 4658                        .iter()
 4659                        .map(|s| {
 4660                            let anchor = snapshot.anchor_after(s.head());
 4661                            s.map(|_| anchor)
 4662                        })
 4663                        .collect::<Vec<_>>()
 4664                };
 4665                buffer.edit(
 4666                    old_selections
 4667                        .iter()
 4668                        .map(|s| (s.start..s.end, text.clone())),
 4669                    autoindent_mode,
 4670                    cx,
 4671                );
 4672                anchors
 4673            });
 4674
 4675            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4676                s.select_anchors(selection_anchors);
 4677            });
 4678
 4679            cx.notify();
 4680        });
 4681    }
 4682
 4683    fn trigger_completion_on_input(
 4684        &mut self,
 4685        text: &str,
 4686        trigger_in_words: bool,
 4687        window: &mut Window,
 4688        cx: &mut Context<Self>,
 4689    ) {
 4690        let completions_source = self
 4691            .context_menu
 4692            .borrow()
 4693            .as_ref()
 4694            .and_then(|menu| match menu {
 4695                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4696                CodeContextMenu::CodeActions(_) => None,
 4697            });
 4698
 4699        match completions_source {
 4700            Some(CompletionsMenuSource::Words) => {
 4701                self.show_word_completions(&ShowWordCompletions, window, cx)
 4702            }
 4703            Some(CompletionsMenuSource::Normal)
 4704            | Some(CompletionsMenuSource::SnippetChoices)
 4705            | None
 4706                if self.is_completion_trigger(
 4707                    text,
 4708                    trigger_in_words,
 4709                    completions_source.is_some(),
 4710                    cx,
 4711                ) =>
 4712            {
 4713                self.show_completions(
 4714                    &ShowCompletions {
 4715                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4716                    },
 4717                    window,
 4718                    cx,
 4719                )
 4720            }
 4721            _ => {
 4722                self.hide_context_menu(window, cx);
 4723            }
 4724        }
 4725    }
 4726
 4727    fn is_completion_trigger(
 4728        &self,
 4729        text: &str,
 4730        trigger_in_words: bool,
 4731        menu_is_open: bool,
 4732        cx: &mut Context<Self>,
 4733    ) -> bool {
 4734        let position = self.selections.newest_anchor().head();
 4735        let multibuffer = self.buffer.read(cx);
 4736        let Some(buffer) = position
 4737            .buffer_id
 4738            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4739        else {
 4740            return false;
 4741        };
 4742
 4743        if let Some(completion_provider) = &self.completion_provider {
 4744            completion_provider.is_completion_trigger(
 4745                &buffer,
 4746                position.text_anchor,
 4747                text,
 4748                trigger_in_words,
 4749                menu_is_open,
 4750                cx,
 4751            )
 4752        } else {
 4753            false
 4754        }
 4755    }
 4756
 4757    /// If any empty selections is touching the start of its innermost containing autoclose
 4758    /// region, expand it to select the brackets.
 4759    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4760        let selections = self.selections.all::<usize>(cx);
 4761        let buffer = self.buffer.read(cx).read(cx);
 4762        let new_selections = self
 4763            .selections_with_autoclose_regions(selections, &buffer)
 4764            .map(|(mut selection, region)| {
 4765                if !selection.is_empty() {
 4766                    return selection;
 4767                }
 4768
 4769                if let Some(region) = region {
 4770                    let mut range = region.range.to_offset(&buffer);
 4771                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4772                        range.start -= region.pair.start.len();
 4773                        if buffer.contains_str_at(range.start, &region.pair.start)
 4774                            && buffer.contains_str_at(range.end, &region.pair.end)
 4775                        {
 4776                            range.end += region.pair.end.len();
 4777                            selection.start = range.start;
 4778                            selection.end = range.end;
 4779
 4780                            return selection;
 4781                        }
 4782                    }
 4783                }
 4784
 4785                let always_treat_brackets_as_autoclosed = buffer
 4786                    .language_settings_at(selection.start, cx)
 4787                    .always_treat_brackets_as_autoclosed;
 4788
 4789                if !always_treat_brackets_as_autoclosed {
 4790                    return selection;
 4791                }
 4792
 4793                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4794                    for (pair, enabled) in scope.brackets() {
 4795                        if !enabled || !pair.close {
 4796                            continue;
 4797                        }
 4798
 4799                        if buffer.contains_str_at(selection.start, &pair.end) {
 4800                            let pair_start_len = pair.start.len();
 4801                            if buffer.contains_str_at(
 4802                                selection.start.saturating_sub(pair_start_len),
 4803                                &pair.start,
 4804                            ) {
 4805                                selection.start -= pair_start_len;
 4806                                selection.end += pair.end.len();
 4807
 4808                                return selection;
 4809                            }
 4810                        }
 4811                    }
 4812                }
 4813
 4814                selection
 4815            })
 4816            .collect();
 4817
 4818        drop(buffer);
 4819        self.change_selections(None, window, cx, |selections| {
 4820            selections.select(new_selections)
 4821        });
 4822    }
 4823
 4824    /// Iterate the given selections, and for each one, find the smallest surrounding
 4825    /// autoclose region. This uses the ordering of the selections and the autoclose
 4826    /// regions to avoid repeated comparisons.
 4827    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4828        &'a self,
 4829        selections: impl IntoIterator<Item = Selection<D>>,
 4830        buffer: &'a MultiBufferSnapshot,
 4831    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4832        let mut i = 0;
 4833        let mut regions = self.autoclose_regions.as_slice();
 4834        selections.into_iter().map(move |selection| {
 4835            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4836
 4837            let mut enclosing = None;
 4838            while let Some(pair_state) = regions.get(i) {
 4839                if pair_state.range.end.to_offset(buffer) < range.start {
 4840                    regions = &regions[i + 1..];
 4841                    i = 0;
 4842                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4843                    break;
 4844                } else {
 4845                    if pair_state.selection_id == selection.id {
 4846                        enclosing = Some(pair_state);
 4847                    }
 4848                    i += 1;
 4849                }
 4850            }
 4851
 4852            (selection, enclosing)
 4853        })
 4854    }
 4855
 4856    /// Remove any autoclose regions that no longer contain their selection.
 4857    fn invalidate_autoclose_regions(
 4858        &mut self,
 4859        mut selections: &[Selection<Anchor>],
 4860        buffer: &MultiBufferSnapshot,
 4861    ) {
 4862        self.autoclose_regions.retain(|state| {
 4863            let mut i = 0;
 4864            while let Some(selection) = selections.get(i) {
 4865                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4866                    selections = &selections[1..];
 4867                    continue;
 4868                }
 4869                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4870                    break;
 4871                }
 4872                if selection.id == state.selection_id {
 4873                    return true;
 4874                } else {
 4875                    i += 1;
 4876                }
 4877            }
 4878            false
 4879        });
 4880    }
 4881
 4882    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4883        let offset = position.to_offset(buffer);
 4884        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4885        if offset > word_range.start && kind == Some(CharKind::Word) {
 4886            Some(
 4887                buffer
 4888                    .text_for_range(word_range.start..offset)
 4889                    .collect::<String>(),
 4890            )
 4891        } else {
 4892            None
 4893        }
 4894    }
 4895
 4896    pub fn toggle_inline_values(
 4897        &mut self,
 4898        _: &ToggleInlineValues,
 4899        _: &mut Window,
 4900        cx: &mut Context<Self>,
 4901    ) {
 4902        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4903
 4904        self.refresh_inline_values(cx);
 4905    }
 4906
 4907    pub fn toggle_inlay_hints(
 4908        &mut self,
 4909        _: &ToggleInlayHints,
 4910        _: &mut Window,
 4911        cx: &mut Context<Self>,
 4912    ) {
 4913        self.refresh_inlay_hints(
 4914            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4915            cx,
 4916        );
 4917    }
 4918
 4919    pub fn inlay_hints_enabled(&self) -> bool {
 4920        self.inlay_hint_cache.enabled
 4921    }
 4922
 4923    pub fn inline_values_enabled(&self) -> bool {
 4924        self.inline_value_cache.enabled
 4925    }
 4926
 4927    #[cfg(any(test, feature = "test-support"))]
 4928    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4929        self.display_map
 4930            .read(cx)
 4931            .current_inlays()
 4932            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4933            .cloned()
 4934            .collect()
 4935    }
 4936
 4937    #[cfg(any(test, feature = "test-support"))]
 4938    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 4939        self.display_map
 4940            .read(cx)
 4941            .current_inlays()
 4942            .cloned()
 4943            .collect()
 4944    }
 4945
 4946    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4947        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4948            return;
 4949        }
 4950
 4951        let reason_description = reason.description();
 4952        let ignore_debounce = matches!(
 4953            reason,
 4954            InlayHintRefreshReason::SettingsChange(_)
 4955                | InlayHintRefreshReason::Toggle(_)
 4956                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4957                | InlayHintRefreshReason::ModifiersChanged(_)
 4958        );
 4959        let (invalidate_cache, required_languages) = match reason {
 4960            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4961                match self.inlay_hint_cache.modifiers_override(enabled) {
 4962                    Some(enabled) => {
 4963                        if enabled {
 4964                            (InvalidationStrategy::RefreshRequested, None)
 4965                        } else {
 4966                            self.splice_inlays(
 4967                                &self
 4968                                    .visible_inlay_hints(cx)
 4969                                    .iter()
 4970                                    .map(|inlay| inlay.id)
 4971                                    .collect::<Vec<InlayId>>(),
 4972                                Vec::new(),
 4973                                cx,
 4974                            );
 4975                            return;
 4976                        }
 4977                    }
 4978                    None => return,
 4979                }
 4980            }
 4981            InlayHintRefreshReason::Toggle(enabled) => {
 4982                if self.inlay_hint_cache.toggle(enabled) {
 4983                    if enabled {
 4984                        (InvalidationStrategy::RefreshRequested, None)
 4985                    } else {
 4986                        self.splice_inlays(
 4987                            &self
 4988                                .visible_inlay_hints(cx)
 4989                                .iter()
 4990                                .map(|inlay| inlay.id)
 4991                                .collect::<Vec<InlayId>>(),
 4992                            Vec::new(),
 4993                            cx,
 4994                        );
 4995                        return;
 4996                    }
 4997                } else {
 4998                    return;
 4999                }
 5000            }
 5001            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5002                match self.inlay_hint_cache.update_settings(
 5003                    &self.buffer,
 5004                    new_settings,
 5005                    self.visible_inlay_hints(cx),
 5006                    cx,
 5007                ) {
 5008                    ControlFlow::Break(Some(InlaySplice {
 5009                        to_remove,
 5010                        to_insert,
 5011                    })) => {
 5012                        self.splice_inlays(&to_remove, to_insert, cx);
 5013                        return;
 5014                    }
 5015                    ControlFlow::Break(None) => return,
 5016                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5017                }
 5018            }
 5019            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5020                if let Some(InlaySplice {
 5021                    to_remove,
 5022                    to_insert,
 5023                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5024                {
 5025                    self.splice_inlays(&to_remove, to_insert, cx);
 5026                }
 5027                self.display_map.update(cx, |display_map, _| {
 5028                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5029                });
 5030                return;
 5031            }
 5032            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5033            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5034                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5035            }
 5036            InlayHintRefreshReason::RefreshRequested => {
 5037                (InvalidationStrategy::RefreshRequested, None)
 5038            }
 5039        };
 5040
 5041        if let Some(InlaySplice {
 5042            to_remove,
 5043            to_insert,
 5044        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5045            reason_description,
 5046            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 5047            invalidate_cache,
 5048            ignore_debounce,
 5049            cx,
 5050        ) {
 5051            self.splice_inlays(&to_remove, to_insert, cx);
 5052        }
 5053    }
 5054
 5055    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5056        self.display_map
 5057            .read(cx)
 5058            .current_inlays()
 5059            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5060            .cloned()
 5061            .collect()
 5062    }
 5063
 5064    pub fn excerpts_for_inlay_hints_query(
 5065        &self,
 5066        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5067        cx: &mut Context<Editor>,
 5068    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5069        let Some(project) = self.project.as_ref() else {
 5070            return HashMap::default();
 5071        };
 5072        let project = project.read(cx);
 5073        let multi_buffer = self.buffer().read(cx);
 5074        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5075        let multi_buffer_visible_start = self
 5076            .scroll_manager
 5077            .anchor()
 5078            .anchor
 5079            .to_point(&multi_buffer_snapshot);
 5080        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5081            multi_buffer_visible_start
 5082                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5083            Bias::Left,
 5084        );
 5085        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5086        multi_buffer_snapshot
 5087            .range_to_buffer_ranges(multi_buffer_visible_range)
 5088            .into_iter()
 5089            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5090            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5091                let buffer_file = project::File::from_dyn(buffer.file())?;
 5092                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5093                let worktree_entry = buffer_worktree
 5094                    .read(cx)
 5095                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5096                if worktree_entry.is_ignored {
 5097                    return None;
 5098                }
 5099
 5100                let language = buffer.language()?;
 5101                if let Some(restrict_to_languages) = restrict_to_languages {
 5102                    if !restrict_to_languages.contains(language) {
 5103                        return None;
 5104                    }
 5105                }
 5106                Some((
 5107                    excerpt_id,
 5108                    (
 5109                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5110                        buffer.version().clone(),
 5111                        excerpt_visible_range,
 5112                    ),
 5113                ))
 5114            })
 5115            .collect()
 5116    }
 5117
 5118    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5119        TextLayoutDetails {
 5120            text_system: window.text_system().clone(),
 5121            editor_style: self.style.clone().unwrap(),
 5122            rem_size: window.rem_size(),
 5123            scroll_anchor: self.scroll_manager.anchor(),
 5124            visible_rows: self.visible_line_count(),
 5125            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5126        }
 5127    }
 5128
 5129    pub fn splice_inlays(
 5130        &self,
 5131        to_remove: &[InlayId],
 5132        to_insert: Vec<Inlay>,
 5133        cx: &mut Context<Self>,
 5134    ) {
 5135        self.display_map.update(cx, |display_map, cx| {
 5136            display_map.splice_inlays(to_remove, to_insert, cx)
 5137        });
 5138        cx.notify();
 5139    }
 5140
 5141    fn trigger_on_type_formatting(
 5142        &self,
 5143        input: String,
 5144        window: &mut Window,
 5145        cx: &mut Context<Self>,
 5146    ) -> Option<Task<Result<()>>> {
 5147        if input.len() != 1 {
 5148            return None;
 5149        }
 5150
 5151        let project = self.project.as_ref()?;
 5152        let position = self.selections.newest_anchor().head();
 5153        let (buffer, buffer_position) = self
 5154            .buffer
 5155            .read(cx)
 5156            .text_anchor_for_position(position, cx)?;
 5157
 5158        let settings = language_settings::language_settings(
 5159            buffer
 5160                .read(cx)
 5161                .language_at(buffer_position)
 5162                .map(|l| l.name()),
 5163            buffer.read(cx).file(),
 5164            cx,
 5165        );
 5166        if !settings.use_on_type_format {
 5167            return None;
 5168        }
 5169
 5170        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5171        // hence we do LSP request & edit on host side only — add formats to host's history.
 5172        let push_to_lsp_host_history = true;
 5173        // If this is not the host, append its history with new edits.
 5174        let push_to_client_history = project.read(cx).is_via_collab();
 5175
 5176        let on_type_formatting = project.update(cx, |project, cx| {
 5177            project.on_type_format(
 5178                buffer.clone(),
 5179                buffer_position,
 5180                input,
 5181                push_to_lsp_host_history,
 5182                cx,
 5183            )
 5184        });
 5185        Some(cx.spawn_in(window, async move |editor, cx| {
 5186            if let Some(transaction) = on_type_formatting.await? {
 5187                if push_to_client_history {
 5188                    buffer
 5189                        .update(cx, |buffer, _| {
 5190                            buffer.push_transaction(transaction, Instant::now());
 5191                            buffer.finalize_last_transaction();
 5192                        })
 5193                        .ok();
 5194                }
 5195                editor.update(cx, |editor, cx| {
 5196                    editor.refresh_document_highlights(cx);
 5197                })?;
 5198            }
 5199            Ok(())
 5200        }))
 5201    }
 5202
 5203    pub fn show_word_completions(
 5204        &mut self,
 5205        _: &ShowWordCompletions,
 5206        window: &mut Window,
 5207        cx: &mut Context<Self>,
 5208    ) {
 5209        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5210    }
 5211
 5212    pub fn show_completions(
 5213        &mut self,
 5214        options: &ShowCompletions,
 5215        window: &mut Window,
 5216        cx: &mut Context<Self>,
 5217    ) {
 5218        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5219    }
 5220
 5221    fn open_or_update_completions_menu(
 5222        &mut self,
 5223        requested_source: Option<CompletionsMenuSource>,
 5224        trigger: Option<&str>,
 5225        window: &mut Window,
 5226        cx: &mut Context<Self>,
 5227    ) {
 5228        if self.pending_rename.is_some() {
 5229            return;
 5230        }
 5231
 5232        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5233
 5234        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5235        // inserted and selected. To handle that case, the start of the selection is used so that
 5236        // the menu starts with all choices.
 5237        let position = self
 5238            .selections
 5239            .newest_anchor()
 5240            .start
 5241            .bias_right(&multibuffer_snapshot);
 5242        if position.diff_base_anchor.is_some() {
 5243            return;
 5244        }
 5245        let (buffer, buffer_position) =
 5246            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5247                output
 5248            } else {
 5249                return;
 5250            };
 5251        let buffer_snapshot = buffer.read(cx).snapshot();
 5252
 5253        let query: Option<Arc<String>> =
 5254            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5255
 5256        drop(multibuffer_snapshot);
 5257
 5258        let provider = match requested_source {
 5259            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5260            Some(CompletionsMenuSource::Words) => None,
 5261            Some(CompletionsMenuSource::SnippetChoices) => {
 5262                log::error!("bug: SnippetChoices requested_source is not handled");
 5263                None
 5264            }
 5265        };
 5266
 5267        let sort_completions = provider
 5268            .as_ref()
 5269            .map_or(false, |provider| provider.sort_completions());
 5270
 5271        let filter_completions = provider
 5272            .as_ref()
 5273            .map_or(true, |provider| provider.filter_completions());
 5274
 5275        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5276            if filter_completions {
 5277                menu.filter(query.clone(), provider.clone(), window, cx);
 5278            }
 5279            // When `is_incomplete` is false, no need to re-query completions when the current query
 5280            // is a suffix of the initial query.
 5281            if !menu.is_incomplete {
 5282                // If the new query is a suffix of the old query (typing more characters) and
 5283                // the previous result was complete, the existing completions can be filtered.
 5284                //
 5285                // Note that this is always true for snippet completions.
 5286                let query_matches = match (&menu.initial_query, &query) {
 5287                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5288                    (None, _) => true,
 5289                    _ => false,
 5290                };
 5291                if query_matches {
 5292                    let position_matches = if menu.initial_position == position {
 5293                        true
 5294                    } else {
 5295                        let snapshot = self.buffer.read(cx).read(cx);
 5296                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5297                    };
 5298                    if position_matches {
 5299                        return;
 5300                    }
 5301                }
 5302            }
 5303        };
 5304
 5305        let trigger_kind = match trigger {
 5306            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5307                CompletionTriggerKind::TRIGGER_CHARACTER
 5308            }
 5309            _ => CompletionTriggerKind::INVOKED,
 5310        };
 5311        let completion_context = CompletionContext {
 5312            trigger_character: trigger.and_then(|trigger| {
 5313                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5314                    Some(String::from(trigger))
 5315                } else {
 5316                    None
 5317                }
 5318            }),
 5319            trigger_kind,
 5320        };
 5321
 5322        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5323            buffer_snapshot.surrounding_word(buffer_position)
 5324        {
 5325            let word_to_exclude = buffer_snapshot
 5326                .text_for_range(word_range.clone())
 5327                .collect::<String>();
 5328            (
 5329                buffer_snapshot.anchor_before(word_range.start)
 5330                    ..buffer_snapshot.anchor_after(buffer_position),
 5331                Some(word_to_exclude),
 5332            )
 5333        } else {
 5334            (buffer_position..buffer_position, None)
 5335        };
 5336
 5337        let language = buffer_snapshot
 5338            .language_at(buffer_position)
 5339            .map(|language| language.name());
 5340
 5341        let completion_settings =
 5342            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5343
 5344        let show_completion_documentation = buffer_snapshot
 5345            .settings_at(buffer_position, cx)
 5346            .show_completion_documentation;
 5347
 5348        // The document can be large, so stay in reasonable bounds when searching for words,
 5349        // otherwise completion pop-up might be slow to appear.
 5350        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5351        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5352        let min_word_search = buffer_snapshot.clip_point(
 5353            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5354            Bias::Left,
 5355        );
 5356        let max_word_search = buffer_snapshot.clip_point(
 5357            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5358            Bias::Right,
 5359        );
 5360        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5361            ..buffer_snapshot.point_to_offset(max_word_search);
 5362
 5363        let skip_digits = query
 5364            .as_ref()
 5365            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5366
 5367        let (mut words, provider_responses) = match &provider {
 5368            Some(provider) => {
 5369                let provider_responses = provider.completions(
 5370                    position.excerpt_id,
 5371                    &buffer,
 5372                    buffer_position,
 5373                    completion_context,
 5374                    window,
 5375                    cx,
 5376                );
 5377
 5378                let words = match completion_settings.words {
 5379                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5380                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5381                        .background_spawn(async move {
 5382                            buffer_snapshot.words_in_range(WordsQuery {
 5383                                fuzzy_contents: None,
 5384                                range: word_search_range,
 5385                                skip_digits,
 5386                            })
 5387                        }),
 5388                };
 5389
 5390                (words, provider_responses)
 5391            }
 5392            None => (
 5393                cx.background_spawn(async move {
 5394                    buffer_snapshot.words_in_range(WordsQuery {
 5395                        fuzzy_contents: None,
 5396                        range: word_search_range,
 5397                        skip_digits,
 5398                    })
 5399                }),
 5400                Task::ready(Ok(Vec::new())),
 5401            ),
 5402        };
 5403
 5404        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5405
 5406        let id = post_inc(&mut self.next_completion_id);
 5407        let task = cx.spawn_in(window, async move |editor, cx| {
 5408            let Ok(()) = editor.update(cx, |this, _| {
 5409                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5410            }) else {
 5411                return;
 5412            };
 5413
 5414            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5415            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5416            let mut completions = Vec::new();
 5417            let mut is_incomplete = false;
 5418            if let Some(provider_responses) = provider_responses.await.log_err() {
 5419                if !provider_responses.is_empty() {
 5420                    for response in provider_responses {
 5421                        completions.extend(response.completions);
 5422                        is_incomplete = is_incomplete || response.is_incomplete;
 5423                    }
 5424                    if completion_settings.words == WordsCompletionMode::Fallback {
 5425                        words = Task::ready(BTreeMap::default());
 5426                    }
 5427                }
 5428            }
 5429
 5430            let mut words = words.await;
 5431            if let Some(word_to_exclude) = &word_to_exclude {
 5432                words.remove(word_to_exclude);
 5433            }
 5434            for lsp_completion in &completions {
 5435                words.remove(&lsp_completion.new_text);
 5436            }
 5437            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5438                replace_range: word_replace_range.clone(),
 5439                new_text: word.clone(),
 5440                label: CodeLabel::plain(word, None),
 5441                icon_path: None,
 5442                documentation: None,
 5443                source: CompletionSource::BufferWord {
 5444                    word_range,
 5445                    resolved: false,
 5446                },
 5447                insert_text_mode: Some(InsertTextMode::AS_IS),
 5448                confirm: None,
 5449            }));
 5450
 5451            let menu = if completions.is_empty() {
 5452                None
 5453            } else {
 5454                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5455                    let languages = editor
 5456                        .workspace
 5457                        .as_ref()
 5458                        .and_then(|(workspace, _)| workspace.upgrade())
 5459                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5460                    let menu = CompletionsMenu::new(
 5461                        id,
 5462                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5463                        sort_completions,
 5464                        show_completion_documentation,
 5465                        position,
 5466                        query.clone(),
 5467                        is_incomplete,
 5468                        buffer.clone(),
 5469                        completions.into(),
 5470                        snippet_sort_order,
 5471                        languages,
 5472                        language,
 5473                        cx,
 5474                    );
 5475
 5476                    let query = if filter_completions { query } else { None };
 5477                    let matches_task = if let Some(query) = query {
 5478                        menu.do_async_filtering(query, cx)
 5479                    } else {
 5480                        Task::ready(menu.unfiltered_matches())
 5481                    };
 5482                    (menu, matches_task)
 5483                }) else {
 5484                    return;
 5485                };
 5486
 5487                let matches = matches_task.await;
 5488
 5489                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5490                    // Newer menu already set, so exit.
 5491                    match editor.context_menu.borrow().as_ref() {
 5492                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5493                            if prev_menu.id > id {
 5494                                return;
 5495                            }
 5496                        }
 5497                        _ => {}
 5498                    };
 5499
 5500                    // Only valid to take prev_menu because it the new menu is immediately set
 5501                    // below, or the menu is hidden.
 5502                    match editor.context_menu.borrow_mut().take() {
 5503                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5504                            let position_matches =
 5505                                if prev_menu.initial_position == menu.initial_position {
 5506                                    true
 5507                                } else {
 5508                                    let snapshot = editor.buffer.read(cx).read(cx);
 5509                                    prev_menu.initial_position.to_offset(&snapshot)
 5510                                        == menu.initial_position.to_offset(&snapshot)
 5511                                };
 5512                            if position_matches {
 5513                                // Preserve markdown cache before `set_filter_results` because it will
 5514                                // try to populate the documentation cache.
 5515                                menu.preserve_markdown_cache(prev_menu);
 5516                            }
 5517                        }
 5518                        _ => {}
 5519                    };
 5520
 5521                    menu.set_filter_results(matches, provider, window, cx);
 5522                }) else {
 5523                    return;
 5524                };
 5525
 5526                menu.visible().then_some(menu)
 5527            };
 5528
 5529            editor
 5530                .update_in(cx, |editor, window, cx| {
 5531                    if editor.focus_handle.is_focused(window) {
 5532                        if let Some(menu) = menu {
 5533                            *editor.context_menu.borrow_mut() =
 5534                                Some(CodeContextMenu::Completions(menu));
 5535
 5536                            crate::hover_popover::hide_hover(editor, cx);
 5537                            if editor.show_edit_predictions_in_menu() {
 5538                                editor.update_visible_inline_completion(window, cx);
 5539                            } else {
 5540                                editor.discard_inline_completion(false, cx);
 5541                            }
 5542
 5543                            cx.notify();
 5544                            return;
 5545                        }
 5546                    }
 5547
 5548                    if editor.completion_tasks.len() <= 1 {
 5549                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5550                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5551                        // If it was already hidden and we don't show inline completions in the menu, we should
 5552                        // also show the inline-completion when available.
 5553                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5554                            editor.update_visible_inline_completion(window, cx);
 5555                        }
 5556                    }
 5557                })
 5558                .ok();
 5559        });
 5560
 5561        self.completion_tasks.push((id, task));
 5562    }
 5563
 5564    #[cfg(feature = "test-support")]
 5565    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5566        let menu = self.context_menu.borrow();
 5567        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5568            let completions = menu.completions.borrow();
 5569            Some(completions.to_vec())
 5570        } else {
 5571            None
 5572        }
 5573    }
 5574
 5575    pub fn with_completions_menu_matching_id<R>(
 5576        &self,
 5577        id: CompletionId,
 5578        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5579    ) -> R {
 5580        let mut context_menu = self.context_menu.borrow_mut();
 5581        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5582            return f(None);
 5583        };
 5584        if completions_menu.id != id {
 5585            return f(None);
 5586        }
 5587        f(Some(completions_menu))
 5588    }
 5589
 5590    pub fn confirm_completion(
 5591        &mut self,
 5592        action: &ConfirmCompletion,
 5593        window: &mut Window,
 5594        cx: &mut Context<Self>,
 5595    ) -> Option<Task<Result<()>>> {
 5596        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5597        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5598    }
 5599
 5600    pub fn confirm_completion_insert(
 5601        &mut self,
 5602        _: &ConfirmCompletionInsert,
 5603        window: &mut Window,
 5604        cx: &mut Context<Self>,
 5605    ) -> Option<Task<Result<()>>> {
 5606        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5607        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5608    }
 5609
 5610    pub fn confirm_completion_replace(
 5611        &mut self,
 5612        _: &ConfirmCompletionReplace,
 5613        window: &mut Window,
 5614        cx: &mut Context<Self>,
 5615    ) -> Option<Task<Result<()>>> {
 5616        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5617        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5618    }
 5619
 5620    pub fn compose_completion(
 5621        &mut self,
 5622        action: &ComposeCompletion,
 5623        window: &mut Window,
 5624        cx: &mut Context<Self>,
 5625    ) -> Option<Task<Result<()>>> {
 5626        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5627        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5628    }
 5629
 5630    fn do_completion(
 5631        &mut self,
 5632        item_ix: Option<usize>,
 5633        intent: CompletionIntent,
 5634        window: &mut Window,
 5635        cx: &mut Context<Editor>,
 5636    ) -> Option<Task<Result<()>>> {
 5637        use language::ToOffset as _;
 5638
 5639        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5640        else {
 5641            return None;
 5642        };
 5643
 5644        let candidate_id = {
 5645            let entries = completions_menu.entries.borrow();
 5646            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5647            if self.show_edit_predictions_in_menu() {
 5648                self.discard_inline_completion(true, cx);
 5649            }
 5650            mat.candidate_id
 5651        };
 5652
 5653        let completion = completions_menu
 5654            .completions
 5655            .borrow()
 5656            .get(candidate_id)?
 5657            .clone();
 5658        cx.stop_propagation();
 5659
 5660        let buffer_handle = completions_menu.buffer.clone();
 5661
 5662        let CompletionEdit {
 5663            new_text,
 5664            snippet,
 5665            replace_range,
 5666        } = process_completion_for_edit(
 5667            &completion,
 5668            intent,
 5669            &buffer_handle,
 5670            &completions_menu.initial_position.text_anchor,
 5671            cx,
 5672        );
 5673
 5674        let buffer = buffer_handle.read(cx);
 5675        let snapshot = self.buffer.read(cx).snapshot(cx);
 5676        let newest_anchor = self.selections.newest_anchor();
 5677        let replace_range_multibuffer = {
 5678            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5679            let multibuffer_anchor = snapshot
 5680                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5681                .unwrap()
 5682                ..snapshot
 5683                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5684                    .unwrap();
 5685            multibuffer_anchor.start.to_offset(&snapshot)
 5686                ..multibuffer_anchor.end.to_offset(&snapshot)
 5687        };
 5688        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5689            return None;
 5690        }
 5691
 5692        let old_text = buffer
 5693            .text_for_range(replace_range.clone())
 5694            .collect::<String>();
 5695        let lookbehind = newest_anchor
 5696            .start
 5697            .text_anchor
 5698            .to_offset(buffer)
 5699            .saturating_sub(replace_range.start);
 5700        let lookahead = replace_range
 5701            .end
 5702            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5703        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5704        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5705
 5706        let selections = self.selections.all::<usize>(cx);
 5707        let mut ranges = Vec::new();
 5708        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5709
 5710        for selection in &selections {
 5711            let range = if selection.id == newest_anchor.id {
 5712                replace_range_multibuffer.clone()
 5713            } else {
 5714                let mut range = selection.range();
 5715
 5716                // if prefix is present, don't duplicate it
 5717                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5718                    range.start = range.start.saturating_sub(lookbehind);
 5719
 5720                    // if suffix is also present, mimic the newest cursor and replace it
 5721                    if selection.id != newest_anchor.id
 5722                        && snapshot.contains_str_at(range.end, suffix)
 5723                    {
 5724                        range.end += lookahead;
 5725                    }
 5726                }
 5727                range
 5728            };
 5729
 5730            ranges.push(range.clone());
 5731
 5732            if !self.linked_edit_ranges.is_empty() {
 5733                let start_anchor = snapshot.anchor_before(range.start);
 5734                let end_anchor = snapshot.anchor_after(range.end);
 5735                if let Some(ranges) = self
 5736                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5737                {
 5738                    for (buffer, edits) in ranges {
 5739                        linked_edits
 5740                            .entry(buffer.clone())
 5741                            .or_default()
 5742                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5743                    }
 5744                }
 5745            }
 5746        }
 5747
 5748        let common_prefix_len = old_text
 5749            .chars()
 5750            .zip(new_text.chars())
 5751            .take_while(|(a, b)| a == b)
 5752            .map(|(a, _)| a.len_utf8())
 5753            .sum::<usize>();
 5754
 5755        cx.emit(EditorEvent::InputHandled {
 5756            utf16_range_to_replace: None,
 5757            text: new_text[common_prefix_len..].into(),
 5758        });
 5759
 5760        self.transact(window, cx, |this, window, cx| {
 5761            if let Some(mut snippet) = snippet {
 5762                snippet.text = new_text.to_string();
 5763                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5764            } else {
 5765                this.buffer.update(cx, |buffer, cx| {
 5766                    let auto_indent = match completion.insert_text_mode {
 5767                        Some(InsertTextMode::AS_IS) => None,
 5768                        _ => this.autoindent_mode.clone(),
 5769                    };
 5770                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5771                    buffer.edit(edits, auto_indent, cx);
 5772                });
 5773            }
 5774            for (buffer, edits) in linked_edits {
 5775                buffer.update(cx, |buffer, cx| {
 5776                    let snapshot = buffer.snapshot();
 5777                    let edits = edits
 5778                        .into_iter()
 5779                        .map(|(range, text)| {
 5780                            use text::ToPoint as TP;
 5781                            let end_point = TP::to_point(&range.end, &snapshot);
 5782                            let start_point = TP::to_point(&range.start, &snapshot);
 5783                            (start_point..end_point, text)
 5784                        })
 5785                        .sorted_by_key(|(range, _)| range.start);
 5786                    buffer.edit(edits, None, cx);
 5787                })
 5788            }
 5789
 5790            this.refresh_inline_completion(true, false, window, cx);
 5791        });
 5792
 5793        let show_new_completions_on_confirm = completion
 5794            .confirm
 5795            .as_ref()
 5796            .map_or(false, |confirm| confirm(intent, window, cx));
 5797        if show_new_completions_on_confirm {
 5798            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5799        }
 5800
 5801        let provider = self.completion_provider.as_ref()?;
 5802        drop(completion);
 5803        let apply_edits = provider.apply_additional_edits_for_completion(
 5804            buffer_handle,
 5805            completions_menu.completions.clone(),
 5806            candidate_id,
 5807            true,
 5808            cx,
 5809        );
 5810
 5811        let editor_settings = EditorSettings::get_global(cx);
 5812        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5813            // After the code completion is finished, users often want to know what signatures are needed.
 5814            // so we should automatically call signature_help
 5815            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5816        }
 5817
 5818        Some(cx.foreground_executor().spawn(async move {
 5819            apply_edits.await?;
 5820            Ok(())
 5821        }))
 5822    }
 5823
 5824    pub fn toggle_code_actions(
 5825        &mut self,
 5826        action: &ToggleCodeActions,
 5827        window: &mut Window,
 5828        cx: &mut Context<Self>,
 5829    ) {
 5830        let quick_launch = action.quick_launch;
 5831        let mut context_menu = self.context_menu.borrow_mut();
 5832        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5833            if code_actions.deployed_from == action.deployed_from {
 5834                // Toggle if we're selecting the same one
 5835                *context_menu = None;
 5836                cx.notify();
 5837                return;
 5838            } else {
 5839                // Otherwise, clear it and start a new one
 5840                *context_menu = None;
 5841                cx.notify();
 5842            }
 5843        }
 5844        drop(context_menu);
 5845        let snapshot = self.snapshot(window, cx);
 5846        let deployed_from = action.deployed_from.clone();
 5847        let action = action.clone();
 5848        self.completion_tasks.clear();
 5849        self.discard_inline_completion(false, cx);
 5850
 5851        let multibuffer_point = match &action.deployed_from {
 5852            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5853                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5854            }
 5855            _ => self.selections.newest::<Point>(cx).head(),
 5856        };
 5857        let Some((buffer, buffer_row)) = snapshot
 5858            .buffer_snapshot
 5859            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5860            .and_then(|(buffer_snapshot, range)| {
 5861                self.buffer()
 5862                    .read(cx)
 5863                    .buffer(buffer_snapshot.remote_id())
 5864                    .map(|buffer| (buffer, range.start.row))
 5865            })
 5866        else {
 5867            return;
 5868        };
 5869        let buffer_id = buffer.read(cx).remote_id();
 5870        let tasks = self
 5871            .tasks
 5872            .get(&(buffer_id, buffer_row))
 5873            .map(|t| Arc::new(t.to_owned()));
 5874
 5875        if !self.focus_handle.is_focused(window) {
 5876            return;
 5877        }
 5878        let project = self.project.clone();
 5879
 5880        let code_actions_task = match deployed_from {
 5881            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5882            _ => self.code_actions(buffer_row, window, cx),
 5883        };
 5884
 5885        let runnable_task = match deployed_from {
 5886            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5887            _ => {
 5888                let mut task_context_task = Task::ready(None);
 5889                if let Some(tasks) = &tasks {
 5890                    if let Some(project) = project {
 5891                        task_context_task =
 5892                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5893                    }
 5894                }
 5895
 5896                cx.spawn_in(window, {
 5897                    let buffer = buffer.clone();
 5898                    async move |editor, cx| {
 5899                        let task_context = task_context_task.await;
 5900
 5901                        let resolved_tasks =
 5902                            tasks
 5903                                .zip(task_context.clone())
 5904                                .map(|(tasks, task_context)| ResolvedTasks {
 5905                                    templates: tasks.resolve(&task_context).collect(),
 5906                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5907                                        multibuffer_point.row,
 5908                                        tasks.column,
 5909                                    )),
 5910                                });
 5911                        let debug_scenarios = editor
 5912                            .update(cx, |editor, cx| {
 5913                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5914                            })?
 5915                            .await;
 5916                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5917                    }
 5918                })
 5919            }
 5920        };
 5921
 5922        cx.spawn_in(window, async move |editor, cx| {
 5923            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5924            let code_actions = code_actions_task.await;
 5925            let spawn_straight_away = quick_launch
 5926                && resolved_tasks
 5927                    .as_ref()
 5928                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5929                && code_actions
 5930                    .as_ref()
 5931                    .map_or(true, |actions| actions.is_empty())
 5932                && debug_scenarios.is_empty();
 5933
 5934            editor.update_in(cx, |editor, window, cx| {
 5935                crate::hover_popover::hide_hover(editor, cx);
 5936                *editor.context_menu.borrow_mut() =
 5937                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5938                        buffer,
 5939                        actions: CodeActionContents::new(
 5940                            resolved_tasks,
 5941                            code_actions,
 5942                            debug_scenarios,
 5943                            task_context.unwrap_or_default(),
 5944                        ),
 5945                        selected_item: Default::default(),
 5946                        scroll_handle: UniformListScrollHandle::default(),
 5947                        deployed_from,
 5948                    }));
 5949                cx.notify();
 5950                if spawn_straight_away {
 5951                    if let Some(task) = editor.confirm_code_action(
 5952                        &ConfirmCodeAction { item_ix: Some(0) },
 5953                        window,
 5954                        cx,
 5955                    ) {
 5956                        return task;
 5957                    }
 5958                }
 5959
 5960                Task::ready(Ok(()))
 5961            })
 5962        })
 5963        .detach_and_log_err(cx);
 5964    }
 5965
 5966    fn debug_scenarios(
 5967        &mut self,
 5968        resolved_tasks: &Option<ResolvedTasks>,
 5969        buffer: &Entity<Buffer>,
 5970        cx: &mut App,
 5971    ) -> Task<Vec<task::DebugScenario>> {
 5972        if cx.has_flag::<DebuggerFeatureFlag>() {
 5973            maybe!({
 5974                let project = self.project.as_ref()?;
 5975                let dap_store = project.read(cx).dap_store();
 5976                let mut scenarios = vec![];
 5977                let resolved_tasks = resolved_tasks.as_ref()?;
 5978                let buffer = buffer.read(cx);
 5979                let language = buffer.language()?;
 5980                let file = buffer.file();
 5981                let debug_adapter = language_settings(language.name().into(), file, cx)
 5982                    .debuggers
 5983                    .first()
 5984                    .map(SharedString::from)
 5985                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5986
 5987                dap_store.update(cx, |dap_store, cx| {
 5988                    for (_, task) in &resolved_tasks.templates {
 5989                        let maybe_scenario = dap_store.debug_scenario_for_build_task(
 5990                            task.original_task().clone(),
 5991                            debug_adapter.clone().into(),
 5992                            task.display_label().to_owned().into(),
 5993                            cx,
 5994                        );
 5995                        scenarios.push(maybe_scenario);
 5996                    }
 5997                });
 5998                Some(cx.background_spawn(async move {
 5999                    let scenarios = futures::future::join_all(scenarios)
 6000                        .await
 6001                        .into_iter()
 6002                        .flatten()
 6003                        .collect::<Vec<_>>();
 6004                    scenarios
 6005                }))
 6006            })
 6007            .unwrap_or_else(|| Task::ready(vec![]))
 6008        } else {
 6009            Task::ready(vec![])
 6010        }
 6011    }
 6012
 6013    fn code_actions(
 6014        &mut self,
 6015        buffer_row: u32,
 6016        window: &mut Window,
 6017        cx: &mut Context<Self>,
 6018    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6019        let mut task = self.code_actions_task.take();
 6020        cx.spawn_in(window, async move |editor, cx| {
 6021            while let Some(prev_task) = task {
 6022                prev_task.await.log_err();
 6023                task = editor
 6024                    .update(cx, |this, _| this.code_actions_task.take())
 6025                    .ok()?;
 6026            }
 6027
 6028            editor
 6029                .update(cx, |editor, cx| {
 6030                    editor
 6031                        .available_code_actions
 6032                        .clone()
 6033                        .and_then(|(location, code_actions)| {
 6034                            let snapshot = location.buffer.read(cx).snapshot();
 6035                            let point_range = location.range.to_point(&snapshot);
 6036                            let point_range = point_range.start.row..=point_range.end.row;
 6037                            if point_range.contains(&buffer_row) {
 6038                                Some(code_actions)
 6039                            } else {
 6040                                None
 6041                            }
 6042                        })
 6043                })
 6044                .ok()
 6045                .flatten()
 6046        })
 6047    }
 6048
 6049    pub fn confirm_code_action(
 6050        &mut self,
 6051        action: &ConfirmCodeAction,
 6052        window: &mut Window,
 6053        cx: &mut Context<Self>,
 6054    ) -> Option<Task<Result<()>>> {
 6055        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6056
 6057        let actions_menu =
 6058            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6059                menu
 6060            } else {
 6061                return None;
 6062            };
 6063
 6064        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6065        let action = actions_menu.actions.get(action_ix)?;
 6066        let title = action.label();
 6067        let buffer = actions_menu.buffer;
 6068        let workspace = self.workspace()?;
 6069
 6070        match action {
 6071            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6072                workspace.update(cx, |workspace, cx| {
 6073                    workspace.schedule_resolved_task(
 6074                        task_source_kind,
 6075                        resolved_task,
 6076                        false,
 6077                        window,
 6078                        cx,
 6079                    );
 6080
 6081                    Some(Task::ready(Ok(())))
 6082                })
 6083            }
 6084            CodeActionsItem::CodeAction {
 6085                excerpt_id,
 6086                action,
 6087                provider,
 6088            } => {
 6089                let apply_code_action =
 6090                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6091                let workspace = workspace.downgrade();
 6092                Some(cx.spawn_in(window, async move |editor, cx| {
 6093                    let project_transaction = apply_code_action.await?;
 6094                    Self::open_project_transaction(
 6095                        &editor,
 6096                        workspace,
 6097                        project_transaction,
 6098                        title,
 6099                        cx,
 6100                    )
 6101                    .await
 6102                }))
 6103            }
 6104            CodeActionsItem::DebugScenario(scenario) => {
 6105                let context = actions_menu.actions.context.clone();
 6106
 6107                workspace.update(cx, |workspace, cx| {
 6108                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6109                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6110                });
 6111                Some(Task::ready(Ok(())))
 6112            }
 6113        }
 6114    }
 6115
 6116    pub async fn open_project_transaction(
 6117        this: &WeakEntity<Editor>,
 6118        workspace: WeakEntity<Workspace>,
 6119        transaction: ProjectTransaction,
 6120        title: String,
 6121        cx: &mut AsyncWindowContext,
 6122    ) -> Result<()> {
 6123        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6124        cx.update(|_, cx| {
 6125            entries.sort_unstable_by_key(|(buffer, _)| {
 6126                buffer.read(cx).file().map(|f| f.path().clone())
 6127            });
 6128        })?;
 6129
 6130        // If the project transaction's edits are all contained within this editor, then
 6131        // avoid opening a new editor to display them.
 6132
 6133        if let Some((buffer, transaction)) = entries.first() {
 6134            if entries.len() == 1 {
 6135                let excerpt = this.update(cx, |editor, cx| {
 6136                    editor
 6137                        .buffer()
 6138                        .read(cx)
 6139                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6140                })?;
 6141                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6142                    if excerpted_buffer == *buffer {
 6143                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6144                            let excerpt_range = excerpt_range.to_offset(buffer);
 6145                            buffer
 6146                                .edited_ranges_for_transaction::<usize>(transaction)
 6147                                .all(|range| {
 6148                                    excerpt_range.start <= range.start
 6149                                        && excerpt_range.end >= range.end
 6150                                })
 6151                        })?;
 6152
 6153                        if all_edits_within_excerpt {
 6154                            return Ok(());
 6155                        }
 6156                    }
 6157                }
 6158            }
 6159        } else {
 6160            return Ok(());
 6161        }
 6162
 6163        let mut ranges_to_highlight = Vec::new();
 6164        let excerpt_buffer = cx.new(|cx| {
 6165            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6166            for (buffer_handle, transaction) in &entries {
 6167                let edited_ranges = buffer_handle
 6168                    .read(cx)
 6169                    .edited_ranges_for_transaction::<Point>(transaction)
 6170                    .collect::<Vec<_>>();
 6171                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6172                    PathKey::for_buffer(buffer_handle, cx),
 6173                    buffer_handle.clone(),
 6174                    edited_ranges,
 6175                    DEFAULT_MULTIBUFFER_CONTEXT,
 6176                    cx,
 6177                );
 6178
 6179                ranges_to_highlight.extend(ranges);
 6180            }
 6181            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6182            multibuffer
 6183        })?;
 6184
 6185        workspace.update_in(cx, |workspace, window, cx| {
 6186            let project = workspace.project().clone();
 6187            let editor =
 6188                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6189            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6190            editor.update(cx, |editor, cx| {
 6191                editor.highlight_background::<Self>(
 6192                    &ranges_to_highlight,
 6193                    |theme| theme.colors().editor_highlighted_line_background,
 6194                    cx,
 6195                );
 6196            });
 6197        })?;
 6198
 6199        Ok(())
 6200    }
 6201
 6202    pub fn clear_code_action_providers(&mut self) {
 6203        self.code_action_providers.clear();
 6204        self.available_code_actions.take();
 6205    }
 6206
 6207    pub fn add_code_action_provider(
 6208        &mut self,
 6209        provider: Rc<dyn CodeActionProvider>,
 6210        window: &mut Window,
 6211        cx: &mut Context<Self>,
 6212    ) {
 6213        if self
 6214            .code_action_providers
 6215            .iter()
 6216            .any(|existing_provider| existing_provider.id() == provider.id())
 6217        {
 6218            return;
 6219        }
 6220
 6221        self.code_action_providers.push(provider);
 6222        self.refresh_code_actions(window, cx);
 6223    }
 6224
 6225    pub fn remove_code_action_provider(
 6226        &mut self,
 6227        id: Arc<str>,
 6228        window: &mut Window,
 6229        cx: &mut Context<Self>,
 6230    ) {
 6231        self.code_action_providers
 6232            .retain(|provider| provider.id() != id);
 6233        self.refresh_code_actions(window, cx);
 6234    }
 6235
 6236    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6237        !self.code_action_providers.is_empty()
 6238            && EditorSettings::get_global(cx).toolbar.code_actions
 6239    }
 6240
 6241    pub fn has_available_code_actions(&self) -> bool {
 6242        self.available_code_actions
 6243            .as_ref()
 6244            .is_some_and(|(_, actions)| !actions.is_empty())
 6245    }
 6246
 6247    fn render_inline_code_actions(
 6248        &self,
 6249        icon_size: ui::IconSize,
 6250        display_row: DisplayRow,
 6251        is_active: bool,
 6252        cx: &mut Context<Self>,
 6253    ) -> AnyElement {
 6254        let show_tooltip = !self.context_menu_visible();
 6255        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6256            .icon_size(icon_size)
 6257            .shape(ui::IconButtonShape::Square)
 6258            .style(ButtonStyle::Transparent)
 6259            .icon_color(ui::Color::Hidden)
 6260            .toggle_state(is_active)
 6261            .when(show_tooltip, |this| {
 6262                this.tooltip({
 6263                    let focus_handle = self.focus_handle.clone();
 6264                    move |window, cx| {
 6265                        Tooltip::for_action_in(
 6266                            "Toggle Code Actions",
 6267                            &ToggleCodeActions {
 6268                                deployed_from: None,
 6269                                quick_launch: false,
 6270                            },
 6271                            &focus_handle,
 6272                            window,
 6273                            cx,
 6274                        )
 6275                    }
 6276                })
 6277            })
 6278            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6279                window.focus(&editor.focus_handle(cx));
 6280                editor.toggle_code_actions(
 6281                    &crate::actions::ToggleCodeActions {
 6282                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6283                            display_row,
 6284                        )),
 6285                        quick_launch: false,
 6286                    },
 6287                    window,
 6288                    cx,
 6289                );
 6290            }))
 6291            .into_any_element()
 6292    }
 6293
 6294    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6295        &self.context_menu
 6296    }
 6297
 6298    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6299        let newest_selection = self.selections.newest_anchor().clone();
 6300        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6301        let buffer = self.buffer.read(cx);
 6302        if newest_selection.head().diff_base_anchor.is_some() {
 6303            return None;
 6304        }
 6305        let (start_buffer, start) =
 6306            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6307        let (end_buffer, end) =
 6308            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6309        if start_buffer != end_buffer {
 6310            return None;
 6311        }
 6312
 6313        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6314            cx.background_executor()
 6315                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6316                .await;
 6317
 6318            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6319                let providers = this.code_action_providers.clone();
 6320                let tasks = this
 6321                    .code_action_providers
 6322                    .iter()
 6323                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6324                    .collect::<Vec<_>>();
 6325                (providers, tasks)
 6326            })?;
 6327
 6328            let mut actions = Vec::new();
 6329            for (provider, provider_actions) in
 6330                providers.into_iter().zip(future::join_all(tasks).await)
 6331            {
 6332                if let Some(provider_actions) = provider_actions.log_err() {
 6333                    actions.extend(provider_actions.into_iter().map(|action| {
 6334                        AvailableCodeAction {
 6335                            excerpt_id: newest_selection.start.excerpt_id,
 6336                            action,
 6337                            provider: provider.clone(),
 6338                        }
 6339                    }));
 6340                }
 6341            }
 6342
 6343            this.update(cx, |this, cx| {
 6344                this.available_code_actions = if actions.is_empty() {
 6345                    None
 6346                } else {
 6347                    Some((
 6348                        Location {
 6349                            buffer: start_buffer,
 6350                            range: start..end,
 6351                        },
 6352                        actions.into(),
 6353                    ))
 6354                };
 6355                cx.notify();
 6356            })
 6357        }));
 6358        None
 6359    }
 6360
 6361    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6362        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6363            self.show_git_blame_inline = false;
 6364
 6365            self.show_git_blame_inline_delay_task =
 6366                Some(cx.spawn_in(window, async move |this, cx| {
 6367                    cx.background_executor().timer(delay).await;
 6368
 6369                    this.update(cx, |this, cx| {
 6370                        this.show_git_blame_inline = true;
 6371                        cx.notify();
 6372                    })
 6373                    .log_err();
 6374                }));
 6375        }
 6376    }
 6377
 6378    fn show_blame_popover(
 6379        &mut self,
 6380        blame_entry: &BlameEntry,
 6381        position: gpui::Point<Pixels>,
 6382        cx: &mut Context<Self>,
 6383    ) {
 6384        if let Some(state) = &mut self.inline_blame_popover {
 6385            state.hide_task.take();
 6386        } else {
 6387            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6388            let blame_entry = blame_entry.clone();
 6389            let show_task = cx.spawn(async move |editor, cx| {
 6390                cx.background_executor()
 6391                    .timer(std::time::Duration::from_millis(delay))
 6392                    .await;
 6393                editor
 6394                    .update(cx, |editor, cx| {
 6395                        editor.inline_blame_popover_show_task.take();
 6396                        let Some(blame) = editor.blame.as_ref() else {
 6397                            return;
 6398                        };
 6399                        let blame = blame.read(cx);
 6400                        let details = blame.details_for_entry(&blame_entry);
 6401                        let markdown = cx.new(|cx| {
 6402                            Markdown::new(
 6403                                details
 6404                                    .as_ref()
 6405                                    .map(|message| message.message.clone())
 6406                                    .unwrap_or_default(),
 6407                                None,
 6408                                None,
 6409                                cx,
 6410                            )
 6411                        });
 6412                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6413                            position,
 6414                            hide_task: None,
 6415                            popover_bounds: None,
 6416                            popover_state: InlineBlamePopoverState {
 6417                                scroll_handle: ScrollHandle::new(),
 6418                                commit_message: details,
 6419                                markdown,
 6420                            },
 6421                        });
 6422                        cx.notify();
 6423                    })
 6424                    .ok();
 6425            });
 6426            self.inline_blame_popover_show_task = Some(show_task);
 6427        }
 6428    }
 6429
 6430    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6431        self.inline_blame_popover_show_task.take();
 6432        if let Some(state) = &mut self.inline_blame_popover {
 6433            let hide_task = cx.spawn(async move |editor, cx| {
 6434                cx.background_executor()
 6435                    .timer(std::time::Duration::from_millis(100))
 6436                    .await;
 6437                editor
 6438                    .update(cx, |editor, cx| {
 6439                        editor.inline_blame_popover.take();
 6440                        cx.notify();
 6441                    })
 6442                    .ok();
 6443            });
 6444            state.hide_task = Some(hide_task);
 6445        }
 6446    }
 6447
 6448    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6449        if self.pending_rename.is_some() {
 6450            return None;
 6451        }
 6452
 6453        let provider = self.semantics_provider.clone()?;
 6454        let buffer = self.buffer.read(cx);
 6455        let newest_selection = self.selections.newest_anchor().clone();
 6456        let cursor_position = newest_selection.head();
 6457        let (cursor_buffer, cursor_buffer_position) =
 6458            buffer.text_anchor_for_position(cursor_position, cx)?;
 6459        let (tail_buffer, tail_buffer_position) =
 6460            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6461        if cursor_buffer != tail_buffer {
 6462            return None;
 6463        }
 6464
 6465        let snapshot = cursor_buffer.read(cx).snapshot();
 6466        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6467        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6468        if start_word_range != end_word_range {
 6469            self.document_highlights_task.take();
 6470            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6471            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6472            return None;
 6473        }
 6474
 6475        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6476        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6477            cx.background_executor()
 6478                .timer(Duration::from_millis(debounce))
 6479                .await;
 6480
 6481            let highlights = if let Some(highlights) = cx
 6482                .update(|cx| {
 6483                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6484                })
 6485                .ok()
 6486                .flatten()
 6487            {
 6488                highlights.await.log_err()
 6489            } else {
 6490                None
 6491            };
 6492
 6493            if let Some(highlights) = highlights {
 6494                this.update(cx, |this, cx| {
 6495                    if this.pending_rename.is_some() {
 6496                        return;
 6497                    }
 6498
 6499                    let buffer_id = cursor_position.buffer_id;
 6500                    let buffer = this.buffer.read(cx);
 6501                    if !buffer
 6502                        .text_anchor_for_position(cursor_position, cx)
 6503                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6504                    {
 6505                        return;
 6506                    }
 6507
 6508                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6509                    let mut write_ranges = Vec::new();
 6510                    let mut read_ranges = Vec::new();
 6511                    for highlight in highlights {
 6512                        for (excerpt_id, excerpt_range) in
 6513                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6514                        {
 6515                            let start = highlight
 6516                                .range
 6517                                .start
 6518                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6519                            let end = highlight
 6520                                .range
 6521                                .end
 6522                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6523                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6524                                continue;
 6525                            }
 6526
 6527                            let range = Anchor {
 6528                                buffer_id,
 6529                                excerpt_id,
 6530                                text_anchor: start,
 6531                                diff_base_anchor: None,
 6532                            }..Anchor {
 6533                                buffer_id,
 6534                                excerpt_id,
 6535                                text_anchor: end,
 6536                                diff_base_anchor: None,
 6537                            };
 6538                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6539                                write_ranges.push(range);
 6540                            } else {
 6541                                read_ranges.push(range);
 6542                            }
 6543                        }
 6544                    }
 6545
 6546                    this.highlight_background::<DocumentHighlightRead>(
 6547                        &read_ranges,
 6548                        |theme| theme.colors().editor_document_highlight_read_background,
 6549                        cx,
 6550                    );
 6551                    this.highlight_background::<DocumentHighlightWrite>(
 6552                        &write_ranges,
 6553                        |theme| theme.colors().editor_document_highlight_write_background,
 6554                        cx,
 6555                    );
 6556                    cx.notify();
 6557                })
 6558                .log_err();
 6559            }
 6560        }));
 6561        None
 6562    }
 6563
 6564    fn prepare_highlight_query_from_selection(
 6565        &mut self,
 6566        cx: &mut Context<Editor>,
 6567    ) -> Option<(String, Range<Anchor>)> {
 6568        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6569            return None;
 6570        }
 6571        if !EditorSettings::get_global(cx).selection_highlight {
 6572            return None;
 6573        }
 6574        if self.selections.count() != 1 || self.selections.line_mode {
 6575            return None;
 6576        }
 6577        let selection = self.selections.newest::<Point>(cx);
 6578        if selection.is_empty() || selection.start.row != selection.end.row {
 6579            return None;
 6580        }
 6581        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6582        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6583        let query = multi_buffer_snapshot
 6584            .text_for_range(selection_anchor_range.clone())
 6585            .collect::<String>();
 6586        if query.trim().is_empty() {
 6587            return None;
 6588        }
 6589        Some((query, selection_anchor_range))
 6590    }
 6591
 6592    fn update_selection_occurrence_highlights(
 6593        &mut self,
 6594        query_text: String,
 6595        query_range: Range<Anchor>,
 6596        multi_buffer_range_to_query: Range<Point>,
 6597        use_debounce: bool,
 6598        window: &mut Window,
 6599        cx: &mut Context<Editor>,
 6600    ) -> Task<()> {
 6601        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6602        cx.spawn_in(window, async move |editor, cx| {
 6603            if use_debounce {
 6604                cx.background_executor()
 6605                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6606                    .await;
 6607            }
 6608            let match_task = cx.background_spawn(async move {
 6609                let buffer_ranges = multi_buffer_snapshot
 6610                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6611                    .into_iter()
 6612                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6613                let mut match_ranges = Vec::new();
 6614                let Ok(regex) = project::search::SearchQuery::text(
 6615                    query_text.clone(),
 6616                    false,
 6617                    false,
 6618                    false,
 6619                    Default::default(),
 6620                    Default::default(),
 6621                    false,
 6622                    None,
 6623                ) else {
 6624                    return Vec::default();
 6625                };
 6626                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6627                    match_ranges.extend(
 6628                        regex
 6629                            .search(&buffer_snapshot, Some(search_range.clone()))
 6630                            .await
 6631                            .into_iter()
 6632                            .filter_map(|match_range| {
 6633                                let match_start = buffer_snapshot
 6634                                    .anchor_after(search_range.start + match_range.start);
 6635                                let match_end = buffer_snapshot
 6636                                    .anchor_before(search_range.start + match_range.end);
 6637                                let match_anchor_range = Anchor::range_in_buffer(
 6638                                    excerpt_id,
 6639                                    buffer_snapshot.remote_id(),
 6640                                    match_start..match_end,
 6641                                );
 6642                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6643                            }),
 6644                    );
 6645                }
 6646                match_ranges
 6647            });
 6648            let match_ranges = match_task.await;
 6649            editor
 6650                .update_in(cx, |editor, _, cx| {
 6651                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6652                    if !match_ranges.is_empty() {
 6653                        editor.highlight_background::<SelectedTextHighlight>(
 6654                            &match_ranges,
 6655                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6656                            cx,
 6657                        )
 6658                    }
 6659                })
 6660                .log_err();
 6661        })
 6662    }
 6663
 6664    fn refresh_selected_text_highlights(
 6665        &mut self,
 6666        on_buffer_edit: bool,
 6667        window: &mut Window,
 6668        cx: &mut Context<Editor>,
 6669    ) {
 6670        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6671        else {
 6672            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6673            self.quick_selection_highlight_task.take();
 6674            self.debounced_selection_highlight_task.take();
 6675            return;
 6676        };
 6677        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6678        if on_buffer_edit
 6679            || self
 6680                .quick_selection_highlight_task
 6681                .as_ref()
 6682                .map_or(true, |(prev_anchor_range, _)| {
 6683                    prev_anchor_range != &query_range
 6684                })
 6685        {
 6686            let multi_buffer_visible_start = self
 6687                .scroll_manager
 6688                .anchor()
 6689                .anchor
 6690                .to_point(&multi_buffer_snapshot);
 6691            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6692                multi_buffer_visible_start
 6693                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6694                Bias::Left,
 6695            );
 6696            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6697            self.quick_selection_highlight_task = Some((
 6698                query_range.clone(),
 6699                self.update_selection_occurrence_highlights(
 6700                    query_text.clone(),
 6701                    query_range.clone(),
 6702                    multi_buffer_visible_range,
 6703                    false,
 6704                    window,
 6705                    cx,
 6706                ),
 6707            ));
 6708        }
 6709        if on_buffer_edit
 6710            || self
 6711                .debounced_selection_highlight_task
 6712                .as_ref()
 6713                .map_or(true, |(prev_anchor_range, _)| {
 6714                    prev_anchor_range != &query_range
 6715                })
 6716        {
 6717            let multi_buffer_start = multi_buffer_snapshot
 6718                .anchor_before(0)
 6719                .to_point(&multi_buffer_snapshot);
 6720            let multi_buffer_end = multi_buffer_snapshot
 6721                .anchor_after(multi_buffer_snapshot.len())
 6722                .to_point(&multi_buffer_snapshot);
 6723            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6724            self.debounced_selection_highlight_task = Some((
 6725                query_range.clone(),
 6726                self.update_selection_occurrence_highlights(
 6727                    query_text,
 6728                    query_range,
 6729                    multi_buffer_full_range,
 6730                    true,
 6731                    window,
 6732                    cx,
 6733                ),
 6734            ));
 6735        }
 6736    }
 6737
 6738    pub fn refresh_inline_completion(
 6739        &mut self,
 6740        debounce: bool,
 6741        user_requested: bool,
 6742        window: &mut Window,
 6743        cx: &mut Context<Self>,
 6744    ) -> Option<()> {
 6745        let provider = self.edit_prediction_provider()?;
 6746        let cursor = self.selections.newest_anchor().head();
 6747        let (buffer, cursor_buffer_position) =
 6748            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6749
 6750        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6751            self.discard_inline_completion(false, cx);
 6752            return None;
 6753        }
 6754
 6755        if !user_requested
 6756            && (!self.should_show_edit_predictions()
 6757                || !self.is_focused(window)
 6758                || buffer.read(cx).is_empty())
 6759        {
 6760            self.discard_inline_completion(false, cx);
 6761            return None;
 6762        }
 6763
 6764        self.update_visible_inline_completion(window, cx);
 6765        provider.refresh(
 6766            self.project.clone(),
 6767            buffer,
 6768            cursor_buffer_position,
 6769            debounce,
 6770            cx,
 6771        );
 6772        Some(())
 6773    }
 6774
 6775    fn show_edit_predictions_in_menu(&self) -> bool {
 6776        match self.edit_prediction_settings {
 6777            EditPredictionSettings::Disabled => false,
 6778            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6779        }
 6780    }
 6781
 6782    pub fn edit_predictions_enabled(&self) -> bool {
 6783        match self.edit_prediction_settings {
 6784            EditPredictionSettings::Disabled => false,
 6785            EditPredictionSettings::Enabled { .. } => true,
 6786        }
 6787    }
 6788
 6789    fn edit_prediction_requires_modifier(&self) -> bool {
 6790        match self.edit_prediction_settings {
 6791            EditPredictionSettings::Disabled => false,
 6792            EditPredictionSettings::Enabled {
 6793                preview_requires_modifier,
 6794                ..
 6795            } => preview_requires_modifier,
 6796        }
 6797    }
 6798
 6799    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6800        if self.edit_prediction_provider.is_none() {
 6801            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6802        } else {
 6803            let selection = self.selections.newest_anchor();
 6804            let cursor = selection.head();
 6805
 6806            if let Some((buffer, cursor_buffer_position)) =
 6807                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6808            {
 6809                self.edit_prediction_settings =
 6810                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6811            }
 6812        }
 6813    }
 6814
 6815    fn edit_prediction_settings_at_position(
 6816        &self,
 6817        buffer: &Entity<Buffer>,
 6818        buffer_position: language::Anchor,
 6819        cx: &App,
 6820    ) -> EditPredictionSettings {
 6821        if !self.mode.is_full()
 6822            || !self.show_inline_completions_override.unwrap_or(true)
 6823            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6824        {
 6825            return EditPredictionSettings::Disabled;
 6826        }
 6827
 6828        let buffer = buffer.read(cx);
 6829
 6830        let file = buffer.file();
 6831
 6832        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6833            return EditPredictionSettings::Disabled;
 6834        };
 6835
 6836        let by_provider = matches!(
 6837            self.menu_inline_completions_policy,
 6838            MenuInlineCompletionsPolicy::ByProvider
 6839        );
 6840
 6841        let show_in_menu = by_provider
 6842            && self
 6843                .edit_prediction_provider
 6844                .as_ref()
 6845                .map_or(false, |provider| {
 6846                    provider.provider.show_completions_in_menu()
 6847                });
 6848
 6849        let preview_requires_modifier =
 6850            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6851
 6852        EditPredictionSettings::Enabled {
 6853            show_in_menu,
 6854            preview_requires_modifier,
 6855        }
 6856    }
 6857
 6858    fn should_show_edit_predictions(&self) -> bool {
 6859        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6860    }
 6861
 6862    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6863        matches!(
 6864            self.edit_prediction_preview,
 6865            EditPredictionPreview::Active { .. }
 6866        )
 6867    }
 6868
 6869    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6870        let cursor = self.selections.newest_anchor().head();
 6871        if let Some((buffer, cursor_position)) =
 6872            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6873        {
 6874            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6875        } else {
 6876            false
 6877        }
 6878    }
 6879
 6880    pub fn supports_minimap(&self, cx: &App) -> bool {
 6881        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6882    }
 6883
 6884    fn edit_predictions_enabled_in_buffer(
 6885        &self,
 6886        buffer: &Entity<Buffer>,
 6887        buffer_position: language::Anchor,
 6888        cx: &App,
 6889    ) -> bool {
 6890        maybe!({
 6891            if self.read_only(cx) {
 6892                return Some(false);
 6893            }
 6894            let provider = self.edit_prediction_provider()?;
 6895            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6896                return Some(false);
 6897            }
 6898            let buffer = buffer.read(cx);
 6899            let Some(file) = buffer.file() else {
 6900                return Some(true);
 6901            };
 6902            let settings = all_language_settings(Some(file), cx);
 6903            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6904        })
 6905        .unwrap_or(false)
 6906    }
 6907
 6908    fn cycle_inline_completion(
 6909        &mut self,
 6910        direction: Direction,
 6911        window: &mut Window,
 6912        cx: &mut Context<Self>,
 6913    ) -> Option<()> {
 6914        let provider = self.edit_prediction_provider()?;
 6915        let cursor = self.selections.newest_anchor().head();
 6916        let (buffer, cursor_buffer_position) =
 6917            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6918        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6919            return None;
 6920        }
 6921
 6922        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6923        self.update_visible_inline_completion(window, cx);
 6924
 6925        Some(())
 6926    }
 6927
 6928    pub fn show_inline_completion(
 6929        &mut self,
 6930        _: &ShowEditPrediction,
 6931        window: &mut Window,
 6932        cx: &mut Context<Self>,
 6933    ) {
 6934        if !self.has_active_inline_completion() {
 6935            self.refresh_inline_completion(false, true, window, cx);
 6936            return;
 6937        }
 6938
 6939        self.update_visible_inline_completion(window, cx);
 6940    }
 6941
 6942    pub fn display_cursor_names(
 6943        &mut self,
 6944        _: &DisplayCursorNames,
 6945        window: &mut Window,
 6946        cx: &mut Context<Self>,
 6947    ) {
 6948        self.show_cursor_names(window, cx);
 6949    }
 6950
 6951    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6952        self.show_cursor_names = true;
 6953        cx.notify();
 6954        cx.spawn_in(window, async move |this, cx| {
 6955            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6956            this.update(cx, |this, cx| {
 6957                this.show_cursor_names = false;
 6958                cx.notify()
 6959            })
 6960            .ok()
 6961        })
 6962        .detach();
 6963    }
 6964
 6965    pub fn next_edit_prediction(
 6966        &mut self,
 6967        _: &NextEditPrediction,
 6968        window: &mut Window,
 6969        cx: &mut Context<Self>,
 6970    ) {
 6971        if self.has_active_inline_completion() {
 6972            self.cycle_inline_completion(Direction::Next, window, cx);
 6973        } else {
 6974            let is_copilot_disabled = self
 6975                .refresh_inline_completion(false, true, window, cx)
 6976                .is_none();
 6977            if is_copilot_disabled {
 6978                cx.propagate();
 6979            }
 6980        }
 6981    }
 6982
 6983    pub fn previous_edit_prediction(
 6984        &mut self,
 6985        _: &PreviousEditPrediction,
 6986        window: &mut Window,
 6987        cx: &mut Context<Self>,
 6988    ) {
 6989        if self.has_active_inline_completion() {
 6990            self.cycle_inline_completion(Direction::Prev, window, cx);
 6991        } else {
 6992            let is_copilot_disabled = self
 6993                .refresh_inline_completion(false, true, window, cx)
 6994                .is_none();
 6995            if is_copilot_disabled {
 6996                cx.propagate();
 6997            }
 6998        }
 6999    }
 7000
 7001    pub fn accept_edit_prediction(
 7002        &mut self,
 7003        _: &AcceptEditPrediction,
 7004        window: &mut Window,
 7005        cx: &mut Context<Self>,
 7006    ) {
 7007        if self.show_edit_predictions_in_menu() {
 7008            self.hide_context_menu(window, cx);
 7009        }
 7010
 7011        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7012            return;
 7013        };
 7014
 7015        self.report_inline_completion_event(
 7016            active_inline_completion.completion_id.clone(),
 7017            true,
 7018            cx,
 7019        );
 7020
 7021        match &active_inline_completion.completion {
 7022            InlineCompletion::Move { target, .. } => {
 7023                let target = *target;
 7024
 7025                if let Some(position_map) = &self.last_position_map {
 7026                    if position_map
 7027                        .visible_row_range
 7028                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7029                        || !self.edit_prediction_requires_modifier()
 7030                    {
 7031                        self.unfold_ranges(&[target..target], true, false, cx);
 7032                        // Note that this is also done in vim's handler of the Tab action.
 7033                        self.change_selections(
 7034                            Some(Autoscroll::newest()),
 7035                            window,
 7036                            cx,
 7037                            |selections| {
 7038                                selections.select_anchor_ranges([target..target]);
 7039                            },
 7040                        );
 7041                        self.clear_row_highlights::<EditPredictionPreview>();
 7042
 7043                        self.edit_prediction_preview
 7044                            .set_previous_scroll_position(None);
 7045                    } else {
 7046                        self.edit_prediction_preview
 7047                            .set_previous_scroll_position(Some(
 7048                                position_map.snapshot.scroll_anchor,
 7049                            ));
 7050
 7051                        self.highlight_rows::<EditPredictionPreview>(
 7052                            target..target,
 7053                            cx.theme().colors().editor_highlighted_line_background,
 7054                            RowHighlightOptions {
 7055                                autoscroll: true,
 7056                                ..Default::default()
 7057                            },
 7058                            cx,
 7059                        );
 7060                        self.request_autoscroll(Autoscroll::fit(), cx);
 7061                    }
 7062                }
 7063            }
 7064            InlineCompletion::Edit { edits, .. } => {
 7065                if let Some(provider) = self.edit_prediction_provider() {
 7066                    provider.accept(cx);
 7067                }
 7068
 7069                // Store the transaction ID and selections before applying the edit
 7070                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7071
 7072                let snapshot = self.buffer.read(cx).snapshot(cx);
 7073                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7074
 7075                self.buffer.update(cx, |buffer, cx| {
 7076                    buffer.edit(edits.iter().cloned(), None, cx)
 7077                });
 7078
 7079                self.change_selections(None, window, cx, |s| {
 7080                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7081                });
 7082
 7083                let selections = self.selections.disjoint_anchors();
 7084                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7085                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7086                    if has_new_transaction {
 7087                        self.selection_history
 7088                            .insert_transaction(transaction_id_now, selections);
 7089                    }
 7090                }
 7091
 7092                self.update_visible_inline_completion(window, cx);
 7093                if self.active_inline_completion.is_none() {
 7094                    self.refresh_inline_completion(true, true, window, cx);
 7095                }
 7096
 7097                cx.notify();
 7098            }
 7099        }
 7100
 7101        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7102    }
 7103
 7104    pub fn accept_partial_inline_completion(
 7105        &mut self,
 7106        _: &AcceptPartialEditPrediction,
 7107        window: &mut Window,
 7108        cx: &mut Context<Self>,
 7109    ) {
 7110        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7111            return;
 7112        };
 7113        if self.selections.count() != 1 {
 7114            return;
 7115        }
 7116
 7117        self.report_inline_completion_event(
 7118            active_inline_completion.completion_id.clone(),
 7119            true,
 7120            cx,
 7121        );
 7122
 7123        match &active_inline_completion.completion {
 7124            InlineCompletion::Move { target, .. } => {
 7125                let target = *target;
 7126                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7127                    selections.select_anchor_ranges([target..target]);
 7128                });
 7129            }
 7130            InlineCompletion::Edit { edits, .. } => {
 7131                // Find an insertion that starts at the cursor position.
 7132                let snapshot = self.buffer.read(cx).snapshot(cx);
 7133                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7134                let insertion = edits.iter().find_map(|(range, text)| {
 7135                    let range = range.to_offset(&snapshot);
 7136                    if range.is_empty() && range.start == cursor_offset {
 7137                        Some(text)
 7138                    } else {
 7139                        None
 7140                    }
 7141                });
 7142
 7143                if let Some(text) = insertion {
 7144                    let mut partial_completion = text
 7145                        .chars()
 7146                        .by_ref()
 7147                        .take_while(|c| c.is_alphabetic())
 7148                        .collect::<String>();
 7149                    if partial_completion.is_empty() {
 7150                        partial_completion = text
 7151                            .chars()
 7152                            .by_ref()
 7153                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7154                            .collect::<String>();
 7155                    }
 7156
 7157                    cx.emit(EditorEvent::InputHandled {
 7158                        utf16_range_to_replace: None,
 7159                        text: partial_completion.clone().into(),
 7160                    });
 7161
 7162                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7163
 7164                    self.refresh_inline_completion(true, true, window, cx);
 7165                    cx.notify();
 7166                } else {
 7167                    self.accept_edit_prediction(&Default::default(), window, cx);
 7168                }
 7169            }
 7170        }
 7171    }
 7172
 7173    fn discard_inline_completion(
 7174        &mut self,
 7175        should_report_inline_completion_event: bool,
 7176        cx: &mut Context<Self>,
 7177    ) -> bool {
 7178        if should_report_inline_completion_event {
 7179            let completion_id = self
 7180                .active_inline_completion
 7181                .as_ref()
 7182                .and_then(|active_completion| active_completion.completion_id.clone());
 7183
 7184            self.report_inline_completion_event(completion_id, false, cx);
 7185        }
 7186
 7187        if let Some(provider) = self.edit_prediction_provider() {
 7188            provider.discard(cx);
 7189        }
 7190
 7191        self.take_active_inline_completion(cx)
 7192    }
 7193
 7194    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7195        let Some(provider) = self.edit_prediction_provider() else {
 7196            return;
 7197        };
 7198
 7199        let Some((_, buffer, _)) = self
 7200            .buffer
 7201            .read(cx)
 7202            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7203        else {
 7204            return;
 7205        };
 7206
 7207        let extension = buffer
 7208            .read(cx)
 7209            .file()
 7210            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7211
 7212        let event_type = match accepted {
 7213            true => "Edit Prediction Accepted",
 7214            false => "Edit Prediction Discarded",
 7215        };
 7216        telemetry::event!(
 7217            event_type,
 7218            provider = provider.name(),
 7219            prediction_id = id,
 7220            suggestion_accepted = accepted,
 7221            file_extension = extension,
 7222        );
 7223    }
 7224
 7225    pub fn has_active_inline_completion(&self) -> bool {
 7226        self.active_inline_completion.is_some()
 7227    }
 7228
 7229    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7230        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7231            return false;
 7232        };
 7233
 7234        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7235        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7236        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7237        true
 7238    }
 7239
 7240    /// Returns true when we're displaying the edit prediction popover below the cursor
 7241    /// like we are not previewing and the LSP autocomplete menu is visible
 7242    /// or we are in `when_holding_modifier` mode.
 7243    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7244        if self.edit_prediction_preview_is_active()
 7245            || !self.show_edit_predictions_in_menu()
 7246            || !self.edit_predictions_enabled()
 7247        {
 7248            return false;
 7249        }
 7250
 7251        if self.has_visible_completions_menu() {
 7252            return true;
 7253        }
 7254
 7255        has_completion && self.edit_prediction_requires_modifier()
 7256    }
 7257
 7258    fn handle_modifiers_changed(
 7259        &mut self,
 7260        modifiers: Modifiers,
 7261        position_map: &PositionMap,
 7262        window: &mut Window,
 7263        cx: &mut Context<Self>,
 7264    ) {
 7265        if self.show_edit_predictions_in_menu() {
 7266            self.update_edit_prediction_preview(&modifiers, window, cx);
 7267        }
 7268
 7269        self.update_selection_mode(&modifiers, position_map, window, cx);
 7270
 7271        let mouse_position = window.mouse_position();
 7272        if !position_map.text_hitbox.is_hovered(window) {
 7273            return;
 7274        }
 7275
 7276        self.update_hovered_link(
 7277            position_map.point_for_position(mouse_position),
 7278            &position_map.snapshot,
 7279            modifiers,
 7280            window,
 7281            cx,
 7282        )
 7283    }
 7284
 7285    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7286        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7287        if invert {
 7288            match multi_cursor_setting {
 7289                MultiCursorModifier::Alt => modifiers.alt,
 7290                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7291            }
 7292        } else {
 7293            match multi_cursor_setting {
 7294                MultiCursorModifier::Alt => modifiers.secondary(),
 7295                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7296            }
 7297        }
 7298    }
 7299
 7300    fn columnar_selection_mode(
 7301        modifiers: &Modifiers,
 7302        cx: &mut Context<Self>,
 7303    ) -> Option<ColumnarMode> {
 7304        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7305            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7306                Some(ColumnarMode::FromMouse)
 7307            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7308                Some(ColumnarMode::FromSelection)
 7309            } else {
 7310                None
 7311            }
 7312        } else {
 7313            None
 7314        }
 7315    }
 7316
 7317    fn update_selection_mode(
 7318        &mut self,
 7319        modifiers: &Modifiers,
 7320        position_map: &PositionMap,
 7321        window: &mut Window,
 7322        cx: &mut Context<Self>,
 7323    ) {
 7324        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7325            return;
 7326        };
 7327        if self.selections.pending.is_none() {
 7328            return;
 7329        }
 7330
 7331        let mouse_position = window.mouse_position();
 7332        let point_for_position = position_map.point_for_position(mouse_position);
 7333        let position = point_for_position.previous_valid;
 7334
 7335        self.select(
 7336            SelectPhase::BeginColumnar {
 7337                position,
 7338                reset: false,
 7339                mode,
 7340                goal_column: point_for_position.exact_unclipped.column(),
 7341            },
 7342            window,
 7343            cx,
 7344        );
 7345    }
 7346
 7347    fn update_edit_prediction_preview(
 7348        &mut self,
 7349        modifiers: &Modifiers,
 7350        window: &mut Window,
 7351        cx: &mut Context<Self>,
 7352    ) {
 7353        let mut modifiers_held = false;
 7354        if let Some(accept_keystroke) = self
 7355            .accept_edit_prediction_keybind(false, window, cx)
 7356            .keystroke()
 7357        {
 7358            modifiers_held = modifiers_held
 7359                || (&accept_keystroke.modifiers == modifiers
 7360                    && accept_keystroke.modifiers.modified());
 7361        };
 7362        if let Some(accept_partial_keystroke) = self
 7363            .accept_edit_prediction_keybind(true, window, cx)
 7364            .keystroke()
 7365        {
 7366            modifiers_held = modifiers_held
 7367                || (&accept_partial_keystroke.modifiers == modifiers
 7368                    && accept_partial_keystroke.modifiers.modified());
 7369        }
 7370
 7371        if modifiers_held {
 7372            if matches!(
 7373                self.edit_prediction_preview,
 7374                EditPredictionPreview::Inactive { .. }
 7375            ) {
 7376                self.edit_prediction_preview = EditPredictionPreview::Active {
 7377                    previous_scroll_position: None,
 7378                    since: Instant::now(),
 7379                };
 7380
 7381                self.update_visible_inline_completion(window, cx);
 7382                cx.notify();
 7383            }
 7384        } else if let EditPredictionPreview::Active {
 7385            previous_scroll_position,
 7386            since,
 7387        } = self.edit_prediction_preview
 7388        {
 7389            if let (Some(previous_scroll_position), Some(position_map)) =
 7390                (previous_scroll_position, self.last_position_map.as_ref())
 7391            {
 7392                self.set_scroll_position(
 7393                    previous_scroll_position
 7394                        .scroll_position(&position_map.snapshot.display_snapshot),
 7395                    window,
 7396                    cx,
 7397                );
 7398            }
 7399
 7400            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7401                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7402            };
 7403            self.clear_row_highlights::<EditPredictionPreview>();
 7404            self.update_visible_inline_completion(window, cx);
 7405            cx.notify();
 7406        }
 7407    }
 7408
 7409    fn update_visible_inline_completion(
 7410        &mut self,
 7411        _window: &mut Window,
 7412        cx: &mut Context<Self>,
 7413    ) -> Option<()> {
 7414        let selection = self.selections.newest_anchor();
 7415        let cursor = selection.head();
 7416        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7417        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7418        let excerpt_id = cursor.excerpt_id;
 7419
 7420        let show_in_menu = self.show_edit_predictions_in_menu();
 7421        let completions_menu_has_precedence = !show_in_menu
 7422            && (self.context_menu.borrow().is_some()
 7423                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7424
 7425        if completions_menu_has_precedence
 7426            || !offset_selection.is_empty()
 7427            || self
 7428                .active_inline_completion
 7429                .as_ref()
 7430                .map_or(false, |completion| {
 7431                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7432                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7433                    !invalidation_range.contains(&offset_selection.head())
 7434                })
 7435        {
 7436            self.discard_inline_completion(false, cx);
 7437            return None;
 7438        }
 7439
 7440        self.take_active_inline_completion(cx);
 7441        let Some(provider) = self.edit_prediction_provider() else {
 7442            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7443            return None;
 7444        };
 7445
 7446        let (buffer, cursor_buffer_position) =
 7447            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7448
 7449        self.edit_prediction_settings =
 7450            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7451
 7452        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7453
 7454        if self.edit_prediction_indent_conflict {
 7455            let cursor_point = cursor.to_point(&multibuffer);
 7456
 7457            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7458
 7459            if let Some((_, indent)) = indents.iter().next() {
 7460                if indent.len == cursor_point.column {
 7461                    self.edit_prediction_indent_conflict = false;
 7462                }
 7463            }
 7464        }
 7465
 7466        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7467        let edits = inline_completion
 7468            .edits
 7469            .into_iter()
 7470            .flat_map(|(range, new_text)| {
 7471                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7472                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7473                Some((start..end, new_text))
 7474            })
 7475            .collect::<Vec<_>>();
 7476        if edits.is_empty() {
 7477            return None;
 7478        }
 7479
 7480        let first_edit_start = edits.first().unwrap().0.start;
 7481        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7482        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7483
 7484        let last_edit_end = edits.last().unwrap().0.end;
 7485        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7486        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7487
 7488        let cursor_row = cursor.to_point(&multibuffer).row;
 7489
 7490        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7491
 7492        let mut inlay_ids = Vec::new();
 7493        let invalidation_row_range;
 7494        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7495            Some(cursor_row..edit_end_row)
 7496        } else if cursor_row > edit_end_row {
 7497            Some(edit_start_row..cursor_row)
 7498        } else {
 7499            None
 7500        };
 7501        let is_move =
 7502            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7503        let completion = if is_move {
 7504            invalidation_row_range =
 7505                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7506            let target = first_edit_start;
 7507            InlineCompletion::Move { target, snapshot }
 7508        } else {
 7509            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7510                && !self.inline_completions_hidden_for_vim_mode;
 7511
 7512            if show_completions_in_buffer {
 7513                if edits
 7514                    .iter()
 7515                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7516                {
 7517                    let mut inlays = Vec::new();
 7518                    for (range, new_text) in &edits {
 7519                        let inlay = Inlay::inline_completion(
 7520                            post_inc(&mut self.next_inlay_id),
 7521                            range.start,
 7522                            new_text.as_str(),
 7523                        );
 7524                        inlay_ids.push(inlay.id);
 7525                        inlays.push(inlay);
 7526                    }
 7527
 7528                    self.splice_inlays(&[], inlays, cx);
 7529                } else {
 7530                    let background_color = cx.theme().status().deleted_background;
 7531                    let style = HighlightStyle {
 7532                        background_color: Some(background_color),
 7533                        ..Default::default()
 7534                    };
 7535                    self.highlight_text::<InlineCompletionHighlight>(
 7536                        edits
 7537                            .iter()
 7538                            .map(|(range, _)| (range.clone(), style))
 7539                            .collect(),
 7540                        cx,
 7541                    );
 7542                }
 7543            }
 7544
 7545            invalidation_row_range = edit_start_row..edit_end_row;
 7546
 7547            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7548                if provider.show_tab_accept_marker() {
 7549                    EditDisplayMode::TabAccept
 7550                } else {
 7551                    EditDisplayMode::Inline
 7552                }
 7553            } else {
 7554                EditDisplayMode::DiffPopover
 7555            };
 7556
 7557            InlineCompletion::Edit {
 7558                edits,
 7559                edit_preview: inline_completion.edit_preview,
 7560                display_mode,
 7561                snapshot,
 7562            }
 7563        };
 7564
 7565        let invalidation_range = multibuffer
 7566            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7567            ..multibuffer.anchor_after(Point::new(
 7568                invalidation_row_range.end,
 7569                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7570            ));
 7571
 7572        self.stale_inline_completion_in_menu = None;
 7573        self.active_inline_completion = Some(InlineCompletionState {
 7574            inlay_ids,
 7575            completion,
 7576            completion_id: inline_completion.id,
 7577            invalidation_range,
 7578        });
 7579
 7580        cx.notify();
 7581
 7582        Some(())
 7583    }
 7584
 7585    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7586        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7587    }
 7588
 7589    fn clear_tasks(&mut self) {
 7590        self.tasks.clear()
 7591    }
 7592
 7593    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7594        if self.tasks.insert(key, value).is_some() {
 7595            // This case should hopefully be rare, but just in case...
 7596            log::error!(
 7597                "multiple different run targets found on a single line, only the last target will be rendered"
 7598            )
 7599        }
 7600    }
 7601
 7602    /// Get all display points of breakpoints that will be rendered within editor
 7603    ///
 7604    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7605    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7606    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7607    fn active_breakpoints(
 7608        &self,
 7609        range: Range<DisplayRow>,
 7610        window: &mut Window,
 7611        cx: &mut Context<Self>,
 7612    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7613        let mut breakpoint_display_points = HashMap::default();
 7614
 7615        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7616            return breakpoint_display_points;
 7617        };
 7618
 7619        let snapshot = self.snapshot(window, cx);
 7620
 7621        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7622        let Some(project) = self.project.as_ref() else {
 7623            return breakpoint_display_points;
 7624        };
 7625
 7626        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7627            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7628
 7629        for (buffer_snapshot, range, excerpt_id) in
 7630            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7631        {
 7632            let Some(buffer) = project
 7633                .read(cx)
 7634                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7635            else {
 7636                continue;
 7637            };
 7638            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7639                &buffer,
 7640                Some(
 7641                    buffer_snapshot.anchor_before(range.start)
 7642                        ..buffer_snapshot.anchor_after(range.end),
 7643                ),
 7644                buffer_snapshot,
 7645                cx,
 7646            );
 7647            for (breakpoint, state) in breakpoints {
 7648                let multi_buffer_anchor =
 7649                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7650                let position = multi_buffer_anchor
 7651                    .to_point(&multi_buffer_snapshot)
 7652                    .to_display_point(&snapshot);
 7653
 7654                breakpoint_display_points.insert(
 7655                    position.row(),
 7656                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7657                );
 7658            }
 7659        }
 7660
 7661        breakpoint_display_points
 7662    }
 7663
 7664    fn breakpoint_context_menu(
 7665        &self,
 7666        anchor: Anchor,
 7667        window: &mut Window,
 7668        cx: &mut Context<Self>,
 7669    ) -> Entity<ui::ContextMenu> {
 7670        let weak_editor = cx.weak_entity();
 7671        let focus_handle = self.focus_handle(cx);
 7672
 7673        let row = self
 7674            .buffer
 7675            .read(cx)
 7676            .snapshot(cx)
 7677            .summary_for_anchor::<Point>(&anchor)
 7678            .row;
 7679
 7680        let breakpoint = self
 7681            .breakpoint_at_row(row, window, cx)
 7682            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7683
 7684        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7685            "Edit Log Breakpoint"
 7686        } else {
 7687            "Set Log Breakpoint"
 7688        };
 7689
 7690        let condition_breakpoint_msg = if breakpoint
 7691            .as_ref()
 7692            .is_some_and(|bp| bp.1.condition.is_some())
 7693        {
 7694            "Edit Condition Breakpoint"
 7695        } else {
 7696            "Set Condition Breakpoint"
 7697        };
 7698
 7699        let hit_condition_breakpoint_msg = if breakpoint
 7700            .as_ref()
 7701            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7702        {
 7703            "Edit Hit Condition Breakpoint"
 7704        } else {
 7705            "Set Hit Condition Breakpoint"
 7706        };
 7707
 7708        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7709            "Unset Breakpoint"
 7710        } else {
 7711            "Set Breakpoint"
 7712        };
 7713
 7714        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7715
 7716        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7717            BreakpointState::Enabled => Some("Disable"),
 7718            BreakpointState::Disabled => Some("Enable"),
 7719        });
 7720
 7721        let (anchor, breakpoint) =
 7722            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7723
 7724        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7725            menu.on_blur_subscription(Subscription::new(|| {}))
 7726                .context(focus_handle)
 7727                .when(run_to_cursor, |this| {
 7728                    let weak_editor = weak_editor.clone();
 7729                    this.entry("Run to cursor", None, move |window, cx| {
 7730                        weak_editor
 7731                            .update(cx, |editor, cx| {
 7732                                editor.change_selections(None, window, cx, |s| {
 7733                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7734                                });
 7735                            })
 7736                            .ok();
 7737
 7738                        window.dispatch_action(Box::new(RunToCursor), cx);
 7739                    })
 7740                    .separator()
 7741                })
 7742                .when_some(toggle_state_msg, |this, msg| {
 7743                    this.entry(msg, None, {
 7744                        let weak_editor = weak_editor.clone();
 7745                        let breakpoint = breakpoint.clone();
 7746                        move |_window, cx| {
 7747                            weak_editor
 7748                                .update(cx, |this, cx| {
 7749                                    this.edit_breakpoint_at_anchor(
 7750                                        anchor,
 7751                                        breakpoint.as_ref().clone(),
 7752                                        BreakpointEditAction::InvertState,
 7753                                        cx,
 7754                                    );
 7755                                })
 7756                                .log_err();
 7757                        }
 7758                    })
 7759                })
 7760                .entry(set_breakpoint_msg, None, {
 7761                    let weak_editor = weak_editor.clone();
 7762                    let breakpoint = breakpoint.clone();
 7763                    move |_window, cx| {
 7764                        weak_editor
 7765                            .update(cx, |this, cx| {
 7766                                this.edit_breakpoint_at_anchor(
 7767                                    anchor,
 7768                                    breakpoint.as_ref().clone(),
 7769                                    BreakpointEditAction::Toggle,
 7770                                    cx,
 7771                                );
 7772                            })
 7773                            .log_err();
 7774                    }
 7775                })
 7776                .entry(log_breakpoint_msg, None, {
 7777                    let breakpoint = breakpoint.clone();
 7778                    let weak_editor = weak_editor.clone();
 7779                    move |window, cx| {
 7780                        weak_editor
 7781                            .update(cx, |this, cx| {
 7782                                this.add_edit_breakpoint_block(
 7783                                    anchor,
 7784                                    breakpoint.as_ref(),
 7785                                    BreakpointPromptEditAction::Log,
 7786                                    window,
 7787                                    cx,
 7788                                );
 7789                            })
 7790                            .log_err();
 7791                    }
 7792                })
 7793                .entry(condition_breakpoint_msg, None, {
 7794                    let breakpoint = breakpoint.clone();
 7795                    let weak_editor = weak_editor.clone();
 7796                    move |window, cx| {
 7797                        weak_editor
 7798                            .update(cx, |this, cx| {
 7799                                this.add_edit_breakpoint_block(
 7800                                    anchor,
 7801                                    breakpoint.as_ref(),
 7802                                    BreakpointPromptEditAction::Condition,
 7803                                    window,
 7804                                    cx,
 7805                                );
 7806                            })
 7807                            .log_err();
 7808                    }
 7809                })
 7810                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7811                    weak_editor
 7812                        .update(cx, |this, cx| {
 7813                            this.add_edit_breakpoint_block(
 7814                                anchor,
 7815                                breakpoint.as_ref(),
 7816                                BreakpointPromptEditAction::HitCondition,
 7817                                window,
 7818                                cx,
 7819                            );
 7820                        })
 7821                        .log_err();
 7822                })
 7823        })
 7824    }
 7825
 7826    fn render_breakpoint(
 7827        &self,
 7828        position: Anchor,
 7829        row: DisplayRow,
 7830        breakpoint: &Breakpoint,
 7831        state: Option<BreakpointSessionState>,
 7832        cx: &mut Context<Self>,
 7833    ) -> IconButton {
 7834        let is_rejected = state.is_some_and(|s| !s.verified);
 7835        // Is it a breakpoint that shows up when hovering over gutter?
 7836        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7837            (false, false),
 7838            |PhantomBreakpointIndicator {
 7839                 is_active,
 7840                 display_row,
 7841                 collides_with_existing_breakpoint,
 7842             }| {
 7843                (
 7844                    is_active && display_row == row,
 7845                    collides_with_existing_breakpoint,
 7846                )
 7847            },
 7848        );
 7849
 7850        let (color, icon) = {
 7851            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7852                (false, false) => ui::IconName::DebugBreakpoint,
 7853                (true, false) => ui::IconName::DebugLogBreakpoint,
 7854                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7855                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7856            };
 7857
 7858            let color = if is_phantom {
 7859                Color::Hint
 7860            } else if is_rejected {
 7861                Color::Disabled
 7862            } else {
 7863                Color::Debugger
 7864            };
 7865
 7866            (color, icon)
 7867        };
 7868
 7869        let breakpoint = Arc::from(breakpoint.clone());
 7870
 7871        let alt_as_text = gpui::Keystroke {
 7872            modifiers: Modifiers::secondary_key(),
 7873            ..Default::default()
 7874        };
 7875        let primary_action_text = if breakpoint.is_disabled() {
 7876            "Enable breakpoint"
 7877        } else if is_phantom && !collides_with_existing {
 7878            "Set breakpoint"
 7879        } else {
 7880            "Unset breakpoint"
 7881        };
 7882        let focus_handle = self.focus_handle.clone();
 7883
 7884        let meta = if is_rejected {
 7885            SharedString::from("No executable code is associated with this line.")
 7886        } else if collides_with_existing && !breakpoint.is_disabled() {
 7887            SharedString::from(format!(
 7888                "{alt_as_text}-click to disable,\nright-click for more options."
 7889            ))
 7890        } else {
 7891            SharedString::from("Right-click for more options.")
 7892        };
 7893        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7894            .icon_size(IconSize::XSmall)
 7895            .size(ui::ButtonSize::None)
 7896            .when(is_rejected, |this| {
 7897                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7898            })
 7899            .icon_color(color)
 7900            .style(ButtonStyle::Transparent)
 7901            .on_click(cx.listener({
 7902                let breakpoint = breakpoint.clone();
 7903
 7904                move |editor, event: &ClickEvent, window, cx| {
 7905                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7906                        BreakpointEditAction::InvertState
 7907                    } else {
 7908                        BreakpointEditAction::Toggle
 7909                    };
 7910
 7911                    window.focus(&editor.focus_handle(cx));
 7912                    editor.edit_breakpoint_at_anchor(
 7913                        position,
 7914                        breakpoint.as_ref().clone(),
 7915                        edit_action,
 7916                        cx,
 7917                    );
 7918                }
 7919            }))
 7920            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7921                editor.set_breakpoint_context_menu(
 7922                    row,
 7923                    Some(position),
 7924                    event.down.position,
 7925                    window,
 7926                    cx,
 7927                );
 7928            }))
 7929            .tooltip(move |window, cx| {
 7930                Tooltip::with_meta_in(
 7931                    primary_action_text,
 7932                    Some(&ToggleBreakpoint),
 7933                    meta.clone(),
 7934                    &focus_handle,
 7935                    window,
 7936                    cx,
 7937                )
 7938            })
 7939    }
 7940
 7941    fn build_tasks_context(
 7942        project: &Entity<Project>,
 7943        buffer: &Entity<Buffer>,
 7944        buffer_row: u32,
 7945        tasks: &Arc<RunnableTasks>,
 7946        cx: &mut Context<Self>,
 7947    ) -> Task<Option<task::TaskContext>> {
 7948        let position = Point::new(buffer_row, tasks.column);
 7949        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7950        let location = Location {
 7951            buffer: buffer.clone(),
 7952            range: range_start..range_start,
 7953        };
 7954        // Fill in the environmental variables from the tree-sitter captures
 7955        let mut captured_task_variables = TaskVariables::default();
 7956        for (capture_name, value) in tasks.extra_variables.clone() {
 7957            captured_task_variables.insert(
 7958                task::VariableName::Custom(capture_name.into()),
 7959                value.clone(),
 7960            );
 7961        }
 7962        project.update(cx, |project, cx| {
 7963            project.task_store().update(cx, |task_store, cx| {
 7964                task_store.task_context_for_location(captured_task_variables, location, cx)
 7965            })
 7966        })
 7967    }
 7968
 7969    pub fn spawn_nearest_task(
 7970        &mut self,
 7971        action: &SpawnNearestTask,
 7972        window: &mut Window,
 7973        cx: &mut Context<Self>,
 7974    ) {
 7975        let Some((workspace, _)) = self.workspace.clone() else {
 7976            return;
 7977        };
 7978        let Some(project) = self.project.clone() else {
 7979            return;
 7980        };
 7981
 7982        // Try to find a closest, enclosing node using tree-sitter that has a
 7983        // task
 7984        let Some((buffer, buffer_row, tasks)) = self
 7985            .find_enclosing_node_task(cx)
 7986            // Or find the task that's closest in row-distance.
 7987            .or_else(|| self.find_closest_task(cx))
 7988        else {
 7989            return;
 7990        };
 7991
 7992        let reveal_strategy = action.reveal;
 7993        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7994        cx.spawn_in(window, async move |_, cx| {
 7995            let context = task_context.await?;
 7996            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7997
 7998            let resolved = &mut resolved_task.resolved;
 7999            resolved.reveal = reveal_strategy;
 8000
 8001            workspace
 8002                .update_in(cx, |workspace, window, cx| {
 8003                    workspace.schedule_resolved_task(
 8004                        task_source_kind,
 8005                        resolved_task,
 8006                        false,
 8007                        window,
 8008                        cx,
 8009                    );
 8010                })
 8011                .ok()
 8012        })
 8013        .detach();
 8014    }
 8015
 8016    fn find_closest_task(
 8017        &mut self,
 8018        cx: &mut Context<Self>,
 8019    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8020        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8021
 8022        let ((buffer_id, row), tasks) = self
 8023            .tasks
 8024            .iter()
 8025            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8026
 8027        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8028        let tasks = Arc::new(tasks.to_owned());
 8029        Some((buffer, *row, tasks))
 8030    }
 8031
 8032    fn find_enclosing_node_task(
 8033        &mut self,
 8034        cx: &mut Context<Self>,
 8035    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8036        let snapshot = self.buffer.read(cx).snapshot(cx);
 8037        let offset = self.selections.newest::<usize>(cx).head();
 8038        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8039        let buffer_id = excerpt.buffer().remote_id();
 8040
 8041        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8042        let mut cursor = layer.node().walk();
 8043
 8044        while cursor.goto_first_child_for_byte(offset).is_some() {
 8045            if cursor.node().end_byte() == offset {
 8046                cursor.goto_next_sibling();
 8047            }
 8048        }
 8049
 8050        // Ascend to the smallest ancestor that contains the range and has a task.
 8051        loop {
 8052            let node = cursor.node();
 8053            let node_range = node.byte_range();
 8054            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8055
 8056            // Check if this node contains our offset
 8057            if node_range.start <= offset && node_range.end >= offset {
 8058                // If it contains offset, check for task
 8059                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8060                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8061                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8062                }
 8063            }
 8064
 8065            if !cursor.goto_parent() {
 8066                break;
 8067            }
 8068        }
 8069        None
 8070    }
 8071
 8072    fn render_run_indicator(
 8073        &self,
 8074        _style: &EditorStyle,
 8075        is_active: bool,
 8076        row: DisplayRow,
 8077        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8078        cx: &mut Context<Self>,
 8079    ) -> IconButton {
 8080        let color = Color::Muted;
 8081        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8082
 8083        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8084            .shape(ui::IconButtonShape::Square)
 8085            .icon_size(IconSize::XSmall)
 8086            .icon_color(color)
 8087            .toggle_state(is_active)
 8088            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8089                let quick_launch = e.down.button == MouseButton::Left;
 8090                window.focus(&editor.focus_handle(cx));
 8091                editor.toggle_code_actions(
 8092                    &ToggleCodeActions {
 8093                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8094                        quick_launch,
 8095                    },
 8096                    window,
 8097                    cx,
 8098                );
 8099            }))
 8100            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8101                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8102            }))
 8103    }
 8104
 8105    pub fn context_menu_visible(&self) -> bool {
 8106        !self.edit_prediction_preview_is_active()
 8107            && self
 8108                .context_menu
 8109                .borrow()
 8110                .as_ref()
 8111                .map_or(false, |menu| menu.visible())
 8112    }
 8113
 8114    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8115        self.context_menu
 8116            .borrow()
 8117            .as_ref()
 8118            .map(|menu| menu.origin())
 8119    }
 8120
 8121    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8122        self.context_menu_options = Some(options);
 8123    }
 8124
 8125    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8126    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8127
 8128    fn render_edit_prediction_popover(
 8129        &mut self,
 8130        text_bounds: &Bounds<Pixels>,
 8131        content_origin: gpui::Point<Pixels>,
 8132        right_margin: Pixels,
 8133        editor_snapshot: &EditorSnapshot,
 8134        visible_row_range: Range<DisplayRow>,
 8135        scroll_top: f32,
 8136        scroll_bottom: f32,
 8137        line_layouts: &[LineWithInvisibles],
 8138        line_height: Pixels,
 8139        scroll_pixel_position: gpui::Point<Pixels>,
 8140        newest_selection_head: Option<DisplayPoint>,
 8141        editor_width: Pixels,
 8142        style: &EditorStyle,
 8143        window: &mut Window,
 8144        cx: &mut App,
 8145    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8146        if self.mode().is_minimap() {
 8147            return None;
 8148        }
 8149        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8150
 8151        if self.edit_prediction_visible_in_cursor_popover(true) {
 8152            return None;
 8153        }
 8154
 8155        match &active_inline_completion.completion {
 8156            InlineCompletion::Move { target, .. } => {
 8157                let target_display_point = target.to_display_point(editor_snapshot);
 8158
 8159                if self.edit_prediction_requires_modifier() {
 8160                    if !self.edit_prediction_preview_is_active() {
 8161                        return None;
 8162                    }
 8163
 8164                    self.render_edit_prediction_modifier_jump_popover(
 8165                        text_bounds,
 8166                        content_origin,
 8167                        visible_row_range,
 8168                        line_layouts,
 8169                        line_height,
 8170                        scroll_pixel_position,
 8171                        newest_selection_head,
 8172                        target_display_point,
 8173                        window,
 8174                        cx,
 8175                    )
 8176                } else {
 8177                    self.render_edit_prediction_eager_jump_popover(
 8178                        text_bounds,
 8179                        content_origin,
 8180                        editor_snapshot,
 8181                        visible_row_range,
 8182                        scroll_top,
 8183                        scroll_bottom,
 8184                        line_height,
 8185                        scroll_pixel_position,
 8186                        target_display_point,
 8187                        editor_width,
 8188                        window,
 8189                        cx,
 8190                    )
 8191                }
 8192            }
 8193            InlineCompletion::Edit {
 8194                display_mode: EditDisplayMode::Inline,
 8195                ..
 8196            } => None,
 8197            InlineCompletion::Edit {
 8198                display_mode: EditDisplayMode::TabAccept,
 8199                edits,
 8200                ..
 8201            } => {
 8202                let range = &edits.first()?.0;
 8203                let target_display_point = range.end.to_display_point(editor_snapshot);
 8204
 8205                self.render_edit_prediction_end_of_line_popover(
 8206                    "Accept",
 8207                    editor_snapshot,
 8208                    visible_row_range,
 8209                    target_display_point,
 8210                    line_height,
 8211                    scroll_pixel_position,
 8212                    content_origin,
 8213                    editor_width,
 8214                    window,
 8215                    cx,
 8216                )
 8217            }
 8218            InlineCompletion::Edit {
 8219                edits,
 8220                edit_preview,
 8221                display_mode: EditDisplayMode::DiffPopover,
 8222                snapshot,
 8223            } => self.render_edit_prediction_diff_popover(
 8224                text_bounds,
 8225                content_origin,
 8226                right_margin,
 8227                editor_snapshot,
 8228                visible_row_range,
 8229                line_layouts,
 8230                line_height,
 8231                scroll_pixel_position,
 8232                newest_selection_head,
 8233                editor_width,
 8234                style,
 8235                edits,
 8236                edit_preview,
 8237                snapshot,
 8238                window,
 8239                cx,
 8240            ),
 8241        }
 8242    }
 8243
 8244    fn render_edit_prediction_modifier_jump_popover(
 8245        &mut self,
 8246        text_bounds: &Bounds<Pixels>,
 8247        content_origin: gpui::Point<Pixels>,
 8248        visible_row_range: Range<DisplayRow>,
 8249        line_layouts: &[LineWithInvisibles],
 8250        line_height: Pixels,
 8251        scroll_pixel_position: gpui::Point<Pixels>,
 8252        newest_selection_head: Option<DisplayPoint>,
 8253        target_display_point: DisplayPoint,
 8254        window: &mut Window,
 8255        cx: &mut App,
 8256    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8257        let scrolled_content_origin =
 8258            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8259
 8260        const SCROLL_PADDING_Y: Pixels = px(12.);
 8261
 8262        if target_display_point.row() < visible_row_range.start {
 8263            return self.render_edit_prediction_scroll_popover(
 8264                |_| SCROLL_PADDING_Y,
 8265                IconName::ArrowUp,
 8266                visible_row_range,
 8267                line_layouts,
 8268                newest_selection_head,
 8269                scrolled_content_origin,
 8270                window,
 8271                cx,
 8272            );
 8273        } else if target_display_point.row() >= visible_row_range.end {
 8274            return self.render_edit_prediction_scroll_popover(
 8275                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8276                IconName::ArrowDown,
 8277                visible_row_range,
 8278                line_layouts,
 8279                newest_selection_head,
 8280                scrolled_content_origin,
 8281                window,
 8282                cx,
 8283            );
 8284        }
 8285
 8286        const POLE_WIDTH: Pixels = px(2.);
 8287
 8288        let line_layout =
 8289            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8290        let target_column = target_display_point.column() as usize;
 8291
 8292        let target_x = line_layout.x_for_index(target_column);
 8293        let target_y =
 8294            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8295
 8296        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8297
 8298        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8299        border_color.l += 0.001;
 8300
 8301        let mut element = v_flex()
 8302            .items_end()
 8303            .when(flag_on_right, |el| el.items_start())
 8304            .child(if flag_on_right {
 8305                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8306                    .rounded_bl(px(0.))
 8307                    .rounded_tl(px(0.))
 8308                    .border_l_2()
 8309                    .border_color(border_color)
 8310            } else {
 8311                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8312                    .rounded_br(px(0.))
 8313                    .rounded_tr(px(0.))
 8314                    .border_r_2()
 8315                    .border_color(border_color)
 8316            })
 8317            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8318            .into_any();
 8319
 8320        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8321
 8322        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8323            - point(
 8324                if flag_on_right {
 8325                    POLE_WIDTH
 8326                } else {
 8327                    size.width - POLE_WIDTH
 8328                },
 8329                size.height - line_height,
 8330            );
 8331
 8332        origin.x = origin.x.max(content_origin.x);
 8333
 8334        element.prepaint_at(origin, window, cx);
 8335
 8336        Some((element, origin))
 8337    }
 8338
 8339    fn render_edit_prediction_scroll_popover(
 8340        &mut self,
 8341        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8342        scroll_icon: IconName,
 8343        visible_row_range: Range<DisplayRow>,
 8344        line_layouts: &[LineWithInvisibles],
 8345        newest_selection_head: Option<DisplayPoint>,
 8346        scrolled_content_origin: gpui::Point<Pixels>,
 8347        window: &mut Window,
 8348        cx: &mut App,
 8349    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8350        let mut element = self
 8351            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8352            .into_any();
 8353
 8354        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8355
 8356        let cursor = newest_selection_head?;
 8357        let cursor_row_layout =
 8358            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8359        let cursor_column = cursor.column() as usize;
 8360
 8361        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8362
 8363        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8364
 8365        element.prepaint_at(origin, window, cx);
 8366        Some((element, origin))
 8367    }
 8368
 8369    fn render_edit_prediction_eager_jump_popover(
 8370        &mut self,
 8371        text_bounds: &Bounds<Pixels>,
 8372        content_origin: gpui::Point<Pixels>,
 8373        editor_snapshot: &EditorSnapshot,
 8374        visible_row_range: Range<DisplayRow>,
 8375        scroll_top: f32,
 8376        scroll_bottom: f32,
 8377        line_height: Pixels,
 8378        scroll_pixel_position: gpui::Point<Pixels>,
 8379        target_display_point: DisplayPoint,
 8380        editor_width: Pixels,
 8381        window: &mut Window,
 8382        cx: &mut App,
 8383    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8384        if target_display_point.row().as_f32() < scroll_top {
 8385            let mut element = self
 8386                .render_edit_prediction_line_popover(
 8387                    "Jump to Edit",
 8388                    Some(IconName::ArrowUp),
 8389                    window,
 8390                    cx,
 8391                )?
 8392                .into_any();
 8393
 8394            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8395            let offset = point(
 8396                (text_bounds.size.width - size.width) / 2.,
 8397                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8398            );
 8399
 8400            let origin = text_bounds.origin + offset;
 8401            element.prepaint_at(origin, window, cx);
 8402            Some((element, origin))
 8403        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8404            let mut element = self
 8405                .render_edit_prediction_line_popover(
 8406                    "Jump to Edit",
 8407                    Some(IconName::ArrowDown),
 8408                    window,
 8409                    cx,
 8410                )?
 8411                .into_any();
 8412
 8413            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8414            let offset = point(
 8415                (text_bounds.size.width - size.width) / 2.,
 8416                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8417            );
 8418
 8419            let origin = text_bounds.origin + offset;
 8420            element.prepaint_at(origin, window, cx);
 8421            Some((element, origin))
 8422        } else {
 8423            self.render_edit_prediction_end_of_line_popover(
 8424                "Jump to Edit",
 8425                editor_snapshot,
 8426                visible_row_range,
 8427                target_display_point,
 8428                line_height,
 8429                scroll_pixel_position,
 8430                content_origin,
 8431                editor_width,
 8432                window,
 8433                cx,
 8434            )
 8435        }
 8436    }
 8437
 8438    fn render_edit_prediction_end_of_line_popover(
 8439        self: &mut Editor,
 8440        label: &'static str,
 8441        editor_snapshot: &EditorSnapshot,
 8442        visible_row_range: Range<DisplayRow>,
 8443        target_display_point: DisplayPoint,
 8444        line_height: Pixels,
 8445        scroll_pixel_position: gpui::Point<Pixels>,
 8446        content_origin: gpui::Point<Pixels>,
 8447        editor_width: Pixels,
 8448        window: &mut Window,
 8449        cx: &mut App,
 8450    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8451        let target_line_end = DisplayPoint::new(
 8452            target_display_point.row(),
 8453            editor_snapshot.line_len(target_display_point.row()),
 8454        );
 8455
 8456        let mut element = self
 8457            .render_edit_prediction_line_popover(label, None, window, cx)?
 8458            .into_any();
 8459
 8460        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8461
 8462        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8463
 8464        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8465        let mut origin = start_point
 8466            + line_origin
 8467            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8468        origin.x = origin.x.max(content_origin.x);
 8469
 8470        let max_x = content_origin.x + editor_width - size.width;
 8471
 8472        if origin.x > max_x {
 8473            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8474
 8475            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8476                origin.y += offset;
 8477                IconName::ArrowUp
 8478            } else {
 8479                origin.y -= offset;
 8480                IconName::ArrowDown
 8481            };
 8482
 8483            element = self
 8484                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8485                .into_any();
 8486
 8487            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8488
 8489            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8490        }
 8491
 8492        element.prepaint_at(origin, window, cx);
 8493        Some((element, origin))
 8494    }
 8495
 8496    fn render_edit_prediction_diff_popover(
 8497        self: &Editor,
 8498        text_bounds: &Bounds<Pixels>,
 8499        content_origin: gpui::Point<Pixels>,
 8500        right_margin: Pixels,
 8501        editor_snapshot: &EditorSnapshot,
 8502        visible_row_range: Range<DisplayRow>,
 8503        line_layouts: &[LineWithInvisibles],
 8504        line_height: Pixels,
 8505        scroll_pixel_position: gpui::Point<Pixels>,
 8506        newest_selection_head: Option<DisplayPoint>,
 8507        editor_width: Pixels,
 8508        style: &EditorStyle,
 8509        edits: &Vec<(Range<Anchor>, String)>,
 8510        edit_preview: &Option<language::EditPreview>,
 8511        snapshot: &language::BufferSnapshot,
 8512        window: &mut Window,
 8513        cx: &mut App,
 8514    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8515        let edit_start = edits
 8516            .first()
 8517            .unwrap()
 8518            .0
 8519            .start
 8520            .to_display_point(editor_snapshot);
 8521        let edit_end = edits
 8522            .last()
 8523            .unwrap()
 8524            .0
 8525            .end
 8526            .to_display_point(editor_snapshot);
 8527
 8528        let is_visible = visible_row_range.contains(&edit_start.row())
 8529            || visible_row_range.contains(&edit_end.row());
 8530        if !is_visible {
 8531            return None;
 8532        }
 8533
 8534        let highlighted_edits =
 8535            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8536
 8537        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8538        let line_count = highlighted_edits.text.lines().count();
 8539
 8540        const BORDER_WIDTH: Pixels = px(1.);
 8541
 8542        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8543        let has_keybind = keybind.is_some();
 8544
 8545        let mut element = h_flex()
 8546            .items_start()
 8547            .child(
 8548                h_flex()
 8549                    .bg(cx.theme().colors().editor_background)
 8550                    .border(BORDER_WIDTH)
 8551                    .shadow_sm()
 8552                    .border_color(cx.theme().colors().border)
 8553                    .rounded_l_lg()
 8554                    .when(line_count > 1, |el| el.rounded_br_lg())
 8555                    .pr_1()
 8556                    .child(styled_text),
 8557            )
 8558            .child(
 8559                h_flex()
 8560                    .h(line_height + BORDER_WIDTH * 2.)
 8561                    .px_1p5()
 8562                    .gap_1()
 8563                    // Workaround: For some reason, there's a gap if we don't do this
 8564                    .ml(-BORDER_WIDTH)
 8565                    .shadow(vec![gpui::BoxShadow {
 8566                        color: gpui::black().opacity(0.05),
 8567                        offset: point(px(1.), px(1.)),
 8568                        blur_radius: px(2.),
 8569                        spread_radius: px(0.),
 8570                    }])
 8571                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8572                    .border(BORDER_WIDTH)
 8573                    .border_color(cx.theme().colors().border)
 8574                    .rounded_r_lg()
 8575                    .id("edit_prediction_diff_popover_keybind")
 8576                    .when(!has_keybind, |el| {
 8577                        let status_colors = cx.theme().status();
 8578
 8579                        el.bg(status_colors.error_background)
 8580                            .border_color(status_colors.error.opacity(0.6))
 8581                            .child(Icon::new(IconName::Info).color(Color::Error))
 8582                            .cursor_default()
 8583                            .hoverable_tooltip(move |_window, cx| {
 8584                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8585                            })
 8586                    })
 8587                    .children(keybind),
 8588            )
 8589            .into_any();
 8590
 8591        let longest_row =
 8592            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8593        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8594            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8595        } else {
 8596            layout_line(
 8597                longest_row,
 8598                editor_snapshot,
 8599                style,
 8600                editor_width,
 8601                |_| false,
 8602                window,
 8603                cx,
 8604            )
 8605            .width
 8606        };
 8607
 8608        let viewport_bounds =
 8609            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8610                right: -right_margin,
 8611                ..Default::default()
 8612            });
 8613
 8614        let x_after_longest =
 8615            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8616                - scroll_pixel_position.x;
 8617
 8618        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8619
 8620        // Fully visible if it can be displayed within the window (allow overlapping other
 8621        // panes). However, this is only allowed if the popover starts within text_bounds.
 8622        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8623            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8624
 8625        let mut origin = if can_position_to_the_right {
 8626            point(
 8627                x_after_longest,
 8628                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8629                    - scroll_pixel_position.y,
 8630            )
 8631        } else {
 8632            let cursor_row = newest_selection_head.map(|head| head.row());
 8633            let above_edit = edit_start
 8634                .row()
 8635                .0
 8636                .checked_sub(line_count as u32)
 8637                .map(DisplayRow);
 8638            let below_edit = Some(edit_end.row() + 1);
 8639            let above_cursor =
 8640                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8641            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8642
 8643            // Place the edit popover adjacent to the edit if there is a location
 8644            // available that is onscreen and does not obscure the cursor. Otherwise,
 8645            // place it adjacent to the cursor.
 8646            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8647                .into_iter()
 8648                .flatten()
 8649                .find(|&start_row| {
 8650                    let end_row = start_row + line_count as u32;
 8651                    visible_row_range.contains(&start_row)
 8652                        && visible_row_range.contains(&end_row)
 8653                        && cursor_row.map_or(true, |cursor_row| {
 8654                            !((start_row..end_row).contains(&cursor_row))
 8655                        })
 8656                })?;
 8657
 8658            content_origin
 8659                + point(
 8660                    -scroll_pixel_position.x,
 8661                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8662                )
 8663        };
 8664
 8665        origin.x -= BORDER_WIDTH;
 8666
 8667        window.defer_draw(element, origin, 1);
 8668
 8669        // Do not return an element, since it will already be drawn due to defer_draw.
 8670        None
 8671    }
 8672
 8673    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8674        px(30.)
 8675    }
 8676
 8677    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8678        if self.read_only(cx) {
 8679            cx.theme().players().read_only()
 8680        } else {
 8681            self.style.as_ref().unwrap().local_player
 8682        }
 8683    }
 8684
 8685    fn render_edit_prediction_accept_keybind(
 8686        &self,
 8687        window: &mut Window,
 8688        cx: &App,
 8689    ) -> Option<AnyElement> {
 8690        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8691        let accept_keystroke = accept_binding.keystroke()?;
 8692
 8693        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8694
 8695        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8696            Color::Accent
 8697        } else {
 8698            Color::Muted
 8699        };
 8700
 8701        h_flex()
 8702            .px_0p5()
 8703            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8704            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8705            .text_size(TextSize::XSmall.rems(cx))
 8706            .child(h_flex().children(ui::render_modifiers(
 8707                &accept_keystroke.modifiers,
 8708                PlatformStyle::platform(),
 8709                Some(modifiers_color),
 8710                Some(IconSize::XSmall.rems().into()),
 8711                true,
 8712            )))
 8713            .when(is_platform_style_mac, |parent| {
 8714                parent.child(accept_keystroke.key.clone())
 8715            })
 8716            .when(!is_platform_style_mac, |parent| {
 8717                parent.child(
 8718                    Key::new(
 8719                        util::capitalize(&accept_keystroke.key),
 8720                        Some(Color::Default),
 8721                    )
 8722                    .size(Some(IconSize::XSmall.rems().into())),
 8723                )
 8724            })
 8725            .into_any()
 8726            .into()
 8727    }
 8728
 8729    fn render_edit_prediction_line_popover(
 8730        &self,
 8731        label: impl Into<SharedString>,
 8732        icon: Option<IconName>,
 8733        window: &mut Window,
 8734        cx: &App,
 8735    ) -> Option<Stateful<Div>> {
 8736        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8737
 8738        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8739        let has_keybind = keybind.is_some();
 8740
 8741        let result = h_flex()
 8742            .id("ep-line-popover")
 8743            .py_0p5()
 8744            .pl_1()
 8745            .pr(padding_right)
 8746            .gap_1()
 8747            .rounded_md()
 8748            .border_1()
 8749            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8750            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8751            .shadow_sm()
 8752            .when(!has_keybind, |el| {
 8753                let status_colors = cx.theme().status();
 8754
 8755                el.bg(status_colors.error_background)
 8756                    .border_color(status_colors.error.opacity(0.6))
 8757                    .pl_2()
 8758                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8759                    .cursor_default()
 8760                    .hoverable_tooltip(move |_window, cx| {
 8761                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8762                    })
 8763            })
 8764            .children(keybind)
 8765            .child(
 8766                Label::new(label)
 8767                    .size(LabelSize::Small)
 8768                    .when(!has_keybind, |el| {
 8769                        el.color(cx.theme().status().error.into()).strikethrough()
 8770                    }),
 8771            )
 8772            .when(!has_keybind, |el| {
 8773                el.child(
 8774                    h_flex().ml_1().child(
 8775                        Icon::new(IconName::Info)
 8776                            .size(IconSize::Small)
 8777                            .color(cx.theme().status().error.into()),
 8778                    ),
 8779                )
 8780            })
 8781            .when_some(icon, |element, icon| {
 8782                element.child(
 8783                    div()
 8784                        .mt(px(1.5))
 8785                        .child(Icon::new(icon).size(IconSize::Small)),
 8786                )
 8787            });
 8788
 8789        Some(result)
 8790    }
 8791
 8792    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8793        let accent_color = cx.theme().colors().text_accent;
 8794        let editor_bg_color = cx.theme().colors().editor_background;
 8795        editor_bg_color.blend(accent_color.opacity(0.1))
 8796    }
 8797
 8798    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8799        let accent_color = cx.theme().colors().text_accent;
 8800        let editor_bg_color = cx.theme().colors().editor_background;
 8801        editor_bg_color.blend(accent_color.opacity(0.6))
 8802    }
 8803
 8804    fn render_edit_prediction_cursor_popover(
 8805        &self,
 8806        min_width: Pixels,
 8807        max_width: Pixels,
 8808        cursor_point: Point,
 8809        style: &EditorStyle,
 8810        accept_keystroke: Option<&gpui::Keystroke>,
 8811        _window: &Window,
 8812        cx: &mut Context<Editor>,
 8813    ) -> Option<AnyElement> {
 8814        let provider = self.edit_prediction_provider.as_ref()?;
 8815
 8816        if provider.provider.needs_terms_acceptance(cx) {
 8817            return Some(
 8818                h_flex()
 8819                    .min_w(min_width)
 8820                    .flex_1()
 8821                    .px_2()
 8822                    .py_1()
 8823                    .gap_3()
 8824                    .elevation_2(cx)
 8825                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8826                    .id("accept-terms")
 8827                    .cursor_pointer()
 8828                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8829                    .on_click(cx.listener(|this, _event, window, cx| {
 8830                        cx.stop_propagation();
 8831                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8832                        window.dispatch_action(
 8833                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8834                            cx,
 8835                        );
 8836                    }))
 8837                    .child(
 8838                        h_flex()
 8839                            .flex_1()
 8840                            .gap_2()
 8841                            .child(Icon::new(IconName::ZedPredict))
 8842                            .child(Label::new("Accept Terms of Service"))
 8843                            .child(div().w_full())
 8844                            .child(
 8845                                Icon::new(IconName::ArrowUpRight)
 8846                                    .color(Color::Muted)
 8847                                    .size(IconSize::Small),
 8848                            )
 8849                            .into_any_element(),
 8850                    )
 8851                    .into_any(),
 8852            );
 8853        }
 8854
 8855        let is_refreshing = provider.provider.is_refreshing(cx);
 8856
 8857        fn pending_completion_container() -> Div {
 8858            h_flex()
 8859                .h_full()
 8860                .flex_1()
 8861                .gap_2()
 8862                .child(Icon::new(IconName::ZedPredict))
 8863        }
 8864
 8865        let completion = match &self.active_inline_completion {
 8866            Some(prediction) => {
 8867                if !self.has_visible_completions_menu() {
 8868                    const RADIUS: Pixels = px(6.);
 8869                    const BORDER_WIDTH: Pixels = px(1.);
 8870
 8871                    return Some(
 8872                        h_flex()
 8873                            .elevation_2(cx)
 8874                            .border(BORDER_WIDTH)
 8875                            .border_color(cx.theme().colors().border)
 8876                            .when(accept_keystroke.is_none(), |el| {
 8877                                el.border_color(cx.theme().status().error)
 8878                            })
 8879                            .rounded(RADIUS)
 8880                            .rounded_tl(px(0.))
 8881                            .overflow_hidden()
 8882                            .child(div().px_1p5().child(match &prediction.completion {
 8883                                InlineCompletion::Move { target, snapshot } => {
 8884                                    use text::ToPoint as _;
 8885                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8886                                    {
 8887                                        Icon::new(IconName::ZedPredictDown)
 8888                                    } else {
 8889                                        Icon::new(IconName::ZedPredictUp)
 8890                                    }
 8891                                }
 8892                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8893                            }))
 8894                            .child(
 8895                                h_flex()
 8896                                    .gap_1()
 8897                                    .py_1()
 8898                                    .px_2()
 8899                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8900                                    .border_l_1()
 8901                                    .border_color(cx.theme().colors().border)
 8902                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8903                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8904                                        el.child(
 8905                                            Label::new("Hold")
 8906                                                .size(LabelSize::Small)
 8907                                                .when(accept_keystroke.is_none(), |el| {
 8908                                                    el.strikethrough()
 8909                                                })
 8910                                                .line_height_style(LineHeightStyle::UiLabel),
 8911                                        )
 8912                                    })
 8913                                    .id("edit_prediction_cursor_popover_keybind")
 8914                                    .when(accept_keystroke.is_none(), |el| {
 8915                                        let status_colors = cx.theme().status();
 8916
 8917                                        el.bg(status_colors.error_background)
 8918                                            .border_color(status_colors.error.opacity(0.6))
 8919                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8920                                            .cursor_default()
 8921                                            .hoverable_tooltip(move |_window, cx| {
 8922                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8923                                                    .into()
 8924                                            })
 8925                                    })
 8926                                    .when_some(
 8927                                        accept_keystroke.as_ref(),
 8928                                        |el, accept_keystroke| {
 8929                                            el.child(h_flex().children(ui::render_modifiers(
 8930                                                &accept_keystroke.modifiers,
 8931                                                PlatformStyle::platform(),
 8932                                                Some(Color::Default),
 8933                                                Some(IconSize::XSmall.rems().into()),
 8934                                                false,
 8935                                            )))
 8936                                        },
 8937                                    ),
 8938                            )
 8939                            .into_any(),
 8940                    );
 8941                }
 8942
 8943                self.render_edit_prediction_cursor_popover_preview(
 8944                    prediction,
 8945                    cursor_point,
 8946                    style,
 8947                    cx,
 8948                )?
 8949            }
 8950
 8951            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8952                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8953                    stale_completion,
 8954                    cursor_point,
 8955                    style,
 8956                    cx,
 8957                )?,
 8958
 8959                None => {
 8960                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8961                }
 8962            },
 8963
 8964            None => pending_completion_container().child(Label::new("No Prediction")),
 8965        };
 8966
 8967        let completion = if is_refreshing {
 8968            completion
 8969                .with_animation(
 8970                    "loading-completion",
 8971                    Animation::new(Duration::from_secs(2))
 8972                        .repeat()
 8973                        .with_easing(pulsating_between(0.4, 0.8)),
 8974                    |label, delta| label.opacity(delta),
 8975                )
 8976                .into_any_element()
 8977        } else {
 8978            completion.into_any_element()
 8979        };
 8980
 8981        let has_completion = self.active_inline_completion.is_some();
 8982
 8983        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8984        Some(
 8985            h_flex()
 8986                .min_w(min_width)
 8987                .max_w(max_width)
 8988                .flex_1()
 8989                .elevation_2(cx)
 8990                .border_color(cx.theme().colors().border)
 8991                .child(
 8992                    div()
 8993                        .flex_1()
 8994                        .py_1()
 8995                        .px_2()
 8996                        .overflow_hidden()
 8997                        .child(completion),
 8998                )
 8999                .when_some(accept_keystroke, |el, accept_keystroke| {
 9000                    if !accept_keystroke.modifiers.modified() {
 9001                        return el;
 9002                    }
 9003
 9004                    el.child(
 9005                        h_flex()
 9006                            .h_full()
 9007                            .border_l_1()
 9008                            .rounded_r_lg()
 9009                            .border_color(cx.theme().colors().border)
 9010                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9011                            .gap_1()
 9012                            .py_1()
 9013                            .px_2()
 9014                            .child(
 9015                                h_flex()
 9016                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9017                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9018                                    .child(h_flex().children(ui::render_modifiers(
 9019                                        &accept_keystroke.modifiers,
 9020                                        PlatformStyle::platform(),
 9021                                        Some(if !has_completion {
 9022                                            Color::Muted
 9023                                        } else {
 9024                                            Color::Default
 9025                                        }),
 9026                                        None,
 9027                                        false,
 9028                                    ))),
 9029                            )
 9030                            .child(Label::new("Preview").into_any_element())
 9031                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9032                    )
 9033                })
 9034                .into_any(),
 9035        )
 9036    }
 9037
 9038    fn render_edit_prediction_cursor_popover_preview(
 9039        &self,
 9040        completion: &InlineCompletionState,
 9041        cursor_point: Point,
 9042        style: &EditorStyle,
 9043        cx: &mut Context<Editor>,
 9044    ) -> Option<Div> {
 9045        use text::ToPoint as _;
 9046
 9047        fn render_relative_row_jump(
 9048            prefix: impl Into<String>,
 9049            current_row: u32,
 9050            target_row: u32,
 9051        ) -> Div {
 9052            let (row_diff, arrow) = if target_row < current_row {
 9053                (current_row - target_row, IconName::ArrowUp)
 9054            } else {
 9055                (target_row - current_row, IconName::ArrowDown)
 9056            };
 9057
 9058            h_flex()
 9059                .child(
 9060                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9061                        .color(Color::Muted)
 9062                        .size(LabelSize::Small),
 9063                )
 9064                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9065        }
 9066
 9067        match &completion.completion {
 9068            InlineCompletion::Move {
 9069                target, snapshot, ..
 9070            } => Some(
 9071                h_flex()
 9072                    .px_2()
 9073                    .gap_2()
 9074                    .flex_1()
 9075                    .child(
 9076                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9077                            Icon::new(IconName::ZedPredictDown)
 9078                        } else {
 9079                            Icon::new(IconName::ZedPredictUp)
 9080                        },
 9081                    )
 9082                    .child(Label::new("Jump to Edit")),
 9083            ),
 9084
 9085            InlineCompletion::Edit {
 9086                edits,
 9087                edit_preview,
 9088                snapshot,
 9089                display_mode: _,
 9090            } => {
 9091                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9092
 9093                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9094                    &snapshot,
 9095                    &edits,
 9096                    edit_preview.as_ref()?,
 9097                    true,
 9098                    cx,
 9099                )
 9100                .first_line_preview();
 9101
 9102                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9103                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9104
 9105                let preview = h_flex()
 9106                    .gap_1()
 9107                    .min_w_16()
 9108                    .child(styled_text)
 9109                    .when(has_more_lines, |parent| parent.child(""));
 9110
 9111                let left = if first_edit_row != cursor_point.row {
 9112                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9113                        .into_any_element()
 9114                } else {
 9115                    Icon::new(IconName::ZedPredict).into_any_element()
 9116                };
 9117
 9118                Some(
 9119                    h_flex()
 9120                        .h_full()
 9121                        .flex_1()
 9122                        .gap_2()
 9123                        .pr_1()
 9124                        .overflow_x_hidden()
 9125                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9126                        .child(left)
 9127                        .child(preview),
 9128                )
 9129            }
 9130        }
 9131    }
 9132
 9133    pub fn render_context_menu(
 9134        &self,
 9135        style: &EditorStyle,
 9136        max_height_in_lines: u32,
 9137        window: &mut Window,
 9138        cx: &mut Context<Editor>,
 9139    ) -> Option<AnyElement> {
 9140        let menu = self.context_menu.borrow();
 9141        let menu = menu.as_ref()?;
 9142        if !menu.visible() {
 9143            return None;
 9144        };
 9145        Some(menu.render(style, max_height_in_lines, window, cx))
 9146    }
 9147
 9148    fn render_context_menu_aside(
 9149        &mut self,
 9150        max_size: Size<Pixels>,
 9151        window: &mut Window,
 9152        cx: &mut Context<Editor>,
 9153    ) -> Option<AnyElement> {
 9154        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9155            if menu.visible() {
 9156                menu.render_aside(max_size, window, cx)
 9157            } else {
 9158                None
 9159            }
 9160        })
 9161    }
 9162
 9163    fn hide_context_menu(
 9164        &mut self,
 9165        window: &mut Window,
 9166        cx: &mut Context<Self>,
 9167    ) -> Option<CodeContextMenu> {
 9168        cx.notify();
 9169        self.completion_tasks.clear();
 9170        let context_menu = self.context_menu.borrow_mut().take();
 9171        self.stale_inline_completion_in_menu.take();
 9172        self.update_visible_inline_completion(window, cx);
 9173        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9174            if let Some(completion_provider) = &self.completion_provider {
 9175                completion_provider.selection_changed(None, window, cx);
 9176            }
 9177        }
 9178        context_menu
 9179    }
 9180
 9181    fn show_snippet_choices(
 9182        &mut self,
 9183        choices: &Vec<String>,
 9184        selection: Range<Anchor>,
 9185        cx: &mut Context<Self>,
 9186    ) {
 9187        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9188            (Some(a), Some(b)) if a == b => a,
 9189            _ => {
 9190                log::error!("expected anchor range to have matching buffer IDs");
 9191                return;
 9192            }
 9193        };
 9194        let multi_buffer = self.buffer().read(cx);
 9195        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9196            return;
 9197        };
 9198
 9199        let id = post_inc(&mut self.next_completion_id);
 9200        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9201        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9202            CompletionsMenu::new_snippet_choices(
 9203                id,
 9204                true,
 9205                choices,
 9206                selection,
 9207                buffer,
 9208                snippet_sort_order,
 9209            ),
 9210        ));
 9211    }
 9212
 9213    pub fn insert_snippet(
 9214        &mut self,
 9215        insertion_ranges: &[Range<usize>],
 9216        snippet: Snippet,
 9217        window: &mut Window,
 9218        cx: &mut Context<Self>,
 9219    ) -> Result<()> {
 9220        struct Tabstop<T> {
 9221            is_end_tabstop: bool,
 9222            ranges: Vec<Range<T>>,
 9223            choices: Option<Vec<String>>,
 9224        }
 9225
 9226        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9227            let snippet_text: Arc<str> = snippet.text.clone().into();
 9228            let edits = insertion_ranges
 9229                .iter()
 9230                .cloned()
 9231                .map(|range| (range, snippet_text.clone()));
 9232            let autoindent_mode = AutoindentMode::Block {
 9233                original_indent_columns: Vec::new(),
 9234            };
 9235            buffer.edit(edits, Some(autoindent_mode), cx);
 9236
 9237            let snapshot = &*buffer.read(cx);
 9238            let snippet = &snippet;
 9239            snippet
 9240                .tabstops
 9241                .iter()
 9242                .map(|tabstop| {
 9243                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9244                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9245                    });
 9246                    let mut tabstop_ranges = tabstop
 9247                        .ranges
 9248                        .iter()
 9249                        .flat_map(|tabstop_range| {
 9250                            let mut delta = 0_isize;
 9251                            insertion_ranges.iter().map(move |insertion_range| {
 9252                                let insertion_start = insertion_range.start as isize + delta;
 9253                                delta +=
 9254                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9255
 9256                                let start = ((insertion_start + tabstop_range.start) as usize)
 9257                                    .min(snapshot.len());
 9258                                let end = ((insertion_start + tabstop_range.end) as usize)
 9259                                    .min(snapshot.len());
 9260                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9261                            })
 9262                        })
 9263                        .collect::<Vec<_>>();
 9264                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9265
 9266                    Tabstop {
 9267                        is_end_tabstop,
 9268                        ranges: tabstop_ranges,
 9269                        choices: tabstop.choices.clone(),
 9270                    }
 9271                })
 9272                .collect::<Vec<_>>()
 9273        });
 9274        if let Some(tabstop) = tabstops.first() {
 9275            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9276                // Reverse order so that the first range is the newest created selection.
 9277                // Completions will use it and autoscroll will prioritize it.
 9278                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9279            });
 9280
 9281            if let Some(choices) = &tabstop.choices {
 9282                if let Some(selection) = tabstop.ranges.first() {
 9283                    self.show_snippet_choices(choices, selection.clone(), cx)
 9284                }
 9285            }
 9286
 9287            // If we're already at the last tabstop and it's at the end of the snippet,
 9288            // we're done, we don't need to keep the state around.
 9289            if !tabstop.is_end_tabstop {
 9290                let choices = tabstops
 9291                    .iter()
 9292                    .map(|tabstop| tabstop.choices.clone())
 9293                    .collect();
 9294
 9295                let ranges = tabstops
 9296                    .into_iter()
 9297                    .map(|tabstop| tabstop.ranges)
 9298                    .collect::<Vec<_>>();
 9299
 9300                self.snippet_stack.push(SnippetState {
 9301                    active_index: 0,
 9302                    ranges,
 9303                    choices,
 9304                });
 9305            }
 9306
 9307            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9308            if self.autoclose_regions.is_empty() {
 9309                let snapshot = self.buffer.read(cx).snapshot(cx);
 9310                for selection in &mut self.selections.all::<Point>(cx) {
 9311                    let selection_head = selection.head();
 9312                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9313                        continue;
 9314                    };
 9315
 9316                    let mut bracket_pair = None;
 9317                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9318                    let prev_chars = snapshot
 9319                        .reversed_chars_at(selection_head)
 9320                        .collect::<String>();
 9321                    for (pair, enabled) in scope.brackets() {
 9322                        if enabled
 9323                            && pair.close
 9324                            && prev_chars.starts_with(pair.start.as_str())
 9325                            && next_chars.starts_with(pair.end.as_str())
 9326                        {
 9327                            bracket_pair = Some(pair.clone());
 9328                            break;
 9329                        }
 9330                    }
 9331                    if let Some(pair) = bracket_pair {
 9332                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9333                        let autoclose_enabled =
 9334                            self.use_autoclose && snapshot_settings.use_autoclose;
 9335                        if autoclose_enabled {
 9336                            let start = snapshot.anchor_after(selection_head);
 9337                            let end = snapshot.anchor_after(selection_head);
 9338                            self.autoclose_regions.push(AutocloseRegion {
 9339                                selection_id: selection.id,
 9340                                range: start..end,
 9341                                pair,
 9342                            });
 9343                        }
 9344                    }
 9345                }
 9346            }
 9347        }
 9348        Ok(())
 9349    }
 9350
 9351    pub fn move_to_next_snippet_tabstop(
 9352        &mut self,
 9353        window: &mut Window,
 9354        cx: &mut Context<Self>,
 9355    ) -> bool {
 9356        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9357    }
 9358
 9359    pub fn move_to_prev_snippet_tabstop(
 9360        &mut self,
 9361        window: &mut Window,
 9362        cx: &mut Context<Self>,
 9363    ) -> bool {
 9364        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9365    }
 9366
 9367    pub fn move_to_snippet_tabstop(
 9368        &mut self,
 9369        bias: Bias,
 9370        window: &mut Window,
 9371        cx: &mut Context<Self>,
 9372    ) -> bool {
 9373        if let Some(mut snippet) = self.snippet_stack.pop() {
 9374            match bias {
 9375                Bias::Left => {
 9376                    if snippet.active_index > 0 {
 9377                        snippet.active_index -= 1;
 9378                    } else {
 9379                        self.snippet_stack.push(snippet);
 9380                        return false;
 9381                    }
 9382                }
 9383                Bias::Right => {
 9384                    if snippet.active_index + 1 < snippet.ranges.len() {
 9385                        snippet.active_index += 1;
 9386                    } else {
 9387                        self.snippet_stack.push(snippet);
 9388                        return false;
 9389                    }
 9390                }
 9391            }
 9392            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9393                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9394                    // Reverse order so that the first range is the newest created selection.
 9395                    // Completions will use it and autoscroll will prioritize it.
 9396                    s.select_ranges(current_ranges.iter().rev().cloned())
 9397                });
 9398
 9399                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9400                    if let Some(selection) = current_ranges.first() {
 9401                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9402                    }
 9403                }
 9404
 9405                // If snippet state is not at the last tabstop, push it back on the stack
 9406                if snippet.active_index + 1 < snippet.ranges.len() {
 9407                    self.snippet_stack.push(snippet);
 9408                }
 9409                return true;
 9410            }
 9411        }
 9412
 9413        false
 9414    }
 9415
 9416    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9417        self.transact(window, cx, |this, window, cx| {
 9418            this.select_all(&SelectAll, window, cx);
 9419            this.insert("", window, cx);
 9420        });
 9421    }
 9422
 9423    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9424        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9425        self.transact(window, cx, |this, window, cx| {
 9426            this.select_autoclose_pair(window, cx);
 9427            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9428            if !this.linked_edit_ranges.is_empty() {
 9429                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9430                let snapshot = this.buffer.read(cx).snapshot(cx);
 9431
 9432                for selection in selections.iter() {
 9433                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9434                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9435                    if selection_start.buffer_id != selection_end.buffer_id {
 9436                        continue;
 9437                    }
 9438                    if let Some(ranges) =
 9439                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9440                    {
 9441                        for (buffer, entries) in ranges {
 9442                            linked_ranges.entry(buffer).or_default().extend(entries);
 9443                        }
 9444                    }
 9445                }
 9446            }
 9447
 9448            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9449            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9450            for selection in &mut selections {
 9451                if selection.is_empty() {
 9452                    let old_head = selection.head();
 9453                    let mut new_head =
 9454                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9455                            .to_point(&display_map);
 9456                    if let Some((buffer, line_buffer_range)) = display_map
 9457                        .buffer_snapshot
 9458                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9459                    {
 9460                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9461                        let indent_len = match indent_size.kind {
 9462                            IndentKind::Space => {
 9463                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9464                            }
 9465                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9466                        };
 9467                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9468                            let indent_len = indent_len.get();
 9469                            new_head = cmp::min(
 9470                                new_head,
 9471                                MultiBufferPoint::new(
 9472                                    old_head.row,
 9473                                    ((old_head.column - 1) / indent_len) * indent_len,
 9474                                ),
 9475                            );
 9476                        }
 9477                    }
 9478
 9479                    selection.set_head(new_head, SelectionGoal::None);
 9480                }
 9481            }
 9482
 9483            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9484                s.select(selections)
 9485            });
 9486            this.insert("", window, cx);
 9487            let empty_str: Arc<str> = Arc::from("");
 9488            for (buffer, edits) in linked_ranges {
 9489                let snapshot = buffer.read(cx).snapshot();
 9490                use text::ToPoint as TP;
 9491
 9492                let edits = edits
 9493                    .into_iter()
 9494                    .map(|range| {
 9495                        let end_point = TP::to_point(&range.end, &snapshot);
 9496                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9497
 9498                        if end_point == start_point {
 9499                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9500                                .saturating_sub(1);
 9501                            start_point =
 9502                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9503                        };
 9504
 9505                        (start_point..end_point, empty_str.clone())
 9506                    })
 9507                    .sorted_by_key(|(range, _)| range.start)
 9508                    .collect::<Vec<_>>();
 9509                buffer.update(cx, |this, cx| {
 9510                    this.edit(edits, None, cx);
 9511                })
 9512            }
 9513            this.refresh_inline_completion(true, false, window, cx);
 9514            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9515        });
 9516    }
 9517
 9518    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9519        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9520        self.transact(window, cx, |this, window, cx| {
 9521            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9522                s.move_with(|map, selection| {
 9523                    if selection.is_empty() {
 9524                        let cursor = movement::right(map, selection.head());
 9525                        selection.end = cursor;
 9526                        selection.reversed = true;
 9527                        selection.goal = SelectionGoal::None;
 9528                    }
 9529                })
 9530            });
 9531            this.insert("", window, cx);
 9532            this.refresh_inline_completion(true, false, window, cx);
 9533        });
 9534    }
 9535
 9536    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9538        if self.move_to_prev_snippet_tabstop(window, cx) {
 9539            return;
 9540        }
 9541        self.outdent(&Outdent, window, cx);
 9542    }
 9543
 9544    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9545        if self.move_to_next_snippet_tabstop(window, cx) {
 9546            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9547            return;
 9548        }
 9549        if self.read_only(cx) {
 9550            return;
 9551        }
 9552        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9553        let mut selections = self.selections.all_adjusted(cx);
 9554        let buffer = self.buffer.read(cx);
 9555        let snapshot = buffer.snapshot(cx);
 9556        let rows_iter = selections.iter().map(|s| s.head().row);
 9557        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9558
 9559        let has_some_cursor_in_whitespace = selections
 9560            .iter()
 9561            .filter(|selection| selection.is_empty())
 9562            .any(|selection| {
 9563                let cursor = selection.head();
 9564                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9565                cursor.column < current_indent.len
 9566            });
 9567
 9568        let mut edits = Vec::new();
 9569        let mut prev_edited_row = 0;
 9570        let mut row_delta = 0;
 9571        for selection in &mut selections {
 9572            if selection.start.row != prev_edited_row {
 9573                row_delta = 0;
 9574            }
 9575            prev_edited_row = selection.end.row;
 9576
 9577            // If the selection is non-empty, then increase the indentation of the selected lines.
 9578            if !selection.is_empty() {
 9579                row_delta =
 9580                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9581                continue;
 9582            }
 9583
 9584            let cursor = selection.head();
 9585            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9586            if let Some(suggested_indent) =
 9587                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9588            {
 9589                // Don't do anything if already at suggested indent
 9590                // and there is any other cursor which is not
 9591                if has_some_cursor_in_whitespace
 9592                    && cursor.column == current_indent.len
 9593                    && current_indent.len == suggested_indent.len
 9594                {
 9595                    continue;
 9596                }
 9597
 9598                // Adjust line and move cursor to suggested indent
 9599                // if cursor is not at suggested indent
 9600                if cursor.column < suggested_indent.len
 9601                    && cursor.column <= current_indent.len
 9602                    && current_indent.len <= suggested_indent.len
 9603                {
 9604                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9605                    selection.end = selection.start;
 9606                    if row_delta == 0 {
 9607                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9608                            cursor.row,
 9609                            current_indent,
 9610                            suggested_indent,
 9611                        ));
 9612                        row_delta = suggested_indent.len - current_indent.len;
 9613                    }
 9614                    continue;
 9615                }
 9616
 9617                // If current indent is more than suggested indent
 9618                // only move cursor to current indent and skip indent
 9619                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9620                    selection.start = Point::new(cursor.row, current_indent.len);
 9621                    selection.end = selection.start;
 9622                    continue;
 9623                }
 9624            }
 9625
 9626            // Otherwise, insert a hard or soft tab.
 9627            let settings = buffer.language_settings_at(cursor, cx);
 9628            let tab_size = if settings.hard_tabs {
 9629                IndentSize::tab()
 9630            } else {
 9631                let tab_size = settings.tab_size.get();
 9632                let indent_remainder = snapshot
 9633                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9634                    .flat_map(str::chars)
 9635                    .fold(row_delta % tab_size, |counter: u32, c| {
 9636                        if c == '\t' {
 9637                            0
 9638                        } else {
 9639                            (counter + 1) % tab_size
 9640                        }
 9641                    });
 9642
 9643                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9644                IndentSize::spaces(chars_to_next_tab_stop)
 9645            };
 9646            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9647            selection.end = selection.start;
 9648            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9649            row_delta += tab_size.len;
 9650        }
 9651
 9652        self.transact(window, cx, |this, window, cx| {
 9653            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9654            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9655                s.select(selections)
 9656            });
 9657            this.refresh_inline_completion(true, false, window, cx);
 9658        });
 9659    }
 9660
 9661    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9662        if self.read_only(cx) {
 9663            return;
 9664        }
 9665        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9666        let mut selections = self.selections.all::<Point>(cx);
 9667        let mut prev_edited_row = 0;
 9668        let mut row_delta = 0;
 9669        let mut edits = Vec::new();
 9670        let buffer = self.buffer.read(cx);
 9671        let snapshot = buffer.snapshot(cx);
 9672        for selection in &mut selections {
 9673            if selection.start.row != prev_edited_row {
 9674                row_delta = 0;
 9675            }
 9676            prev_edited_row = selection.end.row;
 9677
 9678            row_delta =
 9679                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9680        }
 9681
 9682        self.transact(window, cx, |this, window, cx| {
 9683            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9684            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9685                s.select(selections)
 9686            });
 9687        });
 9688    }
 9689
 9690    fn indent_selection(
 9691        buffer: &MultiBuffer,
 9692        snapshot: &MultiBufferSnapshot,
 9693        selection: &mut Selection<Point>,
 9694        edits: &mut Vec<(Range<Point>, String)>,
 9695        delta_for_start_row: u32,
 9696        cx: &App,
 9697    ) -> u32 {
 9698        let settings = buffer.language_settings_at(selection.start, cx);
 9699        let tab_size = settings.tab_size.get();
 9700        let indent_kind = if settings.hard_tabs {
 9701            IndentKind::Tab
 9702        } else {
 9703            IndentKind::Space
 9704        };
 9705        let mut start_row = selection.start.row;
 9706        let mut end_row = selection.end.row + 1;
 9707
 9708        // If a selection ends at the beginning of a line, don't indent
 9709        // that last line.
 9710        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9711            end_row -= 1;
 9712        }
 9713
 9714        // Avoid re-indenting a row that has already been indented by a
 9715        // previous selection, but still update this selection's column
 9716        // to reflect that indentation.
 9717        if delta_for_start_row > 0 {
 9718            start_row += 1;
 9719            selection.start.column += delta_for_start_row;
 9720            if selection.end.row == selection.start.row {
 9721                selection.end.column += delta_for_start_row;
 9722            }
 9723        }
 9724
 9725        let mut delta_for_end_row = 0;
 9726        let has_multiple_rows = start_row + 1 != end_row;
 9727        for row in start_row..end_row {
 9728            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9729            let indent_delta = match (current_indent.kind, indent_kind) {
 9730                (IndentKind::Space, IndentKind::Space) => {
 9731                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9732                    IndentSize::spaces(columns_to_next_tab_stop)
 9733                }
 9734                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9735                (_, IndentKind::Tab) => IndentSize::tab(),
 9736            };
 9737
 9738            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9739                0
 9740            } else {
 9741                selection.start.column
 9742            };
 9743            let row_start = Point::new(row, start);
 9744            edits.push((
 9745                row_start..row_start,
 9746                indent_delta.chars().collect::<String>(),
 9747            ));
 9748
 9749            // Update this selection's endpoints to reflect the indentation.
 9750            if row == selection.start.row {
 9751                selection.start.column += indent_delta.len;
 9752            }
 9753            if row == selection.end.row {
 9754                selection.end.column += indent_delta.len;
 9755                delta_for_end_row = indent_delta.len;
 9756            }
 9757        }
 9758
 9759        if selection.start.row == selection.end.row {
 9760            delta_for_start_row + delta_for_end_row
 9761        } else {
 9762            delta_for_end_row
 9763        }
 9764    }
 9765
 9766    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9767        if self.read_only(cx) {
 9768            return;
 9769        }
 9770        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9771        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9772        let selections = self.selections.all::<Point>(cx);
 9773        let mut deletion_ranges = Vec::new();
 9774        let mut last_outdent = None;
 9775        {
 9776            let buffer = self.buffer.read(cx);
 9777            let snapshot = buffer.snapshot(cx);
 9778            for selection in &selections {
 9779                let settings = buffer.language_settings_at(selection.start, cx);
 9780                let tab_size = settings.tab_size.get();
 9781                let mut rows = selection.spanned_rows(false, &display_map);
 9782
 9783                // Avoid re-outdenting a row that has already been outdented by a
 9784                // previous selection.
 9785                if let Some(last_row) = last_outdent {
 9786                    if last_row == rows.start {
 9787                        rows.start = rows.start.next_row();
 9788                    }
 9789                }
 9790                let has_multiple_rows = rows.len() > 1;
 9791                for row in rows.iter_rows() {
 9792                    let indent_size = snapshot.indent_size_for_line(row);
 9793                    if indent_size.len > 0 {
 9794                        let deletion_len = match indent_size.kind {
 9795                            IndentKind::Space => {
 9796                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9797                                if columns_to_prev_tab_stop == 0 {
 9798                                    tab_size
 9799                                } else {
 9800                                    columns_to_prev_tab_stop
 9801                                }
 9802                            }
 9803                            IndentKind::Tab => 1,
 9804                        };
 9805                        let start = if has_multiple_rows
 9806                            || deletion_len > selection.start.column
 9807                            || indent_size.len < selection.start.column
 9808                        {
 9809                            0
 9810                        } else {
 9811                            selection.start.column - deletion_len
 9812                        };
 9813                        deletion_ranges.push(
 9814                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9815                        );
 9816                        last_outdent = Some(row);
 9817                    }
 9818                }
 9819            }
 9820        }
 9821
 9822        self.transact(window, cx, |this, window, cx| {
 9823            this.buffer.update(cx, |buffer, cx| {
 9824                let empty_str: Arc<str> = Arc::default();
 9825                buffer.edit(
 9826                    deletion_ranges
 9827                        .into_iter()
 9828                        .map(|range| (range, empty_str.clone())),
 9829                    None,
 9830                    cx,
 9831                );
 9832            });
 9833            let selections = this.selections.all::<usize>(cx);
 9834            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9835                s.select(selections)
 9836            });
 9837        });
 9838    }
 9839
 9840    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9841        if self.read_only(cx) {
 9842            return;
 9843        }
 9844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9845        let selections = self
 9846            .selections
 9847            .all::<usize>(cx)
 9848            .into_iter()
 9849            .map(|s| s.range());
 9850
 9851        self.transact(window, cx, |this, window, cx| {
 9852            this.buffer.update(cx, |buffer, cx| {
 9853                buffer.autoindent_ranges(selections, cx);
 9854            });
 9855            let selections = this.selections.all::<usize>(cx);
 9856            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9857                s.select(selections)
 9858            });
 9859        });
 9860    }
 9861
 9862    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9863        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9864        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9865        let selections = self.selections.all::<Point>(cx);
 9866
 9867        let mut new_cursors = Vec::new();
 9868        let mut edit_ranges = Vec::new();
 9869        let mut selections = selections.iter().peekable();
 9870        while let Some(selection) = selections.next() {
 9871            let mut rows = selection.spanned_rows(false, &display_map);
 9872            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9873
 9874            // Accumulate contiguous regions of rows that we want to delete.
 9875            while let Some(next_selection) = selections.peek() {
 9876                let next_rows = next_selection.spanned_rows(false, &display_map);
 9877                if next_rows.start <= rows.end {
 9878                    rows.end = next_rows.end;
 9879                    selections.next().unwrap();
 9880                } else {
 9881                    break;
 9882                }
 9883            }
 9884
 9885            let buffer = &display_map.buffer_snapshot;
 9886            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9887            let edit_end;
 9888            let cursor_buffer_row;
 9889            if buffer.max_point().row >= rows.end.0 {
 9890                // If there's a line after the range, delete the \n from the end of the row range
 9891                // and position the cursor on the next line.
 9892                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9893                cursor_buffer_row = rows.end;
 9894            } else {
 9895                // If there isn't a line after the range, delete the \n from the line before the
 9896                // start of the row range and position the cursor there.
 9897                edit_start = edit_start.saturating_sub(1);
 9898                edit_end = buffer.len();
 9899                cursor_buffer_row = rows.start.previous_row();
 9900            }
 9901
 9902            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9903            *cursor.column_mut() =
 9904                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9905
 9906            new_cursors.push((
 9907                selection.id,
 9908                buffer.anchor_after(cursor.to_point(&display_map)),
 9909            ));
 9910            edit_ranges.push(edit_start..edit_end);
 9911        }
 9912
 9913        self.transact(window, cx, |this, window, cx| {
 9914            let buffer = this.buffer.update(cx, |buffer, cx| {
 9915                let empty_str: Arc<str> = Arc::default();
 9916                buffer.edit(
 9917                    edit_ranges
 9918                        .into_iter()
 9919                        .map(|range| (range, empty_str.clone())),
 9920                    None,
 9921                    cx,
 9922                );
 9923                buffer.snapshot(cx)
 9924            });
 9925            let new_selections = new_cursors
 9926                .into_iter()
 9927                .map(|(id, cursor)| {
 9928                    let cursor = cursor.to_point(&buffer);
 9929                    Selection {
 9930                        id,
 9931                        start: cursor,
 9932                        end: cursor,
 9933                        reversed: false,
 9934                        goal: SelectionGoal::None,
 9935                    }
 9936                })
 9937                .collect();
 9938
 9939            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9940                s.select(new_selections);
 9941            });
 9942        });
 9943    }
 9944
 9945    pub fn join_lines_impl(
 9946        &mut self,
 9947        insert_whitespace: bool,
 9948        window: &mut Window,
 9949        cx: &mut Context<Self>,
 9950    ) {
 9951        if self.read_only(cx) {
 9952            return;
 9953        }
 9954        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9955        for selection in self.selections.all::<Point>(cx) {
 9956            let start = MultiBufferRow(selection.start.row);
 9957            // Treat single line selections as if they include the next line. Otherwise this action
 9958            // would do nothing for single line selections individual cursors.
 9959            let end = if selection.start.row == selection.end.row {
 9960                MultiBufferRow(selection.start.row + 1)
 9961            } else {
 9962                MultiBufferRow(selection.end.row)
 9963            };
 9964
 9965            if let Some(last_row_range) = row_ranges.last_mut() {
 9966                if start <= last_row_range.end {
 9967                    last_row_range.end = end;
 9968                    continue;
 9969                }
 9970            }
 9971            row_ranges.push(start..end);
 9972        }
 9973
 9974        let snapshot = self.buffer.read(cx).snapshot(cx);
 9975        let mut cursor_positions = Vec::new();
 9976        for row_range in &row_ranges {
 9977            let anchor = snapshot.anchor_before(Point::new(
 9978                row_range.end.previous_row().0,
 9979                snapshot.line_len(row_range.end.previous_row()),
 9980            ));
 9981            cursor_positions.push(anchor..anchor);
 9982        }
 9983
 9984        self.transact(window, cx, |this, window, cx| {
 9985            for row_range in row_ranges.into_iter().rev() {
 9986                for row in row_range.iter_rows().rev() {
 9987                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9988                    let next_line_row = row.next_row();
 9989                    let indent = snapshot.indent_size_for_line(next_line_row);
 9990                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9991
 9992                    let replace =
 9993                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9994                            " "
 9995                        } else {
 9996                            ""
 9997                        };
 9998
 9999                    this.buffer.update(cx, |buffer, cx| {
10000                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10001                    });
10002                }
10003            }
10004
10005            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10006                s.select_anchor_ranges(cursor_positions)
10007            });
10008        });
10009    }
10010
10011    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10012        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10013        self.join_lines_impl(true, window, cx);
10014    }
10015
10016    pub fn sort_lines_case_sensitive(
10017        &mut self,
10018        _: &SortLinesCaseSensitive,
10019        window: &mut Window,
10020        cx: &mut Context<Self>,
10021    ) {
10022        self.manipulate_lines(window, cx, |lines| lines.sort())
10023    }
10024
10025    pub fn sort_lines_case_insensitive(
10026        &mut self,
10027        _: &SortLinesCaseInsensitive,
10028        window: &mut Window,
10029        cx: &mut Context<Self>,
10030    ) {
10031        self.manipulate_lines(window, cx, |lines| {
10032            lines.sort_by_key(|line| line.to_lowercase())
10033        })
10034    }
10035
10036    pub fn unique_lines_case_insensitive(
10037        &mut self,
10038        _: &UniqueLinesCaseInsensitive,
10039        window: &mut Window,
10040        cx: &mut Context<Self>,
10041    ) {
10042        self.manipulate_lines(window, cx, |lines| {
10043            let mut seen = HashSet::default();
10044            lines.retain(|line| seen.insert(line.to_lowercase()));
10045        })
10046    }
10047
10048    pub fn unique_lines_case_sensitive(
10049        &mut self,
10050        _: &UniqueLinesCaseSensitive,
10051        window: &mut Window,
10052        cx: &mut Context<Self>,
10053    ) {
10054        self.manipulate_lines(window, cx, |lines| {
10055            let mut seen = HashSet::default();
10056            lines.retain(|line| seen.insert(*line));
10057        })
10058    }
10059
10060    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10061        let Some(project) = self.project.clone() else {
10062            return;
10063        };
10064        self.reload(project, window, cx)
10065            .detach_and_notify_err(window, cx);
10066    }
10067
10068    pub fn restore_file(
10069        &mut self,
10070        _: &::git::RestoreFile,
10071        window: &mut Window,
10072        cx: &mut Context<Self>,
10073    ) {
10074        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10075        let mut buffer_ids = HashSet::default();
10076        let snapshot = self.buffer().read(cx).snapshot(cx);
10077        for selection in self.selections.all::<usize>(cx) {
10078            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10079        }
10080
10081        let buffer = self.buffer().read(cx);
10082        let ranges = buffer_ids
10083            .into_iter()
10084            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10085            .collect::<Vec<_>>();
10086
10087        self.restore_hunks_in_ranges(ranges, window, cx);
10088    }
10089
10090    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10091        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10092        let selections = self
10093            .selections
10094            .all(cx)
10095            .into_iter()
10096            .map(|s| s.range())
10097            .collect();
10098        self.restore_hunks_in_ranges(selections, window, cx);
10099    }
10100
10101    pub fn restore_hunks_in_ranges(
10102        &mut self,
10103        ranges: Vec<Range<Point>>,
10104        window: &mut Window,
10105        cx: &mut Context<Editor>,
10106    ) {
10107        let mut revert_changes = HashMap::default();
10108        let chunk_by = self
10109            .snapshot(window, cx)
10110            .hunks_for_ranges(ranges)
10111            .into_iter()
10112            .chunk_by(|hunk| hunk.buffer_id);
10113        for (buffer_id, hunks) in &chunk_by {
10114            let hunks = hunks.collect::<Vec<_>>();
10115            for hunk in &hunks {
10116                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10117            }
10118            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10119        }
10120        drop(chunk_by);
10121        if !revert_changes.is_empty() {
10122            self.transact(window, cx, |editor, window, cx| {
10123                editor.restore(revert_changes, window, cx);
10124            });
10125        }
10126    }
10127
10128    pub fn open_active_item_in_terminal(
10129        &mut self,
10130        _: &OpenInTerminal,
10131        window: &mut Window,
10132        cx: &mut Context<Self>,
10133    ) {
10134        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10135            let project_path = buffer.read(cx).project_path(cx)?;
10136            let project = self.project.as_ref()?.read(cx);
10137            let entry = project.entry_for_path(&project_path, cx)?;
10138            let parent = match &entry.canonical_path {
10139                Some(canonical_path) => canonical_path.to_path_buf(),
10140                None => project.absolute_path(&project_path, cx)?,
10141            }
10142            .parent()?
10143            .to_path_buf();
10144            Some(parent)
10145        }) {
10146            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10147        }
10148    }
10149
10150    fn set_breakpoint_context_menu(
10151        &mut self,
10152        display_row: DisplayRow,
10153        position: Option<Anchor>,
10154        clicked_point: gpui::Point<Pixels>,
10155        window: &mut Window,
10156        cx: &mut Context<Self>,
10157    ) {
10158        if !cx.has_flag::<DebuggerFeatureFlag>() {
10159            return;
10160        }
10161        let source = self
10162            .buffer
10163            .read(cx)
10164            .snapshot(cx)
10165            .anchor_before(Point::new(display_row.0, 0u32));
10166
10167        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10168
10169        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10170            self,
10171            source,
10172            clicked_point,
10173            context_menu,
10174            window,
10175            cx,
10176        );
10177    }
10178
10179    fn add_edit_breakpoint_block(
10180        &mut self,
10181        anchor: Anchor,
10182        breakpoint: &Breakpoint,
10183        edit_action: BreakpointPromptEditAction,
10184        window: &mut Window,
10185        cx: &mut Context<Self>,
10186    ) {
10187        let weak_editor = cx.weak_entity();
10188        let bp_prompt = cx.new(|cx| {
10189            BreakpointPromptEditor::new(
10190                weak_editor,
10191                anchor,
10192                breakpoint.clone(),
10193                edit_action,
10194                window,
10195                cx,
10196            )
10197        });
10198
10199        let height = bp_prompt.update(cx, |this, cx| {
10200            this.prompt
10201                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10202        });
10203        let cloned_prompt = bp_prompt.clone();
10204        let blocks = vec![BlockProperties {
10205            style: BlockStyle::Sticky,
10206            placement: BlockPlacement::Above(anchor),
10207            height: Some(height),
10208            render: Arc::new(move |cx| {
10209                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10210                cloned_prompt.clone().into_any_element()
10211            }),
10212            priority: 0,
10213            render_in_minimap: true,
10214        }];
10215
10216        let focus_handle = bp_prompt.focus_handle(cx);
10217        window.focus(&focus_handle);
10218
10219        let block_ids = self.insert_blocks(blocks, None, cx);
10220        bp_prompt.update(cx, |prompt, _| {
10221            prompt.add_block_ids(block_ids);
10222        });
10223    }
10224
10225    pub(crate) fn breakpoint_at_row(
10226        &self,
10227        row: u32,
10228        window: &mut Window,
10229        cx: &mut Context<Self>,
10230    ) -> Option<(Anchor, Breakpoint)> {
10231        let snapshot = self.snapshot(window, cx);
10232        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10233
10234        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10235    }
10236
10237    pub(crate) fn breakpoint_at_anchor(
10238        &self,
10239        breakpoint_position: Anchor,
10240        snapshot: &EditorSnapshot,
10241        cx: &mut Context<Self>,
10242    ) -> Option<(Anchor, Breakpoint)> {
10243        let project = self.project.clone()?;
10244
10245        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10246            snapshot
10247                .buffer_snapshot
10248                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10249        })?;
10250
10251        let enclosing_excerpt = breakpoint_position.excerpt_id;
10252        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10253        let buffer_snapshot = buffer.read(cx).snapshot();
10254
10255        let row = buffer_snapshot
10256            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10257            .row;
10258
10259        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10260        let anchor_end = snapshot
10261            .buffer_snapshot
10262            .anchor_after(Point::new(row, line_len));
10263
10264        let bp = self
10265            .breakpoint_store
10266            .as_ref()?
10267            .read_with(cx, |breakpoint_store, cx| {
10268                breakpoint_store
10269                    .breakpoints(
10270                        &buffer,
10271                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10272                        &buffer_snapshot,
10273                        cx,
10274                    )
10275                    .next()
10276                    .and_then(|(bp, _)| {
10277                        let breakpoint_row = buffer_snapshot
10278                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10279                            .row;
10280
10281                        if breakpoint_row == row {
10282                            snapshot
10283                                .buffer_snapshot
10284                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10285                                .map(|position| (position, bp.bp.clone()))
10286                        } else {
10287                            None
10288                        }
10289                    })
10290            });
10291        bp
10292    }
10293
10294    pub fn edit_log_breakpoint(
10295        &mut self,
10296        _: &EditLogBreakpoint,
10297        window: &mut Window,
10298        cx: &mut Context<Self>,
10299    ) {
10300        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10301            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10302                message: None,
10303                state: BreakpointState::Enabled,
10304                condition: None,
10305                hit_condition: None,
10306            });
10307
10308            self.add_edit_breakpoint_block(
10309                anchor,
10310                &breakpoint,
10311                BreakpointPromptEditAction::Log,
10312                window,
10313                cx,
10314            );
10315        }
10316    }
10317
10318    fn breakpoints_at_cursors(
10319        &self,
10320        window: &mut Window,
10321        cx: &mut Context<Self>,
10322    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10323        let snapshot = self.snapshot(window, cx);
10324        let cursors = self
10325            .selections
10326            .disjoint_anchors()
10327            .into_iter()
10328            .map(|selection| {
10329                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10330
10331                let breakpoint_position = self
10332                    .breakpoint_at_row(cursor_position.row, window, cx)
10333                    .map(|bp| bp.0)
10334                    .unwrap_or_else(|| {
10335                        snapshot
10336                            .display_snapshot
10337                            .buffer_snapshot
10338                            .anchor_after(Point::new(cursor_position.row, 0))
10339                    });
10340
10341                let breakpoint = self
10342                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10343                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10344
10345                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10346            })
10347            // 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.
10348            .collect::<HashMap<Anchor, _>>();
10349
10350        cursors.into_iter().collect()
10351    }
10352
10353    pub fn enable_breakpoint(
10354        &mut self,
10355        _: &crate::actions::EnableBreakpoint,
10356        window: &mut Window,
10357        cx: &mut Context<Self>,
10358    ) {
10359        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10360            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10361                continue;
10362            };
10363            self.edit_breakpoint_at_anchor(
10364                anchor,
10365                breakpoint,
10366                BreakpointEditAction::InvertState,
10367                cx,
10368            );
10369        }
10370    }
10371
10372    pub fn disable_breakpoint(
10373        &mut self,
10374        _: &crate::actions::DisableBreakpoint,
10375        window: &mut Window,
10376        cx: &mut Context<Self>,
10377    ) {
10378        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10379            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10380                continue;
10381            };
10382            self.edit_breakpoint_at_anchor(
10383                anchor,
10384                breakpoint,
10385                BreakpointEditAction::InvertState,
10386                cx,
10387            );
10388        }
10389    }
10390
10391    pub fn toggle_breakpoint(
10392        &mut self,
10393        _: &crate::actions::ToggleBreakpoint,
10394        window: &mut Window,
10395        cx: &mut Context<Self>,
10396    ) {
10397        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10398            if let Some(breakpoint) = breakpoint {
10399                self.edit_breakpoint_at_anchor(
10400                    anchor,
10401                    breakpoint,
10402                    BreakpointEditAction::Toggle,
10403                    cx,
10404                );
10405            } else {
10406                self.edit_breakpoint_at_anchor(
10407                    anchor,
10408                    Breakpoint::new_standard(),
10409                    BreakpointEditAction::Toggle,
10410                    cx,
10411                );
10412            }
10413        }
10414    }
10415
10416    pub fn edit_breakpoint_at_anchor(
10417        &mut self,
10418        breakpoint_position: Anchor,
10419        breakpoint: Breakpoint,
10420        edit_action: BreakpointEditAction,
10421        cx: &mut Context<Self>,
10422    ) {
10423        let Some(breakpoint_store) = &self.breakpoint_store else {
10424            return;
10425        };
10426
10427        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10428            if breakpoint_position == Anchor::min() {
10429                self.buffer()
10430                    .read(cx)
10431                    .excerpt_buffer_ids()
10432                    .into_iter()
10433                    .next()
10434            } else {
10435                None
10436            }
10437        }) else {
10438            return;
10439        };
10440
10441        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10442            return;
10443        };
10444
10445        breakpoint_store.update(cx, |breakpoint_store, cx| {
10446            breakpoint_store.toggle_breakpoint(
10447                buffer,
10448                BreakpointWithPosition {
10449                    position: breakpoint_position.text_anchor,
10450                    bp: breakpoint,
10451                },
10452                edit_action,
10453                cx,
10454            );
10455        });
10456
10457        cx.notify();
10458    }
10459
10460    #[cfg(any(test, feature = "test-support"))]
10461    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10462        self.breakpoint_store.clone()
10463    }
10464
10465    pub fn prepare_restore_change(
10466        &self,
10467        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10468        hunk: &MultiBufferDiffHunk,
10469        cx: &mut App,
10470    ) -> Option<()> {
10471        if hunk.is_created_file() {
10472            return None;
10473        }
10474        let buffer = self.buffer.read(cx);
10475        let diff = buffer.diff_for(hunk.buffer_id)?;
10476        let buffer = buffer.buffer(hunk.buffer_id)?;
10477        let buffer = buffer.read(cx);
10478        let original_text = diff
10479            .read(cx)
10480            .base_text()
10481            .as_rope()
10482            .slice(hunk.diff_base_byte_range.clone());
10483        let buffer_snapshot = buffer.snapshot();
10484        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10485        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10486            probe
10487                .0
10488                .start
10489                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10490                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10491        }) {
10492            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10493            Some(())
10494        } else {
10495            None
10496        }
10497    }
10498
10499    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10500        self.manipulate_lines(window, cx, |lines| lines.reverse())
10501    }
10502
10503    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10504        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10505    }
10506
10507    fn manipulate_lines<Fn>(
10508        &mut self,
10509        window: &mut Window,
10510        cx: &mut Context<Self>,
10511        mut callback: Fn,
10512    ) where
10513        Fn: FnMut(&mut Vec<&str>),
10514    {
10515        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10516
10517        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10518        let buffer = self.buffer.read(cx).snapshot(cx);
10519
10520        let mut edits = Vec::new();
10521
10522        let selections = self.selections.all::<Point>(cx);
10523        let mut selections = selections.iter().peekable();
10524        let mut contiguous_row_selections = Vec::new();
10525        let mut new_selections = Vec::new();
10526        let mut added_lines = 0;
10527        let mut removed_lines = 0;
10528
10529        while let Some(selection) = selections.next() {
10530            let (start_row, end_row) = consume_contiguous_rows(
10531                &mut contiguous_row_selections,
10532                selection,
10533                &display_map,
10534                &mut selections,
10535            );
10536
10537            let start_point = Point::new(start_row.0, 0);
10538            let end_point = Point::new(
10539                end_row.previous_row().0,
10540                buffer.line_len(end_row.previous_row()),
10541            );
10542            let text = buffer
10543                .text_for_range(start_point..end_point)
10544                .collect::<String>();
10545
10546            let mut lines = text.split('\n').collect_vec();
10547
10548            let lines_before = lines.len();
10549            callback(&mut lines);
10550            let lines_after = lines.len();
10551
10552            edits.push((start_point..end_point, lines.join("\n")));
10553
10554            // Selections must change based on added and removed line count
10555            let start_row =
10556                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10557            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10558            new_selections.push(Selection {
10559                id: selection.id,
10560                start: start_row,
10561                end: end_row,
10562                goal: SelectionGoal::None,
10563                reversed: selection.reversed,
10564            });
10565
10566            if lines_after > lines_before {
10567                added_lines += lines_after - lines_before;
10568            } else if lines_before > lines_after {
10569                removed_lines += lines_before - lines_after;
10570            }
10571        }
10572
10573        self.transact(window, cx, |this, window, cx| {
10574            let buffer = this.buffer.update(cx, |buffer, cx| {
10575                buffer.edit(edits, None, cx);
10576                buffer.snapshot(cx)
10577            });
10578
10579            // Recalculate offsets on newly edited buffer
10580            let new_selections = new_selections
10581                .iter()
10582                .map(|s| {
10583                    let start_point = Point::new(s.start.0, 0);
10584                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10585                    Selection {
10586                        id: s.id,
10587                        start: buffer.point_to_offset(start_point),
10588                        end: buffer.point_to_offset(end_point),
10589                        goal: s.goal,
10590                        reversed: s.reversed,
10591                    }
10592                })
10593                .collect();
10594
10595            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10596                s.select(new_selections);
10597            });
10598
10599            this.request_autoscroll(Autoscroll::fit(), cx);
10600        });
10601    }
10602
10603    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10604        self.manipulate_text(window, cx, |text| {
10605            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10606            if has_upper_case_characters {
10607                text.to_lowercase()
10608            } else {
10609                text.to_uppercase()
10610            }
10611        })
10612    }
10613
10614    pub fn convert_to_upper_case(
10615        &mut self,
10616        _: &ConvertToUpperCase,
10617        window: &mut Window,
10618        cx: &mut Context<Self>,
10619    ) {
10620        self.manipulate_text(window, cx, |text| text.to_uppercase())
10621    }
10622
10623    pub fn convert_to_lower_case(
10624        &mut self,
10625        _: &ConvertToLowerCase,
10626        window: &mut Window,
10627        cx: &mut Context<Self>,
10628    ) {
10629        self.manipulate_text(window, cx, |text| text.to_lowercase())
10630    }
10631
10632    pub fn convert_to_title_case(
10633        &mut self,
10634        _: &ConvertToTitleCase,
10635        window: &mut Window,
10636        cx: &mut Context<Self>,
10637    ) {
10638        self.manipulate_text(window, cx, |text| {
10639            text.split('\n')
10640                .map(|line| line.to_case(Case::Title))
10641                .join("\n")
10642        })
10643    }
10644
10645    pub fn convert_to_snake_case(
10646        &mut self,
10647        _: &ConvertToSnakeCase,
10648        window: &mut Window,
10649        cx: &mut Context<Self>,
10650    ) {
10651        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10652    }
10653
10654    pub fn convert_to_kebab_case(
10655        &mut self,
10656        _: &ConvertToKebabCase,
10657        window: &mut Window,
10658        cx: &mut Context<Self>,
10659    ) {
10660        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10661    }
10662
10663    pub fn convert_to_upper_camel_case(
10664        &mut self,
10665        _: &ConvertToUpperCamelCase,
10666        window: &mut Window,
10667        cx: &mut Context<Self>,
10668    ) {
10669        self.manipulate_text(window, cx, |text| {
10670            text.split('\n')
10671                .map(|line| line.to_case(Case::UpperCamel))
10672                .join("\n")
10673        })
10674    }
10675
10676    pub fn convert_to_lower_camel_case(
10677        &mut self,
10678        _: &ConvertToLowerCamelCase,
10679        window: &mut Window,
10680        cx: &mut Context<Self>,
10681    ) {
10682        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10683    }
10684
10685    pub fn convert_to_opposite_case(
10686        &mut self,
10687        _: &ConvertToOppositeCase,
10688        window: &mut Window,
10689        cx: &mut Context<Self>,
10690    ) {
10691        self.manipulate_text(window, cx, |text| {
10692            text.chars()
10693                .fold(String::with_capacity(text.len()), |mut t, c| {
10694                    if c.is_uppercase() {
10695                        t.extend(c.to_lowercase());
10696                    } else {
10697                        t.extend(c.to_uppercase());
10698                    }
10699                    t
10700                })
10701        })
10702    }
10703
10704    pub fn convert_to_rot13(
10705        &mut self,
10706        _: &ConvertToRot13,
10707        window: &mut Window,
10708        cx: &mut Context<Self>,
10709    ) {
10710        self.manipulate_text(window, cx, |text| {
10711            text.chars()
10712                .map(|c| match c {
10713                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10714                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10715                    _ => c,
10716                })
10717                .collect()
10718        })
10719    }
10720
10721    pub fn convert_to_rot47(
10722        &mut self,
10723        _: &ConvertToRot47,
10724        window: &mut Window,
10725        cx: &mut Context<Self>,
10726    ) {
10727        self.manipulate_text(window, cx, |text| {
10728            text.chars()
10729                .map(|c| {
10730                    let code_point = c as u32;
10731                    if code_point >= 33 && code_point <= 126 {
10732                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10733                    }
10734                    c
10735                })
10736                .collect()
10737        })
10738    }
10739
10740    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10741    where
10742        Fn: FnMut(&str) -> String,
10743    {
10744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10745        let buffer = self.buffer.read(cx).snapshot(cx);
10746
10747        let mut new_selections = Vec::new();
10748        let mut edits = Vec::new();
10749        let mut selection_adjustment = 0i32;
10750
10751        for selection in self.selections.all::<usize>(cx) {
10752            let selection_is_empty = selection.is_empty();
10753
10754            let (start, end) = if selection_is_empty {
10755                let word_range = movement::surrounding_word(
10756                    &display_map,
10757                    selection.start.to_display_point(&display_map),
10758                );
10759                let start = word_range.start.to_offset(&display_map, Bias::Left);
10760                let end = word_range.end.to_offset(&display_map, Bias::Left);
10761                (start, end)
10762            } else {
10763                (selection.start, selection.end)
10764            };
10765
10766            let text = buffer.text_for_range(start..end).collect::<String>();
10767            let old_length = text.len() as i32;
10768            let text = callback(&text);
10769
10770            new_selections.push(Selection {
10771                start: (start as i32 - selection_adjustment) as usize,
10772                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10773                goal: SelectionGoal::None,
10774                ..selection
10775            });
10776
10777            selection_adjustment += old_length - text.len() as i32;
10778
10779            edits.push((start..end, text));
10780        }
10781
10782        self.transact(window, cx, |this, window, cx| {
10783            this.buffer.update(cx, |buffer, cx| {
10784                buffer.edit(edits, None, cx);
10785            });
10786
10787            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10788                s.select(new_selections);
10789            });
10790
10791            this.request_autoscroll(Autoscroll::fit(), cx);
10792        });
10793    }
10794
10795    pub fn move_selection_on_drop(
10796        &mut self,
10797        selection: &Selection<Anchor>,
10798        target: DisplayPoint,
10799        is_cut: bool,
10800        window: &mut Window,
10801        cx: &mut Context<Self>,
10802    ) {
10803        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10804        let buffer = &display_map.buffer_snapshot;
10805        let mut edits = Vec::new();
10806        let insert_point = display_map
10807            .clip_point(target, Bias::Left)
10808            .to_point(&display_map);
10809        let text = buffer
10810            .text_for_range(selection.start..selection.end)
10811            .collect::<String>();
10812        if is_cut {
10813            edits.push(((selection.start..selection.end), String::new()));
10814        }
10815        let insert_anchor = buffer.anchor_before(insert_point);
10816        edits.push(((insert_anchor..insert_anchor), text));
10817        let last_edit_start = insert_anchor.bias_left(buffer);
10818        let last_edit_end = insert_anchor.bias_right(buffer);
10819        self.transact(window, cx, |this, window, cx| {
10820            this.buffer.update(cx, |buffer, cx| {
10821                buffer.edit(edits, None, cx);
10822            });
10823            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10824                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10825            });
10826        });
10827    }
10828
10829    pub fn clear_selection_drag_state(&mut self) {
10830        self.selection_drag_state = SelectionDragState::None;
10831    }
10832
10833    pub fn duplicate(
10834        &mut self,
10835        upwards: bool,
10836        whole_lines: bool,
10837        window: &mut Window,
10838        cx: &mut Context<Self>,
10839    ) {
10840        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10841
10842        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10843        let buffer = &display_map.buffer_snapshot;
10844        let selections = self.selections.all::<Point>(cx);
10845
10846        let mut edits = Vec::new();
10847        let mut selections_iter = selections.iter().peekable();
10848        while let Some(selection) = selections_iter.next() {
10849            let mut rows = selection.spanned_rows(false, &display_map);
10850            // duplicate line-wise
10851            if whole_lines || selection.start == selection.end {
10852                // Avoid duplicating the same lines twice.
10853                while let Some(next_selection) = selections_iter.peek() {
10854                    let next_rows = next_selection.spanned_rows(false, &display_map);
10855                    if next_rows.start < rows.end {
10856                        rows.end = next_rows.end;
10857                        selections_iter.next().unwrap();
10858                    } else {
10859                        break;
10860                    }
10861                }
10862
10863                // Copy the text from the selected row region and splice it either at the start
10864                // or end of the region.
10865                let start = Point::new(rows.start.0, 0);
10866                let end = Point::new(
10867                    rows.end.previous_row().0,
10868                    buffer.line_len(rows.end.previous_row()),
10869                );
10870                let text = buffer
10871                    .text_for_range(start..end)
10872                    .chain(Some("\n"))
10873                    .collect::<String>();
10874                let insert_location = if upwards {
10875                    Point::new(rows.end.0, 0)
10876                } else {
10877                    start
10878                };
10879                edits.push((insert_location..insert_location, text));
10880            } else {
10881                // duplicate character-wise
10882                let start = selection.start;
10883                let end = selection.end;
10884                let text = buffer.text_for_range(start..end).collect::<String>();
10885                edits.push((selection.end..selection.end, text));
10886            }
10887        }
10888
10889        self.transact(window, cx, |this, _, cx| {
10890            this.buffer.update(cx, |buffer, cx| {
10891                buffer.edit(edits, None, cx);
10892            });
10893
10894            this.request_autoscroll(Autoscroll::fit(), cx);
10895        });
10896    }
10897
10898    pub fn duplicate_line_up(
10899        &mut self,
10900        _: &DuplicateLineUp,
10901        window: &mut Window,
10902        cx: &mut Context<Self>,
10903    ) {
10904        self.duplicate(true, true, window, cx);
10905    }
10906
10907    pub fn duplicate_line_down(
10908        &mut self,
10909        _: &DuplicateLineDown,
10910        window: &mut Window,
10911        cx: &mut Context<Self>,
10912    ) {
10913        self.duplicate(false, true, window, cx);
10914    }
10915
10916    pub fn duplicate_selection(
10917        &mut self,
10918        _: &DuplicateSelection,
10919        window: &mut Window,
10920        cx: &mut Context<Self>,
10921    ) {
10922        self.duplicate(false, false, window, cx);
10923    }
10924
10925    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10927
10928        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10929        let buffer = self.buffer.read(cx).snapshot(cx);
10930
10931        let mut edits = Vec::new();
10932        let mut unfold_ranges = Vec::new();
10933        let mut refold_creases = Vec::new();
10934
10935        let selections = self.selections.all::<Point>(cx);
10936        let mut selections = selections.iter().peekable();
10937        let mut contiguous_row_selections = Vec::new();
10938        let mut new_selections = Vec::new();
10939
10940        while let Some(selection) = selections.next() {
10941            // Find all the selections that span a contiguous row range
10942            let (start_row, end_row) = consume_contiguous_rows(
10943                &mut contiguous_row_selections,
10944                selection,
10945                &display_map,
10946                &mut selections,
10947            );
10948
10949            // Move the text spanned by the row range to be before the line preceding the row range
10950            if start_row.0 > 0 {
10951                let range_to_move = Point::new(
10952                    start_row.previous_row().0,
10953                    buffer.line_len(start_row.previous_row()),
10954                )
10955                    ..Point::new(
10956                        end_row.previous_row().0,
10957                        buffer.line_len(end_row.previous_row()),
10958                    );
10959                let insertion_point = display_map
10960                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10961                    .0;
10962
10963                // Don't move lines across excerpts
10964                if buffer
10965                    .excerpt_containing(insertion_point..range_to_move.end)
10966                    .is_some()
10967                {
10968                    let text = buffer
10969                        .text_for_range(range_to_move.clone())
10970                        .flat_map(|s| s.chars())
10971                        .skip(1)
10972                        .chain(['\n'])
10973                        .collect::<String>();
10974
10975                    edits.push((
10976                        buffer.anchor_after(range_to_move.start)
10977                            ..buffer.anchor_before(range_to_move.end),
10978                        String::new(),
10979                    ));
10980                    let insertion_anchor = buffer.anchor_after(insertion_point);
10981                    edits.push((insertion_anchor..insertion_anchor, text));
10982
10983                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10984
10985                    // Move selections up
10986                    new_selections.extend(contiguous_row_selections.drain(..).map(
10987                        |mut selection| {
10988                            selection.start.row -= row_delta;
10989                            selection.end.row -= row_delta;
10990                            selection
10991                        },
10992                    ));
10993
10994                    // Move folds up
10995                    unfold_ranges.push(range_to_move.clone());
10996                    for fold in display_map.folds_in_range(
10997                        buffer.anchor_before(range_to_move.start)
10998                            ..buffer.anchor_after(range_to_move.end),
10999                    ) {
11000                        let mut start = fold.range.start.to_point(&buffer);
11001                        let mut end = fold.range.end.to_point(&buffer);
11002                        start.row -= row_delta;
11003                        end.row -= row_delta;
11004                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11005                    }
11006                }
11007            }
11008
11009            // If we didn't move line(s), preserve the existing selections
11010            new_selections.append(&mut contiguous_row_selections);
11011        }
11012
11013        self.transact(window, cx, |this, window, cx| {
11014            this.unfold_ranges(&unfold_ranges, true, true, cx);
11015            this.buffer.update(cx, |buffer, cx| {
11016                for (range, text) in edits {
11017                    buffer.edit([(range, text)], None, cx);
11018                }
11019            });
11020            this.fold_creases(refold_creases, true, window, cx);
11021            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11022                s.select(new_selections);
11023            })
11024        });
11025    }
11026
11027    pub fn move_line_down(
11028        &mut self,
11029        _: &MoveLineDown,
11030        window: &mut Window,
11031        cx: &mut Context<Self>,
11032    ) {
11033        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11034
11035        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11036        let buffer = self.buffer.read(cx).snapshot(cx);
11037
11038        let mut edits = Vec::new();
11039        let mut unfold_ranges = Vec::new();
11040        let mut refold_creases = Vec::new();
11041
11042        let selections = self.selections.all::<Point>(cx);
11043        let mut selections = selections.iter().peekable();
11044        let mut contiguous_row_selections = Vec::new();
11045        let mut new_selections = Vec::new();
11046
11047        while let Some(selection) = selections.next() {
11048            // Find all the selections that span a contiguous row range
11049            let (start_row, end_row) = consume_contiguous_rows(
11050                &mut contiguous_row_selections,
11051                selection,
11052                &display_map,
11053                &mut selections,
11054            );
11055
11056            // Move the text spanned by the row range to be after the last line of the row range
11057            if end_row.0 <= buffer.max_point().row {
11058                let range_to_move =
11059                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11060                let insertion_point = display_map
11061                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11062                    .0;
11063
11064                // Don't move lines across excerpt boundaries
11065                if buffer
11066                    .excerpt_containing(range_to_move.start..insertion_point)
11067                    .is_some()
11068                {
11069                    let mut text = String::from("\n");
11070                    text.extend(buffer.text_for_range(range_to_move.clone()));
11071                    text.pop(); // Drop trailing newline
11072                    edits.push((
11073                        buffer.anchor_after(range_to_move.start)
11074                            ..buffer.anchor_before(range_to_move.end),
11075                        String::new(),
11076                    ));
11077                    let insertion_anchor = buffer.anchor_after(insertion_point);
11078                    edits.push((insertion_anchor..insertion_anchor, text));
11079
11080                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11081
11082                    // Move selections down
11083                    new_selections.extend(contiguous_row_selections.drain(..).map(
11084                        |mut selection| {
11085                            selection.start.row += row_delta;
11086                            selection.end.row += row_delta;
11087                            selection
11088                        },
11089                    ));
11090
11091                    // Move folds down
11092                    unfold_ranges.push(range_to_move.clone());
11093                    for fold in display_map.folds_in_range(
11094                        buffer.anchor_before(range_to_move.start)
11095                            ..buffer.anchor_after(range_to_move.end),
11096                    ) {
11097                        let mut start = fold.range.start.to_point(&buffer);
11098                        let mut end = fold.range.end.to_point(&buffer);
11099                        start.row += row_delta;
11100                        end.row += row_delta;
11101                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11102                    }
11103                }
11104            }
11105
11106            // If we didn't move line(s), preserve the existing selections
11107            new_selections.append(&mut contiguous_row_selections);
11108        }
11109
11110        self.transact(window, cx, |this, window, cx| {
11111            this.unfold_ranges(&unfold_ranges, true, true, cx);
11112            this.buffer.update(cx, |buffer, cx| {
11113                for (range, text) in edits {
11114                    buffer.edit([(range, text)], None, cx);
11115                }
11116            });
11117            this.fold_creases(refold_creases, true, window, cx);
11118            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11119                s.select(new_selections)
11120            });
11121        });
11122    }
11123
11124    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11125        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11126        let text_layout_details = &self.text_layout_details(window);
11127        self.transact(window, cx, |this, window, cx| {
11128            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11129                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11130                s.move_with(|display_map, selection| {
11131                    if !selection.is_empty() {
11132                        return;
11133                    }
11134
11135                    let mut head = selection.head();
11136                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11137                    if head.column() == display_map.line_len(head.row()) {
11138                        transpose_offset = display_map
11139                            .buffer_snapshot
11140                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11141                    }
11142
11143                    if transpose_offset == 0 {
11144                        return;
11145                    }
11146
11147                    *head.column_mut() += 1;
11148                    head = display_map.clip_point(head, Bias::Right);
11149                    let goal = SelectionGoal::HorizontalPosition(
11150                        display_map
11151                            .x_for_display_point(head, text_layout_details)
11152                            .into(),
11153                    );
11154                    selection.collapse_to(head, goal);
11155
11156                    let transpose_start = display_map
11157                        .buffer_snapshot
11158                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11159                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11160                        let transpose_end = display_map
11161                            .buffer_snapshot
11162                            .clip_offset(transpose_offset + 1, Bias::Right);
11163                        if let Some(ch) =
11164                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11165                        {
11166                            edits.push((transpose_start..transpose_offset, String::new()));
11167                            edits.push((transpose_end..transpose_end, ch.to_string()));
11168                        }
11169                    }
11170                });
11171                edits
11172            });
11173            this.buffer
11174                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11175            let selections = this.selections.all::<usize>(cx);
11176            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11177                s.select(selections);
11178            });
11179        });
11180    }
11181
11182    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11183        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11184        self.rewrap_impl(RewrapOptions::default(), cx)
11185    }
11186
11187    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11188        let buffer = self.buffer.read(cx).snapshot(cx);
11189        let selections = self.selections.all::<Point>(cx);
11190
11191        // Shrink and split selections to respect paragraph boundaries.
11192        let ranges = selections.into_iter().flat_map(|selection| {
11193            let language_settings = buffer.language_settings_at(selection.head(), cx);
11194            let language_scope = buffer.language_scope_at(selection.head());
11195
11196            let Some(start_row) = (selection.start.row..=selection.end.row)
11197                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11198            else {
11199                return vec![];
11200            };
11201            let Some(end_row) = (selection.start.row..=selection.end.row)
11202                .rev()
11203                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11204            else {
11205                return vec![];
11206            };
11207
11208            let mut row = start_row;
11209            let mut ranges = Vec::new();
11210            while let Some(blank_row) =
11211                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11212            {
11213                let next_paragraph_start = (blank_row + 1..=end_row)
11214                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11215                    .unwrap();
11216                ranges.push((
11217                    language_settings.clone(),
11218                    language_scope.clone(),
11219                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11220                ));
11221                row = next_paragraph_start;
11222            }
11223            ranges.push((
11224                language_settings.clone(),
11225                language_scope.clone(),
11226                Point::new(row, 0)..Point::new(end_row, 0),
11227            ));
11228
11229            ranges
11230        });
11231
11232        let mut edits = Vec::new();
11233        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11234
11235        for (language_settings, language_scope, range) in ranges {
11236            let mut start_row = range.start.row;
11237            let mut end_row = range.end.row;
11238
11239            // Skip selections that overlap with a range that has already been rewrapped.
11240            let selection_range = start_row..end_row;
11241            if rewrapped_row_ranges
11242                .iter()
11243                .any(|range| range.overlaps(&selection_range))
11244            {
11245                continue;
11246            }
11247
11248            let tab_size = language_settings.tab_size;
11249
11250            // Since not all lines in the selection may be at the same indent
11251            // level, choose the indent size that is the most common between all
11252            // of the lines.
11253            //
11254            // If there is a tie, we use the deepest indent.
11255            let (indent_size, indent_end) = {
11256                let mut indent_size_occurrences = HashMap::default();
11257                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11258
11259                for row in start_row..=end_row {
11260                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11261                    rows_by_indent_size.entry(indent).or_default().push(row);
11262                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11263                }
11264
11265                let indent_size = indent_size_occurrences
11266                    .into_iter()
11267                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11268                    .map(|(indent, _)| indent)
11269                    .unwrap_or_default();
11270                let row = rows_by_indent_size[&indent_size][0];
11271                let indent_end = Point::new(row, indent_size.len);
11272
11273                (indent_size, indent_end)
11274            };
11275
11276            let mut line_prefix = indent_size.chars().collect::<String>();
11277
11278            let mut inside_comment = false;
11279            if let Some(comment_prefix) = language_scope.and_then(|language| {
11280                language
11281                    .line_comment_prefixes()
11282                    .iter()
11283                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11284                    .cloned()
11285            }) {
11286                line_prefix.push_str(&comment_prefix);
11287                inside_comment = true;
11288            }
11289
11290            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11291                RewrapBehavior::InComments => inside_comment,
11292                RewrapBehavior::InSelections => !range.is_empty(),
11293                RewrapBehavior::Anywhere => true,
11294            };
11295
11296            let should_rewrap = options.override_language_settings
11297                || allow_rewrap_based_on_language
11298                || self.hard_wrap.is_some();
11299            if !should_rewrap {
11300                continue;
11301            }
11302
11303            if range.is_empty() {
11304                'expand_upwards: while start_row > 0 {
11305                    let prev_row = start_row - 1;
11306                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11307                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11308                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11309                    {
11310                        start_row = prev_row;
11311                    } else {
11312                        break 'expand_upwards;
11313                    }
11314                }
11315
11316                'expand_downwards: while end_row < buffer.max_point().row {
11317                    let next_row = end_row + 1;
11318                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11319                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11320                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11321                    {
11322                        end_row = next_row;
11323                    } else {
11324                        break 'expand_downwards;
11325                    }
11326                }
11327            }
11328
11329            let start = Point::new(start_row, 0);
11330            let start_offset = start.to_offset(&buffer);
11331            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11332            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11333            let Some(lines_without_prefixes) = selection_text
11334                .lines()
11335                .map(|line| {
11336                    line.strip_prefix(&line_prefix)
11337                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11338                        .with_context(|| {
11339                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11340                        })
11341                })
11342                .collect::<Result<Vec<_>, _>>()
11343                .log_err()
11344            else {
11345                continue;
11346            };
11347
11348            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11349                buffer
11350                    .language_settings_at(Point::new(start_row, 0), cx)
11351                    .preferred_line_length as usize
11352            });
11353            let wrapped_text = wrap_with_prefix(
11354                line_prefix,
11355                lines_without_prefixes.join("\n"),
11356                wrap_column,
11357                tab_size,
11358                options.preserve_existing_whitespace,
11359            );
11360
11361            // TODO: should always use char-based diff while still supporting cursor behavior that
11362            // matches vim.
11363            let mut diff_options = DiffOptions::default();
11364            if options.override_language_settings {
11365                diff_options.max_word_diff_len = 0;
11366                diff_options.max_word_diff_line_count = 0;
11367            } else {
11368                diff_options.max_word_diff_len = usize::MAX;
11369                diff_options.max_word_diff_line_count = usize::MAX;
11370            }
11371
11372            for (old_range, new_text) in
11373                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11374            {
11375                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11376                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11377                edits.push((edit_start..edit_end, new_text));
11378            }
11379
11380            rewrapped_row_ranges.push(start_row..=end_row);
11381        }
11382
11383        self.buffer
11384            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11385    }
11386
11387    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11388        let mut text = String::new();
11389        let buffer = self.buffer.read(cx).snapshot(cx);
11390        let mut selections = self.selections.all::<Point>(cx);
11391        let mut clipboard_selections = Vec::with_capacity(selections.len());
11392        {
11393            let max_point = buffer.max_point();
11394            let mut is_first = true;
11395            for selection in &mut selections {
11396                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11397                if is_entire_line {
11398                    selection.start = Point::new(selection.start.row, 0);
11399                    if !selection.is_empty() && selection.end.column == 0 {
11400                        selection.end = cmp::min(max_point, selection.end);
11401                    } else {
11402                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11403                    }
11404                    selection.goal = SelectionGoal::None;
11405                }
11406                if is_first {
11407                    is_first = false;
11408                } else {
11409                    text += "\n";
11410                }
11411                let mut len = 0;
11412                for chunk in buffer.text_for_range(selection.start..selection.end) {
11413                    text.push_str(chunk);
11414                    len += chunk.len();
11415                }
11416                clipboard_selections.push(ClipboardSelection {
11417                    len,
11418                    is_entire_line,
11419                    first_line_indent: buffer
11420                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11421                        .len,
11422                });
11423            }
11424        }
11425
11426        self.transact(window, cx, |this, window, cx| {
11427            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11428                s.select(selections);
11429            });
11430            this.insert("", window, cx);
11431        });
11432        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11433    }
11434
11435    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11436        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11437        let item = self.cut_common(window, cx);
11438        cx.write_to_clipboard(item);
11439    }
11440
11441    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11442        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11443        self.change_selections(None, window, cx, |s| {
11444            s.move_with(|snapshot, sel| {
11445                if sel.is_empty() {
11446                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11447                }
11448            });
11449        });
11450        let item = self.cut_common(window, cx);
11451        cx.set_global(KillRing(item))
11452    }
11453
11454    pub fn kill_ring_yank(
11455        &mut self,
11456        _: &KillRingYank,
11457        window: &mut Window,
11458        cx: &mut Context<Self>,
11459    ) {
11460        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11461        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11462            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11463                (kill_ring.text().to_string(), kill_ring.metadata_json())
11464            } else {
11465                return;
11466            }
11467        } else {
11468            return;
11469        };
11470        self.do_paste(&text, metadata, false, window, cx);
11471    }
11472
11473    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11474        self.do_copy(true, cx);
11475    }
11476
11477    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11478        self.do_copy(false, cx);
11479    }
11480
11481    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11482        let selections = self.selections.all::<Point>(cx);
11483        let buffer = self.buffer.read(cx).read(cx);
11484        let mut text = String::new();
11485
11486        let mut clipboard_selections = Vec::with_capacity(selections.len());
11487        {
11488            let max_point = buffer.max_point();
11489            let mut is_first = true;
11490            for selection in &selections {
11491                let mut start = selection.start;
11492                let mut end = selection.end;
11493                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11494                if is_entire_line {
11495                    start = Point::new(start.row, 0);
11496                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11497                }
11498
11499                let mut trimmed_selections = Vec::new();
11500                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11501                    let row = MultiBufferRow(start.row);
11502                    let first_indent = buffer.indent_size_for_line(row);
11503                    if first_indent.len == 0 || start.column > first_indent.len {
11504                        trimmed_selections.push(start..end);
11505                    } else {
11506                        trimmed_selections.push(
11507                            Point::new(row.0, first_indent.len)
11508                                ..Point::new(row.0, buffer.line_len(row)),
11509                        );
11510                        for row in start.row + 1..=end.row {
11511                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11512                            if row == end.row {
11513                                line_len = end.column;
11514                            }
11515                            if line_len == 0 {
11516                                trimmed_selections
11517                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11518                                continue;
11519                            }
11520                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11521                            if row_indent_size.len >= first_indent.len {
11522                                trimmed_selections.push(
11523                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11524                                );
11525                            } else {
11526                                trimmed_selections.clear();
11527                                trimmed_selections.push(start..end);
11528                                break;
11529                            }
11530                        }
11531                    }
11532                } else {
11533                    trimmed_selections.push(start..end);
11534                }
11535
11536                for trimmed_range in trimmed_selections {
11537                    if is_first {
11538                        is_first = false;
11539                    } else {
11540                        text += "\n";
11541                    }
11542                    let mut len = 0;
11543                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11544                        text.push_str(chunk);
11545                        len += chunk.len();
11546                    }
11547                    clipboard_selections.push(ClipboardSelection {
11548                        len,
11549                        is_entire_line,
11550                        first_line_indent: buffer
11551                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11552                            .len,
11553                    });
11554                }
11555            }
11556        }
11557
11558        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11559            text,
11560            clipboard_selections,
11561        ));
11562    }
11563
11564    pub fn do_paste(
11565        &mut self,
11566        text: &String,
11567        clipboard_selections: Option<Vec<ClipboardSelection>>,
11568        handle_entire_lines: bool,
11569        window: &mut Window,
11570        cx: &mut Context<Self>,
11571    ) {
11572        if self.read_only(cx) {
11573            return;
11574        }
11575
11576        let clipboard_text = Cow::Borrowed(text);
11577
11578        self.transact(window, cx, |this, window, cx| {
11579            if let Some(mut clipboard_selections) = clipboard_selections {
11580                let old_selections = this.selections.all::<usize>(cx);
11581                let all_selections_were_entire_line =
11582                    clipboard_selections.iter().all(|s| s.is_entire_line);
11583                let first_selection_indent_column =
11584                    clipboard_selections.first().map(|s| s.first_line_indent);
11585                if clipboard_selections.len() != old_selections.len() {
11586                    clipboard_selections.drain(..);
11587                }
11588                let cursor_offset = this.selections.last::<usize>(cx).head();
11589                let mut auto_indent_on_paste = true;
11590
11591                this.buffer.update(cx, |buffer, cx| {
11592                    let snapshot = buffer.read(cx);
11593                    auto_indent_on_paste = snapshot
11594                        .language_settings_at(cursor_offset, cx)
11595                        .auto_indent_on_paste;
11596
11597                    let mut start_offset = 0;
11598                    let mut edits = Vec::new();
11599                    let mut original_indent_columns = Vec::new();
11600                    for (ix, selection) in old_selections.iter().enumerate() {
11601                        let to_insert;
11602                        let entire_line;
11603                        let original_indent_column;
11604                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11605                            let end_offset = start_offset + clipboard_selection.len;
11606                            to_insert = &clipboard_text[start_offset..end_offset];
11607                            entire_line = clipboard_selection.is_entire_line;
11608                            start_offset = end_offset + 1;
11609                            original_indent_column = Some(clipboard_selection.first_line_indent);
11610                        } else {
11611                            to_insert = clipboard_text.as_str();
11612                            entire_line = all_selections_were_entire_line;
11613                            original_indent_column = first_selection_indent_column
11614                        }
11615
11616                        // If the corresponding selection was empty when this slice of the
11617                        // clipboard text was written, then the entire line containing the
11618                        // selection was copied. If this selection is also currently empty,
11619                        // then paste the line before the current line of the buffer.
11620                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11621                            let column = selection.start.to_point(&snapshot).column as usize;
11622                            let line_start = selection.start - column;
11623                            line_start..line_start
11624                        } else {
11625                            selection.range()
11626                        };
11627
11628                        edits.push((range, to_insert));
11629                        original_indent_columns.push(original_indent_column);
11630                    }
11631                    drop(snapshot);
11632
11633                    buffer.edit(
11634                        edits,
11635                        if auto_indent_on_paste {
11636                            Some(AutoindentMode::Block {
11637                                original_indent_columns,
11638                            })
11639                        } else {
11640                            None
11641                        },
11642                        cx,
11643                    );
11644                });
11645
11646                let selections = this.selections.all::<usize>(cx);
11647                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11648                    s.select(selections)
11649                });
11650            } else {
11651                this.insert(&clipboard_text, window, cx);
11652            }
11653        });
11654    }
11655
11656    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11657        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11658        if let Some(item) = cx.read_from_clipboard() {
11659            let entries = item.entries();
11660
11661            match entries.first() {
11662                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11663                // of all the pasted entries.
11664                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11665                    .do_paste(
11666                        clipboard_string.text(),
11667                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11668                        true,
11669                        window,
11670                        cx,
11671                    ),
11672                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11673            }
11674        }
11675    }
11676
11677    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11678        if self.read_only(cx) {
11679            return;
11680        }
11681
11682        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11683
11684        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11685            if let Some((selections, _)) =
11686                self.selection_history.transaction(transaction_id).cloned()
11687            {
11688                self.change_selections(None, window, cx, |s| {
11689                    s.select_anchors(selections.to_vec());
11690                });
11691            } else {
11692                log::error!(
11693                    "No entry in selection_history found for undo. \
11694                     This may correspond to a bug where undo does not update the selection. \
11695                     If this is occurring, please add details to \
11696                     https://github.com/zed-industries/zed/issues/22692"
11697                );
11698            }
11699            self.request_autoscroll(Autoscroll::fit(), cx);
11700            self.unmark_text(window, cx);
11701            self.refresh_inline_completion(true, false, window, cx);
11702            cx.emit(EditorEvent::Edited { transaction_id });
11703            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11704        }
11705    }
11706
11707    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11708        if self.read_only(cx) {
11709            return;
11710        }
11711
11712        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11713
11714        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11715            if let Some((_, Some(selections))) =
11716                self.selection_history.transaction(transaction_id).cloned()
11717            {
11718                self.change_selections(None, window, cx, |s| {
11719                    s.select_anchors(selections.to_vec());
11720                });
11721            } else {
11722                log::error!(
11723                    "No entry in selection_history found for redo. \
11724                     This may correspond to a bug where undo does not update the selection. \
11725                     If this is occurring, please add details to \
11726                     https://github.com/zed-industries/zed/issues/22692"
11727                );
11728            }
11729            self.request_autoscroll(Autoscroll::fit(), cx);
11730            self.unmark_text(window, cx);
11731            self.refresh_inline_completion(true, false, window, cx);
11732            cx.emit(EditorEvent::Edited { transaction_id });
11733        }
11734    }
11735
11736    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11737        self.buffer
11738            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11739    }
11740
11741    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11742        self.buffer
11743            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11744    }
11745
11746    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11748        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11749            s.move_with(|map, selection| {
11750                let cursor = if selection.is_empty() {
11751                    movement::left(map, selection.start)
11752                } else {
11753                    selection.start
11754                };
11755                selection.collapse_to(cursor, SelectionGoal::None);
11756            });
11757        })
11758    }
11759
11760    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11762        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11763            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11764        })
11765    }
11766
11767    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11768        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11769        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11770            s.move_with(|map, selection| {
11771                let cursor = if selection.is_empty() {
11772                    movement::right(map, selection.end)
11773                } else {
11774                    selection.end
11775                };
11776                selection.collapse_to(cursor, SelectionGoal::None)
11777            });
11778        })
11779    }
11780
11781    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11782        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11783        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11784            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11785        })
11786    }
11787
11788    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11789        if self.take_rename(true, window, cx).is_some() {
11790            return;
11791        }
11792
11793        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11794            cx.propagate();
11795            return;
11796        }
11797
11798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11799
11800        let text_layout_details = &self.text_layout_details(window);
11801        let selection_count = self.selections.count();
11802        let first_selection = self.selections.first_anchor();
11803
11804        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11805            s.move_with(|map, selection| {
11806                if !selection.is_empty() {
11807                    selection.goal = SelectionGoal::None;
11808                }
11809                let (cursor, goal) = movement::up(
11810                    map,
11811                    selection.start,
11812                    selection.goal,
11813                    false,
11814                    text_layout_details,
11815                );
11816                selection.collapse_to(cursor, goal);
11817            });
11818        });
11819
11820        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11821        {
11822            cx.propagate();
11823        }
11824    }
11825
11826    pub fn move_up_by_lines(
11827        &mut self,
11828        action: &MoveUpByLines,
11829        window: &mut Window,
11830        cx: &mut Context<Self>,
11831    ) {
11832        if self.take_rename(true, window, cx).is_some() {
11833            return;
11834        }
11835
11836        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11837            cx.propagate();
11838            return;
11839        }
11840
11841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11842
11843        let text_layout_details = &self.text_layout_details(window);
11844
11845        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11846            s.move_with(|map, selection| {
11847                if !selection.is_empty() {
11848                    selection.goal = SelectionGoal::None;
11849                }
11850                let (cursor, goal) = movement::up_by_rows(
11851                    map,
11852                    selection.start,
11853                    action.lines,
11854                    selection.goal,
11855                    false,
11856                    text_layout_details,
11857                );
11858                selection.collapse_to(cursor, goal);
11859            });
11860        })
11861    }
11862
11863    pub fn move_down_by_lines(
11864        &mut self,
11865        action: &MoveDownByLines,
11866        window: &mut Window,
11867        cx: &mut Context<Self>,
11868    ) {
11869        if self.take_rename(true, window, cx).is_some() {
11870            return;
11871        }
11872
11873        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11874            cx.propagate();
11875            return;
11876        }
11877
11878        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11879
11880        let text_layout_details = &self.text_layout_details(window);
11881
11882        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11883            s.move_with(|map, selection| {
11884                if !selection.is_empty() {
11885                    selection.goal = SelectionGoal::None;
11886                }
11887                let (cursor, goal) = movement::down_by_rows(
11888                    map,
11889                    selection.start,
11890                    action.lines,
11891                    selection.goal,
11892                    false,
11893                    text_layout_details,
11894                );
11895                selection.collapse_to(cursor, goal);
11896            });
11897        })
11898    }
11899
11900    pub fn select_down_by_lines(
11901        &mut self,
11902        action: &SelectDownByLines,
11903        window: &mut Window,
11904        cx: &mut Context<Self>,
11905    ) {
11906        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11907        let text_layout_details = &self.text_layout_details(window);
11908        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11909            s.move_heads_with(|map, head, goal| {
11910                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11911            })
11912        })
11913    }
11914
11915    pub fn select_up_by_lines(
11916        &mut self,
11917        action: &SelectUpByLines,
11918        window: &mut Window,
11919        cx: &mut Context<Self>,
11920    ) {
11921        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11922        let text_layout_details = &self.text_layout_details(window);
11923        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11924            s.move_heads_with(|map, head, goal| {
11925                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11926            })
11927        })
11928    }
11929
11930    pub fn select_page_up(
11931        &mut self,
11932        _: &SelectPageUp,
11933        window: &mut Window,
11934        cx: &mut Context<Self>,
11935    ) {
11936        let Some(row_count) = self.visible_row_count() else {
11937            return;
11938        };
11939
11940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11941
11942        let text_layout_details = &self.text_layout_details(window);
11943
11944        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11945            s.move_heads_with(|map, head, goal| {
11946                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11947            })
11948        })
11949    }
11950
11951    pub fn move_page_up(
11952        &mut self,
11953        action: &MovePageUp,
11954        window: &mut Window,
11955        cx: &mut Context<Self>,
11956    ) {
11957        if self.take_rename(true, window, cx).is_some() {
11958            return;
11959        }
11960
11961        if self
11962            .context_menu
11963            .borrow_mut()
11964            .as_mut()
11965            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11966            .unwrap_or(false)
11967        {
11968            return;
11969        }
11970
11971        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11972            cx.propagate();
11973            return;
11974        }
11975
11976        let Some(row_count) = self.visible_row_count() else {
11977            return;
11978        };
11979
11980        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11981
11982        let autoscroll = if action.center_cursor {
11983            Autoscroll::center()
11984        } else {
11985            Autoscroll::fit()
11986        };
11987
11988        let text_layout_details = &self.text_layout_details(window);
11989
11990        self.change_selections(Some(autoscroll), window, cx, |s| {
11991            s.move_with(|map, selection| {
11992                if !selection.is_empty() {
11993                    selection.goal = SelectionGoal::None;
11994                }
11995                let (cursor, goal) = movement::up_by_rows(
11996                    map,
11997                    selection.end,
11998                    row_count,
11999                    selection.goal,
12000                    false,
12001                    text_layout_details,
12002                );
12003                selection.collapse_to(cursor, goal);
12004            });
12005        });
12006    }
12007
12008    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12009        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12010        let text_layout_details = &self.text_layout_details(window);
12011        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12012            s.move_heads_with(|map, head, goal| {
12013                movement::up(map, head, goal, false, text_layout_details)
12014            })
12015        })
12016    }
12017
12018    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12019        self.take_rename(true, window, cx);
12020
12021        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12022            cx.propagate();
12023            return;
12024        }
12025
12026        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12027
12028        let text_layout_details = &self.text_layout_details(window);
12029        let selection_count = self.selections.count();
12030        let first_selection = self.selections.first_anchor();
12031
12032        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12033            s.move_with(|map, selection| {
12034                if !selection.is_empty() {
12035                    selection.goal = SelectionGoal::None;
12036                }
12037                let (cursor, goal) = movement::down(
12038                    map,
12039                    selection.end,
12040                    selection.goal,
12041                    false,
12042                    text_layout_details,
12043                );
12044                selection.collapse_to(cursor, goal);
12045            });
12046        });
12047
12048        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12049        {
12050            cx.propagate();
12051        }
12052    }
12053
12054    pub fn select_page_down(
12055        &mut self,
12056        _: &SelectPageDown,
12057        window: &mut Window,
12058        cx: &mut Context<Self>,
12059    ) {
12060        let Some(row_count) = self.visible_row_count() else {
12061            return;
12062        };
12063
12064        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12065
12066        let text_layout_details = &self.text_layout_details(window);
12067
12068        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12069            s.move_heads_with(|map, head, goal| {
12070                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12071            })
12072        })
12073    }
12074
12075    pub fn move_page_down(
12076        &mut self,
12077        action: &MovePageDown,
12078        window: &mut Window,
12079        cx: &mut Context<Self>,
12080    ) {
12081        if self.take_rename(true, window, cx).is_some() {
12082            return;
12083        }
12084
12085        if self
12086            .context_menu
12087            .borrow_mut()
12088            .as_mut()
12089            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12090            .unwrap_or(false)
12091        {
12092            return;
12093        }
12094
12095        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12096            cx.propagate();
12097            return;
12098        }
12099
12100        let Some(row_count) = self.visible_row_count() else {
12101            return;
12102        };
12103
12104        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12105
12106        let autoscroll = if action.center_cursor {
12107            Autoscroll::center()
12108        } else {
12109            Autoscroll::fit()
12110        };
12111
12112        let text_layout_details = &self.text_layout_details(window);
12113        self.change_selections(Some(autoscroll), window, cx, |s| {
12114            s.move_with(|map, selection| {
12115                if !selection.is_empty() {
12116                    selection.goal = SelectionGoal::None;
12117                }
12118                let (cursor, goal) = movement::down_by_rows(
12119                    map,
12120                    selection.end,
12121                    row_count,
12122                    selection.goal,
12123                    false,
12124                    text_layout_details,
12125                );
12126                selection.collapse_to(cursor, goal);
12127            });
12128        });
12129    }
12130
12131    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12132        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12133        let text_layout_details = &self.text_layout_details(window);
12134        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12135            s.move_heads_with(|map, head, goal| {
12136                movement::down(map, head, goal, false, text_layout_details)
12137            })
12138        });
12139    }
12140
12141    pub fn context_menu_first(
12142        &mut self,
12143        _: &ContextMenuFirst,
12144        window: &mut Window,
12145        cx: &mut Context<Self>,
12146    ) {
12147        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12148            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12149        }
12150    }
12151
12152    pub fn context_menu_prev(
12153        &mut self,
12154        _: &ContextMenuPrevious,
12155        window: &mut Window,
12156        cx: &mut Context<Self>,
12157    ) {
12158        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12159            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12160        }
12161    }
12162
12163    pub fn context_menu_next(
12164        &mut self,
12165        _: &ContextMenuNext,
12166        window: &mut Window,
12167        cx: &mut Context<Self>,
12168    ) {
12169        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12170            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12171        }
12172    }
12173
12174    pub fn context_menu_last(
12175        &mut self,
12176        _: &ContextMenuLast,
12177        window: &mut Window,
12178        cx: &mut Context<Self>,
12179    ) {
12180        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12181            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12182        }
12183    }
12184
12185    pub fn move_to_previous_word_start(
12186        &mut self,
12187        _: &MoveToPreviousWordStart,
12188        window: &mut Window,
12189        cx: &mut Context<Self>,
12190    ) {
12191        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12192        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12193            s.move_cursors_with(|map, head, _| {
12194                (
12195                    movement::previous_word_start(map, head),
12196                    SelectionGoal::None,
12197                )
12198            });
12199        })
12200    }
12201
12202    pub fn move_to_previous_subword_start(
12203        &mut self,
12204        _: &MoveToPreviousSubwordStart,
12205        window: &mut Window,
12206        cx: &mut Context<Self>,
12207    ) {
12208        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12209        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12210            s.move_cursors_with(|map, head, _| {
12211                (
12212                    movement::previous_subword_start(map, head),
12213                    SelectionGoal::None,
12214                )
12215            });
12216        })
12217    }
12218
12219    pub fn select_to_previous_word_start(
12220        &mut self,
12221        _: &SelectToPreviousWordStart,
12222        window: &mut Window,
12223        cx: &mut Context<Self>,
12224    ) {
12225        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12226        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12227            s.move_heads_with(|map, head, _| {
12228                (
12229                    movement::previous_word_start(map, head),
12230                    SelectionGoal::None,
12231                )
12232            });
12233        })
12234    }
12235
12236    pub fn select_to_previous_subword_start(
12237        &mut self,
12238        _: &SelectToPreviousSubwordStart,
12239        window: &mut Window,
12240        cx: &mut Context<Self>,
12241    ) {
12242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12243        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12244            s.move_heads_with(|map, head, _| {
12245                (
12246                    movement::previous_subword_start(map, head),
12247                    SelectionGoal::None,
12248                )
12249            });
12250        })
12251    }
12252
12253    pub fn delete_to_previous_word_start(
12254        &mut self,
12255        action: &DeleteToPreviousWordStart,
12256        window: &mut Window,
12257        cx: &mut Context<Self>,
12258    ) {
12259        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12260        self.transact(window, cx, |this, window, cx| {
12261            this.select_autoclose_pair(window, cx);
12262            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12263                s.move_with(|map, selection| {
12264                    if selection.is_empty() {
12265                        let cursor = if action.ignore_newlines {
12266                            movement::previous_word_start(map, selection.head())
12267                        } else {
12268                            movement::previous_word_start_or_newline(map, selection.head())
12269                        };
12270                        selection.set_head(cursor, SelectionGoal::None);
12271                    }
12272                });
12273            });
12274            this.insert("", window, cx);
12275        });
12276    }
12277
12278    pub fn delete_to_previous_subword_start(
12279        &mut self,
12280        _: &DeleteToPreviousSubwordStart,
12281        window: &mut Window,
12282        cx: &mut Context<Self>,
12283    ) {
12284        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12285        self.transact(window, cx, |this, window, cx| {
12286            this.select_autoclose_pair(window, cx);
12287            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12288                s.move_with(|map, selection| {
12289                    if selection.is_empty() {
12290                        let cursor = movement::previous_subword_start(map, selection.head());
12291                        selection.set_head(cursor, SelectionGoal::None);
12292                    }
12293                });
12294            });
12295            this.insert("", window, cx);
12296        });
12297    }
12298
12299    pub fn move_to_next_word_end(
12300        &mut self,
12301        _: &MoveToNextWordEnd,
12302        window: &mut Window,
12303        cx: &mut Context<Self>,
12304    ) {
12305        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12306        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12307            s.move_cursors_with(|map, head, _| {
12308                (movement::next_word_end(map, head), SelectionGoal::None)
12309            });
12310        })
12311    }
12312
12313    pub fn move_to_next_subword_end(
12314        &mut self,
12315        _: &MoveToNextSubwordEnd,
12316        window: &mut Window,
12317        cx: &mut Context<Self>,
12318    ) {
12319        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12320        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12321            s.move_cursors_with(|map, head, _| {
12322                (movement::next_subword_end(map, head), SelectionGoal::None)
12323            });
12324        })
12325    }
12326
12327    pub fn select_to_next_word_end(
12328        &mut self,
12329        _: &SelectToNextWordEnd,
12330        window: &mut Window,
12331        cx: &mut Context<Self>,
12332    ) {
12333        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12334        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12335            s.move_heads_with(|map, head, _| {
12336                (movement::next_word_end(map, head), SelectionGoal::None)
12337            });
12338        })
12339    }
12340
12341    pub fn select_to_next_subword_end(
12342        &mut self,
12343        _: &SelectToNextSubwordEnd,
12344        window: &mut Window,
12345        cx: &mut Context<Self>,
12346    ) {
12347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12348        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12349            s.move_heads_with(|map, head, _| {
12350                (movement::next_subword_end(map, head), SelectionGoal::None)
12351            });
12352        })
12353    }
12354
12355    pub fn delete_to_next_word_end(
12356        &mut self,
12357        action: &DeleteToNextWordEnd,
12358        window: &mut Window,
12359        cx: &mut Context<Self>,
12360    ) {
12361        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12362        self.transact(window, cx, |this, window, cx| {
12363            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12364                s.move_with(|map, selection| {
12365                    if selection.is_empty() {
12366                        let cursor = if action.ignore_newlines {
12367                            movement::next_word_end(map, selection.head())
12368                        } else {
12369                            movement::next_word_end_or_newline(map, selection.head())
12370                        };
12371                        selection.set_head(cursor, SelectionGoal::None);
12372                    }
12373                });
12374            });
12375            this.insert("", window, cx);
12376        });
12377    }
12378
12379    pub fn delete_to_next_subword_end(
12380        &mut self,
12381        _: &DeleteToNextSubwordEnd,
12382        window: &mut Window,
12383        cx: &mut Context<Self>,
12384    ) {
12385        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12386        self.transact(window, cx, |this, window, cx| {
12387            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12388                s.move_with(|map, selection| {
12389                    if selection.is_empty() {
12390                        let cursor = movement::next_subword_end(map, selection.head());
12391                        selection.set_head(cursor, SelectionGoal::None);
12392                    }
12393                });
12394            });
12395            this.insert("", window, cx);
12396        });
12397    }
12398
12399    pub fn move_to_beginning_of_line(
12400        &mut self,
12401        action: &MoveToBeginningOfLine,
12402        window: &mut Window,
12403        cx: &mut Context<Self>,
12404    ) {
12405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12406        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12407            s.move_cursors_with(|map, head, _| {
12408                (
12409                    movement::indented_line_beginning(
12410                        map,
12411                        head,
12412                        action.stop_at_soft_wraps,
12413                        action.stop_at_indent,
12414                    ),
12415                    SelectionGoal::None,
12416                )
12417            });
12418        })
12419    }
12420
12421    pub fn select_to_beginning_of_line(
12422        &mut self,
12423        action: &SelectToBeginningOfLine,
12424        window: &mut Window,
12425        cx: &mut Context<Self>,
12426    ) {
12427        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12428        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12429            s.move_heads_with(|map, head, _| {
12430                (
12431                    movement::indented_line_beginning(
12432                        map,
12433                        head,
12434                        action.stop_at_soft_wraps,
12435                        action.stop_at_indent,
12436                    ),
12437                    SelectionGoal::None,
12438                )
12439            });
12440        });
12441    }
12442
12443    pub fn delete_to_beginning_of_line(
12444        &mut self,
12445        action: &DeleteToBeginningOfLine,
12446        window: &mut Window,
12447        cx: &mut Context<Self>,
12448    ) {
12449        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12450        self.transact(window, cx, |this, window, cx| {
12451            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12452                s.move_with(|_, selection| {
12453                    selection.reversed = true;
12454                });
12455            });
12456
12457            this.select_to_beginning_of_line(
12458                &SelectToBeginningOfLine {
12459                    stop_at_soft_wraps: false,
12460                    stop_at_indent: action.stop_at_indent,
12461                },
12462                window,
12463                cx,
12464            );
12465            this.backspace(&Backspace, window, cx);
12466        });
12467    }
12468
12469    pub fn move_to_end_of_line(
12470        &mut self,
12471        action: &MoveToEndOfLine,
12472        window: &mut Window,
12473        cx: &mut Context<Self>,
12474    ) {
12475        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12476        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12477            s.move_cursors_with(|map, head, _| {
12478                (
12479                    movement::line_end(map, head, action.stop_at_soft_wraps),
12480                    SelectionGoal::None,
12481                )
12482            });
12483        })
12484    }
12485
12486    pub fn select_to_end_of_line(
12487        &mut self,
12488        action: &SelectToEndOfLine,
12489        window: &mut Window,
12490        cx: &mut Context<Self>,
12491    ) {
12492        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12493        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12494            s.move_heads_with(|map, head, _| {
12495                (
12496                    movement::line_end(map, head, action.stop_at_soft_wraps),
12497                    SelectionGoal::None,
12498                )
12499            });
12500        })
12501    }
12502
12503    pub fn delete_to_end_of_line(
12504        &mut self,
12505        _: &DeleteToEndOfLine,
12506        window: &mut Window,
12507        cx: &mut Context<Self>,
12508    ) {
12509        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12510        self.transact(window, cx, |this, window, cx| {
12511            this.select_to_end_of_line(
12512                &SelectToEndOfLine {
12513                    stop_at_soft_wraps: false,
12514                },
12515                window,
12516                cx,
12517            );
12518            this.delete(&Delete, window, cx);
12519        });
12520    }
12521
12522    pub fn cut_to_end_of_line(
12523        &mut self,
12524        _: &CutToEndOfLine,
12525        window: &mut Window,
12526        cx: &mut Context<Self>,
12527    ) {
12528        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12529        self.transact(window, cx, |this, window, cx| {
12530            this.select_to_end_of_line(
12531                &SelectToEndOfLine {
12532                    stop_at_soft_wraps: false,
12533                },
12534                window,
12535                cx,
12536            );
12537            this.cut(&Cut, window, cx);
12538        });
12539    }
12540
12541    pub fn move_to_start_of_paragraph(
12542        &mut self,
12543        _: &MoveToStartOfParagraph,
12544        window: &mut Window,
12545        cx: &mut Context<Self>,
12546    ) {
12547        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12548            cx.propagate();
12549            return;
12550        }
12551        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12552        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12553            s.move_with(|map, selection| {
12554                selection.collapse_to(
12555                    movement::start_of_paragraph(map, selection.head(), 1),
12556                    SelectionGoal::None,
12557                )
12558            });
12559        })
12560    }
12561
12562    pub fn move_to_end_of_paragraph(
12563        &mut self,
12564        _: &MoveToEndOfParagraph,
12565        window: &mut Window,
12566        cx: &mut Context<Self>,
12567    ) {
12568        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12569            cx.propagate();
12570            return;
12571        }
12572        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12573        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12574            s.move_with(|map, selection| {
12575                selection.collapse_to(
12576                    movement::end_of_paragraph(map, selection.head(), 1),
12577                    SelectionGoal::None,
12578                )
12579            });
12580        })
12581    }
12582
12583    pub fn select_to_start_of_paragraph(
12584        &mut self,
12585        _: &SelectToStartOfParagraph,
12586        window: &mut Window,
12587        cx: &mut Context<Self>,
12588    ) {
12589        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12590            cx.propagate();
12591            return;
12592        }
12593        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12594        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12595            s.move_heads_with(|map, head, _| {
12596                (
12597                    movement::start_of_paragraph(map, head, 1),
12598                    SelectionGoal::None,
12599                )
12600            });
12601        })
12602    }
12603
12604    pub fn select_to_end_of_paragraph(
12605        &mut self,
12606        _: &SelectToEndOfParagraph,
12607        window: &mut Window,
12608        cx: &mut Context<Self>,
12609    ) {
12610        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12611            cx.propagate();
12612            return;
12613        }
12614        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12615        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12616            s.move_heads_with(|map, head, _| {
12617                (
12618                    movement::end_of_paragraph(map, head, 1),
12619                    SelectionGoal::None,
12620                )
12621            });
12622        })
12623    }
12624
12625    pub fn move_to_start_of_excerpt(
12626        &mut self,
12627        _: &MoveToStartOfExcerpt,
12628        window: &mut Window,
12629        cx: &mut Context<Self>,
12630    ) {
12631        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12632            cx.propagate();
12633            return;
12634        }
12635        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12636        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12637            s.move_with(|map, selection| {
12638                selection.collapse_to(
12639                    movement::start_of_excerpt(
12640                        map,
12641                        selection.head(),
12642                        workspace::searchable::Direction::Prev,
12643                    ),
12644                    SelectionGoal::None,
12645                )
12646            });
12647        })
12648    }
12649
12650    pub fn move_to_start_of_next_excerpt(
12651        &mut self,
12652        _: &MoveToStartOfNextExcerpt,
12653        window: &mut Window,
12654        cx: &mut Context<Self>,
12655    ) {
12656        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12657            cx.propagate();
12658            return;
12659        }
12660
12661        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12662            s.move_with(|map, selection| {
12663                selection.collapse_to(
12664                    movement::start_of_excerpt(
12665                        map,
12666                        selection.head(),
12667                        workspace::searchable::Direction::Next,
12668                    ),
12669                    SelectionGoal::None,
12670                )
12671            });
12672        })
12673    }
12674
12675    pub fn move_to_end_of_excerpt(
12676        &mut self,
12677        _: &MoveToEndOfExcerpt,
12678        window: &mut Window,
12679        cx: &mut Context<Self>,
12680    ) {
12681        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12682            cx.propagate();
12683            return;
12684        }
12685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12686        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12687            s.move_with(|map, selection| {
12688                selection.collapse_to(
12689                    movement::end_of_excerpt(
12690                        map,
12691                        selection.head(),
12692                        workspace::searchable::Direction::Next,
12693                    ),
12694                    SelectionGoal::None,
12695                )
12696            });
12697        })
12698    }
12699
12700    pub fn move_to_end_of_previous_excerpt(
12701        &mut self,
12702        _: &MoveToEndOfPreviousExcerpt,
12703        window: &mut Window,
12704        cx: &mut Context<Self>,
12705    ) {
12706        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12707            cx.propagate();
12708            return;
12709        }
12710        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12711        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12712            s.move_with(|map, selection| {
12713                selection.collapse_to(
12714                    movement::end_of_excerpt(
12715                        map,
12716                        selection.head(),
12717                        workspace::searchable::Direction::Prev,
12718                    ),
12719                    SelectionGoal::None,
12720                )
12721            });
12722        })
12723    }
12724
12725    pub fn select_to_start_of_excerpt(
12726        &mut self,
12727        _: &SelectToStartOfExcerpt,
12728        window: &mut Window,
12729        cx: &mut Context<Self>,
12730    ) {
12731        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12732            cx.propagate();
12733            return;
12734        }
12735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12736        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12737            s.move_heads_with(|map, head, _| {
12738                (
12739                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12740                    SelectionGoal::None,
12741                )
12742            });
12743        })
12744    }
12745
12746    pub fn select_to_start_of_next_excerpt(
12747        &mut self,
12748        _: &SelectToStartOfNextExcerpt,
12749        window: &mut Window,
12750        cx: &mut Context<Self>,
12751    ) {
12752        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12753            cx.propagate();
12754            return;
12755        }
12756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12757        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12758            s.move_heads_with(|map, head, _| {
12759                (
12760                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12761                    SelectionGoal::None,
12762                )
12763            });
12764        })
12765    }
12766
12767    pub fn select_to_end_of_excerpt(
12768        &mut self,
12769        _: &SelectToEndOfExcerpt,
12770        window: &mut Window,
12771        cx: &mut Context<Self>,
12772    ) {
12773        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12774            cx.propagate();
12775            return;
12776        }
12777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12778        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12779            s.move_heads_with(|map, head, _| {
12780                (
12781                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12782                    SelectionGoal::None,
12783                )
12784            });
12785        })
12786    }
12787
12788    pub fn select_to_end_of_previous_excerpt(
12789        &mut self,
12790        _: &SelectToEndOfPreviousExcerpt,
12791        window: &mut Window,
12792        cx: &mut Context<Self>,
12793    ) {
12794        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12795            cx.propagate();
12796            return;
12797        }
12798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12799        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12800            s.move_heads_with(|map, head, _| {
12801                (
12802                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12803                    SelectionGoal::None,
12804                )
12805            });
12806        })
12807    }
12808
12809    pub fn move_to_beginning(
12810        &mut self,
12811        _: &MoveToBeginning,
12812        window: &mut Window,
12813        cx: &mut Context<Self>,
12814    ) {
12815        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12816            cx.propagate();
12817            return;
12818        }
12819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12820        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12821            s.select_ranges(vec![0..0]);
12822        });
12823    }
12824
12825    pub fn select_to_beginning(
12826        &mut self,
12827        _: &SelectToBeginning,
12828        window: &mut Window,
12829        cx: &mut Context<Self>,
12830    ) {
12831        let mut selection = self.selections.last::<Point>(cx);
12832        selection.set_head(Point::zero(), SelectionGoal::None);
12833        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12834        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12835            s.select(vec![selection]);
12836        });
12837    }
12838
12839    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12840        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12841            cx.propagate();
12842            return;
12843        }
12844        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12845        let cursor = self.buffer.read(cx).read(cx).len();
12846        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12847            s.select_ranges(vec![cursor..cursor])
12848        });
12849    }
12850
12851    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12852        self.nav_history = nav_history;
12853    }
12854
12855    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12856        self.nav_history.as_ref()
12857    }
12858
12859    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12860        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12861    }
12862
12863    fn push_to_nav_history(
12864        &mut self,
12865        cursor_anchor: Anchor,
12866        new_position: Option<Point>,
12867        is_deactivate: bool,
12868        cx: &mut Context<Self>,
12869    ) {
12870        if let Some(nav_history) = self.nav_history.as_mut() {
12871            let buffer = self.buffer.read(cx).read(cx);
12872            let cursor_position = cursor_anchor.to_point(&buffer);
12873            let scroll_state = self.scroll_manager.anchor();
12874            let scroll_top_row = scroll_state.top_row(&buffer);
12875            drop(buffer);
12876
12877            if let Some(new_position) = new_position {
12878                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12879                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12880                    return;
12881                }
12882            }
12883
12884            nav_history.push(
12885                Some(NavigationData {
12886                    cursor_anchor,
12887                    cursor_position,
12888                    scroll_anchor: scroll_state,
12889                    scroll_top_row,
12890                }),
12891                cx,
12892            );
12893            cx.emit(EditorEvent::PushedToNavHistory {
12894                anchor: cursor_anchor,
12895                is_deactivate,
12896            })
12897        }
12898    }
12899
12900    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12901        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12902        let buffer = self.buffer.read(cx).snapshot(cx);
12903        let mut selection = self.selections.first::<usize>(cx);
12904        selection.set_head(buffer.len(), SelectionGoal::None);
12905        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12906            s.select(vec![selection]);
12907        });
12908    }
12909
12910    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12912        let end = self.buffer.read(cx).read(cx).len();
12913        self.change_selections(None, window, cx, |s| {
12914            s.select_ranges(vec![0..end]);
12915        });
12916    }
12917
12918    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12920        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12921        let mut selections = self.selections.all::<Point>(cx);
12922        let max_point = display_map.buffer_snapshot.max_point();
12923        for selection in &mut selections {
12924            let rows = selection.spanned_rows(true, &display_map);
12925            selection.start = Point::new(rows.start.0, 0);
12926            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12927            selection.reversed = false;
12928        }
12929        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12930            s.select(selections);
12931        });
12932    }
12933
12934    pub fn split_selection_into_lines(
12935        &mut self,
12936        _: &SplitSelectionIntoLines,
12937        window: &mut Window,
12938        cx: &mut Context<Self>,
12939    ) {
12940        let selections = self
12941            .selections
12942            .all::<Point>(cx)
12943            .into_iter()
12944            .map(|selection| selection.start..selection.end)
12945            .collect::<Vec<_>>();
12946        self.unfold_ranges(&selections, true, true, cx);
12947
12948        let mut new_selection_ranges = Vec::new();
12949        {
12950            let buffer = self.buffer.read(cx).read(cx);
12951            for selection in selections {
12952                for row in selection.start.row..selection.end.row {
12953                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12954                    new_selection_ranges.push(cursor..cursor);
12955                }
12956
12957                let is_multiline_selection = selection.start.row != selection.end.row;
12958                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12959                // so this action feels more ergonomic when paired with other selection operations
12960                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12961                if !should_skip_last {
12962                    new_selection_ranges.push(selection.end..selection.end);
12963                }
12964            }
12965        }
12966        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12967            s.select_ranges(new_selection_ranges);
12968        });
12969    }
12970
12971    pub fn add_selection_above(
12972        &mut self,
12973        _: &AddSelectionAbove,
12974        window: &mut Window,
12975        cx: &mut Context<Self>,
12976    ) {
12977        self.add_selection(true, window, cx);
12978    }
12979
12980    pub fn add_selection_below(
12981        &mut self,
12982        _: &AddSelectionBelow,
12983        window: &mut Window,
12984        cx: &mut Context<Self>,
12985    ) {
12986        self.add_selection(false, window, cx);
12987    }
12988
12989    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12990        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12991
12992        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12993        let all_selections = self.selections.all::<Point>(cx);
12994        let text_layout_details = self.text_layout_details(window);
12995
12996        let (mut columnar_selections, new_selections_to_columnarize) = {
12997            if let Some(state) = self.add_selections_state.as_ref() {
12998                let columnar_selection_ids: HashSet<_> = state
12999                    .groups
13000                    .iter()
13001                    .flat_map(|group| group.stack.iter())
13002                    .copied()
13003                    .collect();
13004
13005                all_selections
13006                    .into_iter()
13007                    .partition(|s| columnar_selection_ids.contains(&s.id))
13008            } else {
13009                (Vec::new(), all_selections)
13010            }
13011        };
13012
13013        let mut state = self
13014            .add_selections_state
13015            .take()
13016            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13017
13018        for selection in new_selections_to_columnarize {
13019            let range = selection.display_range(&display_map).sorted();
13020            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13021            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13022            let positions = start_x.min(end_x)..start_x.max(end_x);
13023            let mut stack = Vec::new();
13024            for row in range.start.row().0..=range.end.row().0 {
13025                if let Some(selection) = self.selections.build_columnar_selection(
13026                    &display_map,
13027                    DisplayRow(row),
13028                    &positions,
13029                    selection.reversed,
13030                    &text_layout_details,
13031                ) {
13032                    stack.push(selection.id);
13033                    columnar_selections.push(selection);
13034                }
13035            }
13036            if !stack.is_empty() {
13037                if above {
13038                    stack.reverse();
13039                }
13040                state.groups.push(AddSelectionsGroup { above, stack });
13041            }
13042        }
13043
13044        let mut final_selections = Vec::new();
13045        let end_row = if above {
13046            DisplayRow(0)
13047        } else {
13048            display_map.max_point().row()
13049        };
13050
13051        let mut last_added_item_per_group = HashMap::default();
13052        for group in state.groups.iter_mut() {
13053            if let Some(last_id) = group.stack.last() {
13054                last_added_item_per_group.insert(*last_id, group);
13055            }
13056        }
13057
13058        for selection in columnar_selections {
13059            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13060                if above == group.above {
13061                    let range = selection.display_range(&display_map).sorted();
13062                    debug_assert_eq!(range.start.row(), range.end.row());
13063                    let mut row = range.start.row();
13064                    let positions =
13065                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13066                            px(start)..px(end)
13067                        } else {
13068                            let start_x =
13069                                display_map.x_for_display_point(range.start, &text_layout_details);
13070                            let end_x =
13071                                display_map.x_for_display_point(range.end, &text_layout_details);
13072                            start_x.min(end_x)..start_x.max(end_x)
13073                        };
13074
13075                    let mut maybe_new_selection = None;
13076                    while row != end_row {
13077                        if above {
13078                            row.0 -= 1;
13079                        } else {
13080                            row.0 += 1;
13081                        }
13082                        if let Some(new_selection) = self.selections.build_columnar_selection(
13083                            &display_map,
13084                            row,
13085                            &positions,
13086                            selection.reversed,
13087                            &text_layout_details,
13088                        ) {
13089                            maybe_new_selection = Some(new_selection);
13090                            break;
13091                        }
13092                    }
13093
13094                    if let Some(new_selection) = maybe_new_selection {
13095                        group.stack.push(new_selection.id);
13096                        if above {
13097                            final_selections.push(new_selection);
13098                            final_selections.push(selection);
13099                        } else {
13100                            final_selections.push(selection);
13101                            final_selections.push(new_selection);
13102                        }
13103                    } else {
13104                        final_selections.push(selection);
13105                    }
13106                } else {
13107                    group.stack.pop();
13108                }
13109            } else {
13110                final_selections.push(selection);
13111            }
13112        }
13113
13114        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13115            s.select(final_selections);
13116        });
13117
13118        let final_selection_ids: HashSet<_> = self
13119            .selections
13120            .all::<Point>(cx)
13121            .iter()
13122            .map(|s| s.id)
13123            .collect();
13124        state.groups.retain_mut(|group| {
13125            // selections might get merged above so we remove invalid items from stacks
13126            group.stack.retain(|id| final_selection_ids.contains(id));
13127
13128            // single selection in stack can be treated as initial state
13129            group.stack.len() > 1
13130        });
13131
13132        if !state.groups.is_empty() {
13133            self.add_selections_state = Some(state);
13134        }
13135    }
13136
13137    fn select_match_ranges(
13138        &mut self,
13139        range: Range<usize>,
13140        reversed: bool,
13141        replace_newest: bool,
13142        auto_scroll: Option<Autoscroll>,
13143        window: &mut Window,
13144        cx: &mut Context<Editor>,
13145    ) {
13146        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13147        self.change_selections(auto_scroll, window, cx, |s| {
13148            if replace_newest {
13149                s.delete(s.newest_anchor().id);
13150            }
13151            if reversed {
13152                s.insert_range(range.end..range.start);
13153            } else {
13154                s.insert_range(range);
13155            }
13156        });
13157    }
13158
13159    pub fn select_next_match_internal(
13160        &mut self,
13161        display_map: &DisplaySnapshot,
13162        replace_newest: bool,
13163        autoscroll: Option<Autoscroll>,
13164        window: &mut Window,
13165        cx: &mut Context<Self>,
13166    ) -> Result<()> {
13167        let buffer = &display_map.buffer_snapshot;
13168        let mut selections = self.selections.all::<usize>(cx);
13169        if let Some(mut select_next_state) = self.select_next_state.take() {
13170            let query = &select_next_state.query;
13171            if !select_next_state.done {
13172                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13173                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13174                let mut next_selected_range = None;
13175
13176                let bytes_after_last_selection =
13177                    buffer.bytes_in_range(last_selection.end..buffer.len());
13178                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13179                let query_matches = query
13180                    .stream_find_iter(bytes_after_last_selection)
13181                    .map(|result| (last_selection.end, result))
13182                    .chain(
13183                        query
13184                            .stream_find_iter(bytes_before_first_selection)
13185                            .map(|result| (0, result)),
13186                    );
13187
13188                for (start_offset, query_match) in query_matches {
13189                    let query_match = query_match.unwrap(); // can only fail due to I/O
13190                    let offset_range =
13191                        start_offset + query_match.start()..start_offset + query_match.end();
13192                    let display_range = offset_range.start.to_display_point(display_map)
13193                        ..offset_range.end.to_display_point(display_map);
13194
13195                    if !select_next_state.wordwise
13196                        || (!movement::is_inside_word(display_map, display_range.start)
13197                            && !movement::is_inside_word(display_map, display_range.end))
13198                    {
13199                        // TODO: This is n^2, because we might check all the selections
13200                        if !selections
13201                            .iter()
13202                            .any(|selection| selection.range().overlaps(&offset_range))
13203                        {
13204                            next_selected_range = Some(offset_range);
13205                            break;
13206                        }
13207                    }
13208                }
13209
13210                if let Some(next_selected_range) = next_selected_range {
13211                    self.select_match_ranges(
13212                        next_selected_range,
13213                        last_selection.reversed,
13214                        replace_newest,
13215                        autoscroll,
13216                        window,
13217                        cx,
13218                    );
13219                } else {
13220                    select_next_state.done = true;
13221                }
13222            }
13223
13224            self.select_next_state = Some(select_next_state);
13225        } else {
13226            let mut only_carets = true;
13227            let mut same_text_selected = true;
13228            let mut selected_text = None;
13229
13230            let mut selections_iter = selections.iter().peekable();
13231            while let Some(selection) = selections_iter.next() {
13232                if selection.start != selection.end {
13233                    only_carets = false;
13234                }
13235
13236                if same_text_selected {
13237                    if selected_text.is_none() {
13238                        selected_text =
13239                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13240                    }
13241
13242                    if let Some(next_selection) = selections_iter.peek() {
13243                        if next_selection.range().len() == selection.range().len() {
13244                            let next_selected_text = buffer
13245                                .text_for_range(next_selection.range())
13246                                .collect::<String>();
13247                            if Some(next_selected_text) != selected_text {
13248                                same_text_selected = false;
13249                                selected_text = None;
13250                            }
13251                        } else {
13252                            same_text_selected = false;
13253                            selected_text = None;
13254                        }
13255                    }
13256                }
13257            }
13258
13259            if only_carets {
13260                for selection in &mut selections {
13261                    let word_range = movement::surrounding_word(
13262                        display_map,
13263                        selection.start.to_display_point(display_map),
13264                    );
13265                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13266                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13267                    selection.goal = SelectionGoal::None;
13268                    selection.reversed = false;
13269                    self.select_match_ranges(
13270                        selection.start..selection.end,
13271                        selection.reversed,
13272                        replace_newest,
13273                        autoscroll,
13274                        window,
13275                        cx,
13276                    );
13277                }
13278
13279                if selections.len() == 1 {
13280                    let selection = selections
13281                        .last()
13282                        .expect("ensured that there's only one selection");
13283                    let query = buffer
13284                        .text_for_range(selection.start..selection.end)
13285                        .collect::<String>();
13286                    let is_empty = query.is_empty();
13287                    let select_state = SelectNextState {
13288                        query: AhoCorasick::new(&[query])?,
13289                        wordwise: true,
13290                        done: is_empty,
13291                    };
13292                    self.select_next_state = Some(select_state);
13293                } else {
13294                    self.select_next_state = None;
13295                }
13296            } else if let Some(selected_text) = selected_text {
13297                self.select_next_state = Some(SelectNextState {
13298                    query: AhoCorasick::new(&[selected_text])?,
13299                    wordwise: false,
13300                    done: false,
13301                });
13302                self.select_next_match_internal(
13303                    display_map,
13304                    replace_newest,
13305                    autoscroll,
13306                    window,
13307                    cx,
13308                )?;
13309            }
13310        }
13311        Ok(())
13312    }
13313
13314    pub fn select_all_matches(
13315        &mut self,
13316        _action: &SelectAllMatches,
13317        window: &mut Window,
13318        cx: &mut Context<Self>,
13319    ) -> Result<()> {
13320        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13321
13322        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13323
13324        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13325        let Some(select_next_state) = self.select_next_state.as_mut() else {
13326            return Ok(());
13327        };
13328        if select_next_state.done {
13329            return Ok(());
13330        }
13331
13332        let mut new_selections = Vec::new();
13333
13334        let reversed = self.selections.oldest::<usize>(cx).reversed;
13335        let buffer = &display_map.buffer_snapshot;
13336        let query_matches = select_next_state
13337            .query
13338            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13339
13340        for query_match in query_matches.into_iter() {
13341            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13342            let offset_range = if reversed {
13343                query_match.end()..query_match.start()
13344            } else {
13345                query_match.start()..query_match.end()
13346            };
13347            let display_range = offset_range.start.to_display_point(&display_map)
13348                ..offset_range.end.to_display_point(&display_map);
13349
13350            if !select_next_state.wordwise
13351                || (!movement::is_inside_word(&display_map, display_range.start)
13352                    && !movement::is_inside_word(&display_map, display_range.end))
13353            {
13354                new_selections.push(offset_range.start..offset_range.end);
13355            }
13356        }
13357
13358        select_next_state.done = true;
13359        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13360        self.change_selections(None, window, cx, |selections| {
13361            selections.select_ranges(new_selections)
13362        });
13363
13364        Ok(())
13365    }
13366
13367    pub fn select_next(
13368        &mut self,
13369        action: &SelectNext,
13370        window: &mut Window,
13371        cx: &mut Context<Self>,
13372    ) -> Result<()> {
13373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13374        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13375        self.select_next_match_internal(
13376            &display_map,
13377            action.replace_newest,
13378            Some(Autoscroll::newest()),
13379            window,
13380            cx,
13381        )?;
13382        Ok(())
13383    }
13384
13385    pub fn select_previous(
13386        &mut self,
13387        action: &SelectPrevious,
13388        window: &mut Window,
13389        cx: &mut Context<Self>,
13390    ) -> Result<()> {
13391        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13392        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13393        let buffer = &display_map.buffer_snapshot;
13394        let mut selections = self.selections.all::<usize>(cx);
13395        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13396            let query = &select_prev_state.query;
13397            if !select_prev_state.done {
13398                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13399                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13400                let mut next_selected_range = None;
13401                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13402                let bytes_before_last_selection =
13403                    buffer.reversed_bytes_in_range(0..last_selection.start);
13404                let bytes_after_first_selection =
13405                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13406                let query_matches = query
13407                    .stream_find_iter(bytes_before_last_selection)
13408                    .map(|result| (last_selection.start, result))
13409                    .chain(
13410                        query
13411                            .stream_find_iter(bytes_after_first_selection)
13412                            .map(|result| (buffer.len(), result)),
13413                    );
13414                for (end_offset, query_match) in query_matches {
13415                    let query_match = query_match.unwrap(); // can only fail due to I/O
13416                    let offset_range =
13417                        end_offset - query_match.end()..end_offset - query_match.start();
13418                    let display_range = offset_range.start.to_display_point(&display_map)
13419                        ..offset_range.end.to_display_point(&display_map);
13420
13421                    if !select_prev_state.wordwise
13422                        || (!movement::is_inside_word(&display_map, display_range.start)
13423                            && !movement::is_inside_word(&display_map, display_range.end))
13424                    {
13425                        next_selected_range = Some(offset_range);
13426                        break;
13427                    }
13428                }
13429
13430                if let Some(next_selected_range) = next_selected_range {
13431                    self.select_match_ranges(
13432                        next_selected_range,
13433                        last_selection.reversed,
13434                        action.replace_newest,
13435                        Some(Autoscroll::newest()),
13436                        window,
13437                        cx,
13438                    );
13439                } else {
13440                    select_prev_state.done = true;
13441                }
13442            }
13443
13444            self.select_prev_state = Some(select_prev_state);
13445        } else {
13446            let mut only_carets = true;
13447            let mut same_text_selected = true;
13448            let mut selected_text = None;
13449
13450            let mut selections_iter = selections.iter().peekable();
13451            while let Some(selection) = selections_iter.next() {
13452                if selection.start != selection.end {
13453                    only_carets = false;
13454                }
13455
13456                if same_text_selected {
13457                    if selected_text.is_none() {
13458                        selected_text =
13459                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13460                    }
13461
13462                    if let Some(next_selection) = selections_iter.peek() {
13463                        if next_selection.range().len() == selection.range().len() {
13464                            let next_selected_text = buffer
13465                                .text_for_range(next_selection.range())
13466                                .collect::<String>();
13467                            if Some(next_selected_text) != selected_text {
13468                                same_text_selected = false;
13469                                selected_text = None;
13470                            }
13471                        } else {
13472                            same_text_selected = false;
13473                            selected_text = None;
13474                        }
13475                    }
13476                }
13477            }
13478
13479            if only_carets {
13480                for selection in &mut selections {
13481                    let word_range = movement::surrounding_word(
13482                        &display_map,
13483                        selection.start.to_display_point(&display_map),
13484                    );
13485                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13486                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13487                    selection.goal = SelectionGoal::None;
13488                    selection.reversed = false;
13489                    self.select_match_ranges(
13490                        selection.start..selection.end,
13491                        selection.reversed,
13492                        action.replace_newest,
13493                        Some(Autoscroll::newest()),
13494                        window,
13495                        cx,
13496                    );
13497                }
13498                if selections.len() == 1 {
13499                    let selection = selections
13500                        .last()
13501                        .expect("ensured that there's only one selection");
13502                    let query = buffer
13503                        .text_for_range(selection.start..selection.end)
13504                        .collect::<String>();
13505                    let is_empty = query.is_empty();
13506                    let select_state = SelectNextState {
13507                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13508                        wordwise: true,
13509                        done: is_empty,
13510                    };
13511                    self.select_prev_state = Some(select_state);
13512                } else {
13513                    self.select_prev_state = None;
13514                }
13515            } else if let Some(selected_text) = selected_text {
13516                self.select_prev_state = Some(SelectNextState {
13517                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13518                    wordwise: false,
13519                    done: false,
13520                });
13521                self.select_previous(action, window, cx)?;
13522            }
13523        }
13524        Ok(())
13525    }
13526
13527    pub fn find_next_match(
13528        &mut self,
13529        _: &FindNextMatch,
13530        window: &mut Window,
13531        cx: &mut Context<Self>,
13532    ) -> Result<()> {
13533        let selections = self.selections.disjoint_anchors();
13534        match selections.first() {
13535            Some(first) if selections.len() >= 2 => {
13536                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13537                    s.select_ranges([first.range()]);
13538                });
13539            }
13540            _ => self.select_next(
13541                &SelectNext {
13542                    replace_newest: true,
13543                },
13544                window,
13545                cx,
13546            )?,
13547        }
13548        Ok(())
13549    }
13550
13551    pub fn find_previous_match(
13552        &mut self,
13553        _: &FindPreviousMatch,
13554        window: &mut Window,
13555        cx: &mut Context<Self>,
13556    ) -> Result<()> {
13557        let selections = self.selections.disjoint_anchors();
13558        match selections.last() {
13559            Some(last) if selections.len() >= 2 => {
13560                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13561                    s.select_ranges([last.range()]);
13562                });
13563            }
13564            _ => self.select_previous(
13565                &SelectPrevious {
13566                    replace_newest: true,
13567                },
13568                window,
13569                cx,
13570            )?,
13571        }
13572        Ok(())
13573    }
13574
13575    pub fn toggle_comments(
13576        &mut self,
13577        action: &ToggleComments,
13578        window: &mut Window,
13579        cx: &mut Context<Self>,
13580    ) {
13581        if self.read_only(cx) {
13582            return;
13583        }
13584        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13585        let text_layout_details = &self.text_layout_details(window);
13586        self.transact(window, cx, |this, window, cx| {
13587            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13588            let mut edits = Vec::new();
13589            let mut selection_edit_ranges = Vec::new();
13590            let mut last_toggled_row = None;
13591            let snapshot = this.buffer.read(cx).read(cx);
13592            let empty_str: Arc<str> = Arc::default();
13593            let mut suffixes_inserted = Vec::new();
13594            let ignore_indent = action.ignore_indent;
13595
13596            fn comment_prefix_range(
13597                snapshot: &MultiBufferSnapshot,
13598                row: MultiBufferRow,
13599                comment_prefix: &str,
13600                comment_prefix_whitespace: &str,
13601                ignore_indent: bool,
13602            ) -> Range<Point> {
13603                let indent_size = if ignore_indent {
13604                    0
13605                } else {
13606                    snapshot.indent_size_for_line(row).len
13607                };
13608
13609                let start = Point::new(row.0, indent_size);
13610
13611                let mut line_bytes = snapshot
13612                    .bytes_in_range(start..snapshot.max_point())
13613                    .flatten()
13614                    .copied();
13615
13616                // If this line currently begins with the line comment prefix, then record
13617                // the range containing the prefix.
13618                if line_bytes
13619                    .by_ref()
13620                    .take(comment_prefix.len())
13621                    .eq(comment_prefix.bytes())
13622                {
13623                    // Include any whitespace that matches the comment prefix.
13624                    let matching_whitespace_len = line_bytes
13625                        .zip(comment_prefix_whitespace.bytes())
13626                        .take_while(|(a, b)| a == b)
13627                        .count() as u32;
13628                    let end = Point::new(
13629                        start.row,
13630                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13631                    );
13632                    start..end
13633                } else {
13634                    start..start
13635                }
13636            }
13637
13638            fn comment_suffix_range(
13639                snapshot: &MultiBufferSnapshot,
13640                row: MultiBufferRow,
13641                comment_suffix: &str,
13642                comment_suffix_has_leading_space: bool,
13643            ) -> Range<Point> {
13644                let end = Point::new(row.0, snapshot.line_len(row));
13645                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13646
13647                let mut line_end_bytes = snapshot
13648                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13649                    .flatten()
13650                    .copied();
13651
13652                let leading_space_len = if suffix_start_column > 0
13653                    && line_end_bytes.next() == Some(b' ')
13654                    && comment_suffix_has_leading_space
13655                {
13656                    1
13657                } else {
13658                    0
13659                };
13660
13661                // If this line currently begins with the line comment prefix, then record
13662                // the range containing the prefix.
13663                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13664                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13665                    start..end
13666                } else {
13667                    end..end
13668                }
13669            }
13670
13671            // TODO: Handle selections that cross excerpts
13672            for selection in &mut selections {
13673                let start_column = snapshot
13674                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13675                    .len;
13676                let language = if let Some(language) =
13677                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13678                {
13679                    language
13680                } else {
13681                    continue;
13682                };
13683
13684                selection_edit_ranges.clear();
13685
13686                // If multiple selections contain a given row, avoid processing that
13687                // row more than once.
13688                let mut start_row = MultiBufferRow(selection.start.row);
13689                if last_toggled_row == Some(start_row) {
13690                    start_row = start_row.next_row();
13691                }
13692                let end_row =
13693                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13694                        MultiBufferRow(selection.end.row - 1)
13695                    } else {
13696                        MultiBufferRow(selection.end.row)
13697                    };
13698                last_toggled_row = Some(end_row);
13699
13700                if start_row > end_row {
13701                    continue;
13702                }
13703
13704                // If the language has line comments, toggle those.
13705                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13706
13707                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13708                if ignore_indent {
13709                    full_comment_prefixes = full_comment_prefixes
13710                        .into_iter()
13711                        .map(|s| Arc::from(s.trim_end()))
13712                        .collect();
13713                }
13714
13715                if !full_comment_prefixes.is_empty() {
13716                    let first_prefix = full_comment_prefixes
13717                        .first()
13718                        .expect("prefixes is non-empty");
13719                    let prefix_trimmed_lengths = full_comment_prefixes
13720                        .iter()
13721                        .map(|p| p.trim_end_matches(' ').len())
13722                        .collect::<SmallVec<[usize; 4]>>();
13723
13724                    let mut all_selection_lines_are_comments = true;
13725
13726                    for row in start_row.0..=end_row.0 {
13727                        let row = MultiBufferRow(row);
13728                        if start_row < end_row && snapshot.is_line_blank(row) {
13729                            continue;
13730                        }
13731
13732                        let prefix_range = full_comment_prefixes
13733                            .iter()
13734                            .zip(prefix_trimmed_lengths.iter().copied())
13735                            .map(|(prefix, trimmed_prefix_len)| {
13736                                comment_prefix_range(
13737                                    snapshot.deref(),
13738                                    row,
13739                                    &prefix[..trimmed_prefix_len],
13740                                    &prefix[trimmed_prefix_len..],
13741                                    ignore_indent,
13742                                )
13743                            })
13744                            .max_by_key(|range| range.end.column - range.start.column)
13745                            .expect("prefixes is non-empty");
13746
13747                        if prefix_range.is_empty() {
13748                            all_selection_lines_are_comments = false;
13749                        }
13750
13751                        selection_edit_ranges.push(prefix_range);
13752                    }
13753
13754                    if all_selection_lines_are_comments {
13755                        edits.extend(
13756                            selection_edit_ranges
13757                                .iter()
13758                                .cloned()
13759                                .map(|range| (range, empty_str.clone())),
13760                        );
13761                    } else {
13762                        let min_column = selection_edit_ranges
13763                            .iter()
13764                            .map(|range| range.start.column)
13765                            .min()
13766                            .unwrap_or(0);
13767                        edits.extend(selection_edit_ranges.iter().map(|range| {
13768                            let position = Point::new(range.start.row, min_column);
13769                            (position..position, first_prefix.clone())
13770                        }));
13771                    }
13772                } else if let Some((full_comment_prefix, comment_suffix)) =
13773                    language.block_comment_delimiters()
13774                {
13775                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13776                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13777                    let prefix_range = comment_prefix_range(
13778                        snapshot.deref(),
13779                        start_row,
13780                        comment_prefix,
13781                        comment_prefix_whitespace,
13782                        ignore_indent,
13783                    );
13784                    let suffix_range = comment_suffix_range(
13785                        snapshot.deref(),
13786                        end_row,
13787                        comment_suffix.trim_start_matches(' '),
13788                        comment_suffix.starts_with(' '),
13789                    );
13790
13791                    if prefix_range.is_empty() || suffix_range.is_empty() {
13792                        edits.push((
13793                            prefix_range.start..prefix_range.start,
13794                            full_comment_prefix.clone(),
13795                        ));
13796                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13797                        suffixes_inserted.push((end_row, comment_suffix.len()));
13798                    } else {
13799                        edits.push((prefix_range, empty_str.clone()));
13800                        edits.push((suffix_range, empty_str.clone()));
13801                    }
13802                } else {
13803                    continue;
13804                }
13805            }
13806
13807            drop(snapshot);
13808            this.buffer.update(cx, |buffer, cx| {
13809                buffer.edit(edits, None, cx);
13810            });
13811
13812            // Adjust selections so that they end before any comment suffixes that
13813            // were inserted.
13814            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13815            let mut selections = this.selections.all::<Point>(cx);
13816            let snapshot = this.buffer.read(cx).read(cx);
13817            for selection in &mut selections {
13818                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13819                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13820                        Ordering::Less => {
13821                            suffixes_inserted.next();
13822                            continue;
13823                        }
13824                        Ordering::Greater => break,
13825                        Ordering::Equal => {
13826                            if selection.end.column == snapshot.line_len(row) {
13827                                if selection.is_empty() {
13828                                    selection.start.column -= suffix_len as u32;
13829                                }
13830                                selection.end.column -= suffix_len as u32;
13831                            }
13832                            break;
13833                        }
13834                    }
13835                }
13836            }
13837
13838            drop(snapshot);
13839            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13840                s.select(selections)
13841            });
13842
13843            let selections = this.selections.all::<Point>(cx);
13844            let selections_on_single_row = selections.windows(2).all(|selections| {
13845                selections[0].start.row == selections[1].start.row
13846                    && selections[0].end.row == selections[1].end.row
13847                    && selections[0].start.row == selections[0].end.row
13848            });
13849            let selections_selecting = selections
13850                .iter()
13851                .any(|selection| selection.start != selection.end);
13852            let advance_downwards = action.advance_downwards
13853                && selections_on_single_row
13854                && !selections_selecting
13855                && !matches!(this.mode, EditorMode::SingleLine { .. });
13856
13857            if advance_downwards {
13858                let snapshot = this.buffer.read(cx).snapshot(cx);
13859
13860                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13861                    s.move_cursors_with(|display_snapshot, display_point, _| {
13862                        let mut point = display_point.to_point(display_snapshot);
13863                        point.row += 1;
13864                        point = snapshot.clip_point(point, Bias::Left);
13865                        let display_point = point.to_display_point(display_snapshot);
13866                        let goal = SelectionGoal::HorizontalPosition(
13867                            display_snapshot
13868                                .x_for_display_point(display_point, text_layout_details)
13869                                .into(),
13870                        );
13871                        (display_point, goal)
13872                    })
13873                });
13874            }
13875        });
13876    }
13877
13878    pub fn select_enclosing_symbol(
13879        &mut self,
13880        _: &SelectEnclosingSymbol,
13881        window: &mut Window,
13882        cx: &mut Context<Self>,
13883    ) {
13884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13885
13886        let buffer = self.buffer.read(cx).snapshot(cx);
13887        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13888
13889        fn update_selection(
13890            selection: &Selection<usize>,
13891            buffer_snap: &MultiBufferSnapshot,
13892        ) -> Option<Selection<usize>> {
13893            let cursor = selection.head();
13894            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13895            for symbol in symbols.iter().rev() {
13896                let start = symbol.range.start.to_offset(buffer_snap);
13897                let end = symbol.range.end.to_offset(buffer_snap);
13898                let new_range = start..end;
13899                if start < selection.start || end > selection.end {
13900                    return Some(Selection {
13901                        id: selection.id,
13902                        start: new_range.start,
13903                        end: new_range.end,
13904                        goal: SelectionGoal::None,
13905                        reversed: selection.reversed,
13906                    });
13907                }
13908            }
13909            None
13910        }
13911
13912        let mut selected_larger_symbol = false;
13913        let new_selections = old_selections
13914            .iter()
13915            .map(|selection| match update_selection(selection, &buffer) {
13916                Some(new_selection) => {
13917                    if new_selection.range() != selection.range() {
13918                        selected_larger_symbol = true;
13919                    }
13920                    new_selection
13921                }
13922                None => selection.clone(),
13923            })
13924            .collect::<Vec<_>>();
13925
13926        if selected_larger_symbol {
13927            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13928                s.select(new_selections);
13929            });
13930        }
13931    }
13932
13933    pub fn select_larger_syntax_node(
13934        &mut self,
13935        _: &SelectLargerSyntaxNode,
13936        window: &mut Window,
13937        cx: &mut Context<Self>,
13938    ) {
13939        let Some(visible_row_count) = self.visible_row_count() else {
13940            return;
13941        };
13942        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13943        if old_selections.is_empty() {
13944            return;
13945        }
13946
13947        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13948
13949        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13950        let buffer = self.buffer.read(cx).snapshot(cx);
13951
13952        let mut selected_larger_node = false;
13953        let mut new_selections = old_selections
13954            .iter()
13955            .map(|selection| {
13956                let old_range = selection.start..selection.end;
13957
13958                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13959                    // manually select word at selection
13960                    if ["string_content", "inline"].contains(&node.kind()) {
13961                        let word_range = {
13962                            let display_point = buffer
13963                                .offset_to_point(old_range.start)
13964                                .to_display_point(&display_map);
13965                            let Range { start, end } =
13966                                movement::surrounding_word(&display_map, display_point);
13967                            start.to_point(&display_map).to_offset(&buffer)
13968                                ..end.to_point(&display_map).to_offset(&buffer)
13969                        };
13970                        // ignore if word is already selected
13971                        if !word_range.is_empty() && old_range != word_range {
13972                            let last_word_range = {
13973                                let display_point = buffer
13974                                    .offset_to_point(old_range.end)
13975                                    .to_display_point(&display_map);
13976                                let Range { start, end } =
13977                                    movement::surrounding_word(&display_map, display_point);
13978                                start.to_point(&display_map).to_offset(&buffer)
13979                                    ..end.to_point(&display_map).to_offset(&buffer)
13980                            };
13981                            // only select word if start and end point belongs to same word
13982                            if word_range == last_word_range {
13983                                selected_larger_node = true;
13984                                return Selection {
13985                                    id: selection.id,
13986                                    start: word_range.start,
13987                                    end: word_range.end,
13988                                    goal: SelectionGoal::None,
13989                                    reversed: selection.reversed,
13990                                };
13991                            }
13992                        }
13993                    }
13994                }
13995
13996                let mut new_range = old_range.clone();
13997                while let Some((_node, containing_range)) =
13998                    buffer.syntax_ancestor(new_range.clone())
13999                {
14000                    new_range = match containing_range {
14001                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14002                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14003                    };
14004                    if !display_map.intersects_fold(new_range.start)
14005                        && !display_map.intersects_fold(new_range.end)
14006                    {
14007                        break;
14008                    }
14009                }
14010
14011                selected_larger_node |= new_range != old_range;
14012                Selection {
14013                    id: selection.id,
14014                    start: new_range.start,
14015                    end: new_range.end,
14016                    goal: SelectionGoal::None,
14017                    reversed: selection.reversed,
14018                }
14019            })
14020            .collect::<Vec<_>>();
14021
14022        if !selected_larger_node {
14023            return; // don't put this call in the history
14024        }
14025
14026        // scroll based on transformation done to the last selection created by the user
14027        let (last_old, last_new) = old_selections
14028            .last()
14029            .zip(new_selections.last().cloned())
14030            .expect("old_selections isn't empty");
14031
14032        // revert selection
14033        let is_selection_reversed = {
14034            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14035            new_selections.last_mut().expect("checked above").reversed =
14036                should_newest_selection_be_reversed;
14037            should_newest_selection_be_reversed
14038        };
14039
14040        if selected_larger_node {
14041            self.select_syntax_node_history.disable_clearing = true;
14042            self.change_selections(None, window, cx, |s| {
14043                s.select(new_selections.clone());
14044            });
14045            self.select_syntax_node_history.disable_clearing = false;
14046        }
14047
14048        let start_row = last_new.start.to_display_point(&display_map).row().0;
14049        let end_row = last_new.end.to_display_point(&display_map).row().0;
14050        let selection_height = end_row - start_row + 1;
14051        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14052
14053        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14054        let scroll_behavior = if fits_on_the_screen {
14055            self.request_autoscroll(Autoscroll::fit(), cx);
14056            SelectSyntaxNodeScrollBehavior::FitSelection
14057        } else if is_selection_reversed {
14058            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14059            SelectSyntaxNodeScrollBehavior::CursorTop
14060        } else {
14061            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14062            SelectSyntaxNodeScrollBehavior::CursorBottom
14063        };
14064
14065        self.select_syntax_node_history.push((
14066            old_selections,
14067            scroll_behavior,
14068            is_selection_reversed,
14069        ));
14070    }
14071
14072    pub fn select_smaller_syntax_node(
14073        &mut self,
14074        _: &SelectSmallerSyntaxNode,
14075        window: &mut Window,
14076        cx: &mut Context<Self>,
14077    ) {
14078        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14079
14080        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14081            self.select_syntax_node_history.pop()
14082        {
14083            if let Some(selection) = selections.last_mut() {
14084                selection.reversed = is_selection_reversed;
14085            }
14086
14087            self.select_syntax_node_history.disable_clearing = true;
14088            self.change_selections(None, window, cx, |s| {
14089                s.select(selections.to_vec());
14090            });
14091            self.select_syntax_node_history.disable_clearing = false;
14092
14093            match scroll_behavior {
14094                SelectSyntaxNodeScrollBehavior::CursorTop => {
14095                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14096                }
14097                SelectSyntaxNodeScrollBehavior::FitSelection => {
14098                    self.request_autoscroll(Autoscroll::fit(), cx);
14099                }
14100                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14101                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14102                }
14103            }
14104        }
14105    }
14106
14107    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14108        if !EditorSettings::get_global(cx).gutter.runnables {
14109            self.clear_tasks();
14110            return Task::ready(());
14111        }
14112        let project = self.project.as_ref().map(Entity::downgrade);
14113        let task_sources = self.lsp_task_sources(cx);
14114        let multi_buffer = self.buffer.downgrade();
14115        cx.spawn_in(window, async move |editor, cx| {
14116            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14117            let Some(project) = project.and_then(|p| p.upgrade()) else {
14118                return;
14119            };
14120            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14121                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14122            }) else {
14123                return;
14124            };
14125
14126            let hide_runnables = project
14127                .update(cx, |project, cx| {
14128                    // Do not display any test indicators in non-dev server remote projects.
14129                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14130                })
14131                .unwrap_or(true);
14132            if hide_runnables {
14133                return;
14134            }
14135            let new_rows =
14136                cx.background_spawn({
14137                    let snapshot = display_snapshot.clone();
14138                    async move {
14139                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14140                    }
14141                })
14142                    .await;
14143            let Ok(lsp_tasks) =
14144                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14145            else {
14146                return;
14147            };
14148            let lsp_tasks = lsp_tasks.await;
14149
14150            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14151                lsp_tasks
14152                    .into_iter()
14153                    .flat_map(|(kind, tasks)| {
14154                        tasks.into_iter().filter_map(move |(location, task)| {
14155                            Some((kind.clone(), location?, task))
14156                        })
14157                    })
14158                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14159                        let buffer = location.target.buffer;
14160                        let buffer_snapshot = buffer.read(cx).snapshot();
14161                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14162                            |(excerpt_id, snapshot, _)| {
14163                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14164                                    display_snapshot
14165                                        .buffer_snapshot
14166                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14167                                } else {
14168                                    None
14169                                }
14170                            },
14171                        );
14172                        if let Some(offset) = offset {
14173                            let task_buffer_range =
14174                                location.target.range.to_point(&buffer_snapshot);
14175                            let context_buffer_range =
14176                                task_buffer_range.to_offset(&buffer_snapshot);
14177                            let context_range = BufferOffset(context_buffer_range.start)
14178                                ..BufferOffset(context_buffer_range.end);
14179
14180                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14181                                .or_insert_with(|| RunnableTasks {
14182                                    templates: Vec::new(),
14183                                    offset,
14184                                    column: task_buffer_range.start.column,
14185                                    extra_variables: HashMap::default(),
14186                                    context_range,
14187                                })
14188                                .templates
14189                                .push((kind, task.original_task().clone()));
14190                        }
14191
14192                        acc
14193                    })
14194            }) else {
14195                return;
14196            };
14197
14198            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14199                buffer.language_settings(cx).tasks.prefer_lsp
14200            }) else {
14201                return;
14202            };
14203
14204            let rows = Self::runnable_rows(
14205                project,
14206                display_snapshot,
14207                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14208                new_rows,
14209                cx.clone(),
14210            )
14211            .await;
14212            editor
14213                .update(cx, |editor, _| {
14214                    editor.clear_tasks();
14215                    for (key, mut value) in rows {
14216                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14217                            value.templates.extend(lsp_tasks.templates);
14218                        }
14219
14220                        editor.insert_tasks(key, value);
14221                    }
14222                    for (key, value) in lsp_tasks_by_rows {
14223                        editor.insert_tasks(key, value);
14224                    }
14225                })
14226                .ok();
14227        })
14228    }
14229    fn fetch_runnable_ranges(
14230        snapshot: &DisplaySnapshot,
14231        range: Range<Anchor>,
14232    ) -> Vec<language::RunnableRange> {
14233        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14234    }
14235
14236    fn runnable_rows(
14237        project: Entity<Project>,
14238        snapshot: DisplaySnapshot,
14239        prefer_lsp: bool,
14240        runnable_ranges: Vec<RunnableRange>,
14241        cx: AsyncWindowContext,
14242    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14243        cx.spawn(async move |cx| {
14244            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14245            for mut runnable in runnable_ranges {
14246                let Some(tasks) = cx
14247                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14248                    .ok()
14249                else {
14250                    continue;
14251                };
14252                let mut tasks = tasks.await;
14253
14254                if prefer_lsp {
14255                    tasks.retain(|(task_kind, _)| {
14256                        !matches!(task_kind, TaskSourceKind::Language { .. })
14257                    });
14258                }
14259                if tasks.is_empty() {
14260                    continue;
14261                }
14262
14263                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14264                let Some(row) = snapshot
14265                    .buffer_snapshot
14266                    .buffer_line_for_row(MultiBufferRow(point.row))
14267                    .map(|(_, range)| range.start.row)
14268                else {
14269                    continue;
14270                };
14271
14272                let context_range =
14273                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14274                runnable_rows.push((
14275                    (runnable.buffer_id, row),
14276                    RunnableTasks {
14277                        templates: tasks,
14278                        offset: snapshot
14279                            .buffer_snapshot
14280                            .anchor_before(runnable.run_range.start),
14281                        context_range,
14282                        column: point.column,
14283                        extra_variables: runnable.extra_captures,
14284                    },
14285                ));
14286            }
14287            runnable_rows
14288        })
14289    }
14290
14291    fn templates_with_tags(
14292        project: &Entity<Project>,
14293        runnable: &mut Runnable,
14294        cx: &mut App,
14295    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14296        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14297            let (worktree_id, file) = project
14298                .buffer_for_id(runnable.buffer, cx)
14299                .and_then(|buffer| buffer.read(cx).file())
14300                .map(|file| (file.worktree_id(cx), file.clone()))
14301                .unzip();
14302
14303            (
14304                project.task_store().read(cx).task_inventory().cloned(),
14305                worktree_id,
14306                file,
14307            )
14308        });
14309
14310        let tags = mem::take(&mut runnable.tags);
14311        let language = runnable.language.clone();
14312        cx.spawn(async move |cx| {
14313            let mut templates_with_tags = Vec::new();
14314            if let Some(inventory) = inventory {
14315                for RunnableTag(tag) in tags {
14316                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14317                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14318                    }) else {
14319                        return templates_with_tags;
14320                    };
14321                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14322                        move |(_, template)| {
14323                            template.tags.iter().any(|source_tag| source_tag == &tag)
14324                        },
14325                    ));
14326                }
14327            }
14328            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14329
14330            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14331                // Strongest source wins; if we have worktree tag binding, prefer that to
14332                // global and language bindings;
14333                // if we have a global binding, prefer that to language binding.
14334                let first_mismatch = templates_with_tags
14335                    .iter()
14336                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14337                if let Some(index) = first_mismatch {
14338                    templates_with_tags.truncate(index);
14339                }
14340            }
14341
14342            templates_with_tags
14343        })
14344    }
14345
14346    pub fn move_to_enclosing_bracket(
14347        &mut self,
14348        _: &MoveToEnclosingBracket,
14349        window: &mut Window,
14350        cx: &mut Context<Self>,
14351    ) {
14352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14353        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14354            s.move_offsets_with(|snapshot, selection| {
14355                let Some(enclosing_bracket_ranges) =
14356                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14357                else {
14358                    return;
14359                };
14360
14361                let mut best_length = usize::MAX;
14362                let mut best_inside = false;
14363                let mut best_in_bracket_range = false;
14364                let mut best_destination = None;
14365                for (open, close) in enclosing_bracket_ranges {
14366                    let close = close.to_inclusive();
14367                    let length = close.end() - open.start;
14368                    let inside = selection.start >= open.end && selection.end <= *close.start();
14369                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14370                        || close.contains(&selection.head());
14371
14372                    // If best is next to a bracket and current isn't, skip
14373                    if !in_bracket_range && best_in_bracket_range {
14374                        continue;
14375                    }
14376
14377                    // Prefer smaller lengths unless best is inside and current isn't
14378                    if length > best_length && (best_inside || !inside) {
14379                        continue;
14380                    }
14381
14382                    best_length = length;
14383                    best_inside = inside;
14384                    best_in_bracket_range = in_bracket_range;
14385                    best_destination = Some(
14386                        if close.contains(&selection.start) && close.contains(&selection.end) {
14387                            if inside { open.end } else { open.start }
14388                        } else if inside {
14389                            *close.start()
14390                        } else {
14391                            *close.end()
14392                        },
14393                    );
14394                }
14395
14396                if let Some(destination) = best_destination {
14397                    selection.collapse_to(destination, SelectionGoal::None);
14398                }
14399            })
14400        });
14401    }
14402
14403    pub fn undo_selection(
14404        &mut self,
14405        _: &UndoSelection,
14406        window: &mut Window,
14407        cx: &mut Context<Self>,
14408    ) {
14409        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14410        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14411            self.selection_history.mode = SelectionHistoryMode::Undoing;
14412            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14413                this.end_selection(window, cx);
14414                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14415                    s.select_anchors(entry.selections.to_vec())
14416                });
14417            });
14418            self.selection_history.mode = SelectionHistoryMode::Normal;
14419
14420            self.select_next_state = entry.select_next_state;
14421            self.select_prev_state = entry.select_prev_state;
14422            self.add_selections_state = entry.add_selections_state;
14423        }
14424    }
14425
14426    pub fn redo_selection(
14427        &mut self,
14428        _: &RedoSelection,
14429        window: &mut Window,
14430        cx: &mut Context<Self>,
14431    ) {
14432        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14433        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14434            self.selection_history.mode = SelectionHistoryMode::Redoing;
14435            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14436                this.end_selection(window, cx);
14437                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14438                    s.select_anchors(entry.selections.to_vec())
14439                });
14440            });
14441            self.selection_history.mode = SelectionHistoryMode::Normal;
14442
14443            self.select_next_state = entry.select_next_state;
14444            self.select_prev_state = entry.select_prev_state;
14445            self.add_selections_state = entry.add_selections_state;
14446        }
14447    }
14448
14449    pub fn expand_excerpts(
14450        &mut self,
14451        action: &ExpandExcerpts,
14452        _: &mut Window,
14453        cx: &mut Context<Self>,
14454    ) {
14455        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14456    }
14457
14458    pub fn expand_excerpts_down(
14459        &mut self,
14460        action: &ExpandExcerptsDown,
14461        _: &mut Window,
14462        cx: &mut Context<Self>,
14463    ) {
14464        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14465    }
14466
14467    pub fn expand_excerpts_up(
14468        &mut self,
14469        action: &ExpandExcerptsUp,
14470        _: &mut Window,
14471        cx: &mut Context<Self>,
14472    ) {
14473        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14474    }
14475
14476    pub fn expand_excerpts_for_direction(
14477        &mut self,
14478        lines: u32,
14479        direction: ExpandExcerptDirection,
14480
14481        cx: &mut Context<Self>,
14482    ) {
14483        let selections = self.selections.disjoint_anchors();
14484
14485        let lines = if lines == 0 {
14486            EditorSettings::get_global(cx).expand_excerpt_lines
14487        } else {
14488            lines
14489        };
14490
14491        self.buffer.update(cx, |buffer, cx| {
14492            let snapshot = buffer.snapshot(cx);
14493            let mut excerpt_ids = selections
14494                .iter()
14495                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14496                .collect::<Vec<_>>();
14497            excerpt_ids.sort();
14498            excerpt_ids.dedup();
14499            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14500        })
14501    }
14502
14503    pub fn expand_excerpt(
14504        &mut self,
14505        excerpt: ExcerptId,
14506        direction: ExpandExcerptDirection,
14507        window: &mut Window,
14508        cx: &mut Context<Self>,
14509    ) {
14510        let current_scroll_position = self.scroll_position(cx);
14511        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14512        let mut should_scroll_up = false;
14513
14514        if direction == ExpandExcerptDirection::Down {
14515            let multi_buffer = self.buffer.read(cx);
14516            let snapshot = multi_buffer.snapshot(cx);
14517            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14518                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14519                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14520                        let buffer_snapshot = buffer.read(cx).snapshot();
14521                        let excerpt_end_row =
14522                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14523                        let last_row = buffer_snapshot.max_point().row;
14524                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14525                        should_scroll_up = lines_below >= lines_to_expand;
14526                    }
14527                }
14528            }
14529        }
14530
14531        self.buffer.update(cx, |buffer, cx| {
14532            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14533        });
14534
14535        if should_scroll_up {
14536            let new_scroll_position =
14537                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14538            self.set_scroll_position(new_scroll_position, window, cx);
14539        }
14540    }
14541
14542    pub fn go_to_singleton_buffer_point(
14543        &mut self,
14544        point: Point,
14545        window: &mut Window,
14546        cx: &mut Context<Self>,
14547    ) {
14548        self.go_to_singleton_buffer_range(point..point, window, cx);
14549    }
14550
14551    pub fn go_to_singleton_buffer_range(
14552        &mut self,
14553        range: Range<Point>,
14554        window: &mut Window,
14555        cx: &mut Context<Self>,
14556    ) {
14557        let multibuffer = self.buffer().read(cx);
14558        let Some(buffer) = multibuffer.as_singleton() else {
14559            return;
14560        };
14561        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14562            return;
14563        };
14564        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14565            return;
14566        };
14567        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14568            s.select_anchor_ranges([start..end])
14569        });
14570    }
14571
14572    pub fn go_to_diagnostic(
14573        &mut self,
14574        _: &GoToDiagnostic,
14575        window: &mut Window,
14576        cx: &mut Context<Self>,
14577    ) {
14578        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14579        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14580    }
14581
14582    pub fn go_to_prev_diagnostic(
14583        &mut self,
14584        _: &GoToPreviousDiagnostic,
14585        window: &mut Window,
14586        cx: &mut Context<Self>,
14587    ) {
14588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14589        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14590    }
14591
14592    pub fn go_to_diagnostic_impl(
14593        &mut self,
14594        direction: Direction,
14595        window: &mut Window,
14596        cx: &mut Context<Self>,
14597    ) {
14598        let buffer = self.buffer.read(cx).snapshot(cx);
14599        let selection = self.selections.newest::<usize>(cx);
14600
14601        let mut active_group_id = None;
14602        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14603            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14604                active_group_id = Some(active_group.group_id);
14605            }
14606        }
14607
14608        fn filtered(
14609            snapshot: EditorSnapshot,
14610            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14611        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14612            diagnostics
14613                .filter(|entry| entry.range.start != entry.range.end)
14614                .filter(|entry| !entry.diagnostic.is_unnecessary)
14615                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14616        }
14617
14618        let snapshot = self.snapshot(window, cx);
14619        let before = filtered(
14620            snapshot.clone(),
14621            buffer
14622                .diagnostics_in_range(0..selection.start)
14623                .filter(|entry| entry.range.start <= selection.start),
14624        );
14625        let after = filtered(
14626            snapshot,
14627            buffer
14628                .diagnostics_in_range(selection.start..buffer.len())
14629                .filter(|entry| entry.range.start >= selection.start),
14630        );
14631
14632        let mut found: Option<DiagnosticEntry<usize>> = None;
14633        if direction == Direction::Prev {
14634            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14635            {
14636                for diagnostic in prev_diagnostics.into_iter().rev() {
14637                    if diagnostic.range.start != selection.start
14638                        || active_group_id
14639                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14640                    {
14641                        found = Some(diagnostic);
14642                        break 'outer;
14643                    }
14644                }
14645            }
14646        } else {
14647            for diagnostic in after.chain(before) {
14648                if diagnostic.range.start != selection.start
14649                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14650                {
14651                    found = Some(diagnostic);
14652                    break;
14653                }
14654            }
14655        }
14656        let Some(next_diagnostic) = found else {
14657            return;
14658        };
14659
14660        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14661            return;
14662        };
14663        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14664            s.select_ranges(vec![
14665                next_diagnostic.range.start..next_diagnostic.range.start,
14666            ])
14667        });
14668        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14669        self.refresh_inline_completion(false, true, window, cx);
14670    }
14671
14672    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14673        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14674        let snapshot = self.snapshot(window, cx);
14675        let selection = self.selections.newest::<Point>(cx);
14676        self.go_to_hunk_before_or_after_position(
14677            &snapshot,
14678            selection.head(),
14679            Direction::Next,
14680            window,
14681            cx,
14682        );
14683    }
14684
14685    pub fn go_to_hunk_before_or_after_position(
14686        &mut self,
14687        snapshot: &EditorSnapshot,
14688        position: Point,
14689        direction: Direction,
14690        window: &mut Window,
14691        cx: &mut Context<Editor>,
14692    ) {
14693        let row = if direction == Direction::Next {
14694            self.hunk_after_position(snapshot, position)
14695                .map(|hunk| hunk.row_range.start)
14696        } else {
14697            self.hunk_before_position(snapshot, position)
14698        };
14699
14700        if let Some(row) = row {
14701            let destination = Point::new(row.0, 0);
14702            let autoscroll = Autoscroll::center();
14703
14704            self.unfold_ranges(&[destination..destination], false, false, cx);
14705            self.change_selections(Some(autoscroll), window, cx, |s| {
14706                s.select_ranges([destination..destination]);
14707            });
14708        }
14709    }
14710
14711    fn hunk_after_position(
14712        &mut self,
14713        snapshot: &EditorSnapshot,
14714        position: Point,
14715    ) -> Option<MultiBufferDiffHunk> {
14716        snapshot
14717            .buffer_snapshot
14718            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14719            .find(|hunk| hunk.row_range.start.0 > position.row)
14720            .or_else(|| {
14721                snapshot
14722                    .buffer_snapshot
14723                    .diff_hunks_in_range(Point::zero()..position)
14724                    .find(|hunk| hunk.row_range.end.0 < position.row)
14725            })
14726    }
14727
14728    fn go_to_prev_hunk(
14729        &mut self,
14730        _: &GoToPreviousHunk,
14731        window: &mut Window,
14732        cx: &mut Context<Self>,
14733    ) {
14734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14735        let snapshot = self.snapshot(window, cx);
14736        let selection = self.selections.newest::<Point>(cx);
14737        self.go_to_hunk_before_or_after_position(
14738            &snapshot,
14739            selection.head(),
14740            Direction::Prev,
14741            window,
14742            cx,
14743        );
14744    }
14745
14746    fn hunk_before_position(
14747        &mut self,
14748        snapshot: &EditorSnapshot,
14749        position: Point,
14750    ) -> Option<MultiBufferRow> {
14751        snapshot
14752            .buffer_snapshot
14753            .diff_hunk_before(position)
14754            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14755    }
14756
14757    fn go_to_next_change(
14758        &mut self,
14759        _: &GoToNextChange,
14760        window: &mut Window,
14761        cx: &mut Context<Self>,
14762    ) {
14763        if let Some(selections) = self
14764            .change_list
14765            .next_change(1, Direction::Next)
14766            .map(|s| s.to_vec())
14767        {
14768            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14769                let map = s.display_map();
14770                s.select_display_ranges(selections.iter().map(|a| {
14771                    let point = a.to_display_point(&map);
14772                    point..point
14773                }))
14774            })
14775        }
14776    }
14777
14778    fn go_to_previous_change(
14779        &mut self,
14780        _: &GoToPreviousChange,
14781        window: &mut Window,
14782        cx: &mut Context<Self>,
14783    ) {
14784        if let Some(selections) = self
14785            .change_list
14786            .next_change(1, Direction::Prev)
14787            .map(|s| s.to_vec())
14788        {
14789            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14790                let map = s.display_map();
14791                s.select_display_ranges(selections.iter().map(|a| {
14792                    let point = a.to_display_point(&map);
14793                    point..point
14794                }))
14795            })
14796        }
14797    }
14798
14799    fn go_to_line<T: 'static>(
14800        &mut self,
14801        position: Anchor,
14802        highlight_color: Option<Hsla>,
14803        window: &mut Window,
14804        cx: &mut Context<Self>,
14805    ) {
14806        let snapshot = self.snapshot(window, cx).display_snapshot;
14807        let position = position.to_point(&snapshot.buffer_snapshot);
14808        let start = snapshot
14809            .buffer_snapshot
14810            .clip_point(Point::new(position.row, 0), Bias::Left);
14811        let end = start + Point::new(1, 0);
14812        let start = snapshot.buffer_snapshot.anchor_before(start);
14813        let end = snapshot.buffer_snapshot.anchor_before(end);
14814
14815        self.highlight_rows::<T>(
14816            start..end,
14817            highlight_color
14818                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14819            Default::default(),
14820            cx,
14821        );
14822
14823        if self.buffer.read(cx).is_singleton() {
14824            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14825        }
14826    }
14827
14828    pub fn go_to_definition(
14829        &mut self,
14830        _: &GoToDefinition,
14831        window: &mut Window,
14832        cx: &mut Context<Self>,
14833    ) -> Task<Result<Navigated>> {
14834        let definition =
14835            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14836        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14837        cx.spawn_in(window, async move |editor, cx| {
14838            if definition.await? == Navigated::Yes {
14839                return Ok(Navigated::Yes);
14840            }
14841            match fallback_strategy {
14842                GoToDefinitionFallback::None => Ok(Navigated::No),
14843                GoToDefinitionFallback::FindAllReferences => {
14844                    match editor.update_in(cx, |editor, window, cx| {
14845                        editor.find_all_references(&FindAllReferences, window, cx)
14846                    })? {
14847                        Some(references) => references.await,
14848                        None => Ok(Navigated::No),
14849                    }
14850                }
14851            }
14852        })
14853    }
14854
14855    pub fn go_to_declaration(
14856        &mut self,
14857        _: &GoToDeclaration,
14858        window: &mut Window,
14859        cx: &mut Context<Self>,
14860    ) -> Task<Result<Navigated>> {
14861        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14862    }
14863
14864    pub fn go_to_declaration_split(
14865        &mut self,
14866        _: &GoToDeclaration,
14867        window: &mut Window,
14868        cx: &mut Context<Self>,
14869    ) -> Task<Result<Navigated>> {
14870        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14871    }
14872
14873    pub fn go_to_implementation(
14874        &mut self,
14875        _: &GoToImplementation,
14876        window: &mut Window,
14877        cx: &mut Context<Self>,
14878    ) -> Task<Result<Navigated>> {
14879        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14880    }
14881
14882    pub fn go_to_implementation_split(
14883        &mut self,
14884        _: &GoToImplementationSplit,
14885        window: &mut Window,
14886        cx: &mut Context<Self>,
14887    ) -> Task<Result<Navigated>> {
14888        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14889    }
14890
14891    pub fn go_to_type_definition(
14892        &mut self,
14893        _: &GoToTypeDefinition,
14894        window: &mut Window,
14895        cx: &mut Context<Self>,
14896    ) -> Task<Result<Navigated>> {
14897        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14898    }
14899
14900    pub fn go_to_definition_split(
14901        &mut self,
14902        _: &GoToDefinitionSplit,
14903        window: &mut Window,
14904        cx: &mut Context<Self>,
14905    ) -> Task<Result<Navigated>> {
14906        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14907    }
14908
14909    pub fn go_to_type_definition_split(
14910        &mut self,
14911        _: &GoToTypeDefinitionSplit,
14912        window: &mut Window,
14913        cx: &mut Context<Self>,
14914    ) -> Task<Result<Navigated>> {
14915        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14916    }
14917
14918    fn go_to_definition_of_kind(
14919        &mut self,
14920        kind: GotoDefinitionKind,
14921        split: bool,
14922        window: &mut Window,
14923        cx: &mut Context<Self>,
14924    ) -> Task<Result<Navigated>> {
14925        let Some(provider) = self.semantics_provider.clone() else {
14926            return Task::ready(Ok(Navigated::No));
14927        };
14928        let head = self.selections.newest::<usize>(cx).head();
14929        let buffer = self.buffer.read(cx);
14930        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14931            text_anchor
14932        } else {
14933            return Task::ready(Ok(Navigated::No));
14934        };
14935
14936        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14937            return Task::ready(Ok(Navigated::No));
14938        };
14939
14940        cx.spawn_in(window, async move |editor, cx| {
14941            let definitions = definitions.await?;
14942            let navigated = editor
14943                .update_in(cx, |editor, window, cx| {
14944                    editor.navigate_to_hover_links(
14945                        Some(kind),
14946                        definitions
14947                            .into_iter()
14948                            .filter(|location| {
14949                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14950                            })
14951                            .map(HoverLink::Text)
14952                            .collect::<Vec<_>>(),
14953                        split,
14954                        window,
14955                        cx,
14956                    )
14957                })?
14958                .await?;
14959            anyhow::Ok(navigated)
14960        })
14961    }
14962
14963    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14964        let selection = self.selections.newest_anchor();
14965        let head = selection.head();
14966        let tail = selection.tail();
14967
14968        let Some((buffer, start_position)) =
14969            self.buffer.read(cx).text_anchor_for_position(head, cx)
14970        else {
14971            return;
14972        };
14973
14974        let end_position = if head != tail {
14975            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14976                return;
14977            };
14978            Some(pos)
14979        } else {
14980            None
14981        };
14982
14983        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14984            let url = if let Some(end_pos) = end_position {
14985                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14986            } else {
14987                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14988            };
14989
14990            if let Some(url) = url {
14991                editor.update(cx, |_, cx| {
14992                    cx.open_url(&url);
14993                })
14994            } else {
14995                Ok(())
14996            }
14997        });
14998
14999        url_finder.detach();
15000    }
15001
15002    pub fn open_selected_filename(
15003        &mut self,
15004        _: &OpenSelectedFilename,
15005        window: &mut Window,
15006        cx: &mut Context<Self>,
15007    ) {
15008        let Some(workspace) = self.workspace() else {
15009            return;
15010        };
15011
15012        let position = self.selections.newest_anchor().head();
15013
15014        let Some((buffer, buffer_position)) =
15015            self.buffer.read(cx).text_anchor_for_position(position, cx)
15016        else {
15017            return;
15018        };
15019
15020        let project = self.project.clone();
15021
15022        cx.spawn_in(window, async move |_, cx| {
15023            let result = find_file(&buffer, project, buffer_position, cx).await;
15024
15025            if let Some((_, path)) = result {
15026                workspace
15027                    .update_in(cx, |workspace, window, cx| {
15028                        workspace.open_resolved_path(path, window, cx)
15029                    })?
15030                    .await?;
15031            }
15032            anyhow::Ok(())
15033        })
15034        .detach();
15035    }
15036
15037    pub(crate) fn navigate_to_hover_links(
15038        &mut self,
15039        kind: Option<GotoDefinitionKind>,
15040        mut definitions: Vec<HoverLink>,
15041        split: bool,
15042        window: &mut Window,
15043        cx: &mut Context<Editor>,
15044    ) -> Task<Result<Navigated>> {
15045        // If there is one definition, just open it directly
15046        if definitions.len() == 1 {
15047            let definition = definitions.pop().unwrap();
15048
15049            enum TargetTaskResult {
15050                Location(Option<Location>),
15051                AlreadyNavigated,
15052            }
15053
15054            let target_task = match definition {
15055                HoverLink::Text(link) => {
15056                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15057                }
15058                HoverLink::InlayHint(lsp_location, server_id) => {
15059                    let computation =
15060                        self.compute_target_location(lsp_location, server_id, window, cx);
15061                    cx.background_spawn(async move {
15062                        let location = computation.await?;
15063                        Ok(TargetTaskResult::Location(location))
15064                    })
15065                }
15066                HoverLink::Url(url) => {
15067                    cx.open_url(&url);
15068                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15069                }
15070                HoverLink::File(path) => {
15071                    if let Some(workspace) = self.workspace() {
15072                        cx.spawn_in(window, async move |_, cx| {
15073                            workspace
15074                                .update_in(cx, |workspace, window, cx| {
15075                                    workspace.open_resolved_path(path, window, cx)
15076                                })?
15077                                .await
15078                                .map(|_| TargetTaskResult::AlreadyNavigated)
15079                        })
15080                    } else {
15081                        Task::ready(Ok(TargetTaskResult::Location(None)))
15082                    }
15083                }
15084            };
15085            cx.spawn_in(window, async move |editor, cx| {
15086                let target = match target_task.await.context("target resolution task")? {
15087                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15088                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15089                    TargetTaskResult::Location(Some(target)) => target,
15090                };
15091
15092                editor.update_in(cx, |editor, window, cx| {
15093                    let Some(workspace) = editor.workspace() else {
15094                        return Navigated::No;
15095                    };
15096                    let pane = workspace.read(cx).active_pane().clone();
15097
15098                    let range = target.range.to_point(target.buffer.read(cx));
15099                    let range = editor.range_for_match(&range);
15100                    let range = collapse_multiline_range(range);
15101
15102                    if !split
15103                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15104                    {
15105                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15106                    } else {
15107                        window.defer(cx, move |window, cx| {
15108                            let target_editor: Entity<Self> =
15109                                workspace.update(cx, |workspace, cx| {
15110                                    let pane = if split {
15111                                        workspace.adjacent_pane(window, cx)
15112                                    } else {
15113                                        workspace.active_pane().clone()
15114                                    };
15115
15116                                    workspace.open_project_item(
15117                                        pane,
15118                                        target.buffer.clone(),
15119                                        true,
15120                                        true,
15121                                        window,
15122                                        cx,
15123                                    )
15124                                });
15125                            target_editor.update(cx, |target_editor, cx| {
15126                                // When selecting a definition in a different buffer, disable the nav history
15127                                // to avoid creating a history entry at the previous cursor location.
15128                                pane.update(cx, |pane, _| pane.disable_history());
15129                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15130                                pane.update(cx, |pane, _| pane.enable_history());
15131                            });
15132                        });
15133                    }
15134                    Navigated::Yes
15135                })
15136            })
15137        } else if !definitions.is_empty() {
15138            cx.spawn_in(window, async move |editor, cx| {
15139                let (title, location_tasks, workspace) = editor
15140                    .update_in(cx, |editor, window, cx| {
15141                        let tab_kind = match kind {
15142                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15143                            _ => "Definitions",
15144                        };
15145                        let title = definitions
15146                            .iter()
15147                            .find_map(|definition| match definition {
15148                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15149                                    let buffer = origin.buffer.read(cx);
15150                                    format!(
15151                                        "{} for {}",
15152                                        tab_kind,
15153                                        buffer
15154                                            .text_for_range(origin.range.clone())
15155                                            .collect::<String>()
15156                                    )
15157                                }),
15158                                HoverLink::InlayHint(_, _) => None,
15159                                HoverLink::Url(_) => None,
15160                                HoverLink::File(_) => None,
15161                            })
15162                            .unwrap_or(tab_kind.to_string());
15163                        let location_tasks = definitions
15164                            .into_iter()
15165                            .map(|definition| match definition {
15166                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15167                                HoverLink::InlayHint(lsp_location, server_id) => editor
15168                                    .compute_target_location(lsp_location, server_id, window, cx),
15169                                HoverLink::Url(_) => Task::ready(Ok(None)),
15170                                HoverLink::File(_) => Task::ready(Ok(None)),
15171                            })
15172                            .collect::<Vec<_>>();
15173                        (title, location_tasks, editor.workspace().clone())
15174                    })
15175                    .context("location tasks preparation")?;
15176
15177                let locations: Vec<Location> = future::join_all(location_tasks)
15178                    .await
15179                    .into_iter()
15180                    .filter_map(|location| location.transpose())
15181                    .collect::<Result<_>>()
15182                    .context("location tasks")?;
15183
15184                if locations.is_empty() {
15185                    return Ok(Navigated::No);
15186                }
15187
15188                let Some(workspace) = workspace else {
15189                    return Ok(Navigated::No);
15190                };
15191
15192                let opened = workspace
15193                    .update_in(cx, |workspace, window, cx| {
15194                        Self::open_locations_in_multibuffer(
15195                            workspace,
15196                            locations,
15197                            title,
15198                            split,
15199                            MultibufferSelectionMode::First,
15200                            window,
15201                            cx,
15202                        )
15203                    })
15204                    .ok();
15205
15206                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15207            })
15208        } else {
15209            Task::ready(Ok(Navigated::No))
15210        }
15211    }
15212
15213    fn compute_target_location(
15214        &self,
15215        lsp_location: lsp::Location,
15216        server_id: LanguageServerId,
15217        window: &mut Window,
15218        cx: &mut Context<Self>,
15219    ) -> Task<anyhow::Result<Option<Location>>> {
15220        let Some(project) = self.project.clone() else {
15221            return Task::ready(Ok(None));
15222        };
15223
15224        cx.spawn_in(window, async move |editor, cx| {
15225            let location_task = editor.update(cx, |_, cx| {
15226                project.update(cx, |project, cx| {
15227                    let language_server_name = project
15228                        .language_server_statuses(cx)
15229                        .find(|(id, _)| server_id == *id)
15230                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15231                    language_server_name.map(|language_server_name| {
15232                        project.open_local_buffer_via_lsp(
15233                            lsp_location.uri.clone(),
15234                            server_id,
15235                            language_server_name,
15236                            cx,
15237                        )
15238                    })
15239                })
15240            })?;
15241            let location = match location_task {
15242                Some(task) => Some({
15243                    let target_buffer_handle = task.await.context("open local buffer")?;
15244                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15245                        let target_start = target_buffer
15246                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15247                        let target_end = target_buffer
15248                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15249                        target_buffer.anchor_after(target_start)
15250                            ..target_buffer.anchor_before(target_end)
15251                    })?;
15252                    Location {
15253                        buffer: target_buffer_handle,
15254                        range,
15255                    }
15256                }),
15257                None => None,
15258            };
15259            Ok(location)
15260        })
15261    }
15262
15263    pub fn find_all_references(
15264        &mut self,
15265        _: &FindAllReferences,
15266        window: &mut Window,
15267        cx: &mut Context<Self>,
15268    ) -> Option<Task<Result<Navigated>>> {
15269        let selection = self.selections.newest::<usize>(cx);
15270        let multi_buffer = self.buffer.read(cx);
15271        let head = selection.head();
15272
15273        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15274        let head_anchor = multi_buffer_snapshot.anchor_at(
15275            head,
15276            if head < selection.tail() {
15277                Bias::Right
15278            } else {
15279                Bias::Left
15280            },
15281        );
15282
15283        match self
15284            .find_all_references_task_sources
15285            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15286        {
15287            Ok(_) => {
15288                log::info!(
15289                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15290                );
15291                return None;
15292            }
15293            Err(i) => {
15294                self.find_all_references_task_sources.insert(i, head_anchor);
15295            }
15296        }
15297
15298        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15299        let workspace = self.workspace()?;
15300        let project = workspace.read(cx).project().clone();
15301        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15302        Some(cx.spawn_in(window, async move |editor, cx| {
15303            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15304                if let Ok(i) = editor
15305                    .find_all_references_task_sources
15306                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15307                {
15308                    editor.find_all_references_task_sources.remove(i);
15309                }
15310            });
15311
15312            let locations = references.await?;
15313            if locations.is_empty() {
15314                return anyhow::Ok(Navigated::No);
15315            }
15316
15317            workspace.update_in(cx, |workspace, window, cx| {
15318                let title = locations
15319                    .first()
15320                    .as_ref()
15321                    .map(|location| {
15322                        let buffer = location.buffer.read(cx);
15323                        format!(
15324                            "References to `{}`",
15325                            buffer
15326                                .text_for_range(location.range.clone())
15327                                .collect::<String>()
15328                        )
15329                    })
15330                    .unwrap();
15331                Self::open_locations_in_multibuffer(
15332                    workspace,
15333                    locations,
15334                    title,
15335                    false,
15336                    MultibufferSelectionMode::First,
15337                    window,
15338                    cx,
15339                );
15340                Navigated::Yes
15341            })
15342        }))
15343    }
15344
15345    /// Opens a multibuffer with the given project locations in it
15346    pub fn open_locations_in_multibuffer(
15347        workspace: &mut Workspace,
15348        mut locations: Vec<Location>,
15349        title: String,
15350        split: bool,
15351        multibuffer_selection_mode: MultibufferSelectionMode,
15352        window: &mut Window,
15353        cx: &mut Context<Workspace>,
15354    ) {
15355        if locations.is_empty() {
15356            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15357            return;
15358        }
15359
15360        // If there are multiple definitions, open them in a multibuffer
15361        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15362        let mut locations = locations.into_iter().peekable();
15363        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15364        let capability = workspace.project().read(cx).capability();
15365
15366        let excerpt_buffer = cx.new(|cx| {
15367            let mut multibuffer = MultiBuffer::new(capability);
15368            while let Some(location) = locations.next() {
15369                let buffer = location.buffer.read(cx);
15370                let mut ranges_for_buffer = Vec::new();
15371                let range = location.range.to_point(buffer);
15372                ranges_for_buffer.push(range.clone());
15373
15374                while let Some(next_location) = locations.peek() {
15375                    if next_location.buffer == location.buffer {
15376                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15377                        locations.next();
15378                    } else {
15379                        break;
15380                    }
15381                }
15382
15383                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15384                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15385                    PathKey::for_buffer(&location.buffer, cx),
15386                    location.buffer.clone(),
15387                    ranges_for_buffer,
15388                    DEFAULT_MULTIBUFFER_CONTEXT,
15389                    cx,
15390                );
15391                ranges.extend(new_ranges)
15392            }
15393
15394            multibuffer.with_title(title)
15395        });
15396
15397        let editor = cx.new(|cx| {
15398            Editor::for_multibuffer(
15399                excerpt_buffer,
15400                Some(workspace.project().clone()),
15401                window,
15402                cx,
15403            )
15404        });
15405        editor.update(cx, |editor, cx| {
15406            match multibuffer_selection_mode {
15407                MultibufferSelectionMode::First => {
15408                    if let Some(first_range) = ranges.first() {
15409                        editor.change_selections(None, window, cx, |selections| {
15410                            selections.clear_disjoint();
15411                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15412                        });
15413                    }
15414                    editor.highlight_background::<Self>(
15415                        &ranges,
15416                        |theme| theme.colors().editor_highlighted_line_background,
15417                        cx,
15418                    );
15419                }
15420                MultibufferSelectionMode::All => {
15421                    editor.change_selections(None, window, cx, |selections| {
15422                        selections.clear_disjoint();
15423                        selections.select_anchor_ranges(ranges);
15424                    });
15425                }
15426            }
15427            editor.register_buffers_with_language_servers(cx);
15428        });
15429
15430        let item = Box::new(editor);
15431        let item_id = item.item_id();
15432
15433        if split {
15434            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15435        } else {
15436            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15437                let (preview_item_id, preview_item_idx) =
15438                    workspace.active_pane().read_with(cx, |pane, _| {
15439                        (pane.preview_item_id(), pane.preview_item_idx())
15440                    });
15441
15442                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15443
15444                if let Some(preview_item_id) = preview_item_id {
15445                    workspace.active_pane().update(cx, |pane, cx| {
15446                        pane.remove_item(preview_item_id, false, false, window, cx);
15447                    });
15448                }
15449            } else {
15450                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15451            }
15452        }
15453        workspace.active_pane().update(cx, |pane, cx| {
15454            pane.set_preview_item_id(Some(item_id), cx);
15455        });
15456    }
15457
15458    pub fn rename(
15459        &mut self,
15460        _: &Rename,
15461        window: &mut Window,
15462        cx: &mut Context<Self>,
15463    ) -> Option<Task<Result<()>>> {
15464        use language::ToOffset as _;
15465
15466        let provider = self.semantics_provider.clone()?;
15467        let selection = self.selections.newest_anchor().clone();
15468        let (cursor_buffer, cursor_buffer_position) = self
15469            .buffer
15470            .read(cx)
15471            .text_anchor_for_position(selection.head(), cx)?;
15472        let (tail_buffer, cursor_buffer_position_end) = self
15473            .buffer
15474            .read(cx)
15475            .text_anchor_for_position(selection.tail(), cx)?;
15476        if tail_buffer != cursor_buffer {
15477            return None;
15478        }
15479
15480        let snapshot = cursor_buffer.read(cx).snapshot();
15481        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15482        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15483        let prepare_rename = provider
15484            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15485            .unwrap_or_else(|| Task::ready(Ok(None)));
15486        drop(snapshot);
15487
15488        Some(cx.spawn_in(window, async move |this, cx| {
15489            let rename_range = if let Some(range) = prepare_rename.await? {
15490                Some(range)
15491            } else {
15492                this.update(cx, |this, cx| {
15493                    let buffer = this.buffer.read(cx).snapshot(cx);
15494                    let mut buffer_highlights = this
15495                        .document_highlights_for_position(selection.head(), &buffer)
15496                        .filter(|highlight| {
15497                            highlight.start.excerpt_id == selection.head().excerpt_id
15498                                && highlight.end.excerpt_id == selection.head().excerpt_id
15499                        });
15500                    buffer_highlights
15501                        .next()
15502                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15503                })?
15504            };
15505            if let Some(rename_range) = rename_range {
15506                this.update_in(cx, |this, window, cx| {
15507                    let snapshot = cursor_buffer.read(cx).snapshot();
15508                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15509                    let cursor_offset_in_rename_range =
15510                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15511                    let cursor_offset_in_rename_range_end =
15512                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15513
15514                    this.take_rename(false, window, cx);
15515                    let buffer = this.buffer.read(cx).read(cx);
15516                    let cursor_offset = selection.head().to_offset(&buffer);
15517                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15518                    let rename_end = rename_start + rename_buffer_range.len();
15519                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15520                    let mut old_highlight_id = None;
15521                    let old_name: Arc<str> = buffer
15522                        .chunks(rename_start..rename_end, true)
15523                        .map(|chunk| {
15524                            if old_highlight_id.is_none() {
15525                                old_highlight_id = chunk.syntax_highlight_id;
15526                            }
15527                            chunk.text
15528                        })
15529                        .collect::<String>()
15530                        .into();
15531
15532                    drop(buffer);
15533
15534                    // Position the selection in the rename editor so that it matches the current selection.
15535                    this.show_local_selections = false;
15536                    let rename_editor = cx.new(|cx| {
15537                        let mut editor = Editor::single_line(window, cx);
15538                        editor.buffer.update(cx, |buffer, cx| {
15539                            buffer.edit([(0..0, old_name.clone())], None, cx)
15540                        });
15541                        let rename_selection_range = match cursor_offset_in_rename_range
15542                            .cmp(&cursor_offset_in_rename_range_end)
15543                        {
15544                            Ordering::Equal => {
15545                                editor.select_all(&SelectAll, window, cx);
15546                                return editor;
15547                            }
15548                            Ordering::Less => {
15549                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15550                            }
15551                            Ordering::Greater => {
15552                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15553                            }
15554                        };
15555                        if rename_selection_range.end > old_name.len() {
15556                            editor.select_all(&SelectAll, window, cx);
15557                        } else {
15558                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15559                                s.select_ranges([rename_selection_range]);
15560                            });
15561                        }
15562                        editor
15563                    });
15564                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15565                        if e == &EditorEvent::Focused {
15566                            cx.emit(EditorEvent::FocusedIn)
15567                        }
15568                    })
15569                    .detach();
15570
15571                    let write_highlights = this
15572                        .clear_background_highlights::<DocumentHighlightWrite>(cx)
15573                        .unwrap_or_default();
15574                    let read_highlights = this
15575                        .clear_background_highlights::<DocumentHighlightRead>(cx)
15576                        .unwrap_or_default();
15577                    let ranges = write_highlights
15578                        .iter()
15579                        .chain(read_highlights.iter())
15580                        .cloned()
15581                        .map(|highlight| {
15582                            (
15583                                highlight.range,
15584                                HighlightStyle {
15585                                    fade_out: Some(0.6),
15586                                    ..Default::default()
15587                                },
15588                            )
15589                        })
15590                        .collect();
15591
15592                    this.highlight_text::<Rename>(ranges, cx);
15593                    let rename_focus_handle = rename_editor.focus_handle(cx);
15594                    window.focus(&rename_focus_handle);
15595                    let block_id = this.insert_blocks(
15596                        [BlockProperties {
15597                            style: BlockStyle::Flex,
15598                            placement: BlockPlacement::Below(range.start),
15599                            height: Some(1),
15600                            render: Arc::new({
15601                                let rename_editor = rename_editor.clone();
15602                                move |cx: &mut BlockContext| {
15603                                    let mut text_style = cx.editor_style.text.clone();
15604                                    if let Some(highlight_style) = old_highlight_id
15605                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15606                                    {
15607                                        text_style = text_style.highlight(highlight_style);
15608                                    }
15609                                    div()
15610                                        .block_mouse_except_scroll()
15611                                        .pl(cx.anchor_x)
15612                                        .child(EditorElement::new(
15613                                            &rename_editor,
15614                                            EditorStyle {
15615                                                background: cx.theme().system().transparent,
15616                                                local_player: cx.editor_style.local_player,
15617                                                text: text_style,
15618                                                scrollbar_width: cx.editor_style.scrollbar_width,
15619                                                syntax: cx.editor_style.syntax.clone(),
15620                                                status: cx.editor_style.status.clone(),
15621                                                inlay_hints_style: HighlightStyle {
15622                                                    font_weight: Some(FontWeight::BOLD),
15623                                                    ..make_inlay_hints_style(cx.app)
15624                                                },
15625                                                inline_completion_styles: make_suggestion_styles(
15626                                                    cx.app,
15627                                                ),
15628                                                ..EditorStyle::default()
15629                                            },
15630                                        ))
15631                                        .into_any_element()
15632                                }
15633                            }),
15634                            priority: 0,
15635                            render_in_minimap: true,
15636                        }],
15637                        Some(Autoscroll::fit()),
15638                        cx,
15639                    )[0];
15640                    this.pending_rename = Some(RenameState {
15641                        range,
15642                        old_name,
15643                        editor: rename_editor,
15644                        block_id,
15645                    });
15646                })?;
15647            }
15648
15649            Ok(())
15650        }))
15651    }
15652
15653    pub fn confirm_rename(
15654        &mut self,
15655        _: &ConfirmRename,
15656        window: &mut Window,
15657        cx: &mut Context<Self>,
15658    ) -> Option<Task<Result<()>>> {
15659        let rename = self.take_rename(false, window, cx)?;
15660        let workspace = self.workspace()?.downgrade();
15661        let (buffer, start) = self
15662            .buffer
15663            .read(cx)
15664            .text_anchor_for_position(rename.range.start, cx)?;
15665        let (end_buffer, _) = self
15666            .buffer
15667            .read(cx)
15668            .text_anchor_for_position(rename.range.end, cx)?;
15669        if buffer != end_buffer {
15670            return None;
15671        }
15672
15673        let old_name = rename.old_name;
15674        let new_name = rename.editor.read(cx).text(cx);
15675
15676        let rename = self.semantics_provider.as_ref()?.perform_rename(
15677            &buffer,
15678            start,
15679            new_name.clone(),
15680            cx,
15681        )?;
15682
15683        Some(cx.spawn_in(window, async move |editor, cx| {
15684            let project_transaction = rename.await?;
15685            Self::open_project_transaction(
15686                &editor,
15687                workspace,
15688                project_transaction,
15689                format!("Rename: {}{}", old_name, new_name),
15690                cx,
15691            )
15692            .await?;
15693
15694            editor.update(cx, |editor, cx| {
15695                editor.refresh_document_highlights(cx);
15696            })?;
15697            Ok(())
15698        }))
15699    }
15700
15701    fn take_rename(
15702        &mut self,
15703        moving_cursor: bool,
15704        window: &mut Window,
15705        cx: &mut Context<Self>,
15706    ) -> Option<RenameState> {
15707        let rename = self.pending_rename.take()?;
15708        if rename.editor.focus_handle(cx).is_focused(window) {
15709            window.focus(&self.focus_handle);
15710        }
15711
15712        self.remove_blocks(
15713            [rename.block_id].into_iter().collect(),
15714            Some(Autoscroll::fit()),
15715            cx,
15716        );
15717        self.clear_highlights::<Rename>(cx);
15718        self.show_local_selections = true;
15719
15720        if moving_cursor {
15721            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15722                editor.selections.newest::<usize>(cx).head()
15723            });
15724
15725            // Update the selection to match the position of the selection inside
15726            // the rename editor.
15727            let snapshot = self.buffer.read(cx).read(cx);
15728            let rename_range = rename.range.to_offset(&snapshot);
15729            let cursor_in_editor = snapshot
15730                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15731                .min(rename_range.end);
15732            drop(snapshot);
15733
15734            self.change_selections(None, window, cx, |s| {
15735                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15736            });
15737        } else {
15738            self.refresh_document_highlights(cx);
15739        }
15740
15741        Some(rename)
15742    }
15743
15744    pub fn pending_rename(&self) -> Option<&RenameState> {
15745        self.pending_rename.as_ref()
15746    }
15747
15748    fn format(
15749        &mut self,
15750        _: &Format,
15751        window: &mut Window,
15752        cx: &mut Context<Self>,
15753    ) -> Option<Task<Result<()>>> {
15754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15755
15756        let project = match &self.project {
15757            Some(project) => project.clone(),
15758            None => return None,
15759        };
15760
15761        Some(self.perform_format(
15762            project,
15763            FormatTrigger::Manual,
15764            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15765            window,
15766            cx,
15767        ))
15768    }
15769
15770    fn format_selections(
15771        &mut self,
15772        _: &FormatSelections,
15773        window: &mut Window,
15774        cx: &mut Context<Self>,
15775    ) -> Option<Task<Result<()>>> {
15776        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15777
15778        let project = match &self.project {
15779            Some(project) => project.clone(),
15780            None => return None,
15781        };
15782
15783        let ranges = self
15784            .selections
15785            .all_adjusted(cx)
15786            .into_iter()
15787            .map(|selection| selection.range())
15788            .collect_vec();
15789
15790        Some(self.perform_format(
15791            project,
15792            FormatTrigger::Manual,
15793            FormatTarget::Ranges(ranges),
15794            window,
15795            cx,
15796        ))
15797    }
15798
15799    fn perform_format(
15800        &mut self,
15801        project: Entity<Project>,
15802        trigger: FormatTrigger,
15803        target: FormatTarget,
15804        window: &mut Window,
15805        cx: &mut Context<Self>,
15806    ) -> Task<Result<()>> {
15807        let buffer = self.buffer.clone();
15808        let (buffers, target) = match target {
15809            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15810            FormatTarget::Ranges(selection_ranges) => {
15811                let multi_buffer = buffer.read(cx);
15812                let snapshot = multi_buffer.read(cx);
15813                let mut buffers = HashSet::default();
15814                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15815                    BTreeMap::new();
15816                for selection_range in selection_ranges {
15817                    for (buffer, buffer_range, _) in
15818                        snapshot.range_to_buffer_ranges(selection_range)
15819                    {
15820                        let buffer_id = buffer.remote_id();
15821                        let start = buffer.anchor_before(buffer_range.start);
15822                        let end = buffer.anchor_after(buffer_range.end);
15823                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15824                        buffer_id_to_ranges
15825                            .entry(buffer_id)
15826                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15827                            .or_insert_with(|| vec![start..end]);
15828                    }
15829                }
15830                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15831            }
15832        };
15833
15834        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15835        let selections_prev = transaction_id_prev
15836            .and_then(|transaction_id_prev| {
15837                // default to selections as they were after the last edit, if we have them,
15838                // instead of how they are now.
15839                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15840                // will take you back to where you made the last edit, instead of staying where you scrolled
15841                self.selection_history
15842                    .transaction(transaction_id_prev)
15843                    .map(|t| t.0.clone())
15844            })
15845            .unwrap_or_else(|| {
15846                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15847                self.selections.disjoint_anchors()
15848            });
15849
15850        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15851        let format = project.update(cx, |project, cx| {
15852            project.format(buffers, target, true, trigger, cx)
15853        });
15854
15855        cx.spawn_in(window, async move |editor, cx| {
15856            let transaction = futures::select_biased! {
15857                transaction = format.log_err().fuse() => transaction,
15858                () = timeout => {
15859                    log::warn!("timed out waiting for formatting");
15860                    None
15861                }
15862            };
15863
15864            buffer
15865                .update(cx, |buffer, cx| {
15866                    if let Some(transaction) = transaction {
15867                        if !buffer.is_singleton() {
15868                            buffer.push_transaction(&transaction.0, cx);
15869                        }
15870                    }
15871                    cx.notify();
15872                })
15873                .ok();
15874
15875            if let Some(transaction_id_now) =
15876                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15877            {
15878                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15879                if has_new_transaction {
15880                    _ = editor.update(cx, |editor, _| {
15881                        editor
15882                            .selection_history
15883                            .insert_transaction(transaction_id_now, selections_prev);
15884                    });
15885                }
15886            }
15887
15888            Ok(())
15889        })
15890    }
15891
15892    fn organize_imports(
15893        &mut self,
15894        _: &OrganizeImports,
15895        window: &mut Window,
15896        cx: &mut Context<Self>,
15897    ) -> Option<Task<Result<()>>> {
15898        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15899        let project = match &self.project {
15900            Some(project) => project.clone(),
15901            None => return None,
15902        };
15903        Some(self.perform_code_action_kind(
15904            project,
15905            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15906            window,
15907            cx,
15908        ))
15909    }
15910
15911    fn perform_code_action_kind(
15912        &mut self,
15913        project: Entity<Project>,
15914        kind: CodeActionKind,
15915        window: &mut Window,
15916        cx: &mut Context<Self>,
15917    ) -> Task<Result<()>> {
15918        let buffer = self.buffer.clone();
15919        let buffers = buffer.read(cx).all_buffers();
15920        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15921        let apply_action = project.update(cx, |project, cx| {
15922            project.apply_code_action_kind(buffers, kind, true, cx)
15923        });
15924        cx.spawn_in(window, async move |_, cx| {
15925            let transaction = futures::select_biased! {
15926                () = timeout => {
15927                    log::warn!("timed out waiting for executing code action");
15928                    None
15929                }
15930                transaction = apply_action.log_err().fuse() => transaction,
15931            };
15932            buffer
15933                .update(cx, |buffer, cx| {
15934                    // check if we need this
15935                    if let Some(transaction) = transaction {
15936                        if !buffer.is_singleton() {
15937                            buffer.push_transaction(&transaction.0, cx);
15938                        }
15939                    }
15940                    cx.notify();
15941                })
15942                .ok();
15943            Ok(())
15944        })
15945    }
15946
15947    fn restart_language_server(
15948        &mut self,
15949        _: &RestartLanguageServer,
15950        _: &mut Window,
15951        cx: &mut Context<Self>,
15952    ) {
15953        if let Some(project) = self.project.clone() {
15954            self.buffer.update(cx, |multi_buffer, cx| {
15955                project.update(cx, |project, cx| {
15956                    project.restart_language_servers_for_buffers(
15957                        multi_buffer.all_buffers().into_iter().collect(),
15958                        cx,
15959                    );
15960                });
15961            })
15962        }
15963    }
15964
15965    fn stop_language_server(
15966        &mut self,
15967        _: &StopLanguageServer,
15968        _: &mut Window,
15969        cx: &mut Context<Self>,
15970    ) {
15971        if let Some(project) = self.project.clone() {
15972            self.buffer.update(cx, |multi_buffer, cx| {
15973                project.update(cx, |project, cx| {
15974                    project.stop_language_servers_for_buffers(
15975                        multi_buffer.all_buffers().into_iter().collect(),
15976                        cx,
15977                    );
15978                    cx.emit(project::Event::RefreshInlayHints);
15979                });
15980            });
15981        }
15982    }
15983
15984    fn cancel_language_server_work(
15985        workspace: &mut Workspace,
15986        _: &actions::CancelLanguageServerWork,
15987        _: &mut Window,
15988        cx: &mut Context<Workspace>,
15989    ) {
15990        let project = workspace.project();
15991        let buffers = workspace
15992            .active_item(cx)
15993            .and_then(|item| item.act_as::<Editor>(cx))
15994            .map_or(HashSet::default(), |editor| {
15995                editor.read(cx).buffer.read(cx).all_buffers()
15996            });
15997        project.update(cx, |project, cx| {
15998            project.cancel_language_server_work_for_buffers(buffers, cx);
15999        });
16000    }
16001
16002    fn show_character_palette(
16003        &mut self,
16004        _: &ShowCharacterPalette,
16005        window: &mut Window,
16006        _: &mut Context<Self>,
16007    ) {
16008        window.show_character_palette();
16009    }
16010
16011    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16012        if self.mode.is_minimap() {
16013            return;
16014        }
16015
16016        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16017            let buffer = self.buffer.read(cx).snapshot(cx);
16018            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16019            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16020            let is_valid = buffer
16021                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16022                .any(|entry| {
16023                    entry.diagnostic.is_primary
16024                        && !entry.range.is_empty()
16025                        && entry.range.start == primary_range_start
16026                        && entry.diagnostic.message == active_diagnostics.active_message
16027                });
16028
16029            if !is_valid {
16030                self.dismiss_diagnostics(cx);
16031            }
16032        }
16033    }
16034
16035    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16036        match &self.active_diagnostics {
16037            ActiveDiagnostic::Group(group) => Some(group),
16038            _ => None,
16039        }
16040    }
16041
16042    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16043        self.dismiss_diagnostics(cx);
16044        self.active_diagnostics = ActiveDiagnostic::All;
16045    }
16046
16047    fn activate_diagnostics(
16048        &mut self,
16049        buffer_id: BufferId,
16050        diagnostic: DiagnosticEntry<usize>,
16051        window: &mut Window,
16052        cx: &mut Context<Self>,
16053    ) {
16054        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16055            return;
16056        }
16057        self.dismiss_diagnostics(cx);
16058        let snapshot = self.snapshot(window, cx);
16059        let buffer = self.buffer.read(cx).snapshot(cx);
16060        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16061            return;
16062        };
16063
16064        let diagnostic_group = buffer
16065            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16066            .collect::<Vec<_>>();
16067
16068        let blocks =
16069            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16070
16071        let blocks = self.display_map.update(cx, |display_map, cx| {
16072            display_map.insert_blocks(blocks, cx).into_iter().collect()
16073        });
16074        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16075            active_range: buffer.anchor_before(diagnostic.range.start)
16076                ..buffer.anchor_after(diagnostic.range.end),
16077            active_message: diagnostic.diagnostic.message.clone(),
16078            group_id: diagnostic.diagnostic.group_id,
16079            blocks,
16080        });
16081        cx.notify();
16082    }
16083
16084    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16085        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16086            return;
16087        };
16088
16089        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16090        if let ActiveDiagnostic::Group(group) = prev {
16091            self.display_map.update(cx, |display_map, cx| {
16092                display_map.remove_blocks(group.blocks, cx);
16093            });
16094            cx.notify();
16095        }
16096    }
16097
16098    /// Disable inline diagnostics rendering for this editor.
16099    pub fn disable_inline_diagnostics(&mut self) {
16100        self.inline_diagnostics_enabled = false;
16101        self.inline_diagnostics_update = Task::ready(());
16102        self.inline_diagnostics.clear();
16103    }
16104
16105    pub fn diagnostics_enabled(&self) -> bool {
16106        self.mode.is_full()
16107    }
16108
16109    pub fn inline_diagnostics_enabled(&self) -> bool {
16110        self.diagnostics_enabled() && self.inline_diagnostics_enabled
16111    }
16112
16113    pub fn show_inline_diagnostics(&self) -> bool {
16114        self.show_inline_diagnostics
16115    }
16116
16117    pub fn toggle_inline_diagnostics(
16118        &mut self,
16119        _: &ToggleInlineDiagnostics,
16120        window: &mut Window,
16121        cx: &mut Context<Editor>,
16122    ) {
16123        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16124        self.refresh_inline_diagnostics(false, window, cx);
16125    }
16126
16127    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16128        self.diagnostics_max_severity = severity;
16129        self.display_map.update(cx, |display_map, _| {
16130            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16131        });
16132    }
16133
16134    pub fn toggle_diagnostics(
16135        &mut self,
16136        _: &ToggleDiagnostics,
16137        window: &mut Window,
16138        cx: &mut Context<Editor>,
16139    ) {
16140        if !self.diagnostics_enabled() {
16141            return;
16142        }
16143
16144        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16145            EditorSettings::get_global(cx)
16146                .diagnostics_max_severity
16147                .filter(|severity| severity != &DiagnosticSeverity::Off)
16148                .unwrap_or(DiagnosticSeverity::Hint)
16149        } else {
16150            DiagnosticSeverity::Off
16151        };
16152        self.set_max_diagnostics_severity(new_severity, cx);
16153        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16154            self.active_diagnostics = ActiveDiagnostic::None;
16155            self.inline_diagnostics_update = Task::ready(());
16156            self.inline_diagnostics.clear();
16157        } else {
16158            self.refresh_inline_diagnostics(false, window, cx);
16159        }
16160
16161        cx.notify();
16162    }
16163
16164    pub fn toggle_minimap(
16165        &mut self,
16166        _: &ToggleMinimap,
16167        window: &mut Window,
16168        cx: &mut Context<Editor>,
16169    ) {
16170        if self.supports_minimap(cx) {
16171            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16172        }
16173    }
16174
16175    fn refresh_inline_diagnostics(
16176        &mut self,
16177        debounce: bool,
16178        window: &mut Window,
16179        cx: &mut Context<Self>,
16180    ) {
16181        let max_severity = ProjectSettings::get_global(cx)
16182            .diagnostics
16183            .inline
16184            .max_severity
16185            .unwrap_or(self.diagnostics_max_severity);
16186
16187        if !self.inline_diagnostics_enabled()
16188            || !self.show_inline_diagnostics
16189            || max_severity == DiagnosticSeverity::Off
16190        {
16191            self.inline_diagnostics_update = Task::ready(());
16192            self.inline_diagnostics.clear();
16193            return;
16194        }
16195
16196        let debounce_ms = ProjectSettings::get_global(cx)
16197            .diagnostics
16198            .inline
16199            .update_debounce_ms;
16200        let debounce = if debounce && debounce_ms > 0 {
16201            Some(Duration::from_millis(debounce_ms))
16202        } else {
16203            None
16204        };
16205        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16206            if let Some(debounce) = debounce {
16207                cx.background_executor().timer(debounce).await;
16208            }
16209            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16210                editor
16211                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16212                    .ok()
16213            }) else {
16214                return;
16215            };
16216
16217            let new_inline_diagnostics = cx
16218                .background_spawn(async move {
16219                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16220                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16221                        let message = diagnostic_entry
16222                            .diagnostic
16223                            .message
16224                            .split_once('\n')
16225                            .map(|(line, _)| line)
16226                            .map(SharedString::new)
16227                            .unwrap_or_else(|| {
16228                                SharedString::from(diagnostic_entry.diagnostic.message)
16229                            });
16230                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16231                        let (Ok(i) | Err(i)) = inline_diagnostics
16232                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16233                        inline_diagnostics.insert(
16234                            i,
16235                            (
16236                                start_anchor,
16237                                InlineDiagnostic {
16238                                    message,
16239                                    group_id: diagnostic_entry.diagnostic.group_id,
16240                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16241                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16242                                    severity: diagnostic_entry.diagnostic.severity,
16243                                },
16244                            ),
16245                        );
16246                    }
16247                    inline_diagnostics
16248                })
16249                .await;
16250
16251            editor
16252                .update(cx, |editor, cx| {
16253                    editor.inline_diagnostics = new_inline_diagnostics;
16254                    cx.notify();
16255                })
16256                .ok();
16257        });
16258    }
16259
16260    fn pull_diagnostics(
16261        &mut self,
16262        buffer_id: Option<BufferId>,
16263        window: &Window,
16264        cx: &mut Context<Self>,
16265    ) -> Option<()> {
16266        if !self.mode().is_full() {
16267            return None;
16268        }
16269        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16270            .diagnostics
16271            .lsp_pull_diagnostics;
16272        if !pull_diagnostics_settings.enabled {
16273            return None;
16274        }
16275        let project = self.project.as_ref()?.downgrade();
16276        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16277        let mut buffers = self.buffer.read(cx).all_buffers();
16278        if let Some(buffer_id) = buffer_id {
16279            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16280        }
16281
16282        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16283            cx.background_executor().timer(debounce).await;
16284
16285            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16286                buffers
16287                    .into_iter()
16288                    .filter_map(|buffer| {
16289                        project
16290                            .update(cx, |project, cx| {
16291                                project.lsp_store().update(cx, |lsp_store, cx| {
16292                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16293                                })
16294                            })
16295                            .ok()
16296                    })
16297                    .collect::<FuturesUnordered<_>>()
16298            }) else {
16299                return;
16300            };
16301
16302            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16303                match pull_task {
16304                    Ok(()) => {
16305                        if editor
16306                            .update_in(cx, |editor, window, cx| {
16307                                editor.update_diagnostics_state(window, cx);
16308                            })
16309                            .is_err()
16310                        {
16311                            return;
16312                        }
16313                    }
16314                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16315                }
16316            }
16317        });
16318
16319        Some(())
16320    }
16321
16322    pub fn set_selections_from_remote(
16323        &mut self,
16324        selections: Vec<Selection<Anchor>>,
16325        pending_selection: Option<Selection<Anchor>>,
16326        window: &mut Window,
16327        cx: &mut Context<Self>,
16328    ) {
16329        let old_cursor_position = self.selections.newest_anchor().head();
16330        self.selections.change_with(cx, |s| {
16331            s.select_anchors(selections);
16332            if let Some(pending_selection) = pending_selection {
16333                s.set_pending(pending_selection, SelectMode::Character);
16334            } else {
16335                s.clear_pending();
16336            }
16337        });
16338        self.selections_did_change(
16339            false,
16340            &old_cursor_position,
16341            SelectionEffects::default(),
16342            window,
16343            cx,
16344        );
16345    }
16346
16347    pub fn transact(
16348        &mut self,
16349        window: &mut Window,
16350        cx: &mut Context<Self>,
16351        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16352    ) -> Option<TransactionId> {
16353        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16354            this.start_transaction_at(Instant::now(), window, cx);
16355            update(this, window, cx);
16356            this.end_transaction_at(Instant::now(), cx)
16357        })
16358    }
16359
16360    pub fn start_transaction_at(
16361        &mut self,
16362        now: Instant,
16363        window: &mut Window,
16364        cx: &mut Context<Self>,
16365    ) {
16366        self.end_selection(window, cx);
16367        if let Some(tx_id) = self
16368            .buffer
16369            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16370        {
16371            self.selection_history
16372                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16373            cx.emit(EditorEvent::TransactionBegun {
16374                transaction_id: tx_id,
16375            })
16376        }
16377    }
16378
16379    pub fn end_transaction_at(
16380        &mut self,
16381        now: Instant,
16382        cx: &mut Context<Self>,
16383    ) -> Option<TransactionId> {
16384        if let Some(transaction_id) = self
16385            .buffer
16386            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16387        {
16388            if let Some((_, end_selections)) =
16389                self.selection_history.transaction_mut(transaction_id)
16390            {
16391                *end_selections = Some(self.selections.disjoint_anchors());
16392            } else {
16393                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16394            }
16395
16396            cx.emit(EditorEvent::Edited { transaction_id });
16397            Some(transaction_id)
16398        } else {
16399            None
16400        }
16401    }
16402
16403    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16404        if self.selection_mark_mode {
16405            self.change_selections(None, window, cx, |s| {
16406                s.move_with(|_, sel| {
16407                    sel.collapse_to(sel.head(), SelectionGoal::None);
16408                });
16409            })
16410        }
16411        self.selection_mark_mode = true;
16412        cx.notify();
16413    }
16414
16415    pub fn swap_selection_ends(
16416        &mut self,
16417        _: &actions::SwapSelectionEnds,
16418        window: &mut Window,
16419        cx: &mut Context<Self>,
16420    ) {
16421        self.change_selections(None, window, cx, |s| {
16422            s.move_with(|_, sel| {
16423                if sel.start != sel.end {
16424                    sel.reversed = !sel.reversed
16425                }
16426            });
16427        });
16428        self.request_autoscroll(Autoscroll::newest(), cx);
16429        cx.notify();
16430    }
16431
16432    pub fn toggle_fold(
16433        &mut self,
16434        _: &actions::ToggleFold,
16435        window: &mut Window,
16436        cx: &mut Context<Self>,
16437    ) {
16438        if self.is_singleton(cx) {
16439            let selection = self.selections.newest::<Point>(cx);
16440
16441            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16442            let range = if selection.is_empty() {
16443                let point = selection.head().to_display_point(&display_map);
16444                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16445                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16446                    .to_point(&display_map);
16447                start..end
16448            } else {
16449                selection.range()
16450            };
16451            if display_map.folds_in_range(range).next().is_some() {
16452                self.unfold_lines(&Default::default(), window, cx)
16453            } else {
16454                self.fold(&Default::default(), window, cx)
16455            }
16456        } else {
16457            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16458            let buffer_ids: HashSet<_> = self
16459                .selections
16460                .disjoint_anchor_ranges()
16461                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16462                .collect();
16463
16464            let should_unfold = buffer_ids
16465                .iter()
16466                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16467
16468            for buffer_id in buffer_ids {
16469                if should_unfold {
16470                    self.unfold_buffer(buffer_id, cx);
16471                } else {
16472                    self.fold_buffer(buffer_id, cx);
16473                }
16474            }
16475        }
16476    }
16477
16478    pub fn toggle_fold_recursive(
16479        &mut self,
16480        _: &actions::ToggleFoldRecursive,
16481        window: &mut Window,
16482        cx: &mut Context<Self>,
16483    ) {
16484        let selection = self.selections.newest::<Point>(cx);
16485
16486        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16487        let range = if selection.is_empty() {
16488            let point = selection.head().to_display_point(&display_map);
16489            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16490            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16491                .to_point(&display_map);
16492            start..end
16493        } else {
16494            selection.range()
16495        };
16496        if display_map.folds_in_range(range).next().is_some() {
16497            self.unfold_recursive(&Default::default(), window, cx)
16498        } else {
16499            self.fold_recursive(&Default::default(), window, cx)
16500        }
16501    }
16502
16503    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16504        if self.is_singleton(cx) {
16505            let mut to_fold = Vec::new();
16506            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16507            let selections = self.selections.all_adjusted(cx);
16508
16509            for selection in selections {
16510                let range = selection.range().sorted();
16511                let buffer_start_row = range.start.row;
16512
16513                if range.start.row != range.end.row {
16514                    let mut found = false;
16515                    let mut row = range.start.row;
16516                    while row <= range.end.row {
16517                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16518                        {
16519                            found = true;
16520                            row = crease.range().end.row + 1;
16521                            to_fold.push(crease);
16522                        } else {
16523                            row += 1
16524                        }
16525                    }
16526                    if found {
16527                        continue;
16528                    }
16529                }
16530
16531                for row in (0..=range.start.row).rev() {
16532                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16533                        if crease.range().end.row >= buffer_start_row {
16534                            to_fold.push(crease);
16535                            if row <= range.start.row {
16536                                break;
16537                            }
16538                        }
16539                    }
16540                }
16541            }
16542
16543            self.fold_creases(to_fold, true, window, cx);
16544        } else {
16545            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16546            let buffer_ids = self
16547                .selections
16548                .disjoint_anchor_ranges()
16549                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16550                .collect::<HashSet<_>>();
16551            for buffer_id in buffer_ids {
16552                self.fold_buffer(buffer_id, cx);
16553            }
16554        }
16555    }
16556
16557    fn fold_at_level(
16558        &mut self,
16559        fold_at: &FoldAtLevel,
16560        window: &mut Window,
16561        cx: &mut Context<Self>,
16562    ) {
16563        if !self.buffer.read(cx).is_singleton() {
16564            return;
16565        }
16566
16567        let fold_at_level = fold_at.0;
16568        let snapshot = self.buffer.read(cx).snapshot(cx);
16569        let mut to_fold = Vec::new();
16570        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16571
16572        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16573            while start_row < end_row {
16574                match self
16575                    .snapshot(window, cx)
16576                    .crease_for_buffer_row(MultiBufferRow(start_row))
16577                {
16578                    Some(crease) => {
16579                        let nested_start_row = crease.range().start.row + 1;
16580                        let nested_end_row = crease.range().end.row;
16581
16582                        if current_level < fold_at_level {
16583                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16584                        } else if current_level == fold_at_level {
16585                            to_fold.push(crease);
16586                        }
16587
16588                        start_row = nested_end_row + 1;
16589                    }
16590                    None => start_row += 1,
16591                }
16592            }
16593        }
16594
16595        self.fold_creases(to_fold, true, window, cx);
16596    }
16597
16598    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16599        if self.buffer.read(cx).is_singleton() {
16600            let mut fold_ranges = Vec::new();
16601            let snapshot = self.buffer.read(cx).snapshot(cx);
16602
16603            for row in 0..snapshot.max_row().0 {
16604                if let Some(foldable_range) = self
16605                    .snapshot(window, cx)
16606                    .crease_for_buffer_row(MultiBufferRow(row))
16607                {
16608                    fold_ranges.push(foldable_range);
16609                }
16610            }
16611
16612            self.fold_creases(fold_ranges, true, window, cx);
16613        } else {
16614            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16615                editor
16616                    .update_in(cx, |editor, _, cx| {
16617                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16618                            editor.fold_buffer(buffer_id, cx);
16619                        }
16620                    })
16621                    .ok();
16622            });
16623        }
16624    }
16625
16626    pub fn fold_function_bodies(
16627        &mut self,
16628        _: &actions::FoldFunctionBodies,
16629        window: &mut Window,
16630        cx: &mut Context<Self>,
16631    ) {
16632        let snapshot = self.buffer.read(cx).snapshot(cx);
16633
16634        let ranges = snapshot
16635            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16636            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16637            .collect::<Vec<_>>();
16638
16639        let creases = ranges
16640            .into_iter()
16641            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16642            .collect();
16643
16644        self.fold_creases(creases, true, window, cx);
16645    }
16646
16647    pub fn fold_recursive(
16648        &mut self,
16649        _: &actions::FoldRecursive,
16650        window: &mut Window,
16651        cx: &mut Context<Self>,
16652    ) {
16653        let mut to_fold = Vec::new();
16654        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16655        let selections = self.selections.all_adjusted(cx);
16656
16657        for selection in selections {
16658            let range = selection.range().sorted();
16659            let buffer_start_row = range.start.row;
16660
16661            if range.start.row != range.end.row {
16662                let mut found = false;
16663                for row in range.start.row..=range.end.row {
16664                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16665                        found = true;
16666                        to_fold.push(crease);
16667                    }
16668                }
16669                if found {
16670                    continue;
16671                }
16672            }
16673
16674            for row in (0..=range.start.row).rev() {
16675                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16676                    if crease.range().end.row >= buffer_start_row {
16677                        to_fold.push(crease);
16678                    } else {
16679                        break;
16680                    }
16681                }
16682            }
16683        }
16684
16685        self.fold_creases(to_fold, true, window, cx);
16686    }
16687
16688    pub fn fold_at(
16689        &mut self,
16690        buffer_row: MultiBufferRow,
16691        window: &mut Window,
16692        cx: &mut Context<Self>,
16693    ) {
16694        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16695
16696        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16697            let autoscroll = self
16698                .selections
16699                .all::<Point>(cx)
16700                .iter()
16701                .any(|selection| crease.range().overlaps(&selection.range()));
16702
16703            self.fold_creases(vec![crease], autoscroll, window, cx);
16704        }
16705    }
16706
16707    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16708        if self.is_singleton(cx) {
16709            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16710            let buffer = &display_map.buffer_snapshot;
16711            let selections = self.selections.all::<Point>(cx);
16712            let ranges = selections
16713                .iter()
16714                .map(|s| {
16715                    let range = s.display_range(&display_map).sorted();
16716                    let mut start = range.start.to_point(&display_map);
16717                    let mut end = range.end.to_point(&display_map);
16718                    start.column = 0;
16719                    end.column = buffer.line_len(MultiBufferRow(end.row));
16720                    start..end
16721                })
16722                .collect::<Vec<_>>();
16723
16724            self.unfold_ranges(&ranges, true, true, cx);
16725        } else {
16726            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16727            let buffer_ids = self
16728                .selections
16729                .disjoint_anchor_ranges()
16730                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16731                .collect::<HashSet<_>>();
16732            for buffer_id in buffer_ids {
16733                self.unfold_buffer(buffer_id, cx);
16734            }
16735        }
16736    }
16737
16738    pub fn unfold_recursive(
16739        &mut self,
16740        _: &UnfoldRecursive,
16741        _window: &mut Window,
16742        cx: &mut Context<Self>,
16743    ) {
16744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16745        let selections = self.selections.all::<Point>(cx);
16746        let ranges = selections
16747            .iter()
16748            .map(|s| {
16749                let mut range = s.display_range(&display_map).sorted();
16750                *range.start.column_mut() = 0;
16751                *range.end.column_mut() = display_map.line_len(range.end.row());
16752                let start = range.start.to_point(&display_map);
16753                let end = range.end.to_point(&display_map);
16754                start..end
16755            })
16756            .collect::<Vec<_>>();
16757
16758        self.unfold_ranges(&ranges, true, true, cx);
16759    }
16760
16761    pub fn unfold_at(
16762        &mut self,
16763        buffer_row: MultiBufferRow,
16764        _window: &mut Window,
16765        cx: &mut Context<Self>,
16766    ) {
16767        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16768
16769        let intersection_range = Point::new(buffer_row.0, 0)
16770            ..Point::new(
16771                buffer_row.0,
16772                display_map.buffer_snapshot.line_len(buffer_row),
16773            );
16774
16775        let autoscroll = self
16776            .selections
16777            .all::<Point>(cx)
16778            .iter()
16779            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16780
16781        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16782    }
16783
16784    pub fn unfold_all(
16785        &mut self,
16786        _: &actions::UnfoldAll,
16787        _window: &mut Window,
16788        cx: &mut Context<Self>,
16789    ) {
16790        if self.buffer.read(cx).is_singleton() {
16791            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16792            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16793        } else {
16794            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16795                editor
16796                    .update(cx, |editor, cx| {
16797                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16798                            editor.unfold_buffer(buffer_id, cx);
16799                        }
16800                    })
16801                    .ok();
16802            });
16803        }
16804    }
16805
16806    pub fn fold_selected_ranges(
16807        &mut self,
16808        _: &FoldSelectedRanges,
16809        window: &mut Window,
16810        cx: &mut Context<Self>,
16811    ) {
16812        let selections = self.selections.all_adjusted(cx);
16813        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16814        let ranges = selections
16815            .into_iter()
16816            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16817            .collect::<Vec<_>>();
16818        self.fold_creases(ranges, true, window, cx);
16819    }
16820
16821    pub fn fold_ranges<T: ToOffset + Clone>(
16822        &mut self,
16823        ranges: Vec<Range<T>>,
16824        auto_scroll: bool,
16825        window: &mut Window,
16826        cx: &mut Context<Self>,
16827    ) {
16828        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16829        let ranges = ranges
16830            .into_iter()
16831            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16832            .collect::<Vec<_>>();
16833        self.fold_creases(ranges, auto_scroll, window, cx);
16834    }
16835
16836    pub fn fold_creases<T: ToOffset + Clone>(
16837        &mut self,
16838        creases: Vec<Crease<T>>,
16839        auto_scroll: bool,
16840        _window: &mut Window,
16841        cx: &mut Context<Self>,
16842    ) {
16843        if creases.is_empty() {
16844            return;
16845        }
16846
16847        let mut buffers_affected = HashSet::default();
16848        let multi_buffer = self.buffer().read(cx);
16849        for crease in &creases {
16850            if let Some((_, buffer, _)) =
16851                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16852            {
16853                buffers_affected.insert(buffer.read(cx).remote_id());
16854            };
16855        }
16856
16857        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16858
16859        if auto_scroll {
16860            self.request_autoscroll(Autoscroll::fit(), cx);
16861        }
16862
16863        cx.notify();
16864
16865        self.scrollbar_marker_state.dirty = true;
16866        self.folds_did_change(cx);
16867    }
16868
16869    /// Removes any folds whose ranges intersect any of the given ranges.
16870    pub fn unfold_ranges<T: ToOffset + Clone>(
16871        &mut self,
16872        ranges: &[Range<T>],
16873        inclusive: bool,
16874        auto_scroll: bool,
16875        cx: &mut Context<Self>,
16876    ) {
16877        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16878            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16879        });
16880        self.folds_did_change(cx);
16881    }
16882
16883    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16884        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16885            return;
16886        }
16887        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16888        self.display_map.update(cx, |display_map, cx| {
16889            display_map.fold_buffers([buffer_id], cx)
16890        });
16891        cx.emit(EditorEvent::BufferFoldToggled {
16892            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16893            folded: true,
16894        });
16895        cx.notify();
16896    }
16897
16898    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16899        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16900            return;
16901        }
16902        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16903        self.display_map.update(cx, |display_map, cx| {
16904            display_map.unfold_buffers([buffer_id], cx);
16905        });
16906        cx.emit(EditorEvent::BufferFoldToggled {
16907            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16908            folded: false,
16909        });
16910        cx.notify();
16911    }
16912
16913    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16914        self.display_map.read(cx).is_buffer_folded(buffer)
16915    }
16916
16917    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16918        self.display_map.read(cx).folded_buffers()
16919    }
16920
16921    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16922        self.display_map.update(cx, |display_map, cx| {
16923            display_map.disable_header_for_buffer(buffer_id, cx);
16924        });
16925        cx.notify();
16926    }
16927
16928    /// Removes any folds with the given ranges.
16929    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16930        &mut self,
16931        ranges: &[Range<T>],
16932        type_id: TypeId,
16933        auto_scroll: bool,
16934        cx: &mut Context<Self>,
16935    ) {
16936        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16937            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16938        });
16939        self.folds_did_change(cx);
16940    }
16941
16942    fn remove_folds_with<T: ToOffset + Clone>(
16943        &mut self,
16944        ranges: &[Range<T>],
16945        auto_scroll: bool,
16946        cx: &mut Context<Self>,
16947        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16948    ) {
16949        if ranges.is_empty() {
16950            return;
16951        }
16952
16953        let mut buffers_affected = HashSet::default();
16954        let multi_buffer = self.buffer().read(cx);
16955        for range in ranges {
16956            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16957                buffers_affected.insert(buffer.read(cx).remote_id());
16958            };
16959        }
16960
16961        self.display_map.update(cx, update);
16962
16963        if auto_scroll {
16964            self.request_autoscroll(Autoscroll::fit(), cx);
16965        }
16966
16967        cx.notify();
16968        self.scrollbar_marker_state.dirty = true;
16969        self.active_indent_guides_state.dirty = true;
16970    }
16971
16972    pub fn update_fold_widths(
16973        &mut self,
16974        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16975        cx: &mut Context<Self>,
16976    ) -> bool {
16977        self.display_map
16978            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16979    }
16980
16981    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16982        self.display_map.read(cx).fold_placeholder.clone()
16983    }
16984
16985    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16986        self.buffer.update(cx, |buffer, cx| {
16987            buffer.set_all_diff_hunks_expanded(cx);
16988        });
16989    }
16990
16991    pub fn expand_all_diff_hunks(
16992        &mut self,
16993        _: &ExpandAllDiffHunks,
16994        _window: &mut Window,
16995        cx: &mut Context<Self>,
16996    ) {
16997        self.buffer.update(cx, |buffer, cx| {
16998            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16999        });
17000    }
17001
17002    pub fn toggle_selected_diff_hunks(
17003        &mut self,
17004        _: &ToggleSelectedDiffHunks,
17005        _window: &mut Window,
17006        cx: &mut Context<Self>,
17007    ) {
17008        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17009        self.toggle_diff_hunks_in_ranges(ranges, cx);
17010    }
17011
17012    pub fn diff_hunks_in_ranges<'a>(
17013        &'a self,
17014        ranges: &'a [Range<Anchor>],
17015        buffer: &'a MultiBufferSnapshot,
17016    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17017        ranges.iter().flat_map(move |range| {
17018            let end_excerpt_id = range.end.excerpt_id;
17019            let range = range.to_point(buffer);
17020            let mut peek_end = range.end;
17021            if range.end.row < buffer.max_row().0 {
17022                peek_end = Point::new(range.end.row + 1, 0);
17023            }
17024            buffer
17025                .diff_hunks_in_range(range.start..peek_end)
17026                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17027        })
17028    }
17029
17030    pub fn has_stageable_diff_hunks_in_ranges(
17031        &self,
17032        ranges: &[Range<Anchor>],
17033        snapshot: &MultiBufferSnapshot,
17034    ) -> bool {
17035        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17036        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17037    }
17038
17039    pub fn toggle_staged_selected_diff_hunks(
17040        &mut self,
17041        _: &::git::ToggleStaged,
17042        _: &mut Window,
17043        cx: &mut Context<Self>,
17044    ) {
17045        let snapshot = self.buffer.read(cx).snapshot(cx);
17046        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17047        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17048        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17049    }
17050
17051    pub fn set_render_diff_hunk_controls(
17052        &mut self,
17053        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17054        cx: &mut Context<Self>,
17055    ) {
17056        self.render_diff_hunk_controls = render_diff_hunk_controls;
17057        cx.notify();
17058    }
17059
17060    pub fn stage_and_next(
17061        &mut self,
17062        _: &::git::StageAndNext,
17063        window: &mut Window,
17064        cx: &mut Context<Self>,
17065    ) {
17066        self.do_stage_or_unstage_and_next(true, window, cx);
17067    }
17068
17069    pub fn unstage_and_next(
17070        &mut self,
17071        _: &::git::UnstageAndNext,
17072        window: &mut Window,
17073        cx: &mut Context<Self>,
17074    ) {
17075        self.do_stage_or_unstage_and_next(false, window, cx);
17076    }
17077
17078    pub fn stage_or_unstage_diff_hunks(
17079        &mut self,
17080        stage: bool,
17081        ranges: Vec<Range<Anchor>>,
17082        cx: &mut Context<Self>,
17083    ) {
17084        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17085        cx.spawn(async move |this, cx| {
17086            task.await?;
17087            this.update(cx, |this, cx| {
17088                let snapshot = this.buffer.read(cx).snapshot(cx);
17089                let chunk_by = this
17090                    .diff_hunks_in_ranges(&ranges, &snapshot)
17091                    .chunk_by(|hunk| hunk.buffer_id);
17092                for (buffer_id, hunks) in &chunk_by {
17093                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17094                }
17095            })
17096        })
17097        .detach_and_log_err(cx);
17098    }
17099
17100    fn save_buffers_for_ranges_if_needed(
17101        &mut self,
17102        ranges: &[Range<Anchor>],
17103        cx: &mut Context<Editor>,
17104    ) -> Task<Result<()>> {
17105        let multibuffer = self.buffer.read(cx);
17106        let snapshot = multibuffer.read(cx);
17107        let buffer_ids: HashSet<_> = ranges
17108            .iter()
17109            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17110            .collect();
17111        drop(snapshot);
17112
17113        let mut buffers = HashSet::default();
17114        for buffer_id in buffer_ids {
17115            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17116                let buffer = buffer_entity.read(cx);
17117                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17118                {
17119                    buffers.insert(buffer_entity);
17120                }
17121            }
17122        }
17123
17124        if let Some(project) = &self.project {
17125            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17126        } else {
17127            Task::ready(Ok(()))
17128        }
17129    }
17130
17131    fn do_stage_or_unstage_and_next(
17132        &mut self,
17133        stage: bool,
17134        window: &mut Window,
17135        cx: &mut Context<Self>,
17136    ) {
17137        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17138
17139        if ranges.iter().any(|range| range.start != range.end) {
17140            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17141            return;
17142        }
17143
17144        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17145        let snapshot = self.snapshot(window, cx);
17146        let position = self.selections.newest::<Point>(cx).head();
17147        let mut row = snapshot
17148            .buffer_snapshot
17149            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17150            .find(|hunk| hunk.row_range.start.0 > position.row)
17151            .map(|hunk| hunk.row_range.start);
17152
17153        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17154        // Outside of the project diff editor, wrap around to the beginning.
17155        if !all_diff_hunks_expanded {
17156            row = row.or_else(|| {
17157                snapshot
17158                    .buffer_snapshot
17159                    .diff_hunks_in_range(Point::zero()..position)
17160                    .find(|hunk| hunk.row_range.end.0 < position.row)
17161                    .map(|hunk| hunk.row_range.start)
17162            });
17163        }
17164
17165        if let Some(row) = row {
17166            let destination = Point::new(row.0, 0);
17167            let autoscroll = Autoscroll::center();
17168
17169            self.unfold_ranges(&[destination..destination], false, false, cx);
17170            self.change_selections(Some(autoscroll), window, cx, |s| {
17171                s.select_ranges([destination..destination]);
17172            });
17173        }
17174    }
17175
17176    fn do_stage_or_unstage(
17177        &self,
17178        stage: bool,
17179        buffer_id: BufferId,
17180        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17181        cx: &mut App,
17182    ) -> Option<()> {
17183        let project = self.project.as_ref()?;
17184        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17185        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17186        let buffer_snapshot = buffer.read(cx).snapshot();
17187        let file_exists = buffer_snapshot
17188            .file()
17189            .is_some_and(|file| file.disk_state().exists());
17190        diff.update(cx, |diff, cx| {
17191            diff.stage_or_unstage_hunks(
17192                stage,
17193                &hunks
17194                    .map(|hunk| buffer_diff::DiffHunk {
17195                        buffer_range: hunk.buffer_range,
17196                        diff_base_byte_range: hunk.diff_base_byte_range,
17197                        secondary_status: hunk.secondary_status,
17198                        range: Point::zero()..Point::zero(), // unused
17199                    })
17200                    .collect::<Vec<_>>(),
17201                &buffer_snapshot,
17202                file_exists,
17203                cx,
17204            )
17205        });
17206        None
17207    }
17208
17209    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17210        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17211        self.buffer
17212            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17213    }
17214
17215    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17216        self.buffer.update(cx, |buffer, cx| {
17217            let ranges = vec![Anchor::min()..Anchor::max()];
17218            if !buffer.all_diff_hunks_expanded()
17219                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17220            {
17221                buffer.collapse_diff_hunks(ranges, cx);
17222                true
17223            } else {
17224                false
17225            }
17226        })
17227    }
17228
17229    fn toggle_diff_hunks_in_ranges(
17230        &mut self,
17231        ranges: Vec<Range<Anchor>>,
17232        cx: &mut Context<Editor>,
17233    ) {
17234        self.buffer.update(cx, |buffer, cx| {
17235            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17236            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17237        })
17238    }
17239
17240    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17241        self.buffer.update(cx, |buffer, cx| {
17242            let snapshot = buffer.snapshot(cx);
17243            let excerpt_id = range.end.excerpt_id;
17244            let point_range = range.to_point(&snapshot);
17245            let expand = !buffer.single_hunk_is_expanded(range, cx);
17246            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17247        })
17248    }
17249
17250    pub(crate) fn apply_all_diff_hunks(
17251        &mut self,
17252        _: &ApplyAllDiffHunks,
17253        window: &mut Window,
17254        cx: &mut Context<Self>,
17255    ) {
17256        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17257
17258        let buffers = self.buffer.read(cx).all_buffers();
17259        for branch_buffer in buffers {
17260            branch_buffer.update(cx, |branch_buffer, cx| {
17261                branch_buffer.merge_into_base(Vec::new(), cx);
17262            });
17263        }
17264
17265        if let Some(project) = self.project.clone() {
17266            self.save(
17267                SaveOptions {
17268                    format: true,
17269                    autosave: false,
17270                },
17271                project,
17272                window,
17273                cx,
17274            )
17275            .detach_and_log_err(cx);
17276        }
17277    }
17278
17279    pub(crate) fn apply_selected_diff_hunks(
17280        &mut self,
17281        _: &ApplyDiffHunk,
17282        window: &mut Window,
17283        cx: &mut Context<Self>,
17284    ) {
17285        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17286        let snapshot = self.snapshot(window, cx);
17287        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17288        let mut ranges_by_buffer = HashMap::default();
17289        self.transact(window, cx, |editor, _window, cx| {
17290            for hunk in hunks {
17291                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17292                    ranges_by_buffer
17293                        .entry(buffer.clone())
17294                        .or_insert_with(Vec::new)
17295                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17296                }
17297            }
17298
17299            for (buffer, ranges) in ranges_by_buffer {
17300                buffer.update(cx, |buffer, cx| {
17301                    buffer.merge_into_base(ranges, cx);
17302                });
17303            }
17304        });
17305
17306        if let Some(project) = self.project.clone() {
17307            self.save(
17308                SaveOptions {
17309                    format: true,
17310                    autosave: false,
17311                },
17312                project,
17313                window,
17314                cx,
17315            )
17316            .detach_and_log_err(cx);
17317        }
17318    }
17319
17320    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17321        if hovered != self.gutter_hovered {
17322            self.gutter_hovered = hovered;
17323            cx.notify();
17324        }
17325    }
17326
17327    pub fn insert_blocks(
17328        &mut self,
17329        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17330        autoscroll: Option<Autoscroll>,
17331        cx: &mut Context<Self>,
17332    ) -> Vec<CustomBlockId> {
17333        let blocks = self
17334            .display_map
17335            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17336        if let Some(autoscroll) = autoscroll {
17337            self.request_autoscroll(autoscroll, cx);
17338        }
17339        cx.notify();
17340        blocks
17341    }
17342
17343    pub fn resize_blocks(
17344        &mut self,
17345        heights: HashMap<CustomBlockId, u32>,
17346        autoscroll: Option<Autoscroll>,
17347        cx: &mut Context<Self>,
17348    ) {
17349        self.display_map
17350            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17351        if let Some(autoscroll) = autoscroll {
17352            self.request_autoscroll(autoscroll, cx);
17353        }
17354        cx.notify();
17355    }
17356
17357    pub fn replace_blocks(
17358        &mut self,
17359        renderers: HashMap<CustomBlockId, RenderBlock>,
17360        autoscroll: Option<Autoscroll>,
17361        cx: &mut Context<Self>,
17362    ) {
17363        self.display_map
17364            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17365        if let Some(autoscroll) = autoscroll {
17366            self.request_autoscroll(autoscroll, cx);
17367        }
17368        cx.notify();
17369    }
17370
17371    pub fn remove_blocks(
17372        &mut self,
17373        block_ids: HashSet<CustomBlockId>,
17374        autoscroll: Option<Autoscroll>,
17375        cx: &mut Context<Self>,
17376    ) {
17377        self.display_map.update(cx, |display_map, cx| {
17378            display_map.remove_blocks(block_ids, cx)
17379        });
17380        if let Some(autoscroll) = autoscroll {
17381            self.request_autoscroll(autoscroll, cx);
17382        }
17383        cx.notify();
17384    }
17385
17386    pub fn row_for_block(
17387        &self,
17388        block_id: CustomBlockId,
17389        cx: &mut Context<Self>,
17390    ) -> Option<DisplayRow> {
17391        self.display_map
17392            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17393    }
17394
17395    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17396        self.focused_block = Some(focused_block);
17397    }
17398
17399    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17400        self.focused_block.take()
17401    }
17402
17403    pub fn insert_creases(
17404        &mut self,
17405        creases: impl IntoIterator<Item = Crease<Anchor>>,
17406        cx: &mut Context<Self>,
17407    ) -> Vec<CreaseId> {
17408        self.display_map
17409            .update(cx, |map, cx| map.insert_creases(creases, cx))
17410    }
17411
17412    pub fn remove_creases(
17413        &mut self,
17414        ids: impl IntoIterator<Item = CreaseId>,
17415        cx: &mut Context<Self>,
17416    ) -> Vec<(CreaseId, Range<Anchor>)> {
17417        self.display_map
17418            .update(cx, |map, cx| map.remove_creases(ids, cx))
17419    }
17420
17421    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17422        self.display_map
17423            .update(cx, |map, cx| map.snapshot(cx))
17424            .longest_row()
17425    }
17426
17427    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17428        self.display_map
17429            .update(cx, |map, cx| map.snapshot(cx))
17430            .max_point()
17431    }
17432
17433    pub fn text(&self, cx: &App) -> String {
17434        self.buffer.read(cx).read(cx).text()
17435    }
17436
17437    pub fn is_empty(&self, cx: &App) -> bool {
17438        self.buffer.read(cx).read(cx).is_empty()
17439    }
17440
17441    pub fn text_option(&self, cx: &App) -> Option<String> {
17442        let text = self.text(cx);
17443        let text = text.trim();
17444
17445        if text.is_empty() {
17446            return None;
17447        }
17448
17449        Some(text.to_string())
17450    }
17451
17452    pub fn set_text(
17453        &mut self,
17454        text: impl Into<Arc<str>>,
17455        window: &mut Window,
17456        cx: &mut Context<Self>,
17457    ) {
17458        self.transact(window, cx, |this, _, cx| {
17459            this.buffer
17460                .read(cx)
17461                .as_singleton()
17462                .expect("you can only call set_text on editors for singleton buffers")
17463                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17464        });
17465    }
17466
17467    pub fn display_text(&self, cx: &mut App) -> String {
17468        self.display_map
17469            .update(cx, |map, cx| map.snapshot(cx))
17470            .text()
17471    }
17472
17473    fn create_minimap(
17474        &self,
17475        minimap_settings: MinimapSettings,
17476        window: &mut Window,
17477        cx: &mut Context<Self>,
17478    ) -> Option<Entity<Self>> {
17479        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17480            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17481    }
17482
17483    fn initialize_new_minimap(
17484        &self,
17485        minimap_settings: MinimapSettings,
17486        window: &mut Window,
17487        cx: &mut Context<Self>,
17488    ) -> Entity<Self> {
17489        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17490
17491        let mut minimap = Editor::new_internal(
17492            EditorMode::Minimap {
17493                parent: cx.weak_entity(),
17494            },
17495            self.buffer.clone(),
17496            self.project.clone(),
17497            Some(self.display_map.clone()),
17498            window,
17499            cx,
17500        );
17501        minimap.scroll_manager.clone_state(&self.scroll_manager);
17502        minimap.set_text_style_refinement(TextStyleRefinement {
17503            font_size: Some(MINIMAP_FONT_SIZE),
17504            font_weight: Some(MINIMAP_FONT_WEIGHT),
17505            ..Default::default()
17506        });
17507        minimap.update_minimap_configuration(minimap_settings, cx);
17508        cx.new(|_| minimap)
17509    }
17510
17511    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17512        let current_line_highlight = minimap_settings
17513            .current_line_highlight
17514            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17515        self.set_current_line_highlight(Some(current_line_highlight));
17516    }
17517
17518    pub fn minimap(&self) -> Option<&Entity<Self>> {
17519        self.minimap
17520            .as_ref()
17521            .filter(|_| self.minimap_visibility.visible())
17522    }
17523
17524    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17525        let mut wrap_guides = smallvec![];
17526
17527        if self.show_wrap_guides == Some(false) {
17528            return wrap_guides;
17529        }
17530
17531        let settings = self.buffer.read(cx).language_settings(cx);
17532        if settings.show_wrap_guides {
17533            match self.soft_wrap_mode(cx) {
17534                SoftWrap::Column(soft_wrap) => {
17535                    wrap_guides.push((soft_wrap as usize, true));
17536                }
17537                SoftWrap::Bounded(soft_wrap) => {
17538                    wrap_guides.push((soft_wrap as usize, true));
17539                }
17540                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17541            }
17542            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17543        }
17544
17545        wrap_guides
17546    }
17547
17548    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17549        let settings = self.buffer.read(cx).language_settings(cx);
17550        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17551        match mode {
17552            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17553                SoftWrap::None
17554            }
17555            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17556            language_settings::SoftWrap::PreferredLineLength => {
17557                SoftWrap::Column(settings.preferred_line_length)
17558            }
17559            language_settings::SoftWrap::Bounded => {
17560                SoftWrap::Bounded(settings.preferred_line_length)
17561            }
17562        }
17563    }
17564
17565    pub fn set_soft_wrap_mode(
17566        &mut self,
17567        mode: language_settings::SoftWrap,
17568
17569        cx: &mut Context<Self>,
17570    ) {
17571        self.soft_wrap_mode_override = Some(mode);
17572        cx.notify();
17573    }
17574
17575    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17576        self.hard_wrap = hard_wrap;
17577        cx.notify();
17578    }
17579
17580    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17581        self.text_style_refinement = Some(style);
17582    }
17583
17584    /// called by the Element so we know what style we were most recently rendered with.
17585    pub(crate) fn set_style(
17586        &mut self,
17587        style: EditorStyle,
17588        window: &mut Window,
17589        cx: &mut Context<Self>,
17590    ) {
17591        // We intentionally do not inform the display map about the minimap style
17592        // so that wrapping is not recalculated and stays consistent for the editor
17593        // and its linked minimap.
17594        if !self.mode.is_minimap() {
17595            let rem_size = window.rem_size();
17596            self.display_map.update(cx, |map, cx| {
17597                map.set_font(
17598                    style.text.font(),
17599                    style.text.font_size.to_pixels(rem_size),
17600                    cx,
17601                )
17602            });
17603        }
17604        self.style = Some(style);
17605    }
17606
17607    pub fn style(&self) -> Option<&EditorStyle> {
17608        self.style.as_ref()
17609    }
17610
17611    // Called by the element. This method is not designed to be called outside of the editor
17612    // element's layout code because it does not notify when rewrapping is computed synchronously.
17613    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17614        self.display_map
17615            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17616    }
17617
17618    pub fn set_soft_wrap(&mut self) {
17619        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17620    }
17621
17622    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17623        if self.soft_wrap_mode_override.is_some() {
17624            self.soft_wrap_mode_override.take();
17625        } else {
17626            let soft_wrap = match self.soft_wrap_mode(cx) {
17627                SoftWrap::GitDiff => return,
17628                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17629                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17630                    language_settings::SoftWrap::None
17631                }
17632            };
17633            self.soft_wrap_mode_override = Some(soft_wrap);
17634        }
17635        cx.notify();
17636    }
17637
17638    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17639        let Some(workspace) = self.workspace() else {
17640            return;
17641        };
17642        let fs = workspace.read(cx).app_state().fs.clone();
17643        let current_show = TabBarSettings::get_global(cx).show;
17644        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17645            setting.show = Some(!current_show);
17646        });
17647    }
17648
17649    pub fn toggle_indent_guides(
17650        &mut self,
17651        _: &ToggleIndentGuides,
17652        _: &mut Window,
17653        cx: &mut Context<Self>,
17654    ) {
17655        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17656            self.buffer
17657                .read(cx)
17658                .language_settings(cx)
17659                .indent_guides
17660                .enabled
17661        });
17662        self.show_indent_guides = Some(!currently_enabled);
17663        cx.notify();
17664    }
17665
17666    fn should_show_indent_guides(&self) -> Option<bool> {
17667        self.show_indent_guides
17668    }
17669
17670    pub fn toggle_line_numbers(
17671        &mut self,
17672        _: &ToggleLineNumbers,
17673        _: &mut Window,
17674        cx: &mut Context<Self>,
17675    ) {
17676        let mut editor_settings = EditorSettings::get_global(cx).clone();
17677        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17678        EditorSettings::override_global(editor_settings, cx);
17679    }
17680
17681    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17682        if let Some(show_line_numbers) = self.show_line_numbers {
17683            return show_line_numbers;
17684        }
17685        EditorSettings::get_global(cx).gutter.line_numbers
17686    }
17687
17688    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17689        self.use_relative_line_numbers
17690            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17691    }
17692
17693    pub fn toggle_relative_line_numbers(
17694        &mut self,
17695        _: &ToggleRelativeLineNumbers,
17696        _: &mut Window,
17697        cx: &mut Context<Self>,
17698    ) {
17699        let is_relative = self.should_use_relative_line_numbers(cx);
17700        self.set_relative_line_number(Some(!is_relative), cx)
17701    }
17702
17703    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17704        self.use_relative_line_numbers = is_relative;
17705        cx.notify();
17706    }
17707
17708    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17709        self.show_gutter = show_gutter;
17710        cx.notify();
17711    }
17712
17713    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17714        self.show_scrollbars = ScrollbarAxes {
17715            horizontal: show,
17716            vertical: show,
17717        };
17718        cx.notify();
17719    }
17720
17721    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17722        self.show_scrollbars.vertical = show;
17723        cx.notify();
17724    }
17725
17726    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17727        self.show_scrollbars.horizontal = show;
17728        cx.notify();
17729    }
17730
17731    pub fn set_minimap_visibility(
17732        &mut self,
17733        minimap_visibility: MinimapVisibility,
17734        window: &mut Window,
17735        cx: &mut Context<Self>,
17736    ) {
17737        if self.minimap_visibility != minimap_visibility {
17738            if minimap_visibility.visible() && self.minimap.is_none() {
17739                let minimap_settings = EditorSettings::get_global(cx).minimap;
17740                self.minimap =
17741                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17742            }
17743            self.minimap_visibility = minimap_visibility;
17744            cx.notify();
17745        }
17746    }
17747
17748    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17749        self.set_show_scrollbars(false, cx);
17750        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17751    }
17752
17753    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17754        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17755    }
17756
17757    /// Normally the text in full mode and auto height editors is padded on the
17758    /// left side by roughly half a character width for improved hit testing.
17759    ///
17760    /// Use this method to disable this for cases where this is not wanted (e.g.
17761    /// if you want to align the editor text with some other text above or below)
17762    /// or if you want to add this padding to single-line editors.
17763    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17764        self.offset_content = offset_content;
17765        cx.notify();
17766    }
17767
17768    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17769        self.show_line_numbers = Some(show_line_numbers);
17770        cx.notify();
17771    }
17772
17773    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17774        self.disable_expand_excerpt_buttons = true;
17775        cx.notify();
17776    }
17777
17778    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17779        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17780        cx.notify();
17781    }
17782
17783    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17784        self.show_code_actions = Some(show_code_actions);
17785        cx.notify();
17786    }
17787
17788    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17789        self.show_runnables = Some(show_runnables);
17790        cx.notify();
17791    }
17792
17793    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17794        self.show_breakpoints = Some(show_breakpoints);
17795        cx.notify();
17796    }
17797
17798    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17799        if self.display_map.read(cx).masked != masked {
17800            self.display_map.update(cx, |map, _| map.masked = masked);
17801        }
17802        cx.notify()
17803    }
17804
17805    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17806        self.show_wrap_guides = Some(show_wrap_guides);
17807        cx.notify();
17808    }
17809
17810    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17811        self.show_indent_guides = Some(show_indent_guides);
17812        cx.notify();
17813    }
17814
17815    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17816        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17817            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17818                if let Some(dir) = file.abs_path(cx).parent() {
17819                    return Some(dir.to_owned());
17820                }
17821            }
17822
17823            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17824                return Some(project_path.path.to_path_buf());
17825            }
17826        }
17827
17828        None
17829    }
17830
17831    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17832        self.active_excerpt(cx)?
17833            .1
17834            .read(cx)
17835            .file()
17836            .and_then(|f| f.as_local())
17837    }
17838
17839    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17840        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17841            let buffer = buffer.read(cx);
17842            if let Some(project_path) = buffer.project_path(cx) {
17843                let project = self.project.as_ref()?.read(cx);
17844                project.absolute_path(&project_path, cx)
17845            } else {
17846                buffer
17847                    .file()
17848                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17849            }
17850        })
17851    }
17852
17853    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17854        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17855            let project_path = buffer.read(cx).project_path(cx)?;
17856            let project = self.project.as_ref()?.read(cx);
17857            let entry = project.entry_for_path(&project_path, cx)?;
17858            let path = entry.path.to_path_buf();
17859            Some(path)
17860        })
17861    }
17862
17863    pub fn reveal_in_finder(
17864        &mut self,
17865        _: &RevealInFileManager,
17866        _window: &mut Window,
17867        cx: &mut Context<Self>,
17868    ) {
17869        if let Some(target) = self.target_file(cx) {
17870            cx.reveal_path(&target.abs_path(cx));
17871        }
17872    }
17873
17874    pub fn copy_path(
17875        &mut self,
17876        _: &zed_actions::workspace::CopyPath,
17877        _window: &mut Window,
17878        cx: &mut Context<Self>,
17879    ) {
17880        if let Some(path) = self.target_file_abs_path(cx) {
17881            if let Some(path) = path.to_str() {
17882                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17883            }
17884        }
17885    }
17886
17887    pub fn copy_relative_path(
17888        &mut self,
17889        _: &zed_actions::workspace::CopyRelativePath,
17890        _window: &mut Window,
17891        cx: &mut Context<Self>,
17892    ) {
17893        if let Some(path) = self.target_file_path(cx) {
17894            if let Some(path) = path.to_str() {
17895                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17896            }
17897        }
17898    }
17899
17900    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17901        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17902            buffer.read(cx).project_path(cx)
17903        } else {
17904            None
17905        }
17906    }
17907
17908    // Returns true if the editor handled a go-to-line request
17909    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17910        maybe!({
17911            let breakpoint_store = self.breakpoint_store.as_ref()?;
17912
17913            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17914            else {
17915                self.clear_row_highlights::<ActiveDebugLine>();
17916                return None;
17917            };
17918
17919            let position = active_stack_frame.position;
17920            let buffer_id = position.buffer_id?;
17921            let snapshot = self
17922                .project
17923                .as_ref()?
17924                .read(cx)
17925                .buffer_for_id(buffer_id, cx)?
17926                .read(cx)
17927                .snapshot();
17928
17929            let mut handled = false;
17930            for (id, ExcerptRange { context, .. }) in
17931                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17932            {
17933                if context.start.cmp(&position, &snapshot).is_ge()
17934                    || context.end.cmp(&position, &snapshot).is_lt()
17935                {
17936                    continue;
17937                }
17938                let snapshot = self.buffer.read(cx).snapshot(cx);
17939                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17940
17941                handled = true;
17942                self.clear_row_highlights::<ActiveDebugLine>();
17943
17944                self.go_to_line::<ActiveDebugLine>(
17945                    multibuffer_anchor,
17946                    Some(cx.theme().colors().editor_debugger_active_line_background),
17947                    window,
17948                    cx,
17949                );
17950
17951                cx.notify();
17952            }
17953
17954            handled.then_some(())
17955        })
17956        .is_some()
17957    }
17958
17959    pub fn copy_file_name_without_extension(
17960        &mut self,
17961        _: &CopyFileNameWithoutExtension,
17962        _: &mut Window,
17963        cx: &mut Context<Self>,
17964    ) {
17965        if let Some(file) = self.target_file(cx) {
17966            if let Some(file_stem) = file.path().file_stem() {
17967                if let Some(name) = file_stem.to_str() {
17968                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17969                }
17970            }
17971        }
17972    }
17973
17974    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17975        if let Some(file) = self.target_file(cx) {
17976            if let Some(file_name) = file.path().file_name() {
17977                if let Some(name) = file_name.to_str() {
17978                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17979                }
17980            }
17981        }
17982    }
17983
17984    pub fn toggle_git_blame(
17985        &mut self,
17986        _: &::git::Blame,
17987        window: &mut Window,
17988        cx: &mut Context<Self>,
17989    ) {
17990        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17991
17992        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17993            self.start_git_blame(true, window, cx);
17994        }
17995
17996        cx.notify();
17997    }
17998
17999    pub fn toggle_git_blame_inline(
18000        &mut self,
18001        _: &ToggleGitBlameInline,
18002        window: &mut Window,
18003        cx: &mut Context<Self>,
18004    ) {
18005        self.toggle_git_blame_inline_internal(true, window, cx);
18006        cx.notify();
18007    }
18008
18009    pub fn open_git_blame_commit(
18010        &mut self,
18011        _: &OpenGitBlameCommit,
18012        window: &mut Window,
18013        cx: &mut Context<Self>,
18014    ) {
18015        self.open_git_blame_commit_internal(window, cx);
18016    }
18017
18018    fn open_git_blame_commit_internal(
18019        &mut self,
18020        window: &mut Window,
18021        cx: &mut Context<Self>,
18022    ) -> Option<()> {
18023        let blame = self.blame.as_ref()?;
18024        let snapshot = self.snapshot(window, cx);
18025        let cursor = self.selections.newest::<Point>(cx).head();
18026        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18027        let blame_entry = blame
18028            .update(cx, |blame, cx| {
18029                blame
18030                    .blame_for_rows(
18031                        &[RowInfo {
18032                            buffer_id: Some(buffer.remote_id()),
18033                            buffer_row: Some(point.row),
18034                            ..Default::default()
18035                        }],
18036                        cx,
18037                    )
18038                    .next()
18039            })
18040            .flatten()?;
18041        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18042        let repo = blame.read(cx).repository(cx)?;
18043        let workspace = self.workspace()?.downgrade();
18044        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18045        None
18046    }
18047
18048    pub fn git_blame_inline_enabled(&self) -> bool {
18049        self.git_blame_inline_enabled
18050    }
18051
18052    pub fn toggle_selection_menu(
18053        &mut self,
18054        _: &ToggleSelectionMenu,
18055        _: &mut Window,
18056        cx: &mut Context<Self>,
18057    ) {
18058        self.show_selection_menu = self
18059            .show_selection_menu
18060            .map(|show_selections_menu| !show_selections_menu)
18061            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18062
18063        cx.notify();
18064    }
18065
18066    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18067        self.show_selection_menu
18068            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18069    }
18070
18071    fn start_git_blame(
18072        &mut self,
18073        user_triggered: bool,
18074        window: &mut Window,
18075        cx: &mut Context<Self>,
18076    ) {
18077        if let Some(project) = self.project.as_ref() {
18078            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18079                return;
18080            };
18081
18082            if buffer.read(cx).file().is_none() {
18083                return;
18084            }
18085
18086            let focused = self.focus_handle(cx).contains_focused(window, cx);
18087
18088            let project = project.clone();
18089            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18090            self.blame_subscription =
18091                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18092            self.blame = Some(blame);
18093        }
18094    }
18095
18096    fn toggle_git_blame_inline_internal(
18097        &mut self,
18098        user_triggered: bool,
18099        window: &mut Window,
18100        cx: &mut Context<Self>,
18101    ) {
18102        if self.git_blame_inline_enabled {
18103            self.git_blame_inline_enabled = false;
18104            self.show_git_blame_inline = false;
18105            self.show_git_blame_inline_delay_task.take();
18106        } else {
18107            self.git_blame_inline_enabled = true;
18108            self.start_git_blame_inline(user_triggered, window, cx);
18109        }
18110
18111        cx.notify();
18112    }
18113
18114    fn start_git_blame_inline(
18115        &mut self,
18116        user_triggered: bool,
18117        window: &mut Window,
18118        cx: &mut Context<Self>,
18119    ) {
18120        self.start_git_blame(user_triggered, window, cx);
18121
18122        if ProjectSettings::get_global(cx)
18123            .git
18124            .inline_blame_delay()
18125            .is_some()
18126        {
18127            self.start_inline_blame_timer(window, cx);
18128        } else {
18129            self.show_git_blame_inline = true
18130        }
18131    }
18132
18133    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18134        self.blame.as_ref()
18135    }
18136
18137    pub fn show_git_blame_gutter(&self) -> bool {
18138        self.show_git_blame_gutter
18139    }
18140
18141    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18142        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18143    }
18144
18145    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18146        self.show_git_blame_inline
18147            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18148            && !self.newest_selection_head_on_empty_line(cx)
18149            && self.has_blame_entries(cx)
18150    }
18151
18152    fn has_blame_entries(&self, cx: &App) -> bool {
18153        self.blame()
18154            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18155    }
18156
18157    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18158        let cursor_anchor = self.selections.newest_anchor().head();
18159
18160        let snapshot = self.buffer.read(cx).snapshot(cx);
18161        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18162
18163        snapshot.line_len(buffer_row) == 0
18164    }
18165
18166    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18167        let buffer_and_selection = maybe!({
18168            let selection = self.selections.newest::<Point>(cx);
18169            let selection_range = selection.range();
18170
18171            let multi_buffer = self.buffer().read(cx);
18172            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18173            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18174
18175            let (buffer, range, _) = if selection.reversed {
18176                buffer_ranges.first()
18177            } else {
18178                buffer_ranges.last()
18179            }?;
18180
18181            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18182                ..text::ToPoint::to_point(&range.end, &buffer).row;
18183            Some((
18184                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18185                selection,
18186            ))
18187        });
18188
18189        let Some((buffer, selection)) = buffer_and_selection else {
18190            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18191        };
18192
18193        let Some(project) = self.project.as_ref() else {
18194            return Task::ready(Err(anyhow!("editor does not have project")));
18195        };
18196
18197        project.update(cx, |project, cx| {
18198            project.get_permalink_to_line(&buffer, selection, cx)
18199        })
18200    }
18201
18202    pub fn copy_permalink_to_line(
18203        &mut self,
18204        _: &CopyPermalinkToLine,
18205        window: &mut Window,
18206        cx: &mut Context<Self>,
18207    ) {
18208        let permalink_task = self.get_permalink_to_line(cx);
18209        let workspace = self.workspace();
18210
18211        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18212            Ok(permalink) => {
18213                cx.update(|_, cx| {
18214                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18215                })
18216                .ok();
18217            }
18218            Err(err) => {
18219                let message = format!("Failed to copy permalink: {err}");
18220
18221                anyhow::Result::<()>::Err(err).log_err();
18222
18223                if let Some(workspace) = workspace {
18224                    workspace
18225                        .update_in(cx, |workspace, _, cx| {
18226                            struct CopyPermalinkToLine;
18227
18228                            workspace.show_toast(
18229                                Toast::new(
18230                                    NotificationId::unique::<CopyPermalinkToLine>(),
18231                                    message,
18232                                ),
18233                                cx,
18234                            )
18235                        })
18236                        .ok();
18237                }
18238            }
18239        })
18240        .detach();
18241    }
18242
18243    pub fn copy_file_location(
18244        &mut self,
18245        _: &CopyFileLocation,
18246        _: &mut Window,
18247        cx: &mut Context<Self>,
18248    ) {
18249        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18250        if let Some(file) = self.target_file(cx) {
18251            if let Some(path) = file.path().to_str() {
18252                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18253            }
18254        }
18255    }
18256
18257    pub fn open_permalink_to_line(
18258        &mut self,
18259        _: &OpenPermalinkToLine,
18260        window: &mut Window,
18261        cx: &mut Context<Self>,
18262    ) {
18263        let permalink_task = self.get_permalink_to_line(cx);
18264        let workspace = self.workspace();
18265
18266        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18267            Ok(permalink) => {
18268                cx.update(|_, cx| {
18269                    cx.open_url(permalink.as_ref());
18270                })
18271                .ok();
18272            }
18273            Err(err) => {
18274                let message = format!("Failed to open permalink: {err}");
18275
18276                anyhow::Result::<()>::Err(err).log_err();
18277
18278                if let Some(workspace) = workspace {
18279                    workspace
18280                        .update(cx, |workspace, cx| {
18281                            struct OpenPermalinkToLine;
18282
18283                            workspace.show_toast(
18284                                Toast::new(
18285                                    NotificationId::unique::<OpenPermalinkToLine>(),
18286                                    message,
18287                                ),
18288                                cx,
18289                            )
18290                        })
18291                        .ok();
18292                }
18293            }
18294        })
18295        .detach();
18296    }
18297
18298    pub fn insert_uuid_v4(
18299        &mut self,
18300        _: &InsertUuidV4,
18301        window: &mut Window,
18302        cx: &mut Context<Self>,
18303    ) {
18304        self.insert_uuid(UuidVersion::V4, window, cx);
18305    }
18306
18307    pub fn insert_uuid_v7(
18308        &mut self,
18309        _: &InsertUuidV7,
18310        window: &mut Window,
18311        cx: &mut Context<Self>,
18312    ) {
18313        self.insert_uuid(UuidVersion::V7, window, cx);
18314    }
18315
18316    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18318        self.transact(window, cx, |this, window, cx| {
18319            let edits = this
18320                .selections
18321                .all::<Point>(cx)
18322                .into_iter()
18323                .map(|selection| {
18324                    let uuid = match version {
18325                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18326                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18327                    };
18328
18329                    (selection.range(), uuid.to_string())
18330                });
18331            this.edit(edits, cx);
18332            this.refresh_inline_completion(true, false, window, cx);
18333        });
18334    }
18335
18336    pub fn open_selections_in_multibuffer(
18337        &mut self,
18338        _: &OpenSelectionsInMultibuffer,
18339        window: &mut Window,
18340        cx: &mut Context<Self>,
18341    ) {
18342        let multibuffer = self.buffer.read(cx);
18343
18344        let Some(buffer) = multibuffer.as_singleton() else {
18345            return;
18346        };
18347
18348        let Some(workspace) = self.workspace() else {
18349            return;
18350        };
18351
18352        let title = multibuffer.title(cx).to_string();
18353
18354        let locations = self
18355            .selections
18356            .all_anchors(cx)
18357            .into_iter()
18358            .map(|selection| Location {
18359                buffer: buffer.clone(),
18360                range: selection.start.text_anchor..selection.end.text_anchor,
18361            })
18362            .collect::<Vec<_>>();
18363
18364        cx.spawn_in(window, async move |_, cx| {
18365            workspace.update_in(cx, |workspace, window, cx| {
18366                Self::open_locations_in_multibuffer(
18367                    workspace,
18368                    locations,
18369                    format!("Selections for '{title}'"),
18370                    false,
18371                    MultibufferSelectionMode::All,
18372                    window,
18373                    cx,
18374                );
18375            })
18376        })
18377        .detach();
18378    }
18379
18380    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18381    /// last highlight added will be used.
18382    ///
18383    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18384    pub fn highlight_rows<T: 'static>(
18385        &mut self,
18386        range: Range<Anchor>,
18387        color: Hsla,
18388        options: RowHighlightOptions,
18389        cx: &mut Context<Self>,
18390    ) {
18391        let snapshot = self.buffer().read(cx).snapshot(cx);
18392        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18393        let ix = row_highlights.binary_search_by(|highlight| {
18394            Ordering::Equal
18395                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18396                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18397        });
18398
18399        if let Err(mut ix) = ix {
18400            let index = post_inc(&mut self.highlight_order);
18401
18402            // If this range intersects with the preceding highlight, then merge it with
18403            // the preceding highlight. Otherwise insert a new highlight.
18404            let mut merged = false;
18405            if ix > 0 {
18406                let prev_highlight = &mut row_highlights[ix - 1];
18407                if prev_highlight
18408                    .range
18409                    .end
18410                    .cmp(&range.start, &snapshot)
18411                    .is_ge()
18412                {
18413                    ix -= 1;
18414                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18415                        prev_highlight.range.end = range.end;
18416                    }
18417                    merged = true;
18418                    prev_highlight.index = index;
18419                    prev_highlight.color = color;
18420                    prev_highlight.options = options;
18421                }
18422            }
18423
18424            if !merged {
18425                row_highlights.insert(
18426                    ix,
18427                    RowHighlight {
18428                        range: range.clone(),
18429                        index,
18430                        color,
18431                        options,
18432                        type_id: TypeId::of::<T>(),
18433                    },
18434                );
18435            }
18436
18437            // If any of the following highlights intersect with this one, merge them.
18438            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18439                let highlight = &row_highlights[ix];
18440                if next_highlight
18441                    .range
18442                    .start
18443                    .cmp(&highlight.range.end, &snapshot)
18444                    .is_le()
18445                {
18446                    if next_highlight
18447                        .range
18448                        .end
18449                        .cmp(&highlight.range.end, &snapshot)
18450                        .is_gt()
18451                    {
18452                        row_highlights[ix].range.end = next_highlight.range.end;
18453                    }
18454                    row_highlights.remove(ix + 1);
18455                } else {
18456                    break;
18457                }
18458            }
18459        }
18460    }
18461
18462    /// Remove any highlighted row ranges of the given type that intersect the
18463    /// given ranges.
18464    pub fn remove_highlighted_rows<T: 'static>(
18465        &mut self,
18466        ranges_to_remove: Vec<Range<Anchor>>,
18467        cx: &mut Context<Self>,
18468    ) {
18469        let snapshot = self.buffer().read(cx).snapshot(cx);
18470        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18471        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18472        row_highlights.retain(|highlight| {
18473            while let Some(range_to_remove) = ranges_to_remove.peek() {
18474                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18475                    Ordering::Less | Ordering::Equal => {
18476                        ranges_to_remove.next();
18477                    }
18478                    Ordering::Greater => {
18479                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18480                            Ordering::Less | Ordering::Equal => {
18481                                return false;
18482                            }
18483                            Ordering::Greater => break,
18484                        }
18485                    }
18486                }
18487            }
18488
18489            true
18490        })
18491    }
18492
18493    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18494    pub fn clear_row_highlights<T: 'static>(&mut self) {
18495        self.highlighted_rows.remove(&TypeId::of::<T>());
18496    }
18497
18498    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18499    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18500        self.highlighted_rows
18501            .get(&TypeId::of::<T>())
18502            .map_or(&[] as &[_], |vec| vec.as_slice())
18503            .iter()
18504            .map(|highlight| (highlight.range.clone(), highlight.color))
18505    }
18506
18507    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18508    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18509    /// Allows to ignore certain kinds of highlights.
18510    pub fn highlighted_display_rows(
18511        &self,
18512        window: &mut Window,
18513        cx: &mut App,
18514    ) -> BTreeMap<DisplayRow, LineHighlight> {
18515        let snapshot = self.snapshot(window, cx);
18516        let mut used_highlight_orders = HashMap::default();
18517        self.highlighted_rows
18518            .iter()
18519            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18520            .fold(
18521                BTreeMap::<DisplayRow, LineHighlight>::new(),
18522                |mut unique_rows, highlight| {
18523                    let start = highlight.range.start.to_display_point(&snapshot);
18524                    let end = highlight.range.end.to_display_point(&snapshot);
18525                    let start_row = start.row().0;
18526                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18527                        && end.column() == 0
18528                    {
18529                        end.row().0.saturating_sub(1)
18530                    } else {
18531                        end.row().0
18532                    };
18533                    for row in start_row..=end_row {
18534                        let used_index =
18535                            used_highlight_orders.entry(row).or_insert(highlight.index);
18536                        if highlight.index >= *used_index {
18537                            *used_index = highlight.index;
18538                            unique_rows.insert(
18539                                DisplayRow(row),
18540                                LineHighlight {
18541                                    include_gutter: highlight.options.include_gutter,
18542                                    border: None,
18543                                    background: highlight.color.into(),
18544                                    type_id: Some(highlight.type_id),
18545                                },
18546                            );
18547                        }
18548                    }
18549                    unique_rows
18550                },
18551            )
18552    }
18553
18554    pub fn highlighted_display_row_for_autoscroll(
18555        &self,
18556        snapshot: &DisplaySnapshot,
18557    ) -> Option<DisplayRow> {
18558        self.highlighted_rows
18559            .values()
18560            .flat_map(|highlighted_rows| highlighted_rows.iter())
18561            .filter_map(|highlight| {
18562                if highlight.options.autoscroll {
18563                    Some(highlight.range.start.to_display_point(snapshot).row())
18564                } else {
18565                    None
18566                }
18567            })
18568            .min()
18569    }
18570
18571    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18572        self.highlight_background::<SearchWithinRange>(
18573            ranges,
18574            |theme| theme.colors().editor_document_highlight_read_background,
18575            cx,
18576        )
18577    }
18578
18579    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18580        self.breadcrumb_header = Some(new_header);
18581    }
18582
18583    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18584        self.clear_background_highlights::<SearchWithinRange>(cx);
18585    }
18586
18587    pub fn highlight_background<T: 'static>(
18588        &mut self,
18589        ranges: &[Range<Anchor>],
18590        color_fetcher: fn(&Theme) -> Hsla,
18591        cx: &mut Context<Self>,
18592    ) {
18593        let highlights = ranges
18594            .iter()
18595            .map(|range| BackgroundHighlight {
18596                range: range.clone(),
18597                color_fetcher,
18598            })
18599            .collect();
18600        self.background_highlights
18601            .insert(TypeId::of::<T>(), highlights);
18602        self.scrollbar_marker_state.dirty = true;
18603        cx.notify();
18604    }
18605
18606    pub fn highlight_background_ranges<T: 'static>(
18607        &mut self,
18608        background_highlights: Vec<BackgroundHighlight>,
18609        cx: &mut Context<'_, Editor>,
18610    ) {
18611        self.background_highlights
18612            .insert(TypeId::of::<T>(), background_highlights);
18613        self.scrollbar_marker_state.dirty = true;
18614        cx.notify();
18615    }
18616
18617    pub fn clear_background_highlights<T: 'static>(
18618        &mut self,
18619        cx: &mut Context<Self>,
18620    ) -> Option<Vec<BackgroundHighlight>> {
18621        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18622        if !text_highlights.is_empty() {
18623            self.scrollbar_marker_state.dirty = true;
18624            cx.notify();
18625        }
18626        Some(text_highlights)
18627    }
18628
18629    pub fn highlight_gutter<T: 'static>(
18630        &mut self,
18631        ranges: impl Into<Vec<Range<Anchor>>>,
18632        color_fetcher: fn(&App) -> Hsla,
18633        cx: &mut Context<Self>,
18634    ) {
18635        self.gutter_highlights
18636            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18637        cx.notify();
18638    }
18639
18640    pub fn clear_gutter_highlights<T: 'static>(
18641        &mut self,
18642        cx: &mut Context<Self>,
18643    ) -> Option<GutterHighlight> {
18644        cx.notify();
18645        self.gutter_highlights.remove(&TypeId::of::<T>())
18646    }
18647
18648    pub fn insert_gutter_highlight<T: 'static>(
18649        &mut self,
18650        range: Range<Anchor>,
18651        color_fetcher: fn(&App) -> Hsla,
18652        cx: &mut Context<Self>,
18653    ) {
18654        let snapshot = self.buffer().read(cx).snapshot(cx);
18655        let mut highlights = self
18656            .gutter_highlights
18657            .remove(&TypeId::of::<T>())
18658            .map(|(_, highlights)| highlights)
18659            .unwrap_or_default();
18660        let ix = highlights.binary_search_by(|highlight| {
18661            Ordering::Equal
18662                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18663                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18664        });
18665        if let Err(ix) = ix {
18666            highlights.insert(ix, range);
18667        }
18668        self.gutter_highlights
18669            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18670    }
18671
18672    pub fn remove_gutter_highlights<T: 'static>(
18673        &mut self,
18674        ranges_to_remove: Vec<Range<Anchor>>,
18675        cx: &mut Context<Self>,
18676    ) {
18677        let snapshot = self.buffer().read(cx).snapshot(cx);
18678        let Some((color_fetcher, mut gutter_highlights)) =
18679            self.gutter_highlights.remove(&TypeId::of::<T>())
18680        else {
18681            return;
18682        };
18683        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18684        gutter_highlights.retain(|highlight| {
18685            while let Some(range_to_remove) = ranges_to_remove.peek() {
18686                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18687                    Ordering::Less | Ordering::Equal => {
18688                        ranges_to_remove.next();
18689                    }
18690                    Ordering::Greater => {
18691                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18692                            Ordering::Less | Ordering::Equal => {
18693                                return false;
18694                            }
18695                            Ordering::Greater => break,
18696                        }
18697                    }
18698                }
18699            }
18700
18701            true
18702        });
18703        self.gutter_highlights
18704            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18705    }
18706
18707    #[cfg(feature = "test-support")]
18708    pub fn all_text_background_highlights(
18709        &self,
18710        window: &mut Window,
18711        cx: &mut Context<Self>,
18712    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18713        let snapshot = self.snapshot(window, cx);
18714        let buffer = &snapshot.buffer_snapshot;
18715        let start = buffer.anchor_before(0);
18716        let end = buffer.anchor_after(buffer.len());
18717        let theme = cx.theme();
18718        self.background_highlights_in_range(start..end, &snapshot, theme)
18719    }
18720
18721    #[cfg(feature = "test-support")]
18722    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18723        let snapshot = self.buffer().read(cx).snapshot(cx);
18724
18725        let highlights = self
18726            .background_highlights
18727            .get(&TypeId::of::<items::BufferSearchHighlights>());
18728
18729        if let Some(highlights) = highlights {
18730            highlights
18731                .iter()
18732                .map(|highlight| {
18733                    highlight.range.start.to_point(&snapshot)
18734                        ..highlight.range.end.to_point(&snapshot)
18735                })
18736                .collect_vec()
18737        } else {
18738            vec![]
18739        }
18740    }
18741
18742    fn document_highlights_for_position<'a>(
18743        &'a self,
18744        position: Anchor,
18745        buffer: &'a MultiBufferSnapshot,
18746    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18747        let read_highlights = self
18748            .background_highlights
18749            .get(&TypeId::of::<DocumentHighlightRead>());
18750        let write_highlights = self
18751            .background_highlights
18752            .get(&TypeId::of::<DocumentHighlightWrite>());
18753        let left_position = position.bias_left(buffer);
18754        let right_position = position.bias_right(buffer);
18755        read_highlights
18756            .into_iter()
18757            .chain(write_highlights)
18758            .flat_map(move |highlights| {
18759                let start_ix = match highlights.binary_search_by(|probe| {
18760                    let cmp = probe.range.end.cmp(&left_position, buffer);
18761                    if cmp.is_ge() {
18762                        Ordering::Greater
18763                    } else {
18764                        Ordering::Less
18765                    }
18766                }) {
18767                    Ok(i) | Err(i) => i,
18768                };
18769
18770                highlights[start_ix..]
18771                    .iter()
18772                    .take_while(move |highlight| {
18773                        highlight.range.start.cmp(&right_position, buffer).is_le()
18774                    })
18775                    .map(|highlight| &highlight.range)
18776            })
18777    }
18778
18779    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18780        self.background_highlights
18781            .get(&TypeId::of::<T>())
18782            .map_or(false, |highlights| !highlights.is_empty())
18783    }
18784
18785    pub fn background_highlights_in_range(
18786        &self,
18787        search_range: Range<Anchor>,
18788        display_snapshot: &DisplaySnapshot,
18789        theme: &Theme,
18790    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18791        let mut results = Vec::new();
18792        for highlights in self.background_highlights.values() {
18793            let start_ix = match highlights.binary_search_by(|probe| {
18794                let cmp = probe
18795                    .range
18796                    .end
18797                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18798                if cmp.is_gt() {
18799                    Ordering::Greater
18800                } else {
18801                    Ordering::Less
18802                }
18803            }) {
18804                Ok(i) | Err(i) => i,
18805            };
18806            for highlight in &highlights[start_ix..] {
18807                if highlight
18808                    .range
18809                    .start
18810                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18811                    .is_ge()
18812                {
18813                    break;
18814                }
18815
18816                let start = highlight.range.start.to_display_point(display_snapshot);
18817                let end = highlight.range.end.to_display_point(display_snapshot);
18818                let color = (highlight.color_fetcher)(theme);
18819                results.push((start..end, color))
18820            }
18821        }
18822        results
18823    }
18824
18825    pub fn background_highlight_row_ranges<T: 'static>(
18826        &self,
18827        search_range: Range<Anchor>,
18828        display_snapshot: &DisplaySnapshot,
18829        count: usize,
18830    ) -> Vec<RangeInclusive<DisplayPoint>> {
18831        let mut results = Vec::new();
18832        let Some(highlights) = self.background_highlights.get(&TypeId::of::<T>()) else {
18833            return vec![];
18834        };
18835
18836        let start_ix = match highlights.binary_search_by(|probe| {
18837            let cmp = probe
18838                .range
18839                .end
18840                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18841            if cmp.is_gt() {
18842                Ordering::Greater
18843            } else {
18844                Ordering::Less
18845            }
18846        }) {
18847            Ok(i) | Err(i) => i,
18848        };
18849        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18850            if let (Some(start_display), Some(end_display)) = (start, end) {
18851                results.push(
18852                    start_display.to_display_point(display_snapshot)
18853                        ..=end_display.to_display_point(display_snapshot),
18854                );
18855            }
18856        };
18857        let mut start_row: Option<Point> = None;
18858        let mut end_row: Option<Point> = None;
18859        if highlights.len() > count {
18860            return Vec::new();
18861        }
18862        for highlight in &highlights[start_ix..] {
18863            if highlight
18864                .range
18865                .start
18866                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18867                .is_ge()
18868            {
18869                break;
18870            }
18871            let end = highlight
18872                .range
18873                .end
18874                .to_point(&display_snapshot.buffer_snapshot);
18875            if let Some(current_row) = &end_row {
18876                if end.row == current_row.row {
18877                    continue;
18878                }
18879            }
18880            let start = highlight
18881                .range
18882                .start
18883                .to_point(&display_snapshot.buffer_snapshot);
18884            if start_row.is_none() {
18885                assert_eq!(end_row, None);
18886                start_row = Some(start);
18887                end_row = Some(end);
18888                continue;
18889            }
18890            if let Some(current_end) = end_row.as_mut() {
18891                if start.row > current_end.row + 1 {
18892                    push_region(start_row, end_row);
18893                    start_row = Some(start);
18894                    end_row = Some(end);
18895                } else {
18896                    // Merge two hunks.
18897                    *current_end = end;
18898                }
18899            } else {
18900                unreachable!();
18901            }
18902        }
18903        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18904        push_region(start_row, end_row);
18905        results
18906    }
18907
18908    pub fn gutter_highlights_in_range(
18909        &self,
18910        search_range: Range<Anchor>,
18911        display_snapshot: &DisplaySnapshot,
18912        cx: &App,
18913    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18914        let mut results = Vec::new();
18915        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18916            let color = color_fetcher(cx);
18917            let start_ix = match ranges.binary_search_by(|probe| {
18918                let cmp = probe
18919                    .end
18920                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18921                if cmp.is_gt() {
18922                    Ordering::Greater
18923                } else {
18924                    Ordering::Less
18925                }
18926            }) {
18927                Ok(i) | Err(i) => i,
18928            };
18929            for range in &ranges[start_ix..] {
18930                if range
18931                    .start
18932                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18933                    .is_ge()
18934                {
18935                    break;
18936                }
18937
18938                let start = range.start.to_display_point(display_snapshot);
18939                let end = range.end.to_display_point(display_snapshot);
18940                results.push((start..end, color))
18941            }
18942        }
18943        results
18944    }
18945
18946    /// Get the text ranges corresponding to the redaction query
18947    pub fn redacted_ranges(
18948        &self,
18949        search_range: Range<Anchor>,
18950        display_snapshot: &DisplaySnapshot,
18951        cx: &App,
18952    ) -> Vec<Range<DisplayPoint>> {
18953        display_snapshot
18954            .buffer_snapshot
18955            .redacted_ranges(search_range, |file| {
18956                if let Some(file) = file {
18957                    file.is_private()
18958                        && EditorSettings::get(
18959                            Some(SettingsLocation {
18960                                worktree_id: file.worktree_id(cx),
18961                                path: file.path().as_ref(),
18962                            }),
18963                            cx,
18964                        )
18965                        .redact_private_values
18966                } else {
18967                    false
18968                }
18969            })
18970            .map(|range| {
18971                range.start.to_display_point(display_snapshot)
18972                    ..range.end.to_display_point(display_snapshot)
18973            })
18974            .collect()
18975    }
18976
18977    pub fn highlight_text<T: 'static>(
18978        &mut self,
18979        ranges: Vec<(Range<Anchor>, HighlightStyle)>,
18980        cx: &mut Context<Self>,
18981    ) {
18982        self.display_map
18983            .update(cx, |map, _| map.highlight_text(TypeId::of::<T>(), ranges));
18984        cx.notify();
18985    }
18986
18987    pub(crate) fn highlight_inlays<T: 'static>(
18988        &mut self,
18989        highlights: Vec<InlayHighlight>,
18990        style: HighlightStyle,
18991        cx: &mut Context<Self>,
18992    ) {
18993        self.display_map.update(cx, |map, _| {
18994            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18995        });
18996        cx.notify();
18997    }
18998
18999    pub fn text_highlights<'a, T: 'static>(
19000        &'a self,
19001        cx: &'a App,
19002    ) -> Option<&'a [(Range<Anchor>, HighlightStyle)]> {
19003        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19004    }
19005
19006    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19007        let cleared = self
19008            .display_map
19009            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19010        if cleared {
19011            cx.notify();
19012        }
19013    }
19014
19015    pub fn remove_text_highlights<T: 'static>(
19016        &mut self,
19017        cx: &mut Context<Self>,
19018    ) -> Option<Vec<(Range<Anchor>, HighlightStyle)>> {
19019        self.display_map
19020            .update(cx, |map, _| map.remove_text_highlights(TypeId::of::<T>()))
19021    }
19022
19023    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19024        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19025            && self.focus_handle.is_focused(window)
19026    }
19027
19028    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19029        self.show_cursor_when_unfocused = is_enabled;
19030        cx.notify();
19031    }
19032
19033    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19034        cx.notify();
19035    }
19036
19037    fn on_debug_session_event(
19038        &mut self,
19039        _session: Entity<Session>,
19040        event: &SessionEvent,
19041        cx: &mut Context<Self>,
19042    ) {
19043        match event {
19044            SessionEvent::InvalidateInlineValue => {
19045                self.refresh_inline_values(cx);
19046            }
19047            _ => {}
19048        }
19049    }
19050
19051    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19052        let Some(project) = self.project.clone() else {
19053            return;
19054        };
19055
19056        if !self.inline_value_cache.enabled {
19057            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19058            self.splice_inlays(&inlays, Vec::new(), cx);
19059            return;
19060        }
19061
19062        let current_execution_position = self
19063            .highlighted_rows
19064            .get(&TypeId::of::<ActiveDebugLine>())
19065            .and_then(|lines| lines.last().map(|line| line.range.start));
19066
19067        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19068            let inline_values = editor
19069                .update(cx, |editor, cx| {
19070                    let Some(current_execution_position) = current_execution_position else {
19071                        return Some(Task::ready(Ok(Vec::new())));
19072                    };
19073
19074                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19075                        let snapshot = buffer.snapshot(cx);
19076
19077                        let excerpt = snapshot.excerpt_containing(
19078                            current_execution_position..current_execution_position,
19079                        )?;
19080
19081                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19082                    })?;
19083
19084                    let range =
19085                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19086
19087                    project.inline_values(buffer, range, cx)
19088                })
19089                .ok()
19090                .flatten()?
19091                .await
19092                .context("refreshing debugger inlays")
19093                .log_err()?;
19094
19095            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19096
19097            for (buffer_id, inline_value) in inline_values
19098                .into_iter()
19099                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19100            {
19101                buffer_inline_values
19102                    .entry(buffer_id)
19103                    .or_default()
19104                    .push(inline_value);
19105            }
19106
19107            editor
19108                .update(cx, |editor, cx| {
19109                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19110                    let mut new_inlays = Vec::default();
19111
19112                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19113                        let buffer_id = buffer_snapshot.remote_id();
19114                        buffer_inline_values
19115                            .get(&buffer_id)
19116                            .into_iter()
19117                            .flatten()
19118                            .for_each(|hint| {
19119                                let inlay = Inlay::debugger(
19120                                    post_inc(&mut editor.next_inlay_id),
19121                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19122                                    hint.text(),
19123                                );
19124
19125                                new_inlays.push(inlay);
19126                            });
19127                    }
19128
19129                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19130                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19131
19132                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19133                })
19134                .ok()?;
19135            Some(())
19136        });
19137    }
19138
19139    fn on_buffer_event(
19140        &mut self,
19141        multibuffer: &Entity<MultiBuffer>,
19142        event: &multi_buffer::Event,
19143        window: &mut Window,
19144        cx: &mut Context<Self>,
19145    ) {
19146        match event {
19147            multi_buffer::Event::Edited {
19148                singleton_buffer_edited,
19149                edited_buffer,
19150            } => {
19151                self.scrollbar_marker_state.dirty = true;
19152                self.active_indent_guides_state.dirty = true;
19153                self.refresh_active_diagnostics(cx);
19154                self.refresh_code_actions(window, cx);
19155                self.refresh_selected_text_highlights(true, window, cx);
19156                refresh_matching_bracket_highlights(self, window, cx);
19157                if self.has_active_inline_completion() {
19158                    self.update_visible_inline_completion(window, cx);
19159                }
19160                if let Some(project) = self.project.as_ref() {
19161                    if let Some(edited_buffer) = edited_buffer {
19162                        project.update(cx, |project, cx| {
19163                            self.registered_buffers
19164                                .entry(edited_buffer.read(cx).remote_id())
19165                                .or_insert_with(|| {
19166                                    project
19167                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19168                                });
19169                        });
19170                    }
19171                }
19172                cx.emit(EditorEvent::BufferEdited);
19173                cx.emit(SearchEvent::MatchesInvalidated);
19174
19175                if let Some(buffer) = edited_buffer {
19176                    self.update_lsp_data(true, None, Some(buffer.read(cx).remote_id()), window, cx);
19177                }
19178
19179                if *singleton_buffer_edited {
19180                    if let Some(buffer) = edited_buffer {
19181                        if buffer.read(cx).file().is_none() {
19182                            cx.emit(EditorEvent::TitleChanged);
19183                        }
19184                    }
19185                    if let Some(project) = &self.project {
19186                        #[allow(clippy::mutable_key_type)]
19187                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19188                            multibuffer
19189                                .all_buffers()
19190                                .into_iter()
19191                                .filter_map(|buffer| {
19192                                    buffer.update(cx, |buffer, cx| {
19193                                        let language = buffer.language()?;
19194                                        let should_discard = project.update(cx, |project, cx| {
19195                                            project.is_local()
19196                                                && !project.has_language_servers_for(buffer, cx)
19197                                        });
19198                                        should_discard.not().then_some(language.clone())
19199                                    })
19200                                })
19201                                .collect::<HashSet<_>>()
19202                        });
19203                        if !languages_affected.is_empty() {
19204                            self.refresh_inlay_hints(
19205                                InlayHintRefreshReason::BufferEdited(languages_affected),
19206                                cx,
19207                            );
19208                        }
19209                    }
19210                }
19211
19212                let Some(project) = &self.project else { return };
19213                let (telemetry, is_via_ssh) = {
19214                    let project = project.read(cx);
19215                    let telemetry = project.client().telemetry().clone();
19216                    let is_via_ssh = project.is_via_ssh();
19217                    (telemetry, is_via_ssh)
19218                };
19219                refresh_linked_ranges(self, window, cx);
19220                telemetry.log_edit_event("editor", is_via_ssh);
19221            }
19222            multi_buffer::Event::ExcerptsAdded {
19223                buffer,
19224                predecessor,
19225                excerpts,
19226            } => {
19227                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19228                let buffer_id = buffer.read(cx).remote_id();
19229                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19230                    if let Some(project) = &self.project {
19231                        update_uncommitted_diff_for_buffer(
19232                            cx.entity(),
19233                            project,
19234                            [buffer.clone()],
19235                            self.buffer.clone(),
19236                            cx,
19237                        )
19238                        .detach();
19239                    }
19240                }
19241                self.update_lsp_data(false, None, Some(buffer_id), window, cx);
19242                cx.emit(EditorEvent::ExcerptsAdded {
19243                    buffer: buffer.clone(),
19244                    predecessor: *predecessor,
19245                    excerpts: excerpts.clone(),
19246                });
19247                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19248            }
19249            multi_buffer::Event::ExcerptsRemoved {
19250                ids,
19251                removed_buffer_ids,
19252            } => {
19253                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19254                let buffer = self.buffer.read(cx);
19255                self.registered_buffers
19256                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19257                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19258                cx.emit(EditorEvent::ExcerptsRemoved {
19259                    ids: ids.clone(),
19260                    removed_buffer_ids: removed_buffer_ids.clone(),
19261                });
19262            }
19263            multi_buffer::Event::ExcerptsEdited {
19264                excerpt_ids,
19265                buffer_ids,
19266            } => {
19267                self.display_map.update(cx, |map, cx| {
19268                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19269                });
19270                cx.emit(EditorEvent::ExcerptsEdited {
19271                    ids: excerpt_ids.clone(),
19272                });
19273            }
19274            multi_buffer::Event::ExcerptsExpanded { ids } => {
19275                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19276                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19277            }
19278            multi_buffer::Event::Reparsed(buffer_id) => {
19279                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19280                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19281
19282                cx.emit(EditorEvent::Reparsed(*buffer_id));
19283            }
19284            multi_buffer::Event::DiffHunksToggled => {
19285                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19286            }
19287            multi_buffer::Event::LanguageChanged(buffer_id) => {
19288                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19289                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19290                cx.emit(EditorEvent::Reparsed(*buffer_id));
19291                cx.notify();
19292            }
19293            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19294            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19295            multi_buffer::Event::FileHandleChanged
19296            | multi_buffer::Event::Reloaded
19297            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19298            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19299            multi_buffer::Event::DiagnosticsUpdated => {
19300                self.update_diagnostics_state(window, cx);
19301            }
19302            _ => {}
19303        };
19304    }
19305
19306    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19307        self.refresh_active_diagnostics(cx);
19308        self.refresh_inline_diagnostics(true, window, cx);
19309        self.scrollbar_marker_state.dirty = true;
19310        cx.notify();
19311    }
19312
19313    pub fn start_temporary_diff_override(&mut self) {
19314        self.load_diff_task.take();
19315        self.temporary_diff_override = true;
19316    }
19317
19318    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19319        self.temporary_diff_override = false;
19320        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19321        self.buffer.update(cx, |buffer, cx| {
19322            buffer.set_all_diff_hunks_collapsed(cx);
19323        });
19324
19325        if let Some(project) = self.project.clone() {
19326            self.load_diff_task = Some(
19327                update_uncommitted_diff_for_buffer(
19328                    cx.entity(),
19329                    &project,
19330                    self.buffer.read(cx).all_buffers(),
19331                    self.buffer.clone(),
19332                    cx,
19333                )
19334                .shared(),
19335            );
19336        }
19337    }
19338
19339    fn on_display_map_changed(
19340        &mut self,
19341        _: Entity<DisplayMap>,
19342        _: &mut Window,
19343        cx: &mut Context<Self>,
19344    ) {
19345        cx.notify();
19346    }
19347
19348    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19349        let new_severity = if self.diagnostics_enabled() {
19350            EditorSettings::get_global(cx)
19351                .diagnostics_max_severity
19352                .unwrap_or(DiagnosticSeverity::Hint)
19353        } else {
19354            DiagnosticSeverity::Off
19355        };
19356        self.set_max_diagnostics_severity(new_severity, cx);
19357        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19358        self.update_edit_prediction_settings(cx);
19359        self.refresh_inline_completion(true, false, window, cx);
19360        self.refresh_inlay_hints(
19361            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19362                self.selections.newest_anchor().head(),
19363                &self.buffer.read(cx).snapshot(cx),
19364                cx,
19365            )),
19366            cx,
19367        );
19368
19369        let old_cursor_shape = self.cursor_shape;
19370
19371        {
19372            let editor_settings = EditorSettings::get_global(cx);
19373            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19374            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19375            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19376            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19377            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19378        }
19379
19380        if old_cursor_shape != self.cursor_shape {
19381            cx.emit(EditorEvent::CursorShapeChanged);
19382        }
19383
19384        let project_settings = ProjectSettings::get_global(cx);
19385        self.serialize_dirty_buffers =
19386            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19387
19388        if self.mode.is_full() {
19389            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19390            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19391            if self.show_inline_diagnostics != show_inline_diagnostics {
19392                self.show_inline_diagnostics = show_inline_diagnostics;
19393                self.refresh_inline_diagnostics(false, window, cx);
19394            }
19395
19396            if self.git_blame_inline_enabled != inline_blame_enabled {
19397                self.toggle_git_blame_inline_internal(false, window, cx);
19398            }
19399
19400            let minimap_settings = EditorSettings::get_global(cx).minimap;
19401            if self.minimap_visibility != MinimapVisibility::Disabled {
19402                if self.minimap_visibility.settings_visibility()
19403                    != minimap_settings.minimap_enabled()
19404                {
19405                    self.set_minimap_visibility(
19406                        MinimapVisibility::for_mode(self.mode(), cx),
19407                        window,
19408                        cx,
19409                    );
19410                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19411                    minimap_entity.update(cx, |minimap_editor, cx| {
19412                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19413                    })
19414                }
19415            }
19416        }
19417
19418        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19419            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19420        }) {
19421            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19422                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19423            }
19424            self.refresh_colors(true, None, None, window, cx);
19425        }
19426
19427        cx.notify();
19428    }
19429
19430    pub fn set_searchable(&mut self, searchable: bool) {
19431        self.searchable = searchable;
19432    }
19433
19434    pub fn searchable(&self) -> bool {
19435        self.searchable
19436    }
19437
19438    fn open_proposed_changes_editor(
19439        &mut self,
19440        _: &OpenProposedChangesEditor,
19441        window: &mut Window,
19442        cx: &mut Context<Self>,
19443    ) {
19444        let Some(workspace) = self.workspace() else {
19445            cx.propagate();
19446            return;
19447        };
19448
19449        let selections = self.selections.all::<usize>(cx);
19450        let multi_buffer = self.buffer.read(cx);
19451        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19452        let mut new_selections_by_buffer = HashMap::default();
19453        for selection in selections {
19454            for (buffer, range, _) in
19455                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19456            {
19457                let mut range = range.to_point(buffer);
19458                range.start.column = 0;
19459                range.end.column = buffer.line_len(range.end.row);
19460                new_selections_by_buffer
19461                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19462                    .or_insert(Vec::new())
19463                    .push(range)
19464            }
19465        }
19466
19467        let proposed_changes_buffers = new_selections_by_buffer
19468            .into_iter()
19469            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19470            .collect::<Vec<_>>();
19471        let proposed_changes_editor = cx.new(|cx| {
19472            ProposedChangesEditor::new(
19473                "Proposed changes",
19474                proposed_changes_buffers,
19475                self.project.clone(),
19476                window,
19477                cx,
19478            )
19479        });
19480
19481        window.defer(cx, move |window, cx| {
19482            workspace.update(cx, |workspace, cx| {
19483                workspace.active_pane().update(cx, |pane, cx| {
19484                    pane.add_item(
19485                        Box::new(proposed_changes_editor),
19486                        true,
19487                        true,
19488                        None,
19489                        window,
19490                        cx,
19491                    );
19492                });
19493            });
19494        });
19495    }
19496
19497    pub fn open_excerpts_in_split(
19498        &mut self,
19499        _: &OpenExcerptsSplit,
19500        window: &mut Window,
19501        cx: &mut Context<Self>,
19502    ) {
19503        self.open_excerpts_common(None, true, window, cx)
19504    }
19505
19506    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19507        self.open_excerpts_common(None, false, window, cx)
19508    }
19509
19510    fn open_excerpts_common(
19511        &mut self,
19512        jump_data: Option<JumpData>,
19513        split: bool,
19514        window: &mut Window,
19515        cx: &mut Context<Self>,
19516    ) {
19517        let Some(workspace) = self.workspace() else {
19518            cx.propagate();
19519            return;
19520        };
19521
19522        if self.buffer.read(cx).is_singleton() {
19523            cx.propagate();
19524            return;
19525        }
19526
19527        let mut new_selections_by_buffer = HashMap::default();
19528        match &jump_data {
19529            Some(JumpData::MultiBufferPoint {
19530                excerpt_id,
19531                position,
19532                anchor,
19533                line_offset_from_top,
19534            }) => {
19535                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19536                if let Some(buffer) = multi_buffer_snapshot
19537                    .buffer_id_for_excerpt(*excerpt_id)
19538                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19539                {
19540                    let buffer_snapshot = buffer.read(cx).snapshot();
19541                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19542                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19543                    } else {
19544                        buffer_snapshot.clip_point(*position, Bias::Left)
19545                    };
19546                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19547                    new_selections_by_buffer.insert(
19548                        buffer,
19549                        (
19550                            vec![jump_to_offset..jump_to_offset],
19551                            Some(*line_offset_from_top),
19552                        ),
19553                    );
19554                }
19555            }
19556            Some(JumpData::MultiBufferRow {
19557                row,
19558                line_offset_from_top,
19559            }) => {
19560                let point = MultiBufferPoint::new(row.0, 0);
19561                if let Some((buffer, buffer_point, _)) =
19562                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19563                {
19564                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19565                    new_selections_by_buffer
19566                        .entry(buffer)
19567                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19568                        .0
19569                        .push(buffer_offset..buffer_offset)
19570                }
19571            }
19572            None => {
19573                let selections = self.selections.all::<usize>(cx);
19574                let multi_buffer = self.buffer.read(cx);
19575                for selection in selections {
19576                    for (snapshot, range, _, anchor) in multi_buffer
19577                        .snapshot(cx)
19578                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19579                    {
19580                        if let Some(anchor) = anchor {
19581                            // selection is in a deleted hunk
19582                            let Some(buffer_id) = anchor.buffer_id else {
19583                                continue;
19584                            };
19585                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19586                                continue;
19587                            };
19588                            let offset = text::ToOffset::to_offset(
19589                                &anchor.text_anchor,
19590                                &buffer_handle.read(cx).snapshot(),
19591                            );
19592                            let range = offset..offset;
19593                            new_selections_by_buffer
19594                                .entry(buffer_handle)
19595                                .or_insert((Vec::new(), None))
19596                                .0
19597                                .push(range)
19598                        } else {
19599                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19600                            else {
19601                                continue;
19602                            };
19603                            new_selections_by_buffer
19604                                .entry(buffer_handle)
19605                                .or_insert((Vec::new(), None))
19606                                .0
19607                                .push(range)
19608                        }
19609                    }
19610                }
19611            }
19612        }
19613
19614        new_selections_by_buffer
19615            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19616
19617        if new_selections_by_buffer.is_empty() {
19618            return;
19619        }
19620
19621        // We defer the pane interaction because we ourselves are a workspace item
19622        // and activating a new item causes the pane to call a method on us reentrantly,
19623        // which panics if we're on the stack.
19624        window.defer(cx, move |window, cx| {
19625            workspace.update(cx, |workspace, cx| {
19626                let pane = if split {
19627                    workspace.adjacent_pane(window, cx)
19628                } else {
19629                    workspace.active_pane().clone()
19630                };
19631
19632                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19633                    let editor = buffer
19634                        .read(cx)
19635                        .file()
19636                        .is_none()
19637                        .then(|| {
19638                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19639                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19640                            // Instead, we try to activate the existing editor in the pane first.
19641                            let (editor, pane_item_index) =
19642                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19643                                    let editor = item.downcast::<Editor>()?;
19644                                    let singleton_buffer =
19645                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19646                                    if singleton_buffer == buffer {
19647                                        Some((editor, i))
19648                                    } else {
19649                                        None
19650                                    }
19651                                })?;
19652                            pane.update(cx, |pane, cx| {
19653                                pane.activate_item(pane_item_index, true, true, window, cx)
19654                            });
19655                            Some(editor)
19656                        })
19657                        .flatten()
19658                        .unwrap_or_else(|| {
19659                            workspace.open_project_item::<Self>(
19660                                pane.clone(),
19661                                buffer,
19662                                true,
19663                                true,
19664                                window,
19665                                cx,
19666                            )
19667                        });
19668
19669                    editor.update(cx, |editor, cx| {
19670                        let autoscroll = match scroll_offset {
19671                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19672                            None => Autoscroll::newest(),
19673                        };
19674                        let nav_history = editor.nav_history.take();
19675                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19676                            s.select_ranges(ranges);
19677                        });
19678                        editor.nav_history = nav_history;
19679                    });
19680                }
19681            })
19682        });
19683    }
19684
19685    // For now, don't allow opening excerpts in buffers that aren't backed by
19686    // regular project files.
19687    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19688        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19689    }
19690
19691    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19692        let snapshot = self.buffer.read(cx).read(cx);
19693        let ranges = self.text_highlights::<InputComposition>(cx)?;
19694        Some(
19695            ranges
19696                .iter()
19697                .map(move |(range, _)| {
19698                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19699                })
19700                .collect(),
19701        )
19702    }
19703
19704    fn selection_replacement_ranges(
19705        &self,
19706        range: Range<OffsetUtf16>,
19707        cx: &mut App,
19708    ) -> Vec<Range<OffsetUtf16>> {
19709        let selections = self.selections.all::<OffsetUtf16>(cx);
19710        let newest_selection = selections
19711            .iter()
19712            .max_by_key(|selection| selection.id)
19713            .unwrap();
19714        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19715        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19716        let snapshot = self.buffer.read(cx).read(cx);
19717        selections
19718            .into_iter()
19719            .map(|mut selection| {
19720                selection.start.0 =
19721                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19722                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19723                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19724                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19725            })
19726            .collect()
19727    }
19728
19729    fn report_editor_event(
19730        &self,
19731        event_type: &'static str,
19732        file_extension: Option<String>,
19733        cx: &App,
19734    ) {
19735        if cfg!(any(test, feature = "test-support")) {
19736            return;
19737        }
19738
19739        let Some(project) = &self.project else { return };
19740
19741        // If None, we are in a file without an extension
19742        let file = self
19743            .buffer
19744            .read(cx)
19745            .as_singleton()
19746            .and_then(|b| b.read(cx).file());
19747        let file_extension = file_extension.or(file
19748            .as_ref()
19749            .and_then(|file| Path::new(file.file_name(cx)).extension())
19750            .and_then(|e| e.to_str())
19751            .map(|a| a.to_string()));
19752
19753        let vim_mode = vim_enabled(cx);
19754
19755        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19756        let copilot_enabled = edit_predictions_provider
19757            == language::language_settings::EditPredictionProvider::Copilot;
19758        let copilot_enabled_for_language = self
19759            .buffer
19760            .read(cx)
19761            .language_settings(cx)
19762            .show_edit_predictions;
19763
19764        let project = project.read(cx);
19765        telemetry::event!(
19766            event_type,
19767            file_extension,
19768            vim_mode,
19769            copilot_enabled,
19770            copilot_enabled_for_language,
19771            edit_predictions_provider,
19772            is_via_ssh = project.is_via_ssh(),
19773        );
19774    }
19775
19776    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19777    /// with each line being an array of {text, highlight} objects.
19778    fn copy_highlight_json(
19779        &mut self,
19780        _: &CopyHighlightJson,
19781        window: &mut Window,
19782        cx: &mut Context<Self>,
19783    ) {
19784        #[derive(Serialize)]
19785        struct Chunk<'a> {
19786            text: String,
19787            highlight: Option<&'a str>,
19788        }
19789
19790        let snapshot = self.buffer.read(cx).snapshot(cx);
19791        let range = self
19792            .selected_text_range(false, window, cx)
19793            .and_then(|selection| {
19794                if selection.range.is_empty() {
19795                    None
19796                } else {
19797                    Some(selection.range)
19798                }
19799            })
19800            .unwrap_or_else(|| 0..snapshot.len());
19801
19802        let chunks = snapshot.chunks(range, true);
19803        let mut lines = Vec::new();
19804        let mut line: VecDeque<Chunk> = VecDeque::new();
19805
19806        let Some(style) = self.style.as_ref() else {
19807            return;
19808        };
19809
19810        for chunk in chunks {
19811            let highlight = chunk
19812                .syntax_highlight_id
19813                .and_then(|id| id.name(&style.syntax));
19814            let mut chunk_lines = chunk.text.split('\n').peekable();
19815            while let Some(text) = chunk_lines.next() {
19816                let mut merged_with_last_token = false;
19817                if let Some(last_token) = line.back_mut() {
19818                    if last_token.highlight == highlight {
19819                        last_token.text.push_str(text);
19820                        merged_with_last_token = true;
19821                    }
19822                }
19823
19824                if !merged_with_last_token {
19825                    line.push_back(Chunk {
19826                        text: text.into(),
19827                        highlight,
19828                    });
19829                }
19830
19831                if chunk_lines.peek().is_some() {
19832                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19833                        line.pop_front();
19834                    }
19835                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19836                        line.pop_back();
19837                    }
19838
19839                    lines.push(mem::take(&mut line));
19840                }
19841            }
19842        }
19843
19844        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19845            return;
19846        };
19847        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19848    }
19849
19850    pub fn open_context_menu(
19851        &mut self,
19852        _: &OpenContextMenu,
19853        window: &mut Window,
19854        cx: &mut Context<Self>,
19855    ) {
19856        self.request_autoscroll(Autoscroll::newest(), cx);
19857        let position = self.selections.newest_display(cx).start;
19858        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19859    }
19860
19861    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19862        &self.inlay_hint_cache
19863    }
19864
19865    pub fn replay_insert_event(
19866        &mut self,
19867        text: &str,
19868        relative_utf16_range: Option<Range<isize>>,
19869        window: &mut Window,
19870        cx: &mut Context<Self>,
19871    ) {
19872        if !self.input_enabled {
19873            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19874            return;
19875        }
19876        if let Some(relative_utf16_range) = relative_utf16_range {
19877            let selections = self.selections.all::<OffsetUtf16>(cx);
19878            self.change_selections(None, window, cx, |s| {
19879                let new_ranges = selections.into_iter().map(|range| {
19880                    let start = OffsetUtf16(
19881                        range
19882                            .head()
19883                            .0
19884                            .saturating_add_signed(relative_utf16_range.start),
19885                    );
19886                    let end = OffsetUtf16(
19887                        range
19888                            .head()
19889                            .0
19890                            .saturating_add_signed(relative_utf16_range.end),
19891                    );
19892                    start..end
19893                });
19894                s.select_ranges(new_ranges);
19895            });
19896        }
19897
19898        self.handle_input(text, window, cx);
19899    }
19900
19901    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19902        let Some(provider) = self.semantics_provider.as_ref() else {
19903            return false;
19904        };
19905
19906        let mut supports = false;
19907        self.buffer().update(cx, |this, cx| {
19908            this.for_each_buffer(|buffer| {
19909                supports |= provider.supports_inlay_hints(buffer, cx);
19910            });
19911        });
19912
19913        supports
19914    }
19915
19916    pub fn is_focused(&self, window: &Window) -> bool {
19917        self.focus_handle.is_focused(window)
19918    }
19919
19920    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19921        cx.emit(EditorEvent::Focused);
19922
19923        if let Some(descendant) = self
19924            .last_focused_descendant
19925            .take()
19926            .and_then(|descendant| descendant.upgrade())
19927        {
19928            window.focus(&descendant);
19929        } else {
19930            if let Some(blame) = self.blame.as_ref() {
19931                blame.update(cx, GitBlame::focus)
19932            }
19933
19934            self.blink_manager.update(cx, BlinkManager::enable);
19935            self.show_cursor_names(window, cx);
19936            self.buffer.update(cx, |buffer, cx| {
19937                buffer.finalize_last_transaction(cx);
19938                if self.leader_id.is_none() {
19939                    buffer.set_active_selections(
19940                        &self.selections.disjoint_anchors(),
19941                        self.selections.line_mode,
19942                        self.cursor_shape,
19943                        cx,
19944                    );
19945                }
19946            });
19947        }
19948    }
19949
19950    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19951        cx.emit(EditorEvent::FocusedIn)
19952    }
19953
19954    fn handle_focus_out(
19955        &mut self,
19956        event: FocusOutEvent,
19957        _window: &mut Window,
19958        cx: &mut Context<Self>,
19959    ) {
19960        if event.blurred != self.focus_handle {
19961            self.last_focused_descendant = Some(event.blurred);
19962        }
19963        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19964    }
19965
19966    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19967        self.blink_manager.update(cx, BlinkManager::disable);
19968        self.buffer
19969            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19970
19971        if let Some(blame) = self.blame.as_ref() {
19972            blame.update(cx, GitBlame::blur)
19973        }
19974        if !self.hover_state.focused(window, cx) {
19975            hide_hover(self, cx);
19976        }
19977        if !self
19978            .context_menu
19979            .borrow()
19980            .as_ref()
19981            .is_some_and(|context_menu| context_menu.focused(window, cx))
19982        {
19983            self.hide_context_menu(window, cx);
19984        }
19985        self.discard_inline_completion(false, cx);
19986        cx.emit(EditorEvent::Blurred);
19987        cx.notify();
19988    }
19989
19990    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19991        let mut pending: String = window
19992            .pending_input_keystrokes()
19993            .into_iter()
19994            .flatten()
19995            .filter_map(|keystroke| {
19996                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19997                    keystroke.key_char.clone()
19998                } else {
19999                    None
20000                }
20001            })
20002            .collect();
20003
20004        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20005            pending = "".to_string();
20006        }
20007
20008        let existing_pending = self.text_highlights::<PendingInput>(cx).map(|ranges| {
20009            ranges
20010                .iter()
20011                .map(|(range, _)| range.clone())
20012                .collect::<Vec<_>>()
20013        });
20014        if existing_pending.is_none() && pending.is_empty() {
20015            return;
20016        }
20017        let transaction =
20018            self.transact(window, cx, |this, window, cx| {
20019                let selections = this.selections.all::<usize>(cx);
20020                let edits = selections
20021                    .iter()
20022                    .map(|selection| (selection.end..selection.end, pending.clone()));
20023                this.edit(edits, cx);
20024                this.change_selections(None, window, cx, |s| {
20025                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20026                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20027                    }));
20028                });
20029                if let Some(existing_ranges) = existing_pending {
20030                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20031                    this.edit(edits, cx);
20032                }
20033            });
20034
20035        let snapshot = self.snapshot(window, cx);
20036        let ranges = self
20037            .selections
20038            .all::<usize>(cx)
20039            .into_iter()
20040            .map(|selection| {
20041                (
20042                    snapshot.buffer_snapshot.anchor_after(selection.end)
20043                        ..snapshot
20044                            .buffer_snapshot
20045                            .anchor_before(selection.end + pending.len()),
20046                    HighlightStyle {
20047                        underline: Some(UnderlineStyle {
20048                            thickness: px(1.),
20049                            color: None,
20050                            wavy: false,
20051                        }),
20052                        ..Default::default()
20053                    },
20054                )
20055            })
20056            .collect();
20057
20058        if pending.is_empty() {
20059            self.clear_highlights::<PendingInput>(cx);
20060        } else {
20061            self.highlight_text::<PendingInput>(ranges, cx);
20062        }
20063
20064        self.ime_transaction = self.ime_transaction.or(transaction);
20065        if let Some(transaction) = self.ime_transaction {
20066            self.buffer.update(cx, |buffer, cx| {
20067                buffer.group_until_transaction(transaction, cx);
20068            });
20069        }
20070
20071        if self.text_highlights::<PendingInput>(cx).is_none() {
20072            self.ime_transaction.take();
20073        }
20074    }
20075
20076    pub fn register_action_renderer(
20077        &mut self,
20078        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20079    ) -> Subscription {
20080        let id = self.next_editor_action_id.post_inc();
20081        self.editor_actions
20082            .borrow_mut()
20083            .insert(id, Box::new(listener));
20084
20085        let editor_actions = self.editor_actions.clone();
20086        Subscription::new(move || {
20087            editor_actions.borrow_mut().remove(&id);
20088        })
20089    }
20090
20091    pub fn register_action<A: Action>(
20092        &mut self,
20093        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20094    ) -> Subscription {
20095        let id = self.next_editor_action_id.post_inc();
20096        let listener = Arc::new(listener);
20097        self.editor_actions.borrow_mut().insert(
20098            id,
20099            Box::new(move |_, window, _| {
20100                let listener = listener.clone();
20101                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20102                    let action = action.downcast_ref().unwrap();
20103                    if phase == DispatchPhase::Bubble {
20104                        listener(action, window, cx)
20105                    }
20106                })
20107            }),
20108        );
20109
20110        let editor_actions = self.editor_actions.clone();
20111        Subscription::new(move || {
20112            editor_actions.borrow_mut().remove(&id);
20113        })
20114    }
20115
20116    pub fn file_header_size(&self) -> u32 {
20117        FILE_HEADER_HEIGHT
20118    }
20119
20120    pub fn restore(
20121        &mut self,
20122        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20123        window: &mut Window,
20124        cx: &mut Context<Self>,
20125    ) {
20126        let workspace = self.workspace();
20127        let project = self.project.as_ref();
20128        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20129            let mut tasks = Vec::new();
20130            for (buffer_id, changes) in revert_changes {
20131                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20132                    buffer.update(cx, |buffer, cx| {
20133                        buffer.edit(
20134                            changes
20135                                .into_iter()
20136                                .map(|(range, text)| (range, text.to_string())),
20137                            None,
20138                            cx,
20139                        );
20140                    });
20141
20142                    if let Some(project) =
20143                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20144                    {
20145                        project.update(cx, |project, cx| {
20146                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20147                        })
20148                    }
20149                }
20150            }
20151            tasks
20152        });
20153        cx.spawn_in(window, async move |_, cx| {
20154            for (buffer, task) in save_tasks {
20155                let result = task.await;
20156                if result.is_err() {
20157                    let Some(path) = buffer
20158                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20159                        .ok()
20160                    else {
20161                        continue;
20162                    };
20163                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20164                        let Some(task) = cx
20165                            .update_window_entity(&workspace, |workspace, window, cx| {
20166                                workspace
20167                                    .open_path_preview(path, None, false, false, false, window, cx)
20168                            })
20169                            .ok()
20170                        else {
20171                            continue;
20172                        };
20173                        task.await.log_err();
20174                    }
20175                }
20176            }
20177        })
20178        .detach();
20179        self.change_selections(None, window, cx, |selections| selections.refresh());
20180    }
20181
20182    pub fn to_pixel_point(
20183        &self,
20184        source: multi_buffer::Anchor,
20185        editor_snapshot: &EditorSnapshot,
20186        window: &mut Window,
20187    ) -> Option<gpui::Point<Pixels>> {
20188        let source_point = source.to_display_point(editor_snapshot);
20189        self.display_to_pixel_point(source_point, editor_snapshot, window)
20190    }
20191
20192    pub fn display_to_pixel_point(
20193        &self,
20194        source: DisplayPoint,
20195        editor_snapshot: &EditorSnapshot,
20196        window: &mut Window,
20197    ) -> Option<gpui::Point<Pixels>> {
20198        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20199        let text_layout_details = self.text_layout_details(window);
20200        let scroll_top = text_layout_details
20201            .scroll_anchor
20202            .scroll_position(editor_snapshot)
20203            .y;
20204
20205        if source.row().as_f32() < scroll_top.floor() {
20206            return None;
20207        }
20208        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20209        let source_y = line_height * (source.row().as_f32() - scroll_top);
20210        Some(gpui::Point::new(source_x, source_y))
20211    }
20212
20213    pub fn has_visible_completions_menu(&self) -> bool {
20214        !self.edit_prediction_preview_is_active()
20215            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20216                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20217            })
20218    }
20219
20220    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20221        if self.mode.is_minimap() {
20222            return;
20223        }
20224        self.addons
20225            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20226    }
20227
20228    pub fn unregister_addon<T: Addon>(&mut self) {
20229        self.addons.remove(&std::any::TypeId::of::<T>());
20230    }
20231
20232    pub fn addon<T: Addon>(&self) -> Option<&T> {
20233        let type_id = std::any::TypeId::of::<T>();
20234        self.addons
20235            .get(&type_id)
20236            .and_then(|item| item.to_any().downcast_ref::<T>())
20237    }
20238
20239    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20240        let type_id = std::any::TypeId::of::<T>();
20241        self.addons
20242            .get_mut(&type_id)
20243            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20244    }
20245
20246    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20247        let text_layout_details = self.text_layout_details(window);
20248        let style = &text_layout_details.editor_style;
20249        let font_id = window.text_system().resolve_font(&style.text.font());
20250        let font_size = style.text.font_size.to_pixels(window.rem_size());
20251        let line_height = style.text.line_height_in_pixels(window.rem_size());
20252        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20253
20254        gpui::Size::new(em_width, line_height)
20255    }
20256
20257    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20258        self.load_diff_task.clone()
20259    }
20260
20261    fn read_metadata_from_db(
20262        &mut self,
20263        item_id: u64,
20264        workspace_id: WorkspaceId,
20265        window: &mut Window,
20266        cx: &mut Context<Editor>,
20267    ) {
20268        if self.is_singleton(cx)
20269            && !self.mode.is_minimap()
20270            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20271        {
20272            let buffer_snapshot = OnceCell::new();
20273
20274            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20275                if !folds.is_empty() {
20276                    let snapshot =
20277                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20278                    self.fold_ranges(
20279                        folds
20280                            .into_iter()
20281                            .map(|(start, end)| {
20282                                snapshot.clip_offset(start, Bias::Left)
20283                                    ..snapshot.clip_offset(end, Bias::Right)
20284                            })
20285                            .collect(),
20286                        false,
20287                        window,
20288                        cx,
20289                    );
20290                }
20291            }
20292
20293            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20294                if !selections.is_empty() {
20295                    let snapshot =
20296                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20297                    // skip adding the initial selection to selection history
20298                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20299                    self.change_selections(None, window, cx, |s| {
20300                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20301                            snapshot.clip_offset(start, Bias::Left)
20302                                ..snapshot.clip_offset(end, Bias::Right)
20303                        }));
20304                    });
20305                    self.selection_history.mode = SelectionHistoryMode::Normal;
20306                }
20307            };
20308        }
20309
20310        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20311    }
20312
20313    fn update_lsp_data(
20314        &mut self,
20315        update_on_edit: bool,
20316        for_server_id: Option<LanguageServerId>,
20317        for_buffer: Option<BufferId>,
20318        window: &mut Window,
20319        cx: &mut Context<'_, Self>,
20320    ) {
20321        self.pull_diagnostics(for_buffer, window, cx);
20322        self.refresh_colors(update_on_edit, for_server_id, for_buffer, window, cx);
20323    }
20324}
20325
20326fn vim_enabled(cx: &App) -> bool {
20327    cx.global::<SettingsStore>()
20328        .raw_user_settings()
20329        .get("vim_mode")
20330        == Some(&serde_json::Value::Bool(true))
20331}
20332
20333fn process_completion_for_edit(
20334    completion: &Completion,
20335    intent: CompletionIntent,
20336    buffer: &Entity<Buffer>,
20337    cursor_position: &text::Anchor,
20338    cx: &mut Context<Editor>,
20339) -> CompletionEdit {
20340    let buffer = buffer.read(cx);
20341    let buffer_snapshot = buffer.snapshot();
20342    let (snippet, new_text) = if completion.is_snippet() {
20343        // Workaround for typescript language server issues so that methods don't expand within
20344        // strings and functions with type expressions. The previous point is used because the query
20345        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20346        let mut snippet_source = completion.new_text.clone();
20347        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20348        previous_point.column = previous_point.column.saturating_sub(1);
20349        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20350            if scope.prefers_label_for_snippet_in_completion() {
20351                if let Some(label) = completion.label() {
20352                    if matches!(
20353                        completion.kind(),
20354                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20355                    ) {
20356                        snippet_source = label;
20357                    }
20358                }
20359            }
20360        }
20361        match Snippet::parse(&snippet_source).log_err() {
20362            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20363            None => (None, completion.new_text.clone()),
20364        }
20365    } else {
20366        (None, completion.new_text.clone())
20367    };
20368
20369    let mut range_to_replace = {
20370        let replace_range = &completion.replace_range;
20371        if let CompletionSource::Lsp {
20372            insert_range: Some(insert_range),
20373            ..
20374        } = &completion.source
20375        {
20376            debug_assert_eq!(
20377                insert_range.start, replace_range.start,
20378                "insert_range and replace_range should start at the same position"
20379            );
20380            debug_assert!(
20381                insert_range
20382                    .start
20383                    .cmp(&cursor_position, &buffer_snapshot)
20384                    .is_le(),
20385                "insert_range should start before or at cursor position"
20386            );
20387            debug_assert!(
20388                replace_range
20389                    .start
20390                    .cmp(&cursor_position, &buffer_snapshot)
20391                    .is_le(),
20392                "replace_range should start before or at cursor position"
20393            );
20394            debug_assert!(
20395                insert_range
20396                    .end
20397                    .cmp(&cursor_position, &buffer_snapshot)
20398                    .is_le(),
20399                "insert_range should end before or at cursor position"
20400            );
20401
20402            let should_replace = match intent {
20403                CompletionIntent::CompleteWithInsert => false,
20404                CompletionIntent::CompleteWithReplace => true,
20405                CompletionIntent::Complete | CompletionIntent::Compose => {
20406                    let insert_mode =
20407                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20408                            .completions
20409                            .lsp_insert_mode;
20410                    match insert_mode {
20411                        LspInsertMode::Insert => false,
20412                        LspInsertMode::Replace => true,
20413                        LspInsertMode::ReplaceSubsequence => {
20414                            let mut text_to_replace = buffer.chars_for_range(
20415                                buffer.anchor_before(replace_range.start)
20416                                    ..buffer.anchor_after(replace_range.end),
20417                            );
20418                            let mut current_needle = text_to_replace.next();
20419                            for haystack_ch in completion.label.text.chars() {
20420                                if let Some(needle_ch) = current_needle {
20421                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20422                                        current_needle = text_to_replace.next();
20423                                    }
20424                                }
20425                            }
20426                            current_needle.is_none()
20427                        }
20428                        LspInsertMode::ReplaceSuffix => {
20429                            if replace_range
20430                                .end
20431                                .cmp(&cursor_position, &buffer_snapshot)
20432                                .is_gt()
20433                            {
20434                                let range_after_cursor = *cursor_position..replace_range.end;
20435                                let text_after_cursor = buffer
20436                                    .text_for_range(
20437                                        buffer.anchor_before(range_after_cursor.start)
20438                                            ..buffer.anchor_after(range_after_cursor.end),
20439                                    )
20440                                    .collect::<String>()
20441                                    .to_ascii_lowercase();
20442                                completion
20443                                    .label
20444                                    .text
20445                                    .to_ascii_lowercase()
20446                                    .ends_with(&text_after_cursor)
20447                            } else {
20448                                true
20449                            }
20450                        }
20451                    }
20452                }
20453            };
20454
20455            if should_replace {
20456                replace_range.clone()
20457            } else {
20458                insert_range.clone()
20459            }
20460        } else {
20461            replace_range.clone()
20462        }
20463    };
20464
20465    if range_to_replace
20466        .end
20467        .cmp(&cursor_position, &buffer_snapshot)
20468        .is_lt()
20469    {
20470        range_to_replace.end = *cursor_position;
20471    }
20472
20473    CompletionEdit {
20474        new_text,
20475        replace_range: range_to_replace.to_offset(&buffer),
20476        snippet,
20477    }
20478}
20479
20480struct CompletionEdit {
20481    new_text: String,
20482    replace_range: Range<usize>,
20483    snippet: Option<Snippet>,
20484}
20485
20486fn insert_extra_newline_brackets(
20487    buffer: &MultiBufferSnapshot,
20488    range: Range<usize>,
20489    language: &language::LanguageScope,
20490) -> bool {
20491    let leading_whitespace_len = buffer
20492        .reversed_chars_at(range.start)
20493        .take_while(|c| c.is_whitespace() && *c != '\n')
20494        .map(|c| c.len_utf8())
20495        .sum::<usize>();
20496    let trailing_whitespace_len = buffer
20497        .chars_at(range.end)
20498        .take_while(|c| c.is_whitespace() && *c != '\n')
20499        .map(|c| c.len_utf8())
20500        .sum::<usize>();
20501    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20502
20503    language.brackets().any(|(pair, enabled)| {
20504        let pair_start = pair.start.trim_end();
20505        let pair_end = pair.end.trim_start();
20506
20507        enabled
20508            && pair.newline
20509            && buffer.contains_str_at(range.end, pair_end)
20510            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20511    })
20512}
20513
20514fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20515    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20516        [(buffer, range, _)] => (*buffer, range.clone()),
20517        _ => return false,
20518    };
20519    let pair = {
20520        let mut result: Option<BracketMatch> = None;
20521
20522        for pair in buffer
20523            .all_bracket_ranges(range.clone())
20524            .filter(move |pair| {
20525                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20526            })
20527        {
20528            let len = pair.close_range.end - pair.open_range.start;
20529
20530            if let Some(existing) = &result {
20531                let existing_len = existing.close_range.end - existing.open_range.start;
20532                if len > existing_len {
20533                    continue;
20534                }
20535            }
20536
20537            result = Some(pair);
20538        }
20539
20540        result
20541    };
20542    let Some(pair) = pair else {
20543        return false;
20544    };
20545    pair.newline_only
20546        && buffer
20547            .chars_for_range(pair.open_range.end..range.start)
20548            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20549            .all(|c| c.is_whitespace() && c != '\n')
20550}
20551
20552fn update_uncommitted_diff_for_buffer(
20553    editor: Entity<Editor>,
20554    project: &Entity<Project>,
20555    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20556    buffer: Entity<MultiBuffer>,
20557    cx: &mut App,
20558) -> Task<()> {
20559    let mut tasks = Vec::new();
20560    project.update(cx, |project, cx| {
20561        for buffer in buffers {
20562            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20563                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20564            }
20565        }
20566    });
20567    cx.spawn(async move |cx| {
20568        let diffs = future::join_all(tasks).await;
20569        if editor
20570            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20571            .unwrap_or(false)
20572        {
20573            return;
20574        }
20575
20576        buffer
20577            .update(cx, |buffer, cx| {
20578                for diff in diffs.into_iter().flatten() {
20579                    buffer.add_diff(diff, cx);
20580                }
20581            })
20582            .ok();
20583    })
20584}
20585
20586fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20587    let tab_size = tab_size.get() as usize;
20588    let mut width = offset;
20589
20590    for ch in text.chars() {
20591        width += if ch == '\t' {
20592            tab_size - (width % tab_size)
20593        } else {
20594            1
20595        };
20596    }
20597
20598    width - offset
20599}
20600
20601#[cfg(test)]
20602mod tests {
20603    use super::*;
20604
20605    #[test]
20606    fn test_string_size_with_expanded_tabs() {
20607        let nz = |val| NonZeroU32::new(val).unwrap();
20608        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20609        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20610        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20611        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20612        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20613        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20614        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20615        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20616    }
20617}
20618
20619/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20620struct WordBreakingTokenizer<'a> {
20621    input: &'a str,
20622}
20623
20624impl<'a> WordBreakingTokenizer<'a> {
20625    fn new(input: &'a str) -> Self {
20626        Self { input }
20627    }
20628}
20629
20630fn is_char_ideographic(ch: char) -> bool {
20631    use unicode_script::Script::*;
20632    use unicode_script::UnicodeScript;
20633    matches!(ch.script(), Han | Tangut | Yi)
20634}
20635
20636fn is_grapheme_ideographic(text: &str) -> bool {
20637    text.chars().any(is_char_ideographic)
20638}
20639
20640fn is_grapheme_whitespace(text: &str) -> bool {
20641    text.chars().any(|x| x.is_whitespace())
20642}
20643
20644fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20645    text.chars().next().map_or(false, |ch| {
20646        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20647    })
20648}
20649
20650#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20651enum WordBreakToken<'a> {
20652    Word { token: &'a str, grapheme_len: usize },
20653    InlineWhitespace { token: &'a str, grapheme_len: usize },
20654    Newline,
20655}
20656
20657impl<'a> Iterator for WordBreakingTokenizer<'a> {
20658    /// Yields a span, the count of graphemes in the token, and whether it was
20659    /// whitespace. Note that it also breaks at word boundaries.
20660    type Item = WordBreakToken<'a>;
20661
20662    fn next(&mut self) -> Option<Self::Item> {
20663        use unicode_segmentation::UnicodeSegmentation;
20664        if self.input.is_empty() {
20665            return None;
20666        }
20667
20668        let mut iter = self.input.graphemes(true).peekable();
20669        let mut offset = 0;
20670        let mut grapheme_len = 0;
20671        if let Some(first_grapheme) = iter.next() {
20672            let is_newline = first_grapheme == "\n";
20673            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20674            offset += first_grapheme.len();
20675            grapheme_len += 1;
20676            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20677                if let Some(grapheme) = iter.peek().copied() {
20678                    if should_stay_with_preceding_ideograph(grapheme) {
20679                        offset += grapheme.len();
20680                        grapheme_len += 1;
20681                    }
20682                }
20683            } else {
20684                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20685                let mut next_word_bound = words.peek().copied();
20686                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20687                    next_word_bound = words.next();
20688                }
20689                while let Some(grapheme) = iter.peek().copied() {
20690                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20691                        break;
20692                    };
20693                    if is_grapheme_whitespace(grapheme) != is_whitespace
20694                        || (grapheme == "\n") != is_newline
20695                    {
20696                        break;
20697                    };
20698                    offset += grapheme.len();
20699                    grapheme_len += 1;
20700                    iter.next();
20701                }
20702            }
20703            let token = &self.input[..offset];
20704            self.input = &self.input[offset..];
20705            if token == "\n" {
20706                Some(WordBreakToken::Newline)
20707            } else if is_whitespace {
20708                Some(WordBreakToken::InlineWhitespace {
20709                    token,
20710                    grapheme_len,
20711                })
20712            } else {
20713                Some(WordBreakToken::Word {
20714                    token,
20715                    grapheme_len,
20716                })
20717            }
20718        } else {
20719            None
20720        }
20721    }
20722}
20723
20724#[test]
20725fn test_word_breaking_tokenizer() {
20726    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20727        ("", &[]),
20728        ("  ", &[whitespace("  ", 2)]),
20729        ("Ʒ", &[word("Ʒ", 1)]),
20730        ("Ǽ", &[word("Ǽ", 1)]),
20731        ("", &[word("", 1)]),
20732        ("⋑⋑", &[word("⋑⋑", 2)]),
20733        (
20734            "原理,进而",
20735            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20736        ),
20737        (
20738            "hello world",
20739            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20740        ),
20741        (
20742            "hello, world",
20743            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20744        ),
20745        (
20746            "  hello world",
20747            &[
20748                whitespace("  ", 2),
20749                word("hello", 5),
20750                whitespace(" ", 1),
20751                word("world", 5),
20752            ],
20753        ),
20754        (
20755            "这是什么 \n 钢笔",
20756            &[
20757                word("", 1),
20758                word("", 1),
20759                word("", 1),
20760                word("", 1),
20761                whitespace(" ", 1),
20762                newline(),
20763                whitespace(" ", 1),
20764                word("", 1),
20765                word("", 1),
20766            ],
20767        ),
20768        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20769    ];
20770
20771    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20772        WordBreakToken::Word {
20773            token,
20774            grapheme_len,
20775        }
20776    }
20777
20778    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20779        WordBreakToken::InlineWhitespace {
20780            token,
20781            grapheme_len,
20782        }
20783    }
20784
20785    fn newline() -> WordBreakToken<'static> {
20786        WordBreakToken::Newline
20787    }
20788
20789    for (input, result) in tests {
20790        assert_eq!(
20791            WordBreakingTokenizer::new(input)
20792                .collect::<Vec<_>>()
20793                .as_slice(),
20794            *result,
20795        );
20796    }
20797}
20798
20799fn wrap_with_prefix(
20800    line_prefix: String,
20801    unwrapped_text: String,
20802    wrap_column: usize,
20803    tab_size: NonZeroU32,
20804    preserve_existing_whitespace: bool,
20805) -> String {
20806    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20807    let mut wrapped_text = String::new();
20808    let mut current_line = line_prefix.clone();
20809
20810    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20811    let mut current_line_len = line_prefix_len;
20812    let mut in_whitespace = false;
20813    for token in tokenizer {
20814        let have_preceding_whitespace = in_whitespace;
20815        match token {
20816            WordBreakToken::Word {
20817                token,
20818                grapheme_len,
20819            } => {
20820                in_whitespace = false;
20821                if current_line_len + grapheme_len > wrap_column
20822                    && current_line_len != line_prefix_len
20823                {
20824                    wrapped_text.push_str(current_line.trim_end());
20825                    wrapped_text.push('\n');
20826                    current_line.truncate(line_prefix.len());
20827                    current_line_len = line_prefix_len;
20828                }
20829                current_line.push_str(token);
20830                current_line_len += grapheme_len;
20831            }
20832            WordBreakToken::InlineWhitespace {
20833                mut token,
20834                mut grapheme_len,
20835            } => {
20836                in_whitespace = true;
20837                if have_preceding_whitespace && !preserve_existing_whitespace {
20838                    continue;
20839                }
20840                if !preserve_existing_whitespace {
20841                    token = " ";
20842                    grapheme_len = 1;
20843                }
20844                if current_line_len + grapheme_len > wrap_column {
20845                    wrapped_text.push_str(current_line.trim_end());
20846                    wrapped_text.push('\n');
20847                    current_line.truncate(line_prefix.len());
20848                    current_line_len = line_prefix_len;
20849                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20850                    current_line.push_str(token);
20851                    current_line_len += grapheme_len;
20852                }
20853            }
20854            WordBreakToken::Newline => {
20855                in_whitespace = true;
20856                if preserve_existing_whitespace {
20857                    wrapped_text.push_str(current_line.trim_end());
20858                    wrapped_text.push('\n');
20859                    current_line.truncate(line_prefix.len());
20860                    current_line_len = line_prefix_len;
20861                } else if have_preceding_whitespace {
20862                    continue;
20863                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20864                {
20865                    wrapped_text.push_str(current_line.trim_end());
20866                    wrapped_text.push('\n');
20867                    current_line.truncate(line_prefix.len());
20868                    current_line_len = line_prefix_len;
20869                } else if current_line_len != line_prefix_len {
20870                    current_line.push(' ');
20871                    current_line_len += 1;
20872                }
20873            }
20874        }
20875    }
20876
20877    if !current_line.is_empty() {
20878        wrapped_text.push_str(&current_line);
20879    }
20880    wrapped_text
20881}
20882
20883#[test]
20884fn test_wrap_with_prefix() {
20885    assert_eq!(
20886        wrap_with_prefix(
20887            "# ".to_string(),
20888            "abcdefg".to_string(),
20889            4,
20890            NonZeroU32::new(4).unwrap(),
20891            false,
20892        ),
20893        "# abcdefg"
20894    );
20895    assert_eq!(
20896        wrap_with_prefix(
20897            "".to_string(),
20898            "\thello world".to_string(),
20899            8,
20900            NonZeroU32::new(4).unwrap(),
20901            false,
20902        ),
20903        "hello\nworld"
20904    );
20905    assert_eq!(
20906        wrap_with_prefix(
20907            "// ".to_string(),
20908            "xx \nyy zz aa bb cc".to_string(),
20909            12,
20910            NonZeroU32::new(4).unwrap(),
20911            false,
20912        ),
20913        "// xx yy zz\n// aa bb cc"
20914    );
20915    assert_eq!(
20916        wrap_with_prefix(
20917            String::new(),
20918            "这是什么 \n 钢笔".to_string(),
20919            3,
20920            NonZeroU32::new(4).unwrap(),
20921            false,
20922        ),
20923        "这是什\n么 钢\n"
20924    );
20925}
20926
20927pub trait CollaborationHub {
20928    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20929    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20930    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20931}
20932
20933impl CollaborationHub for Entity<Project> {
20934    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20935        self.read(cx).collaborators()
20936    }
20937
20938    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20939        self.read(cx).user_store().read(cx).participant_indices()
20940    }
20941
20942    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20943        let this = self.read(cx);
20944        let user_ids = this.collaborators().values().map(|c| c.user_id);
20945        this.user_store().read(cx).participant_names(user_ids, cx)
20946    }
20947}
20948
20949pub trait SemanticsProvider {
20950    fn hover(
20951        &self,
20952        buffer: &Entity<Buffer>,
20953        position: text::Anchor,
20954        cx: &mut App,
20955    ) -> Option<Task<Vec<project::Hover>>>;
20956
20957    fn inline_values(
20958        &self,
20959        buffer_handle: Entity<Buffer>,
20960        range: Range<text::Anchor>,
20961        cx: &mut App,
20962    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20963
20964    fn inlay_hints(
20965        &self,
20966        buffer_handle: Entity<Buffer>,
20967        range: Range<text::Anchor>,
20968        cx: &mut App,
20969    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20970
20971    fn resolve_inlay_hint(
20972        &self,
20973        hint: InlayHint,
20974        buffer_handle: Entity<Buffer>,
20975        server_id: LanguageServerId,
20976        cx: &mut App,
20977    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20978
20979    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20980
20981    fn document_highlights(
20982        &self,
20983        buffer: &Entity<Buffer>,
20984        position: text::Anchor,
20985        cx: &mut App,
20986    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20987
20988    fn definitions(
20989        &self,
20990        buffer: &Entity<Buffer>,
20991        position: text::Anchor,
20992        kind: GotoDefinitionKind,
20993        cx: &mut App,
20994    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20995
20996    fn range_for_rename(
20997        &self,
20998        buffer: &Entity<Buffer>,
20999        position: text::Anchor,
21000        cx: &mut App,
21001    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21002
21003    fn perform_rename(
21004        &self,
21005        buffer: &Entity<Buffer>,
21006        position: text::Anchor,
21007        new_name: String,
21008        cx: &mut App,
21009    ) -> Option<Task<Result<ProjectTransaction>>>;
21010}
21011
21012pub trait CompletionProvider {
21013    fn completions(
21014        &self,
21015        excerpt_id: ExcerptId,
21016        buffer: &Entity<Buffer>,
21017        buffer_position: text::Anchor,
21018        trigger: CompletionContext,
21019        window: &mut Window,
21020        cx: &mut Context<Editor>,
21021    ) -> Task<Result<Vec<CompletionResponse>>>;
21022
21023    fn resolve_completions(
21024        &self,
21025        _buffer: Entity<Buffer>,
21026        _completion_indices: Vec<usize>,
21027        _completions: Rc<RefCell<Box<[Completion]>>>,
21028        _cx: &mut Context<Editor>,
21029    ) -> Task<Result<bool>> {
21030        Task::ready(Ok(false))
21031    }
21032
21033    fn apply_additional_edits_for_completion(
21034        &self,
21035        _buffer: Entity<Buffer>,
21036        _completions: Rc<RefCell<Box<[Completion]>>>,
21037        _completion_index: usize,
21038        _push_to_history: bool,
21039        _cx: &mut Context<Editor>,
21040    ) -> Task<Result<Option<language::Transaction>>> {
21041        Task::ready(Ok(None))
21042    }
21043
21044    fn is_completion_trigger(
21045        &self,
21046        buffer: &Entity<Buffer>,
21047        position: language::Anchor,
21048        text: &str,
21049        trigger_in_words: bool,
21050        menu_is_open: bool,
21051        cx: &mut Context<Editor>,
21052    ) -> bool;
21053
21054    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21055
21056    fn sort_completions(&self) -> bool {
21057        true
21058    }
21059
21060    fn filter_completions(&self) -> bool {
21061        true
21062    }
21063}
21064
21065pub trait CodeActionProvider {
21066    fn id(&self) -> Arc<str>;
21067
21068    fn code_actions(
21069        &self,
21070        buffer: &Entity<Buffer>,
21071        range: Range<text::Anchor>,
21072        window: &mut Window,
21073        cx: &mut App,
21074    ) -> Task<Result<Vec<CodeAction>>>;
21075
21076    fn apply_code_action(
21077        &self,
21078        buffer_handle: Entity<Buffer>,
21079        action: CodeAction,
21080        excerpt_id: ExcerptId,
21081        push_to_history: bool,
21082        window: &mut Window,
21083        cx: &mut App,
21084    ) -> Task<Result<ProjectTransaction>>;
21085}
21086
21087impl CodeActionProvider for Entity<Project> {
21088    fn id(&self) -> Arc<str> {
21089        "project".into()
21090    }
21091
21092    fn code_actions(
21093        &self,
21094        buffer: &Entity<Buffer>,
21095        range: Range<text::Anchor>,
21096        _window: &mut Window,
21097        cx: &mut App,
21098    ) -> Task<Result<Vec<CodeAction>>> {
21099        self.update(cx, |project, cx| {
21100            let code_lens = project.code_lens(buffer, range.clone(), cx);
21101            let code_actions = project.code_actions(buffer, range, None, cx);
21102            cx.background_spawn(async move {
21103                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21104                Ok(code_lens
21105                    .context("code lens fetch")?
21106                    .into_iter()
21107                    .chain(code_actions.context("code action fetch")?)
21108                    .collect())
21109            })
21110        })
21111    }
21112
21113    fn apply_code_action(
21114        &self,
21115        buffer_handle: Entity<Buffer>,
21116        action: CodeAction,
21117        _excerpt_id: ExcerptId,
21118        push_to_history: bool,
21119        _window: &mut Window,
21120        cx: &mut App,
21121    ) -> Task<Result<ProjectTransaction>> {
21122        self.update(cx, |project, cx| {
21123            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21124        })
21125    }
21126}
21127
21128fn snippet_completions(
21129    project: &Project,
21130    buffer: &Entity<Buffer>,
21131    buffer_position: text::Anchor,
21132    cx: &mut App,
21133) -> Task<Result<CompletionResponse>> {
21134    let languages = buffer.read(cx).languages_at(buffer_position);
21135    let snippet_store = project.snippets().read(cx);
21136
21137    let scopes: Vec<_> = languages
21138        .iter()
21139        .filter_map(|language| {
21140            let language_name = language.lsp_id();
21141            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21142
21143            if snippets.is_empty() {
21144                None
21145            } else {
21146                Some((language.default_scope(), snippets))
21147            }
21148        })
21149        .collect();
21150
21151    if scopes.is_empty() {
21152        return Task::ready(Ok(CompletionResponse {
21153            completions: vec![],
21154            is_incomplete: false,
21155        }));
21156    }
21157
21158    let snapshot = buffer.read(cx).text_snapshot();
21159    let chars: String = snapshot
21160        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21161        .collect();
21162    let executor = cx.background_executor().clone();
21163
21164    cx.background_spawn(async move {
21165        let mut is_incomplete = false;
21166        let mut completions: Vec<Completion> = Vec::new();
21167        for (scope, snippets) in scopes.into_iter() {
21168            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21169            let mut last_word = chars
21170                .chars()
21171                .take_while(|c| classifier.is_word(*c))
21172                .collect::<String>();
21173            last_word = last_word.chars().rev().collect();
21174
21175            if last_word.is_empty() {
21176                return Ok(CompletionResponse {
21177                    completions: vec![],
21178                    is_incomplete: true,
21179                });
21180            }
21181
21182            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21183            let to_lsp = |point: &text::Anchor| {
21184                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21185                point_to_lsp(end)
21186            };
21187            let lsp_end = to_lsp(&buffer_position);
21188
21189            let candidates = snippets
21190                .iter()
21191                .enumerate()
21192                .flat_map(|(ix, snippet)| {
21193                    snippet
21194                        .prefix
21195                        .iter()
21196                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21197                })
21198                .collect::<Vec<StringMatchCandidate>>();
21199
21200            const MAX_RESULTS: usize = 100;
21201            let mut matches = fuzzy::match_strings(
21202                &candidates,
21203                &last_word,
21204                last_word.chars().any(|c| c.is_uppercase()),
21205                MAX_RESULTS,
21206                &Default::default(),
21207                executor.clone(),
21208            )
21209            .await;
21210
21211            if matches.len() >= MAX_RESULTS {
21212                is_incomplete = true;
21213            }
21214
21215            // Remove all candidates where the query's start does not match the start of any word in the candidate
21216            if let Some(query_start) = last_word.chars().next() {
21217                matches.retain(|string_match| {
21218                    split_words(&string_match.string).any(|word| {
21219                        // Check that the first codepoint of the word as lowercase matches the first
21220                        // codepoint of the query as lowercase
21221                        word.chars()
21222                            .flat_map(|codepoint| codepoint.to_lowercase())
21223                            .zip(query_start.to_lowercase())
21224                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21225                    })
21226                });
21227            }
21228
21229            let matched_strings = matches
21230                .into_iter()
21231                .map(|m| m.string)
21232                .collect::<HashSet<_>>();
21233
21234            completions.extend(snippets.iter().filter_map(|snippet| {
21235                let matching_prefix = snippet
21236                    .prefix
21237                    .iter()
21238                    .find(|prefix| matched_strings.contains(*prefix))?;
21239                let start = as_offset - last_word.len();
21240                let start = snapshot.anchor_before(start);
21241                let range = start..buffer_position;
21242                let lsp_start = to_lsp(&start);
21243                let lsp_range = lsp::Range {
21244                    start: lsp_start,
21245                    end: lsp_end,
21246                };
21247                Some(Completion {
21248                    replace_range: range,
21249                    new_text: snippet.body.clone(),
21250                    source: CompletionSource::Lsp {
21251                        insert_range: None,
21252                        server_id: LanguageServerId(usize::MAX),
21253                        resolved: true,
21254                        lsp_completion: Box::new(lsp::CompletionItem {
21255                            label: snippet.prefix.first().unwrap().clone(),
21256                            kind: Some(CompletionItemKind::SNIPPET),
21257                            label_details: snippet.description.as_ref().map(|description| {
21258                                lsp::CompletionItemLabelDetails {
21259                                    detail: Some(description.clone()),
21260                                    description: None,
21261                                }
21262                            }),
21263                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21264                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21265                                lsp::InsertReplaceEdit {
21266                                    new_text: snippet.body.clone(),
21267                                    insert: lsp_range,
21268                                    replace: lsp_range,
21269                                },
21270                            )),
21271                            filter_text: Some(snippet.body.clone()),
21272                            sort_text: Some(char::MAX.to_string()),
21273                            ..lsp::CompletionItem::default()
21274                        }),
21275                        lsp_defaults: None,
21276                    },
21277                    label: CodeLabel {
21278                        text: matching_prefix.clone(),
21279                        runs: Vec::new(),
21280                        filter_range: 0..matching_prefix.len(),
21281                    },
21282                    icon_path: None,
21283                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21284                        single_line: snippet.name.clone().into(),
21285                        plain_text: snippet
21286                            .description
21287                            .clone()
21288                            .map(|description| description.into()),
21289                    }),
21290                    insert_text_mode: None,
21291                    confirm: None,
21292                })
21293            }))
21294        }
21295
21296        Ok(CompletionResponse {
21297            completions,
21298            is_incomplete,
21299        })
21300    })
21301}
21302
21303impl CompletionProvider for Entity<Project> {
21304    fn completions(
21305        &self,
21306        _excerpt_id: ExcerptId,
21307        buffer: &Entity<Buffer>,
21308        buffer_position: text::Anchor,
21309        options: CompletionContext,
21310        _window: &mut Window,
21311        cx: &mut Context<Editor>,
21312    ) -> Task<Result<Vec<CompletionResponse>>> {
21313        self.update(cx, |project, cx| {
21314            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21315            let project_completions = project.completions(buffer, buffer_position, options, cx);
21316            cx.background_spawn(async move {
21317                let mut responses = project_completions.await?;
21318                let snippets = snippets.await?;
21319                if !snippets.completions.is_empty() {
21320                    responses.push(snippets);
21321                }
21322                Ok(responses)
21323            })
21324        })
21325    }
21326
21327    fn resolve_completions(
21328        &self,
21329        buffer: Entity<Buffer>,
21330        completion_indices: Vec<usize>,
21331        completions: Rc<RefCell<Box<[Completion]>>>,
21332        cx: &mut Context<Editor>,
21333    ) -> Task<Result<bool>> {
21334        self.update(cx, |project, cx| {
21335            project.lsp_store().update(cx, |lsp_store, cx| {
21336                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21337            })
21338        })
21339    }
21340
21341    fn apply_additional_edits_for_completion(
21342        &self,
21343        buffer: Entity<Buffer>,
21344        completions: Rc<RefCell<Box<[Completion]>>>,
21345        completion_index: usize,
21346        push_to_history: bool,
21347        cx: &mut Context<Editor>,
21348    ) -> Task<Result<Option<language::Transaction>>> {
21349        self.update(cx, |project, cx| {
21350            project.lsp_store().update(cx, |lsp_store, cx| {
21351                lsp_store.apply_additional_edits_for_completion(
21352                    buffer,
21353                    completions,
21354                    completion_index,
21355                    push_to_history,
21356                    cx,
21357                )
21358            })
21359        })
21360    }
21361
21362    fn is_completion_trigger(
21363        &self,
21364        buffer: &Entity<Buffer>,
21365        position: language::Anchor,
21366        text: &str,
21367        trigger_in_words: bool,
21368        menu_is_open: bool,
21369        cx: &mut Context<Editor>,
21370    ) -> bool {
21371        let mut chars = text.chars();
21372        let char = if let Some(char) = chars.next() {
21373            char
21374        } else {
21375            return false;
21376        };
21377        if chars.next().is_some() {
21378            return false;
21379        }
21380
21381        let buffer = buffer.read(cx);
21382        let snapshot = buffer.snapshot();
21383        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21384            return false;
21385        }
21386        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21387        if trigger_in_words && classifier.is_word(char) {
21388            return true;
21389        }
21390
21391        buffer.completion_triggers().contains(text)
21392    }
21393}
21394
21395impl SemanticsProvider for Entity<Project> {
21396    fn hover(
21397        &self,
21398        buffer: &Entity<Buffer>,
21399        position: text::Anchor,
21400        cx: &mut App,
21401    ) -> Option<Task<Vec<project::Hover>>> {
21402        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21403    }
21404
21405    fn document_highlights(
21406        &self,
21407        buffer: &Entity<Buffer>,
21408        position: text::Anchor,
21409        cx: &mut App,
21410    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21411        Some(self.update(cx, |project, cx| {
21412            project.document_highlights(buffer, position, cx)
21413        }))
21414    }
21415
21416    fn definitions(
21417        &self,
21418        buffer: &Entity<Buffer>,
21419        position: text::Anchor,
21420        kind: GotoDefinitionKind,
21421        cx: &mut App,
21422    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21423        Some(self.update(cx, |project, cx| match kind {
21424            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21425            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21426            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21427            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21428        }))
21429    }
21430
21431    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21432        // TODO: make this work for remote projects
21433        self.update(cx, |project, cx| {
21434            if project
21435                .active_debug_session(cx)
21436                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21437            {
21438                return true;
21439            }
21440
21441            buffer.update(cx, |buffer, cx| {
21442                project.any_language_server_supports_inlay_hints(buffer, cx)
21443            })
21444        })
21445    }
21446
21447    fn inline_values(
21448        &self,
21449        buffer_handle: Entity<Buffer>,
21450
21451        range: Range<text::Anchor>,
21452        cx: &mut App,
21453    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21454        self.update(cx, |project, cx| {
21455            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21456
21457            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21458        })
21459    }
21460
21461    fn inlay_hints(
21462        &self,
21463        buffer_handle: Entity<Buffer>,
21464        range: Range<text::Anchor>,
21465        cx: &mut App,
21466    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21467        Some(self.update(cx, |project, cx| {
21468            project.inlay_hints(buffer_handle, range, cx)
21469        }))
21470    }
21471
21472    fn resolve_inlay_hint(
21473        &self,
21474        hint: InlayHint,
21475        buffer_handle: Entity<Buffer>,
21476        server_id: LanguageServerId,
21477        cx: &mut App,
21478    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21479        Some(self.update(cx, |project, cx| {
21480            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21481        }))
21482    }
21483
21484    fn range_for_rename(
21485        &self,
21486        buffer: &Entity<Buffer>,
21487        position: text::Anchor,
21488        cx: &mut App,
21489    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21490        Some(self.update(cx, |project, cx| {
21491            let buffer = buffer.clone();
21492            let task = project.prepare_rename(buffer.clone(), position, cx);
21493            cx.spawn(async move |_, cx| {
21494                Ok(match task.await? {
21495                    PrepareRenameResponse::Success(range) => Some(range),
21496                    PrepareRenameResponse::InvalidPosition => None,
21497                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21498                        // Fallback on using TreeSitter info to determine identifier range
21499                        buffer.read_with(cx, |buffer, _| {
21500                            let snapshot = buffer.snapshot();
21501                            let (range, kind) = snapshot.surrounding_word(position);
21502                            if kind != Some(CharKind::Word) {
21503                                return None;
21504                            }
21505                            Some(
21506                                snapshot.anchor_before(range.start)
21507                                    ..snapshot.anchor_after(range.end),
21508                            )
21509                        })?
21510                    }
21511                })
21512            })
21513        }))
21514    }
21515
21516    fn perform_rename(
21517        &self,
21518        buffer: &Entity<Buffer>,
21519        position: text::Anchor,
21520        new_name: String,
21521        cx: &mut App,
21522    ) -> Option<Task<Result<ProjectTransaction>>> {
21523        Some(self.update(cx, |project, cx| {
21524            project.perform_rename(buffer.clone(), position, new_name, cx)
21525        }))
21526    }
21527}
21528
21529fn inlay_hint_settings(
21530    location: Anchor,
21531    snapshot: &MultiBufferSnapshot,
21532    cx: &mut Context<Editor>,
21533) -> InlayHintSettings {
21534    let file = snapshot.file_at(location);
21535    let language = snapshot.language_at(location).map(|l| l.name());
21536    language_settings(language, file, cx).inlay_hints
21537}
21538
21539fn consume_contiguous_rows(
21540    contiguous_row_selections: &mut Vec<Selection<Point>>,
21541    selection: &Selection<Point>,
21542    display_map: &DisplaySnapshot,
21543    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21544) -> (MultiBufferRow, MultiBufferRow) {
21545    contiguous_row_selections.push(selection.clone());
21546    let start_row = MultiBufferRow(selection.start.row);
21547    let mut end_row = ending_row(selection, display_map);
21548
21549    while let Some(next_selection) = selections.peek() {
21550        if next_selection.start.row <= end_row.0 {
21551            end_row = ending_row(next_selection, display_map);
21552            contiguous_row_selections.push(selections.next().unwrap().clone());
21553        } else {
21554            break;
21555        }
21556    }
21557    (start_row, end_row)
21558}
21559
21560fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21561    if next_selection.end.column > 0 || next_selection.is_empty() {
21562        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21563    } else {
21564        MultiBufferRow(next_selection.end.row)
21565    }
21566}
21567
21568impl EditorSnapshot {
21569    pub fn remote_selections_in_range<'a>(
21570        &'a self,
21571        range: &'a Range<Anchor>,
21572        collaboration_hub: &dyn CollaborationHub,
21573        cx: &'a App,
21574    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21575        let participant_names = collaboration_hub.user_names(cx);
21576        let participant_indices = collaboration_hub.user_participant_indices(cx);
21577        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21578        let collaborators_by_replica_id = collaborators_by_peer_id
21579            .values()
21580            .map(|collaborator| (collaborator.replica_id, collaborator))
21581            .collect::<HashMap<_, _>>();
21582        self.buffer_snapshot
21583            .selections_in_range(range, false)
21584            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21585                if replica_id == AGENT_REPLICA_ID {
21586                    Some(RemoteSelection {
21587                        replica_id,
21588                        selection,
21589                        cursor_shape,
21590                        line_mode,
21591                        collaborator_id: CollaboratorId::Agent,
21592                        user_name: Some("Agent".into()),
21593                        color: cx.theme().players().agent(),
21594                    })
21595                } else {
21596                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21597                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21598                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21599                    Some(RemoteSelection {
21600                        replica_id,
21601                        selection,
21602                        cursor_shape,
21603                        line_mode,
21604                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21605                        user_name,
21606                        color: if let Some(index) = participant_index {
21607                            cx.theme().players().color_for_participant(index.0)
21608                        } else {
21609                            cx.theme().players().absent()
21610                        },
21611                    })
21612                }
21613            })
21614    }
21615
21616    pub fn hunks_for_ranges(
21617        &self,
21618        ranges: impl IntoIterator<Item = Range<Point>>,
21619    ) -> Vec<MultiBufferDiffHunk> {
21620        let mut hunks = Vec::new();
21621        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21622            HashMap::default();
21623        for query_range in ranges {
21624            let query_rows =
21625                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21626            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21627                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21628            ) {
21629                // Include deleted hunks that are adjacent to the query range, because
21630                // otherwise they would be missed.
21631                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21632                if hunk.status().is_deleted() {
21633                    intersects_range |= hunk.row_range.start == query_rows.end;
21634                    intersects_range |= hunk.row_range.end == query_rows.start;
21635                }
21636                if intersects_range {
21637                    if !processed_buffer_rows
21638                        .entry(hunk.buffer_id)
21639                        .or_default()
21640                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21641                    {
21642                        continue;
21643                    }
21644                    hunks.push(hunk);
21645                }
21646            }
21647        }
21648
21649        hunks
21650    }
21651
21652    fn display_diff_hunks_for_rows<'a>(
21653        &'a self,
21654        display_rows: Range<DisplayRow>,
21655        folded_buffers: &'a HashSet<BufferId>,
21656    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21657        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21658        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21659
21660        self.buffer_snapshot
21661            .diff_hunks_in_range(buffer_start..buffer_end)
21662            .filter_map(|hunk| {
21663                if folded_buffers.contains(&hunk.buffer_id) {
21664                    return None;
21665                }
21666
21667                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21668                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21669
21670                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21671                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21672
21673                let display_hunk = if hunk_display_start.column() != 0 {
21674                    DisplayDiffHunk::Folded {
21675                        display_row: hunk_display_start.row(),
21676                    }
21677                } else {
21678                    let mut end_row = hunk_display_end.row();
21679                    if hunk_display_end.column() > 0 {
21680                        end_row.0 += 1;
21681                    }
21682                    let is_created_file = hunk.is_created_file();
21683                    DisplayDiffHunk::Unfolded {
21684                        status: hunk.status(),
21685                        diff_base_byte_range: hunk.diff_base_byte_range,
21686                        display_row_range: hunk_display_start.row()..end_row,
21687                        multi_buffer_range: Anchor::range_in_buffer(
21688                            hunk.excerpt_id,
21689                            hunk.buffer_id,
21690                            hunk.buffer_range,
21691                        ),
21692                        is_created_file,
21693                    }
21694                };
21695
21696                Some(display_hunk)
21697            })
21698    }
21699
21700    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21701        self.display_snapshot.buffer_snapshot.language_at(position)
21702    }
21703
21704    pub fn is_focused(&self) -> bool {
21705        self.is_focused
21706    }
21707
21708    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21709        self.placeholder_text.as_ref()
21710    }
21711
21712    pub fn scroll_position(&self) -> gpui::Point<f32> {
21713        self.scroll_anchor.scroll_position(&self.display_snapshot)
21714    }
21715
21716    fn gutter_dimensions(
21717        &self,
21718        font_id: FontId,
21719        font_size: Pixels,
21720        max_line_number_width: Pixels,
21721        cx: &App,
21722    ) -> Option<GutterDimensions> {
21723        if !self.show_gutter {
21724            return None;
21725        }
21726
21727        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21728        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21729
21730        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21731            matches!(
21732                ProjectSettings::get_global(cx).git.git_gutter,
21733                Some(GitGutterSetting::TrackedFiles)
21734            )
21735        });
21736        let gutter_settings = EditorSettings::get_global(cx).gutter;
21737        let show_line_numbers = self
21738            .show_line_numbers
21739            .unwrap_or(gutter_settings.line_numbers);
21740        let line_gutter_width = if show_line_numbers {
21741            // Avoid flicker-like gutter resizes when the line number gains another digit by
21742            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21743            let min_width_for_number_on_gutter =
21744                ch_advance * gutter_settings.min_line_number_digits as f32;
21745            max_line_number_width.max(min_width_for_number_on_gutter)
21746        } else {
21747            0.0.into()
21748        };
21749
21750        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21751        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21752
21753        let git_blame_entries_width =
21754            self.git_blame_gutter_max_author_length
21755                .map(|max_author_length| {
21756                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21757                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21758
21759                    /// The number of characters to dedicate to gaps and margins.
21760                    const SPACING_WIDTH: usize = 4;
21761
21762                    let max_char_count = max_author_length.min(renderer.max_author_length())
21763                        + ::git::SHORT_SHA_LENGTH
21764                        + MAX_RELATIVE_TIMESTAMP.len()
21765                        + SPACING_WIDTH;
21766
21767                    ch_advance * max_char_count
21768                });
21769
21770        let is_singleton = self.buffer_snapshot.is_singleton();
21771
21772        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21773        left_padding += if !is_singleton {
21774            ch_width * 4.0
21775        } else if show_runnables || show_breakpoints {
21776            ch_width * 3.0
21777        } else if show_git_gutter && show_line_numbers {
21778            ch_width * 2.0
21779        } else if show_git_gutter || show_line_numbers {
21780            ch_width
21781        } else {
21782            px(0.)
21783        };
21784
21785        let shows_folds = is_singleton && gutter_settings.folds;
21786
21787        let right_padding = if shows_folds && show_line_numbers {
21788            ch_width * 4.0
21789        } else if shows_folds || (!is_singleton && show_line_numbers) {
21790            ch_width * 3.0
21791        } else if show_line_numbers {
21792            ch_width
21793        } else {
21794            px(0.)
21795        };
21796
21797        Some(GutterDimensions {
21798            left_padding,
21799            right_padding,
21800            width: line_gutter_width + left_padding + right_padding,
21801            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21802            git_blame_entries_width,
21803        })
21804    }
21805
21806    pub fn render_crease_toggle(
21807        &self,
21808        buffer_row: MultiBufferRow,
21809        row_contains_cursor: bool,
21810        editor: Entity<Editor>,
21811        window: &mut Window,
21812        cx: &mut App,
21813    ) -> Option<AnyElement> {
21814        let folded = self.is_line_folded(buffer_row);
21815        let mut is_foldable = false;
21816
21817        if let Some(crease) = self
21818            .crease_snapshot
21819            .query_row(buffer_row, &self.buffer_snapshot)
21820        {
21821            is_foldable = true;
21822            match crease {
21823                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21824                    if let Some(render_toggle) = render_toggle {
21825                        let toggle_callback =
21826                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21827                                if folded {
21828                                    editor.update(cx, |editor, cx| {
21829                                        editor.fold_at(buffer_row, window, cx)
21830                                    });
21831                                } else {
21832                                    editor.update(cx, |editor, cx| {
21833                                        editor.unfold_at(buffer_row, window, cx)
21834                                    });
21835                                }
21836                            });
21837                        return Some((render_toggle)(
21838                            buffer_row,
21839                            folded,
21840                            toggle_callback,
21841                            window,
21842                            cx,
21843                        ));
21844                    }
21845                }
21846            }
21847        }
21848
21849        is_foldable |= self.starts_indent(buffer_row);
21850
21851        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21852            Some(
21853                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21854                    .toggle_state(folded)
21855                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21856                        if folded {
21857                            this.unfold_at(buffer_row, window, cx);
21858                        } else {
21859                            this.fold_at(buffer_row, window, cx);
21860                        }
21861                    }))
21862                    .into_any_element(),
21863            )
21864        } else {
21865            None
21866        }
21867    }
21868
21869    pub fn render_crease_trailer(
21870        &self,
21871        buffer_row: MultiBufferRow,
21872        window: &mut Window,
21873        cx: &mut App,
21874    ) -> Option<AnyElement> {
21875        let folded = self.is_line_folded(buffer_row);
21876        if let Crease::Inline { render_trailer, .. } = self
21877            .crease_snapshot
21878            .query_row(buffer_row, &self.buffer_snapshot)?
21879        {
21880            let render_trailer = render_trailer.as_ref()?;
21881            Some(render_trailer(buffer_row, folded, window, cx))
21882        } else {
21883            None
21884        }
21885    }
21886}
21887
21888impl Deref for EditorSnapshot {
21889    type Target = DisplaySnapshot;
21890
21891    fn deref(&self) -> &Self::Target {
21892        &self.display_snapshot
21893    }
21894}
21895
21896#[derive(Clone, Debug, PartialEq, Eq)]
21897pub enum EditorEvent {
21898    InputIgnored {
21899        text: Arc<str>,
21900    },
21901    InputHandled {
21902        utf16_range_to_replace: Option<Range<isize>>,
21903        text: Arc<str>,
21904    },
21905    ExcerptsAdded {
21906        buffer: Entity<Buffer>,
21907        predecessor: ExcerptId,
21908        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21909    },
21910    ExcerptsRemoved {
21911        ids: Vec<ExcerptId>,
21912        removed_buffer_ids: Vec<BufferId>,
21913    },
21914    BufferFoldToggled {
21915        ids: Vec<ExcerptId>,
21916        folded: bool,
21917    },
21918    ExcerptsEdited {
21919        ids: Vec<ExcerptId>,
21920    },
21921    ExcerptsExpanded {
21922        ids: Vec<ExcerptId>,
21923    },
21924    BufferEdited,
21925    Edited {
21926        transaction_id: clock::Lamport,
21927    },
21928    Reparsed(BufferId),
21929    Focused,
21930    FocusedIn,
21931    Blurred,
21932    DirtyChanged,
21933    Saved,
21934    TitleChanged,
21935    DiffBaseChanged,
21936    SelectionsChanged {
21937        local: bool,
21938    },
21939    ScrollPositionChanged {
21940        local: bool,
21941        autoscroll: bool,
21942    },
21943    Closed,
21944    TransactionUndone {
21945        transaction_id: clock::Lamport,
21946    },
21947    TransactionBegun {
21948        transaction_id: clock::Lamport,
21949    },
21950    Reloaded,
21951    CursorShapeChanged,
21952    PushedToNavHistory {
21953        anchor: Anchor,
21954        is_deactivate: bool,
21955    },
21956}
21957
21958impl EventEmitter<EditorEvent> for Editor {}
21959
21960impl Focusable for Editor {
21961    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21962        self.focus_handle.clone()
21963    }
21964}
21965
21966impl Render for Editor {
21967    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21968        let settings = ThemeSettings::get_global(cx);
21969
21970        let mut text_style = match self.mode {
21971            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21972                color: cx.theme().colors().editor_foreground,
21973                font_family: settings.ui_font.family.clone(),
21974                font_features: settings.ui_font.features.clone(),
21975                font_fallbacks: settings.ui_font.fallbacks.clone(),
21976                font_size: rems(0.875).into(),
21977                font_weight: settings.ui_font.weight,
21978                line_height: relative(settings.buffer_line_height.value()),
21979                ..Default::default()
21980            },
21981            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21982                color: cx.theme().colors().editor_foreground,
21983                font_family: settings.buffer_font.family.clone(),
21984                font_features: settings.buffer_font.features.clone(),
21985                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21986                font_size: settings.buffer_font_size(cx).into(),
21987                font_weight: settings.buffer_font.weight,
21988                line_height: relative(settings.buffer_line_height.value()),
21989                ..Default::default()
21990            },
21991        };
21992        if let Some(text_style_refinement) = &self.text_style_refinement {
21993            text_style.refine(text_style_refinement)
21994        }
21995
21996        let background = match self.mode {
21997            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21998            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
21999            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22000            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22001        };
22002
22003        EditorElement::new(
22004            &cx.entity(),
22005            EditorStyle {
22006                background,
22007                local_player: cx.theme().players().local(),
22008                text: text_style,
22009                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22010                syntax: cx.theme().syntax().clone(),
22011                status: cx.theme().status().clone(),
22012                inlay_hints_style: make_inlay_hints_style(cx),
22013                inline_completion_styles: make_suggestion_styles(cx),
22014                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22015                show_underlines: !self.mode.is_minimap(),
22016            },
22017        )
22018    }
22019}
22020
22021impl EntityInputHandler for Editor {
22022    fn text_for_range(
22023        &mut self,
22024        range_utf16: Range<usize>,
22025        adjusted_range: &mut Option<Range<usize>>,
22026        _: &mut Window,
22027        cx: &mut Context<Self>,
22028    ) -> Option<String> {
22029        let snapshot = self.buffer.read(cx).read(cx);
22030        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22031        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22032        if (start.0..end.0) != range_utf16 {
22033            adjusted_range.replace(start.0..end.0);
22034        }
22035        Some(snapshot.text_for_range(start..end).collect())
22036    }
22037
22038    fn selected_text_range(
22039        &mut self,
22040        ignore_disabled_input: bool,
22041        _: &mut Window,
22042        cx: &mut Context<Self>,
22043    ) -> Option<UTF16Selection> {
22044        // Prevent the IME menu from appearing when holding down an alphabetic key
22045        // while input is disabled.
22046        if !ignore_disabled_input && !self.input_enabled {
22047            return None;
22048        }
22049
22050        let selection = self.selections.newest::<OffsetUtf16>(cx);
22051        let range = selection.range();
22052
22053        Some(UTF16Selection {
22054            range: range.start.0..range.end.0,
22055            reversed: selection.reversed,
22056        })
22057    }
22058
22059    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22060        let snapshot = self.buffer.read(cx).read(cx);
22061        let (range, _) = self.text_highlights::<InputComposition>(cx)?.first()?;
22062        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22063    }
22064
22065    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22066        self.clear_highlights::<InputComposition>(cx);
22067        self.ime_transaction.take();
22068    }
22069
22070    fn replace_text_in_range(
22071        &mut self,
22072        range_utf16: Option<Range<usize>>,
22073        text: &str,
22074        window: &mut Window,
22075        cx: &mut Context<Self>,
22076    ) {
22077        if !self.input_enabled {
22078            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22079            return;
22080        }
22081
22082        self.transact(window, cx, |this, window, cx| {
22083            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22084                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22085                Some(this.selection_replacement_ranges(range_utf16, cx))
22086            } else {
22087                this.marked_text_ranges(cx)
22088            };
22089
22090            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22091                let newest_selection_id = this.selections.newest_anchor().id;
22092                this.selections
22093                    .all::<OffsetUtf16>(cx)
22094                    .iter()
22095                    .zip(ranges_to_replace.iter())
22096                    .find_map(|(selection, range)| {
22097                        if selection.id == newest_selection_id {
22098                            Some(
22099                                (range.start.0 as isize - selection.head().0 as isize)
22100                                    ..(range.end.0 as isize - selection.head().0 as isize),
22101                            )
22102                        } else {
22103                            None
22104                        }
22105                    })
22106            });
22107
22108            cx.emit(EditorEvent::InputHandled {
22109                utf16_range_to_replace: range_to_replace,
22110                text: text.into(),
22111            });
22112
22113            if let Some(new_selected_ranges) = new_selected_ranges {
22114                this.change_selections(None, window, cx, |selections| {
22115                    selections.select_ranges(new_selected_ranges)
22116                });
22117                this.backspace(&Default::default(), window, cx);
22118            }
22119
22120            this.handle_input(text, window, cx);
22121        });
22122
22123        if let Some(transaction) = self.ime_transaction {
22124            self.buffer.update(cx, |buffer, cx| {
22125                buffer.group_until_transaction(transaction, cx);
22126            });
22127        }
22128
22129        self.unmark_text(window, cx);
22130    }
22131
22132    fn replace_and_mark_text_in_range(
22133        &mut self,
22134        range_utf16: Option<Range<usize>>,
22135        text: &str,
22136        new_selected_range_utf16: Option<Range<usize>>,
22137        window: &mut Window,
22138        cx: &mut Context<Self>,
22139    ) {
22140        if !self.input_enabled {
22141            return;
22142        }
22143
22144        let transaction = self.transact(window, cx, |this, window, cx| {
22145            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22146                let snapshot = this.buffer.read(cx).read(cx);
22147                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22148                    for marked_range in &mut marked_ranges {
22149                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22150                        marked_range.start.0 += relative_range_utf16.start;
22151                        marked_range.start =
22152                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22153                        marked_range.end =
22154                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22155                    }
22156                }
22157                Some(marked_ranges)
22158            } else if let Some(range_utf16) = range_utf16 {
22159                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22160                Some(this.selection_replacement_ranges(range_utf16, cx))
22161            } else {
22162                None
22163            };
22164
22165            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22166                let newest_selection_id = this.selections.newest_anchor().id;
22167                this.selections
22168                    .all::<OffsetUtf16>(cx)
22169                    .iter()
22170                    .zip(ranges_to_replace.iter())
22171                    .find_map(|(selection, range)| {
22172                        if selection.id == newest_selection_id {
22173                            Some(
22174                                (range.start.0 as isize - selection.head().0 as isize)
22175                                    ..(range.end.0 as isize - selection.head().0 as isize),
22176                            )
22177                        } else {
22178                            None
22179                        }
22180                    })
22181            });
22182
22183            cx.emit(EditorEvent::InputHandled {
22184                utf16_range_to_replace: range_to_replace,
22185                text: text.into(),
22186            });
22187
22188            if let Some(ranges) = ranges_to_replace {
22189                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22190            }
22191
22192            let marked_ranges = {
22193                let snapshot = this.buffer.read(cx).read(cx);
22194                this.selections
22195                    .disjoint_anchors()
22196                    .iter()
22197                    .map(|selection| {
22198                        (
22199                            selection.start.bias_left(&snapshot)
22200                                ..selection.end.bias_right(&snapshot),
22201                            HighlightStyle {
22202                                underline: Some(UnderlineStyle {
22203                                    thickness: px(1.),
22204                                    color: None,
22205                                    wavy: false,
22206                                }),
22207                                ..Default::default()
22208                            },
22209                        )
22210                    })
22211                    .collect::<Vec<_>>()
22212            };
22213
22214            if text.is_empty() {
22215                this.unmark_text(window, cx);
22216            } else {
22217                this.highlight_text::<InputComposition>(marked_ranges.clone(), cx);
22218            }
22219
22220            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22221            let use_autoclose = this.use_autoclose;
22222            let use_auto_surround = this.use_auto_surround;
22223            this.set_use_autoclose(false);
22224            this.set_use_auto_surround(false);
22225            this.handle_input(text, window, cx);
22226            this.set_use_autoclose(use_autoclose);
22227            this.set_use_auto_surround(use_auto_surround);
22228
22229            if let Some(new_selected_range) = new_selected_range_utf16 {
22230                let snapshot = this.buffer.read(cx).read(cx);
22231                let new_selected_ranges = marked_ranges
22232                    .into_iter()
22233                    .map(|(marked_range, _)| {
22234                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22235                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22236                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22237                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22238                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22239                    })
22240                    .collect::<Vec<_>>();
22241
22242                drop(snapshot);
22243                this.change_selections(None, window, cx, |selections| {
22244                    selections.select_ranges(new_selected_ranges)
22245                });
22246            }
22247        });
22248
22249        self.ime_transaction = self.ime_transaction.or(transaction);
22250        if let Some(transaction) = self.ime_transaction {
22251            self.buffer.update(cx, |buffer, cx| {
22252                buffer.group_until_transaction(transaction, cx);
22253            });
22254        }
22255
22256        if self.text_highlights::<InputComposition>(cx).is_none() {
22257            self.ime_transaction.take();
22258        }
22259    }
22260
22261    fn bounds_for_range(
22262        &mut self,
22263        range_utf16: Range<usize>,
22264        element_bounds: gpui::Bounds<Pixels>,
22265        window: &mut Window,
22266        cx: &mut Context<Self>,
22267    ) -> Option<gpui::Bounds<Pixels>> {
22268        let text_layout_details = self.text_layout_details(window);
22269        let gpui::Size {
22270            width: em_width,
22271            height: line_height,
22272        } = self.character_size(window);
22273
22274        let snapshot = self.snapshot(window, cx);
22275        let scroll_position = snapshot.scroll_position();
22276        let scroll_left = scroll_position.x * em_width;
22277
22278        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22279        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22280            + self.gutter_dimensions.width
22281            + self.gutter_dimensions.margin;
22282        let y = line_height * (start.row().as_f32() - scroll_position.y);
22283
22284        Some(Bounds {
22285            origin: element_bounds.origin + point(x, y),
22286            size: size(em_width, line_height),
22287        })
22288    }
22289
22290    fn character_index_for_point(
22291        &mut self,
22292        point: gpui::Point<Pixels>,
22293        _window: &mut Window,
22294        _cx: &mut Context<Self>,
22295    ) -> Option<usize> {
22296        let position_map = self.last_position_map.as_ref()?;
22297        if !position_map.text_hitbox.contains(&point) {
22298            return None;
22299        }
22300        let display_point = position_map.point_for_position(point).previous_valid;
22301        let anchor = position_map
22302            .snapshot
22303            .display_point_to_anchor(display_point, Bias::Left);
22304        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22305        Some(utf16_offset.0)
22306    }
22307}
22308
22309trait SelectionExt {
22310    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22311    fn spanned_rows(
22312        &self,
22313        include_end_if_at_line_start: bool,
22314        map: &DisplaySnapshot,
22315    ) -> Range<MultiBufferRow>;
22316}
22317
22318impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22319    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22320        let start = self
22321            .start
22322            .to_point(&map.buffer_snapshot)
22323            .to_display_point(map);
22324        let end = self
22325            .end
22326            .to_point(&map.buffer_snapshot)
22327            .to_display_point(map);
22328        if self.reversed {
22329            end..start
22330        } else {
22331            start..end
22332        }
22333    }
22334
22335    fn spanned_rows(
22336        &self,
22337        include_end_if_at_line_start: bool,
22338        map: &DisplaySnapshot,
22339    ) -> Range<MultiBufferRow> {
22340        let start = self.start.to_point(&map.buffer_snapshot);
22341        let mut end = self.end.to_point(&map.buffer_snapshot);
22342        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22343            end.row -= 1;
22344        }
22345
22346        let buffer_start = map.prev_line_boundary(start).0;
22347        let buffer_end = map.next_line_boundary(end).0;
22348        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22349    }
22350}
22351
22352impl<T: InvalidationRegion> InvalidationStack<T> {
22353    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22354    where
22355        S: Clone + ToOffset,
22356    {
22357        while let Some(region) = self.last() {
22358            let all_selections_inside_invalidation_ranges =
22359                if selections.len() == region.ranges().len() {
22360                    selections
22361                        .iter()
22362                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22363                        .all(|(selection, invalidation_range)| {
22364                            let head = selection.head().to_offset(buffer);
22365                            invalidation_range.start <= head && invalidation_range.end >= head
22366                        })
22367                } else {
22368                    false
22369                };
22370
22371            if all_selections_inside_invalidation_ranges {
22372                break;
22373            } else {
22374                self.pop();
22375            }
22376        }
22377    }
22378}
22379
22380impl<T> Default for InvalidationStack<T> {
22381    fn default() -> Self {
22382        Self(Default::default())
22383    }
22384}
22385
22386impl<T> Deref for InvalidationStack<T> {
22387    type Target = Vec<T>;
22388
22389    fn deref(&self) -> &Self::Target {
22390        &self.0
22391    }
22392}
22393
22394impl<T> DerefMut for InvalidationStack<T> {
22395    fn deref_mut(&mut self) -> &mut Self::Target {
22396        &mut self.0
22397    }
22398}
22399
22400impl InvalidationRegion for SnippetState {
22401    fn ranges(&self) -> &[Range<Anchor>] {
22402        &self.ranges[self.active_index]
22403    }
22404}
22405
22406fn inline_completion_edit_text(
22407    current_snapshot: &BufferSnapshot,
22408    edits: &[(Range<Anchor>, String)],
22409    edit_preview: &EditPreview,
22410    include_deletions: bool,
22411    cx: &App,
22412) -> HighlightedText {
22413    let edits = edits
22414        .iter()
22415        .map(|(anchor, text)| {
22416            (
22417                anchor.start.text_anchor..anchor.end.text_anchor,
22418                text.clone(),
22419            )
22420        })
22421        .collect::<Vec<_>>();
22422
22423    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22424}
22425
22426pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22427    match severity {
22428        lsp::DiagnosticSeverity::ERROR => colors.error,
22429        lsp::DiagnosticSeverity::WARNING => colors.warning,
22430        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22431        lsp::DiagnosticSeverity::HINT => colors.info,
22432        _ => colors.ignored,
22433    }
22434}
22435
22436pub fn styled_runs_for_code_label<'a>(
22437    label: &'a CodeLabel,
22438    syntax_theme: &'a theme::SyntaxTheme,
22439) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22440    let fade_out = HighlightStyle {
22441        fade_out: Some(0.35),
22442        ..Default::default()
22443    };
22444
22445    let mut prev_end = label.filter_range.end;
22446    label
22447        .runs
22448        .iter()
22449        .enumerate()
22450        .flat_map(move |(ix, (range, highlight_id))| {
22451            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22452                style
22453            } else {
22454                return Default::default();
22455            };
22456            let mut muted_style = style;
22457            muted_style.highlight(fade_out);
22458
22459            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22460            if range.start >= label.filter_range.end {
22461                if range.start > prev_end {
22462                    runs.push((prev_end..range.start, fade_out));
22463                }
22464                runs.push((range.clone(), muted_style));
22465            } else if range.end <= label.filter_range.end {
22466                runs.push((range.clone(), style));
22467            } else {
22468                runs.push((range.start..label.filter_range.end, style));
22469                runs.push((label.filter_range.end..range.end, muted_style));
22470            }
22471            prev_end = cmp::max(prev_end, range.end);
22472
22473            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22474                runs.push((prev_end..label.text.len(), fade_out));
22475            }
22476
22477            runs
22478        })
22479}
22480
22481pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22482    let mut prev_index = 0;
22483    let mut prev_codepoint: Option<char> = None;
22484    text.char_indices()
22485        .chain([(text.len(), '\0')])
22486        .filter_map(move |(index, codepoint)| {
22487            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22488            let is_boundary = index == text.len()
22489                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22490                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22491            if is_boundary {
22492                let chunk = &text[prev_index..index];
22493                prev_index = index;
22494                Some(chunk)
22495            } else {
22496                None
22497            }
22498        })
22499}
22500
22501pub trait RangeToAnchorExt: Sized {
22502    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22503
22504    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22505        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22506        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22507    }
22508}
22509
22510impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22511    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22512        let start_offset = self.start.to_offset(snapshot);
22513        let end_offset = self.end.to_offset(snapshot);
22514        if start_offset == end_offset {
22515            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22516        } else {
22517            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22518        }
22519    }
22520}
22521
22522pub trait RowExt {
22523    fn as_f32(&self) -> f32;
22524
22525    fn next_row(&self) -> Self;
22526
22527    fn previous_row(&self) -> Self;
22528
22529    fn minus(&self, other: Self) -> u32;
22530}
22531
22532impl RowExt for DisplayRow {
22533    fn as_f32(&self) -> f32 {
22534        self.0 as f32
22535    }
22536
22537    fn next_row(&self) -> Self {
22538        Self(self.0 + 1)
22539    }
22540
22541    fn previous_row(&self) -> Self {
22542        Self(self.0.saturating_sub(1))
22543    }
22544
22545    fn minus(&self, other: Self) -> u32 {
22546        self.0 - other.0
22547    }
22548}
22549
22550impl RowExt for MultiBufferRow {
22551    fn as_f32(&self) -> f32 {
22552        self.0 as f32
22553    }
22554
22555    fn next_row(&self) -> Self {
22556        Self(self.0 + 1)
22557    }
22558
22559    fn previous_row(&self) -> Self {
22560        Self(self.0.saturating_sub(1))
22561    }
22562
22563    fn minus(&self, other: Self) -> u32 {
22564        self.0 - other.0
22565    }
22566}
22567
22568trait RowRangeExt {
22569    type Row;
22570
22571    fn len(&self) -> usize;
22572
22573    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22574}
22575
22576impl RowRangeExt for Range<MultiBufferRow> {
22577    type Row = MultiBufferRow;
22578
22579    fn len(&self) -> usize {
22580        (self.end.0 - self.start.0) as usize
22581    }
22582
22583    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22584        (self.start.0..self.end.0).map(MultiBufferRow)
22585    }
22586}
22587
22588impl RowRangeExt for Range<DisplayRow> {
22589    type Row = DisplayRow;
22590
22591    fn len(&self) -> usize {
22592        (self.end.0 - self.start.0) as usize
22593    }
22594
22595    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22596        (self.start.0..self.end.0).map(DisplayRow)
22597    }
22598}
22599
22600/// If select range has more than one line, we
22601/// just point the cursor to range.start.
22602fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22603    if range.start.row == range.end.row {
22604        range
22605    } else {
22606        range.start..range.start
22607    }
22608}
22609pub struct KillRing(ClipboardItem);
22610impl Global for KillRing {}
22611
22612const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22613
22614enum BreakpointPromptEditAction {
22615    Log,
22616    Condition,
22617    HitCondition,
22618}
22619
22620struct BreakpointPromptEditor {
22621    pub(crate) prompt: Entity<Editor>,
22622    editor: WeakEntity<Editor>,
22623    breakpoint_anchor: Anchor,
22624    breakpoint: Breakpoint,
22625    edit_action: BreakpointPromptEditAction,
22626    block_ids: HashSet<CustomBlockId>,
22627    editor_margins: Arc<Mutex<EditorMargins>>,
22628    _subscriptions: Vec<Subscription>,
22629}
22630
22631impl BreakpointPromptEditor {
22632    const MAX_LINES: u8 = 4;
22633
22634    fn new(
22635        editor: WeakEntity<Editor>,
22636        breakpoint_anchor: Anchor,
22637        breakpoint: Breakpoint,
22638        edit_action: BreakpointPromptEditAction,
22639        window: &mut Window,
22640        cx: &mut Context<Self>,
22641    ) -> Self {
22642        let base_text = match edit_action {
22643            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22644            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22645            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22646        }
22647        .map(|msg| msg.to_string())
22648        .unwrap_or_default();
22649
22650        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22651        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22652
22653        let prompt = cx.new(|cx| {
22654            let mut prompt = Editor::new(
22655                EditorMode::AutoHeight {
22656                    min_lines: 1,
22657                    max_lines: Self::MAX_LINES as usize,
22658                },
22659                buffer,
22660                None,
22661                window,
22662                cx,
22663            );
22664            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22665            prompt.set_show_cursor_when_unfocused(false, cx);
22666            prompt.set_placeholder_text(
22667                match edit_action {
22668                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22669                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22670                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22671                },
22672                cx,
22673            );
22674
22675            prompt
22676        });
22677
22678        Self {
22679            prompt,
22680            editor,
22681            breakpoint_anchor,
22682            breakpoint,
22683            edit_action,
22684            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22685            block_ids: Default::default(),
22686            _subscriptions: vec![],
22687        }
22688    }
22689
22690    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22691        self.block_ids.extend(block_ids)
22692    }
22693
22694    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22695        if let Some(editor) = self.editor.upgrade() {
22696            let message = self
22697                .prompt
22698                .read(cx)
22699                .buffer
22700                .read(cx)
22701                .as_singleton()
22702                .expect("A multi buffer in breakpoint prompt isn't possible")
22703                .read(cx)
22704                .as_rope()
22705                .to_string();
22706
22707            editor.update(cx, |editor, cx| {
22708                editor.edit_breakpoint_at_anchor(
22709                    self.breakpoint_anchor,
22710                    self.breakpoint.clone(),
22711                    match self.edit_action {
22712                        BreakpointPromptEditAction::Log => {
22713                            BreakpointEditAction::EditLogMessage(message.into())
22714                        }
22715                        BreakpointPromptEditAction::Condition => {
22716                            BreakpointEditAction::EditCondition(message.into())
22717                        }
22718                        BreakpointPromptEditAction::HitCondition => {
22719                            BreakpointEditAction::EditHitCondition(message.into())
22720                        }
22721                    },
22722                    cx,
22723                );
22724
22725                editor.remove_blocks(self.block_ids.clone(), None, cx);
22726                cx.focus_self(window);
22727            });
22728        }
22729    }
22730
22731    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22732        self.editor
22733            .update(cx, |editor, cx| {
22734                editor.remove_blocks(self.block_ids.clone(), None, cx);
22735                window.focus(&editor.focus_handle);
22736            })
22737            .log_err();
22738    }
22739
22740    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22741        let settings = ThemeSettings::get_global(cx);
22742        let text_style = TextStyle {
22743            color: if self.prompt.read(cx).read_only(cx) {
22744                cx.theme().colors().text_disabled
22745            } else {
22746                cx.theme().colors().text
22747            },
22748            font_family: settings.buffer_font.family.clone(),
22749            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22750            font_size: settings.buffer_font_size(cx).into(),
22751            font_weight: settings.buffer_font.weight,
22752            line_height: relative(settings.buffer_line_height.value()),
22753            ..Default::default()
22754        };
22755        EditorElement::new(
22756            &self.prompt,
22757            EditorStyle {
22758                background: cx.theme().colors().editor_background,
22759                local_player: cx.theme().players().local(),
22760                text: text_style,
22761                ..Default::default()
22762            },
22763        )
22764    }
22765}
22766
22767impl Render for BreakpointPromptEditor {
22768    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22769        let editor_margins = *self.editor_margins.lock();
22770        let gutter_dimensions = editor_margins.gutter;
22771        h_flex()
22772            .key_context("Editor")
22773            .bg(cx.theme().colors().editor_background)
22774            .border_y_1()
22775            .border_color(cx.theme().status().info_border)
22776            .size_full()
22777            .py(window.line_height() / 2.5)
22778            .on_action(cx.listener(Self::confirm))
22779            .on_action(cx.listener(Self::cancel))
22780            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22781            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22782    }
22783}
22784
22785impl Focusable for BreakpointPromptEditor {
22786    fn focus_handle(&self, cx: &App) -> FocusHandle {
22787        self.prompt.focus_handle(cx)
22788    }
22789}
22790
22791fn all_edits_insertions_or_deletions(
22792    edits: &Vec<(Range<Anchor>, String)>,
22793    snapshot: &MultiBufferSnapshot,
22794) -> bool {
22795    let mut all_insertions = true;
22796    let mut all_deletions = true;
22797
22798    for (range, new_text) in edits.iter() {
22799        let range_is_empty = range.to_offset(&snapshot).is_empty();
22800        let text_is_empty = new_text.is_empty();
22801
22802        if range_is_empty != text_is_empty {
22803            if range_is_empty {
22804                all_deletions = false;
22805            } else {
22806                all_insertions = false;
22807            }
22808        } else {
22809            return false;
22810        }
22811
22812        if !all_insertions && !all_deletions {
22813            return false;
22814        }
22815    }
22816    all_insertions || all_deletions
22817}
22818
22819struct MissingEditPredictionKeybindingTooltip;
22820
22821impl Render for MissingEditPredictionKeybindingTooltip {
22822    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22823        ui::tooltip_container(window, cx, |container, _, cx| {
22824            container
22825                .flex_shrink_0()
22826                .max_w_80()
22827                .min_h(rems_from_px(124.))
22828                .justify_between()
22829                .child(
22830                    v_flex()
22831                        .flex_1()
22832                        .text_ui_sm(cx)
22833                        .child(Label::new("Conflict with Accept Keybinding"))
22834                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22835                )
22836                .child(
22837                    h_flex()
22838                        .pb_1()
22839                        .gap_1()
22840                        .items_end()
22841                        .w_full()
22842                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22843                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22844                        }))
22845                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22846                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22847                        })),
22848                )
22849        })
22850    }
22851}
22852
22853#[derive(Debug, Clone, Copy, PartialEq)]
22854pub struct LineHighlight {
22855    pub background: Background,
22856    pub border: Option<gpui::Hsla>,
22857    pub include_gutter: bool,
22858    pub type_id: Option<TypeId>,
22859}
22860
22861fn render_diff_hunk_controls(
22862    row: u32,
22863    status: &DiffHunkStatus,
22864    hunk_range: Range<Anchor>,
22865    is_created_file: bool,
22866    line_height: Pixels,
22867    editor: &Entity<Editor>,
22868    _window: &mut Window,
22869    cx: &mut App,
22870) -> AnyElement {
22871    h_flex()
22872        .h(line_height)
22873        .mr_1()
22874        .gap_1()
22875        .px_0p5()
22876        .pb_1()
22877        .border_x_1()
22878        .border_b_1()
22879        .border_color(cx.theme().colors().border_variant)
22880        .rounded_b_lg()
22881        .bg(cx.theme().colors().editor_background)
22882        .gap_1()
22883        .block_mouse_except_scroll()
22884        .shadow_md()
22885        .child(if status.has_secondary_hunk() {
22886            Button::new(("stage", row as u64), "Stage")
22887                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22888                .tooltip({
22889                    let focus_handle = editor.focus_handle(cx);
22890                    move |window, cx| {
22891                        Tooltip::for_action_in(
22892                            "Stage Hunk",
22893                            &::git::ToggleStaged,
22894                            &focus_handle,
22895                            window,
22896                            cx,
22897                        )
22898                    }
22899                })
22900                .on_click({
22901                    let editor = editor.clone();
22902                    move |_event, _window, cx| {
22903                        editor.update(cx, |editor, cx| {
22904                            editor.stage_or_unstage_diff_hunks(
22905                                true,
22906                                vec![hunk_range.start..hunk_range.start],
22907                                cx,
22908                            );
22909                        });
22910                    }
22911                })
22912        } else {
22913            Button::new(("unstage", row as u64), "Unstage")
22914                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22915                .tooltip({
22916                    let focus_handle = editor.focus_handle(cx);
22917                    move |window, cx| {
22918                        Tooltip::for_action_in(
22919                            "Unstage Hunk",
22920                            &::git::ToggleStaged,
22921                            &focus_handle,
22922                            window,
22923                            cx,
22924                        )
22925                    }
22926                })
22927                .on_click({
22928                    let editor = editor.clone();
22929                    move |_event, _window, cx| {
22930                        editor.update(cx, |editor, cx| {
22931                            editor.stage_or_unstage_diff_hunks(
22932                                false,
22933                                vec![hunk_range.start..hunk_range.start],
22934                                cx,
22935                            );
22936                        });
22937                    }
22938                })
22939        })
22940        .child(
22941            Button::new(("restore", row as u64), "Restore")
22942                .tooltip({
22943                    let focus_handle = editor.focus_handle(cx);
22944                    move |window, cx| {
22945                        Tooltip::for_action_in(
22946                            "Restore Hunk",
22947                            &::git::Restore,
22948                            &focus_handle,
22949                            window,
22950                            cx,
22951                        )
22952                    }
22953                })
22954                .on_click({
22955                    let editor = editor.clone();
22956                    move |_event, window, cx| {
22957                        editor.update(cx, |editor, cx| {
22958                            let snapshot = editor.snapshot(window, cx);
22959                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22960                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22961                        });
22962                    }
22963                })
22964                .disabled(is_created_file),
22965        )
22966        .when(
22967            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22968            |el| {
22969                el.child(
22970                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22971                        .shape(IconButtonShape::Square)
22972                        .icon_size(IconSize::Small)
22973                        // .disabled(!has_multiple_hunks)
22974                        .tooltip({
22975                            let focus_handle = editor.focus_handle(cx);
22976                            move |window, cx| {
22977                                Tooltip::for_action_in(
22978                                    "Next Hunk",
22979                                    &GoToHunk,
22980                                    &focus_handle,
22981                                    window,
22982                                    cx,
22983                                )
22984                            }
22985                        })
22986                        .on_click({
22987                            let editor = editor.clone();
22988                            move |_event, window, cx| {
22989                                editor.update(cx, |editor, cx| {
22990                                    let snapshot = editor.snapshot(window, cx);
22991                                    let position =
22992                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22993                                    editor.go_to_hunk_before_or_after_position(
22994                                        &snapshot,
22995                                        position,
22996                                        Direction::Next,
22997                                        window,
22998                                        cx,
22999                                    );
23000                                    editor.expand_selected_diff_hunks(cx);
23001                                });
23002                            }
23003                        }),
23004                )
23005                .child(
23006                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23007                        .shape(IconButtonShape::Square)
23008                        .icon_size(IconSize::Small)
23009                        // .disabled(!has_multiple_hunks)
23010                        .tooltip({
23011                            let focus_handle = editor.focus_handle(cx);
23012                            move |window, cx| {
23013                                Tooltip::for_action_in(
23014                                    "Previous Hunk",
23015                                    &GoToPreviousHunk,
23016                                    &focus_handle,
23017                                    window,
23018                                    cx,
23019                                )
23020                            }
23021                        })
23022                        .on_click({
23023                            let editor = editor.clone();
23024                            move |_event, window, cx| {
23025                                editor.update(cx, |editor, cx| {
23026                                    let snapshot = editor.snapshot(window, cx);
23027                                    let point =
23028                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23029                                    editor.go_to_hunk_before_or_after_position(
23030                                        &snapshot,
23031                                        point,
23032                                        Direction::Prev,
23033                                        window,
23034                                        cx,
23035                                    );
23036                                    editor.expand_selected_diff_hunks(cx);
23037                                });
23038                            }
23039                        }),
23040                )
23041            },
23042        )
23043        .into_any_element()
23044}