editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt,
   78    future::{self, Shared, join},
   79};
   80use fuzzy::{StringMatch, StringMatchCandidate};
   81
   82use ::git::blame::BlameEntry;
   83use ::git::{Restore, blame::ParsedCommitMessage};
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use git::blame::{GitBlame, GlobalBlameRenderer};
   89use gpui::{
   90    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   91    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   92    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   93    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   94    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   95    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   96    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   97    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   98};
   99use highlight_matching_bracket::refresh_matching_bracket_highlights;
  100use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  101pub use hover_popover::hover_markdown_style;
  102use hover_popover::{HoverState, hide_hover};
  103use indent_guides::ActiveIndentGuidesState;
  104use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  105pub use inline_completion::Direction;
  106use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  107pub use items::MAX_TAB_TITLE_LEN;
  108use itertools::Itertools;
  109use language::{
  110    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  111    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  112    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  113    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  114    language_settings::{
  115        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  116        all_language_settings, language_settings,
  117    },
  118    point_from_lsp, text_diff_with_options,
  119};
  120use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  121use linked_editing_ranges::refresh_linked_ranges;
  122use markdown::Markdown;
  123use mouse_context_menu::MouseContextMenu;
  124use persistence::DB;
  125use project::{
  126    BreakpointWithPosition, CompletionResponse, ProjectPath,
  127    debugger::{
  128        breakpoint_store::{
  129            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  130            BreakpointStoreEvent,
  131        },
  132        session::{Session, SessionEvent},
  133    },
  134    project_settings::DiagnosticSeverity,
  135};
  136
  137pub use git::blame::BlameRenderer;
  138pub use proposed_changes_editor::{
  139    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  140};
  141use std::{cell::OnceCell, iter::Peekable, ops::Not};
  142use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  143
  144pub use lsp::CompletionContext;
  145use lsp::{
  146    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  147    LanguageServerId, LanguageServerName,
  148};
  149
  150use language::BufferSnapshot;
  151pub use lsp_ext::lsp_tasks;
  152use movement::TextLayoutDetails;
  153pub use multi_buffer::{
  154    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  155    RowInfo, ToOffset, ToPoint,
  156};
  157use multi_buffer::{
  158    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  159    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  160};
  161use parking_lot::Mutex;
  162use project::{
  163    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  164    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  165    TaskSourceKind,
  166    debugger::breakpoint_store::Breakpoint,
  167    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  168    project_settings::{GitGutterSetting, ProjectSettings},
  169};
  170use rand::prelude::*;
  171use rpc::{ErrorExt, proto::*};
  172use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  173use selections_collection::{
  174    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  175};
  176use serde::{Deserialize, Serialize};
  177use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  178use smallvec::{SmallVec, smallvec};
  179use snippet::Snippet;
  180use std::sync::Arc;
  181use std::{
  182    any::TypeId,
  183    borrow::Cow,
  184    cell::RefCell,
  185    cmp::{self, Ordering, Reverse},
  186    mem,
  187    num::NonZeroU32,
  188    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  189    path::{Path, PathBuf},
  190    rc::Rc,
  191    time::{Duration, Instant},
  192};
  193pub use sum_tree::Bias;
  194use sum_tree::TreeMap;
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  196use theme::{
  197    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  202    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  203};
  204use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  205use workspace::{
  206    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  207    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  208    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{ItemHandle, PreviewTabsSettings},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::SearchEvent,
  212};
  213
  214use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  215use crate::{
  216    code_context_menus::CompletionsMenuSource,
  217    hover_links::{find_url, find_url_from_range},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  223const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  224const MAX_LINE_LEN: usize = 1024;
  225const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  226const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  227pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  228#[doc(hidden)]
  229pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  230const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  231
  232pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  239pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  240
  241pub type RenderDiffHunkControlsFn = Arc<
  242    dyn Fn(
  243        u32,
  244        &DiffHunkStatus,
  245        Range<Anchor>,
  246        bool,
  247        Pixels,
  248        &Entity<Editor>,
  249        &mut Window,
  250        &mut App,
  251    ) -> AnyElement,
  252>;
  253
  254const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  255    alt: true,
  256    shift: true,
  257    control: false,
  258    platform: false,
  259    function: false,
  260};
  261
  262struct InlineValueCache {
  263    enabled: bool,
  264    inlays: Vec<InlayId>,
  265    refresh_task: Task<Option<()>>,
  266}
  267
  268impl InlineValueCache {
  269    fn new(enabled: bool) -> Self {
  270        Self {
  271            enabled,
  272            inlays: Vec::new(),
  273            refresh_task: Task::ready(None),
  274        }
  275    }
  276}
  277
  278#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  279pub enum InlayId {
  280    InlineCompletion(usize),
  281    Hint(usize),
  282    DebuggerValue(usize),
  283}
  284
  285impl InlayId {
  286    fn id(&self) -> usize {
  287        match self {
  288            Self::InlineCompletion(id) => *id,
  289            Self::Hint(id) => *id,
  290            Self::DebuggerValue(id) => *id,
  291        }
  292    }
  293}
  294
  295pub enum ActiveDebugLine {}
  296pub enum DebugStackFrameLine {}
  297enum DocumentHighlightRead {}
  298enum DocumentHighlightWrite {}
  299enum InputComposition {}
  300enum SelectedTextHighlight {}
  301
  302pub enum ConflictsOuter {}
  303pub enum ConflictsOurs {}
  304pub enum ConflictsTheirs {}
  305pub enum ConflictsOursMarker {}
  306pub enum ConflictsTheirsMarker {}
  307
  308#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  309pub enum Navigated {
  310    Yes,
  311    No,
  312}
  313
  314impl Navigated {
  315    pub fn from_bool(yes: bool) -> Navigated {
  316        if yes { Navigated::Yes } else { Navigated::No }
  317    }
  318}
  319
  320#[derive(Debug, Clone, PartialEq, Eq)]
  321enum DisplayDiffHunk {
  322    Folded {
  323        display_row: DisplayRow,
  324    },
  325    Unfolded {
  326        is_created_file: bool,
  327        diff_base_byte_range: Range<usize>,
  328        display_row_range: Range<DisplayRow>,
  329        multi_buffer_range: Range<Anchor>,
  330        status: DiffHunkStatus,
  331    },
  332}
  333
  334pub enum HideMouseCursorOrigin {
  335    TypingAction,
  336    MovementAction,
  337}
  338
  339pub fn init_settings(cx: &mut App) {
  340    EditorSettings::register(cx);
  341}
  342
  343pub fn init(cx: &mut App) {
  344    init_settings(cx);
  345
  346    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  347
  348    workspace::register_project_item::<Editor>(cx);
  349    workspace::FollowableViewRegistry::register::<Editor>(cx);
  350    workspace::register_serializable_item::<Editor>(cx);
  351
  352    cx.observe_new(
  353        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  354            workspace.register_action(Editor::new_file);
  355            workspace.register_action(Editor::new_file_vertical);
  356            workspace.register_action(Editor::new_file_horizontal);
  357            workspace.register_action(Editor::cancel_language_server_work);
  358        },
  359    )
  360    .detach();
  361
  362    cx.on_action(move |_: &workspace::NewFile, cx| {
  363        let app_state = workspace::AppState::global(cx);
  364        if let Some(app_state) = app_state.upgrade() {
  365            workspace::open_new(
  366                Default::default(),
  367                app_state,
  368                cx,
  369                |workspace, window, cx| {
  370                    Editor::new_file(workspace, &Default::default(), window, cx)
  371                },
  372            )
  373            .detach();
  374        }
  375    });
  376    cx.on_action(move |_: &workspace::NewWindow, cx| {
  377        let app_state = workspace::AppState::global(cx);
  378        if let Some(app_state) = app_state.upgrade() {
  379            workspace::open_new(
  380                Default::default(),
  381                app_state,
  382                cx,
  383                |workspace, window, cx| {
  384                    cx.activate(true);
  385                    Editor::new_file(workspace, &Default::default(), window, cx)
  386                },
  387            )
  388            .detach();
  389        }
  390    });
  391}
  392
  393pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  394    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  395}
  396
  397pub trait DiagnosticRenderer {
  398    fn render_group(
  399        &self,
  400        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  401        buffer_id: BufferId,
  402        snapshot: EditorSnapshot,
  403        editor: WeakEntity<Editor>,
  404        cx: &mut App,
  405    ) -> Vec<BlockProperties<Anchor>>;
  406
  407    fn render_hover(
  408        &self,
  409        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  410        range: Range<Point>,
  411        buffer_id: BufferId,
  412        cx: &mut App,
  413    ) -> Option<Entity<markdown::Markdown>>;
  414
  415    fn open_link(
  416        &self,
  417        editor: &mut Editor,
  418        link: SharedString,
  419        window: &mut Window,
  420        cx: &mut Context<Editor>,
  421    );
  422}
  423
  424pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  425
  426impl GlobalDiagnosticRenderer {
  427    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  428        cx.try_global::<Self>().map(|g| g.0.clone())
  429    }
  430}
  431
  432impl gpui::Global for GlobalDiagnosticRenderer {}
  433pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  434    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  435}
  436
  437pub struct SearchWithinRange;
  438
  439trait InvalidationRegion {
  440    fn ranges(&self) -> &[Range<Anchor>];
  441}
  442
  443#[derive(Clone, Debug, PartialEq)]
  444pub enum SelectPhase {
  445    Begin {
  446        position: DisplayPoint,
  447        add: bool,
  448        click_count: usize,
  449    },
  450    BeginColumnar {
  451        position: DisplayPoint,
  452        reset: bool,
  453        goal_column: u32,
  454    },
  455    Extend {
  456        position: DisplayPoint,
  457        click_count: usize,
  458    },
  459    Update {
  460        position: DisplayPoint,
  461        goal_column: u32,
  462        scroll_delta: gpui::Point<f32>,
  463    },
  464    End,
  465}
  466
  467#[derive(Clone, Debug)]
  468pub enum SelectMode {
  469    Character,
  470    Word(Range<Anchor>),
  471    Line(Range<Anchor>),
  472    All,
  473}
  474
  475#[derive(Clone, PartialEq, Eq, Debug)]
  476pub enum EditorMode {
  477    SingleLine {
  478        auto_width: bool,
  479    },
  480    AutoHeight {
  481        max_lines: usize,
  482    },
  483    Full {
  484        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  485        scale_ui_elements_with_buffer_font_size: bool,
  486        /// When set to `true`, the editor will render a background for the active line.
  487        show_active_line_background: bool,
  488        /// When set to `true`, the editor's height will be determined by its content.
  489        sized_by_content: bool,
  490    },
  491    Minimap {
  492        parent: WeakEntity<Editor>,
  493    },
  494}
  495
  496impl EditorMode {
  497    pub fn full() -> Self {
  498        Self::Full {
  499            scale_ui_elements_with_buffer_font_size: true,
  500            show_active_line_background: true,
  501            sized_by_content: false,
  502        }
  503    }
  504
  505    pub fn is_full(&self) -> bool {
  506        matches!(self, Self::Full { .. })
  507    }
  508
  509    fn is_minimap(&self) -> bool {
  510        matches!(self, Self::Minimap { .. })
  511    }
  512}
  513
  514#[derive(Copy, Clone, Debug)]
  515pub enum SoftWrap {
  516    /// Prefer not to wrap at all.
  517    ///
  518    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  519    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  520    GitDiff,
  521    /// Prefer a single line generally, unless an overly long line is encountered.
  522    None,
  523    /// Soft wrap lines that exceed the editor width.
  524    EditorWidth,
  525    /// Soft wrap lines at the preferred line length.
  526    Column(u32),
  527    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  528    Bounded(u32),
  529}
  530
  531#[derive(Clone)]
  532pub struct EditorStyle {
  533    pub background: Hsla,
  534    pub local_player: PlayerColor,
  535    pub text: TextStyle,
  536    pub scrollbar_width: Pixels,
  537    pub syntax: Arc<SyntaxTheme>,
  538    pub status: StatusColors,
  539    pub inlay_hints_style: HighlightStyle,
  540    pub inline_completion_styles: InlineCompletionStyles,
  541    pub unnecessary_code_fade: f32,
  542    pub show_underlines: bool,
  543}
  544
  545impl Default for EditorStyle {
  546    fn default() -> Self {
  547        Self {
  548            background: Hsla::default(),
  549            local_player: PlayerColor::default(),
  550            text: TextStyle::default(),
  551            scrollbar_width: Pixels::default(),
  552            syntax: Default::default(),
  553            // HACK: Status colors don't have a real default.
  554            // We should look into removing the status colors from the editor
  555            // style and retrieve them directly from the theme.
  556            status: StatusColors::dark(),
  557            inlay_hints_style: HighlightStyle::default(),
  558            inline_completion_styles: InlineCompletionStyles {
  559                insertion: HighlightStyle::default(),
  560                whitespace: HighlightStyle::default(),
  561            },
  562            unnecessary_code_fade: Default::default(),
  563            show_underlines: true,
  564        }
  565    }
  566}
  567
  568pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  569    let show_background = language_settings::language_settings(None, None, cx)
  570        .inlay_hints
  571        .show_background;
  572
  573    HighlightStyle {
  574        color: Some(cx.theme().status().hint),
  575        background_color: show_background.then(|| cx.theme().status().hint_background),
  576        ..HighlightStyle::default()
  577    }
  578}
  579
  580pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  581    InlineCompletionStyles {
  582        insertion: HighlightStyle {
  583            color: Some(cx.theme().status().predictive),
  584            ..HighlightStyle::default()
  585        },
  586        whitespace: HighlightStyle {
  587            background_color: Some(cx.theme().status().created_background),
  588            ..HighlightStyle::default()
  589        },
  590    }
  591}
  592
  593type CompletionId = usize;
  594
  595pub(crate) enum EditDisplayMode {
  596    TabAccept,
  597    DiffPopover,
  598    Inline,
  599}
  600
  601enum InlineCompletion {
  602    Edit {
  603        edits: Vec<(Range<Anchor>, String)>,
  604        edit_preview: Option<EditPreview>,
  605        display_mode: EditDisplayMode,
  606        snapshot: BufferSnapshot,
  607    },
  608    Move {
  609        target: Anchor,
  610        snapshot: BufferSnapshot,
  611    },
  612}
  613
  614struct InlineCompletionState {
  615    inlay_ids: Vec<InlayId>,
  616    completion: InlineCompletion,
  617    completion_id: Option<SharedString>,
  618    invalidation_range: Range<Anchor>,
  619}
  620
  621enum EditPredictionSettings {
  622    Disabled,
  623    Enabled {
  624        show_in_menu: bool,
  625        preview_requires_modifier: bool,
  626    },
  627}
  628
  629enum InlineCompletionHighlight {}
  630
  631#[derive(Debug, Clone)]
  632struct InlineDiagnostic {
  633    message: SharedString,
  634    group_id: usize,
  635    is_primary: bool,
  636    start: Point,
  637    severity: lsp::DiagnosticSeverity,
  638}
  639
  640pub enum MenuInlineCompletionsPolicy {
  641    Never,
  642    ByProvider,
  643}
  644
  645pub enum EditPredictionPreview {
  646    /// Modifier is not pressed
  647    Inactive { released_too_fast: bool },
  648    /// Modifier pressed
  649    Active {
  650        since: Instant,
  651        previous_scroll_position: Option<ScrollAnchor>,
  652    },
  653}
  654
  655impl EditPredictionPreview {
  656    pub fn released_too_fast(&self) -> bool {
  657        match self {
  658            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  659            EditPredictionPreview::Active { .. } => false,
  660        }
  661    }
  662
  663    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  664        if let EditPredictionPreview::Active {
  665            previous_scroll_position,
  666            ..
  667        } = self
  668        {
  669            *previous_scroll_position = scroll_position;
  670        }
  671    }
  672}
  673
  674pub struct ContextMenuOptions {
  675    pub min_entries_visible: usize,
  676    pub max_entries_visible: usize,
  677    pub placement: Option<ContextMenuPlacement>,
  678}
  679
  680#[derive(Debug, Clone, PartialEq, Eq)]
  681pub enum ContextMenuPlacement {
  682    Above,
  683    Below,
  684}
  685
  686#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  687struct EditorActionId(usize);
  688
  689impl EditorActionId {
  690    pub fn post_inc(&mut self) -> Self {
  691        let answer = self.0;
  692
  693        *self = Self(answer + 1);
  694
  695        Self(answer)
  696    }
  697}
  698
  699// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  700// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  701
  702type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  703type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  704
  705#[derive(Default)]
  706struct ScrollbarMarkerState {
  707    scrollbar_size: Size<Pixels>,
  708    dirty: bool,
  709    markers: Arc<[PaintQuad]>,
  710    pending_refresh: Option<Task<Result<()>>>,
  711}
  712
  713impl ScrollbarMarkerState {
  714    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  715        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  716    }
  717}
  718
  719#[derive(Clone, Copy, PartialEq, Eq)]
  720pub enum MinimapVisibility {
  721    Disabled,
  722    Enabled {
  723        /// The configuration currently present in the users settings.
  724        setting_configuration: bool,
  725        /// Whether to override the currently set visibility from the users setting.
  726        toggle_override: bool,
  727    },
  728}
  729
  730impl MinimapVisibility {
  731    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  732        if mode.is_full() {
  733            Self::Enabled {
  734                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  735                toggle_override: false,
  736            }
  737        } else {
  738            Self::Disabled
  739        }
  740    }
  741
  742    fn hidden(&self) -> Self {
  743        match *self {
  744            Self::Enabled {
  745                setting_configuration,
  746                ..
  747            } => Self::Enabled {
  748                setting_configuration,
  749                toggle_override: setting_configuration,
  750            },
  751            Self::Disabled => Self::Disabled,
  752        }
  753    }
  754
  755    fn disabled(&self) -> bool {
  756        match *self {
  757            Self::Disabled => true,
  758            _ => false,
  759        }
  760    }
  761
  762    fn settings_visibility(&self) -> bool {
  763        match *self {
  764            Self::Enabled {
  765                setting_configuration,
  766                ..
  767            } => setting_configuration,
  768            _ => false,
  769        }
  770    }
  771
  772    fn visible(&self) -> bool {
  773        match *self {
  774            Self::Enabled {
  775                setting_configuration,
  776                toggle_override,
  777            } => setting_configuration ^ toggle_override,
  778            _ => false,
  779        }
  780    }
  781
  782    fn toggle_visibility(&self) -> Self {
  783        match *self {
  784            Self::Enabled {
  785                toggle_override,
  786                setting_configuration,
  787            } => Self::Enabled {
  788                setting_configuration,
  789                toggle_override: !toggle_override,
  790            },
  791            Self::Disabled => Self::Disabled,
  792        }
  793    }
  794}
  795
  796#[derive(Clone, Debug)]
  797struct RunnableTasks {
  798    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  799    offset: multi_buffer::Anchor,
  800    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  801    column: u32,
  802    // Values of all named captures, including those starting with '_'
  803    extra_variables: HashMap<String, String>,
  804    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  805    context_range: Range<BufferOffset>,
  806}
  807
  808impl RunnableTasks {
  809    fn resolve<'a>(
  810        &'a self,
  811        cx: &'a task::TaskContext,
  812    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  813        self.templates.iter().filter_map(|(kind, template)| {
  814            template
  815                .resolve_task(&kind.to_id_base(), cx)
  816                .map(|task| (kind.clone(), task))
  817        })
  818    }
  819}
  820
  821#[derive(Clone)]
  822pub struct ResolvedTasks {
  823    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  824    position: Anchor,
  825}
  826
  827#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  828struct BufferOffset(usize);
  829
  830// Addons allow storing per-editor state in other crates (e.g. Vim)
  831pub trait Addon: 'static {
  832    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  833
  834    fn render_buffer_header_controls(
  835        &self,
  836        _: &ExcerptInfo,
  837        _: &Window,
  838        _: &App,
  839    ) -> Option<AnyElement> {
  840        None
  841    }
  842
  843    fn to_any(&self) -> &dyn std::any::Any;
  844
  845    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  846        None
  847    }
  848}
  849
  850/// A set of caret positions, registered when the editor was edited.
  851pub struct ChangeList {
  852    changes: Vec<Vec<Anchor>>,
  853    /// Currently "selected" change.
  854    position: Option<usize>,
  855}
  856
  857impl ChangeList {
  858    pub fn new() -> Self {
  859        Self {
  860            changes: Vec::new(),
  861            position: None,
  862        }
  863    }
  864
  865    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  866    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  867    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  868        if self.changes.is_empty() {
  869            return None;
  870        }
  871
  872        let prev = self.position.unwrap_or(self.changes.len());
  873        let next = if direction == Direction::Prev {
  874            prev.saturating_sub(count)
  875        } else {
  876            (prev + count).min(self.changes.len() - 1)
  877        };
  878        self.position = Some(next);
  879        self.changes.get(next).map(|anchors| anchors.as_slice())
  880    }
  881
  882    /// Adds a new change to the list, resetting the change list position.
  883    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  884        self.position.take();
  885        if pop_state {
  886            self.changes.pop();
  887        }
  888        self.changes.push(new_positions.clone());
  889    }
  890
  891    pub fn last(&self) -> Option<&[Anchor]> {
  892        self.changes.last().map(|anchors| anchors.as_slice())
  893    }
  894}
  895
  896#[derive(Clone)]
  897struct InlineBlamePopoverState {
  898    scroll_handle: ScrollHandle,
  899    commit_message: Option<ParsedCommitMessage>,
  900    markdown: Entity<Markdown>,
  901}
  902
  903struct InlineBlamePopover {
  904    position: gpui::Point<Pixels>,
  905    show_task: Option<Task<()>>,
  906    hide_task: Option<Task<()>>,
  907    popover_bounds: Option<Bounds<Pixels>>,
  908    popover_state: InlineBlamePopoverState,
  909}
  910
  911/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  912/// a breakpoint on them.
  913#[derive(Clone, Copy, Debug)]
  914struct PhantomBreakpointIndicator {
  915    display_row: DisplayRow,
  916    /// There's a small debounce between hovering over the line and showing the indicator.
  917    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  918    is_active: bool,
  919    collides_with_existing_breakpoint: bool,
  920}
  921/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  922///
  923/// See the [module level documentation](self) for more information.
  924pub struct Editor {
  925    focus_handle: FocusHandle,
  926    last_focused_descendant: Option<WeakFocusHandle>,
  927    /// The text buffer being edited
  928    buffer: Entity<MultiBuffer>,
  929    /// Map of how text in the buffer should be displayed.
  930    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  931    pub display_map: Entity<DisplayMap>,
  932    pub selections: SelectionsCollection,
  933    pub scroll_manager: ScrollManager,
  934    /// When inline assist editors are linked, they all render cursors because
  935    /// typing enters text into each of them, even the ones that aren't focused.
  936    pub(crate) show_cursor_when_unfocused: bool,
  937    columnar_selection_tail: Option<Anchor>,
  938    columnar_display_point: Option<DisplayPoint>,
  939    add_selections_state: Option<AddSelectionsState>,
  940    select_next_state: Option<SelectNextState>,
  941    select_prev_state: Option<SelectNextState>,
  942    selection_history: SelectionHistory,
  943    defer_selection_effects: bool,
  944    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  945    autoclose_regions: Vec<AutocloseRegion>,
  946    snippet_stack: InvalidationStack<SnippetState>,
  947    select_syntax_node_history: SelectSyntaxNodeHistory,
  948    ime_transaction: Option<TransactionId>,
  949    pub diagnostics_max_severity: DiagnosticSeverity,
  950    active_diagnostics: ActiveDiagnostic,
  951    show_inline_diagnostics: bool,
  952    inline_diagnostics_update: Task<()>,
  953    inline_diagnostics_enabled: bool,
  954    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  955    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  956    hard_wrap: Option<usize>,
  957
  958    // TODO: make this a access method
  959    pub project: Option<Entity<Project>>,
  960    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  961    completion_provider: Option<Rc<dyn CompletionProvider>>,
  962    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  963    blink_manager: Entity<BlinkManager>,
  964    show_cursor_names: bool,
  965    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  966    pub show_local_selections: bool,
  967    mode: EditorMode,
  968    show_breadcrumbs: bool,
  969    show_gutter: bool,
  970    show_scrollbars: ScrollbarAxes,
  971    minimap_visibility: MinimapVisibility,
  972    offset_content: bool,
  973    disable_expand_excerpt_buttons: bool,
  974    show_line_numbers: Option<bool>,
  975    use_relative_line_numbers: Option<bool>,
  976    show_git_diff_gutter: Option<bool>,
  977    show_code_actions: Option<bool>,
  978    show_runnables: Option<bool>,
  979    show_breakpoints: Option<bool>,
  980    show_wrap_guides: Option<bool>,
  981    show_indent_guides: Option<bool>,
  982    placeholder_text: Option<Arc<str>>,
  983    highlight_order: usize,
  984    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  985    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  986    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  987    scrollbar_marker_state: ScrollbarMarkerState,
  988    active_indent_guides_state: ActiveIndentGuidesState,
  989    nav_history: Option<ItemNavHistory>,
  990    context_menu: RefCell<Option<CodeContextMenu>>,
  991    context_menu_options: Option<ContextMenuOptions>,
  992    mouse_context_menu: Option<MouseContextMenu>,
  993    completion_tasks: Vec<(CompletionId, Task<()>)>,
  994    inline_blame_popover: Option<InlineBlamePopover>,
  995    signature_help_state: SignatureHelpState,
  996    auto_signature_help: Option<bool>,
  997    find_all_references_task_sources: Vec<Anchor>,
  998    next_completion_id: CompletionId,
  999    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1000    code_actions_task: Option<Task<Result<()>>>,
 1001    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1002    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1003    document_highlights_task: Option<Task<()>>,
 1004    linked_editing_range_task: Option<Task<Option<()>>>,
 1005    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1006    pending_rename: Option<RenameState>,
 1007    searchable: bool,
 1008    cursor_shape: CursorShape,
 1009    current_line_highlight: Option<CurrentLineHighlight>,
 1010    collapse_matches: bool,
 1011    autoindent_mode: Option<AutoindentMode>,
 1012    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1013    input_enabled: bool,
 1014    use_modal_editing: bool,
 1015    read_only: bool,
 1016    leader_id: Option<CollaboratorId>,
 1017    remote_id: Option<ViewId>,
 1018    pub hover_state: HoverState,
 1019    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1020    gutter_hovered: bool,
 1021    hovered_link_state: Option<HoveredLinkState>,
 1022    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1023    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1024    active_inline_completion: Option<InlineCompletionState>,
 1025    /// Used to prevent flickering as the user types while the menu is open
 1026    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1027    edit_prediction_settings: EditPredictionSettings,
 1028    inline_completions_hidden_for_vim_mode: bool,
 1029    show_inline_completions_override: Option<bool>,
 1030    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1031    edit_prediction_preview: EditPredictionPreview,
 1032    edit_prediction_indent_conflict: bool,
 1033    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1034    inlay_hint_cache: InlayHintCache,
 1035    next_inlay_id: usize,
 1036    _subscriptions: Vec<Subscription>,
 1037    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1038    gutter_dimensions: GutterDimensions,
 1039    style: Option<EditorStyle>,
 1040    text_style_refinement: Option<TextStyleRefinement>,
 1041    next_editor_action_id: EditorActionId,
 1042    editor_actions:
 1043        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
 1044    use_autoclose: bool,
 1045    use_auto_surround: bool,
 1046    auto_replace_emoji_shortcode: bool,
 1047    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1048    show_git_blame_gutter: bool,
 1049    show_git_blame_inline: bool,
 1050    show_git_blame_inline_delay_task: Option<Task<()>>,
 1051    git_blame_inline_enabled: bool,
 1052    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1053    serialize_dirty_buffers: bool,
 1054    show_selection_menu: Option<bool>,
 1055    blame: Option<Entity<GitBlame>>,
 1056    blame_subscription: Option<Subscription>,
 1057    custom_context_menu: Option<
 1058        Box<
 1059            dyn 'static
 1060                + Fn(
 1061                    &mut Self,
 1062                    DisplayPoint,
 1063                    &mut Window,
 1064                    &mut Context<Self>,
 1065                ) -> Option<Entity<ui::ContextMenu>>,
 1066        >,
 1067    >,
 1068    last_bounds: Option<Bounds<Pixels>>,
 1069    last_position_map: Option<Rc<PositionMap>>,
 1070    expect_bounds_change: Option<Bounds<Pixels>>,
 1071    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1072    tasks_update_task: Option<Task<()>>,
 1073    breakpoint_store: Option<Entity<BreakpointStore>>,
 1074    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1075    in_project_search: bool,
 1076    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1077    breadcrumb_header: Option<String>,
 1078    focused_block: Option<FocusedBlock>,
 1079    next_scroll_position: NextScrollCursorCenterTopBottom,
 1080    addons: HashMap<TypeId, Box<dyn Addon>>,
 1081    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1082    load_diff_task: Option<Shared<Task<()>>>,
 1083    /// Whether we are temporarily displaying a diff other than git's
 1084    temporary_diff_override: bool,
 1085    selection_mark_mode: bool,
 1086    toggle_fold_multiple_buffers: Task<()>,
 1087    _scroll_cursor_center_top_bottom_task: Task<()>,
 1088    serialize_selections: Task<()>,
 1089    serialize_folds: Task<()>,
 1090    mouse_cursor_hidden: bool,
 1091    minimap: Option<Entity<Self>>,
 1092    hide_mouse_mode: HideMouseMode,
 1093    pub change_list: ChangeList,
 1094    inline_value_cache: InlineValueCache,
 1095}
 1096
 1097#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1098enum NextScrollCursorCenterTopBottom {
 1099    #[default]
 1100    Center,
 1101    Top,
 1102    Bottom,
 1103}
 1104
 1105impl NextScrollCursorCenterTopBottom {
 1106    fn next(&self) -> Self {
 1107        match self {
 1108            Self::Center => Self::Top,
 1109            Self::Top => Self::Bottom,
 1110            Self::Bottom => Self::Center,
 1111        }
 1112    }
 1113}
 1114
 1115#[derive(Clone)]
 1116pub struct EditorSnapshot {
 1117    pub mode: EditorMode,
 1118    show_gutter: bool,
 1119    show_line_numbers: Option<bool>,
 1120    show_git_diff_gutter: Option<bool>,
 1121    show_code_actions: Option<bool>,
 1122    show_runnables: Option<bool>,
 1123    show_breakpoints: Option<bool>,
 1124    git_blame_gutter_max_author_length: Option<usize>,
 1125    pub display_snapshot: DisplaySnapshot,
 1126    pub placeholder_text: Option<Arc<str>>,
 1127    is_focused: bool,
 1128    scroll_anchor: ScrollAnchor,
 1129    ongoing_scroll: OngoingScroll,
 1130    current_line_highlight: CurrentLineHighlight,
 1131    gutter_hovered: bool,
 1132}
 1133
 1134#[derive(Default, Debug, Clone, Copy)]
 1135pub struct GutterDimensions {
 1136    pub left_padding: Pixels,
 1137    pub right_padding: Pixels,
 1138    pub width: Pixels,
 1139    pub margin: Pixels,
 1140    pub git_blame_entries_width: Option<Pixels>,
 1141}
 1142
 1143impl GutterDimensions {
 1144    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1145        Self {
 1146            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1147            ..Default::default()
 1148        }
 1149    }
 1150
 1151    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1152        -cx.text_system().descent(font_id, font_size)
 1153    }
 1154    /// The full width of the space taken up by the gutter.
 1155    pub fn full_width(&self) -> Pixels {
 1156        self.margin + self.width
 1157    }
 1158
 1159    /// The width of the space reserved for the fold indicators,
 1160    /// use alongside 'justify_end' and `gutter_width` to
 1161    /// right align content with the line numbers
 1162    pub fn fold_area_width(&self) -> Pixels {
 1163        self.margin + self.right_padding
 1164    }
 1165}
 1166
 1167#[derive(Debug)]
 1168pub struct RemoteSelection {
 1169    pub replica_id: ReplicaId,
 1170    pub selection: Selection<Anchor>,
 1171    pub cursor_shape: CursorShape,
 1172    pub collaborator_id: CollaboratorId,
 1173    pub line_mode: bool,
 1174    pub user_name: Option<SharedString>,
 1175    pub color: PlayerColor,
 1176}
 1177
 1178#[derive(Clone, Debug)]
 1179struct SelectionHistoryEntry {
 1180    selections: Arc<[Selection<Anchor>]>,
 1181    select_next_state: Option<SelectNextState>,
 1182    select_prev_state: Option<SelectNextState>,
 1183    add_selections_state: Option<AddSelectionsState>,
 1184}
 1185
 1186enum SelectionHistoryMode {
 1187    Normal,
 1188    Undoing,
 1189    Redoing,
 1190}
 1191
 1192#[derive(Clone, PartialEq, Eq, Hash)]
 1193struct HoveredCursor {
 1194    replica_id: u16,
 1195    selection_id: usize,
 1196}
 1197
 1198impl Default for SelectionHistoryMode {
 1199    fn default() -> Self {
 1200        Self::Normal
 1201    }
 1202}
 1203
 1204struct DeferredSelectionEffectsState {
 1205    changed: bool,
 1206    should_update_completions: bool,
 1207    autoscroll: Option<Autoscroll>,
 1208    old_cursor_position: Anchor,
 1209    history_entry: SelectionHistoryEntry,
 1210}
 1211
 1212#[derive(Default)]
 1213struct SelectionHistory {
 1214    #[allow(clippy::type_complexity)]
 1215    selections_by_transaction:
 1216        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1217    mode: SelectionHistoryMode,
 1218    undo_stack: VecDeque<SelectionHistoryEntry>,
 1219    redo_stack: VecDeque<SelectionHistoryEntry>,
 1220}
 1221
 1222impl SelectionHistory {
 1223    fn insert_transaction(
 1224        &mut self,
 1225        transaction_id: TransactionId,
 1226        selections: Arc<[Selection<Anchor>]>,
 1227    ) {
 1228        self.selections_by_transaction
 1229            .insert(transaction_id, (selections, None));
 1230    }
 1231
 1232    #[allow(clippy::type_complexity)]
 1233    fn transaction(
 1234        &self,
 1235        transaction_id: TransactionId,
 1236    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1237        self.selections_by_transaction.get(&transaction_id)
 1238    }
 1239
 1240    #[allow(clippy::type_complexity)]
 1241    fn transaction_mut(
 1242        &mut self,
 1243        transaction_id: TransactionId,
 1244    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1245        self.selections_by_transaction.get_mut(&transaction_id)
 1246    }
 1247
 1248    fn push(&mut self, entry: SelectionHistoryEntry) {
 1249        if !entry.selections.is_empty() {
 1250            match self.mode {
 1251                SelectionHistoryMode::Normal => {
 1252                    self.push_undo(entry);
 1253                    self.redo_stack.clear();
 1254                }
 1255                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1256                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1257            }
 1258        }
 1259    }
 1260
 1261    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1262        if self
 1263            .undo_stack
 1264            .back()
 1265            .map_or(true, |e| e.selections != entry.selections)
 1266        {
 1267            self.undo_stack.push_back(entry);
 1268            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1269                self.undo_stack.pop_front();
 1270            }
 1271        }
 1272    }
 1273
 1274    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1275        if self
 1276            .redo_stack
 1277            .back()
 1278            .map_or(true, |e| e.selections != entry.selections)
 1279        {
 1280            self.redo_stack.push_back(entry);
 1281            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1282                self.redo_stack.pop_front();
 1283            }
 1284        }
 1285    }
 1286}
 1287
 1288#[derive(Clone, Copy)]
 1289pub struct RowHighlightOptions {
 1290    pub autoscroll: bool,
 1291    pub include_gutter: bool,
 1292}
 1293
 1294impl Default for RowHighlightOptions {
 1295    fn default() -> Self {
 1296        Self {
 1297            autoscroll: Default::default(),
 1298            include_gutter: true,
 1299        }
 1300    }
 1301}
 1302
 1303struct RowHighlight {
 1304    index: usize,
 1305    range: Range<Anchor>,
 1306    color: Hsla,
 1307    options: RowHighlightOptions,
 1308    type_id: TypeId,
 1309}
 1310
 1311#[derive(Clone, Debug)]
 1312struct AddSelectionsState {
 1313    above: bool,
 1314    stack: Vec<usize>,
 1315}
 1316
 1317#[derive(Clone)]
 1318struct SelectNextState {
 1319    query: AhoCorasick,
 1320    wordwise: bool,
 1321    done: bool,
 1322}
 1323
 1324impl std::fmt::Debug for SelectNextState {
 1325    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1326        f.debug_struct(std::any::type_name::<Self>())
 1327            .field("wordwise", &self.wordwise)
 1328            .field("done", &self.done)
 1329            .finish()
 1330    }
 1331}
 1332
 1333#[derive(Debug)]
 1334struct AutocloseRegion {
 1335    selection_id: usize,
 1336    range: Range<Anchor>,
 1337    pair: BracketPair,
 1338}
 1339
 1340#[derive(Debug)]
 1341struct SnippetState {
 1342    ranges: Vec<Vec<Range<Anchor>>>,
 1343    active_index: usize,
 1344    choices: Vec<Option<Vec<String>>>,
 1345}
 1346
 1347#[doc(hidden)]
 1348pub struct RenameState {
 1349    pub range: Range<Anchor>,
 1350    pub old_name: Arc<str>,
 1351    pub editor: Entity<Editor>,
 1352    block_id: CustomBlockId,
 1353}
 1354
 1355struct InvalidationStack<T>(Vec<T>);
 1356
 1357struct RegisteredInlineCompletionProvider {
 1358    provider: Arc<dyn InlineCompletionProviderHandle>,
 1359    _subscription: Subscription,
 1360}
 1361
 1362#[derive(Debug, PartialEq, Eq)]
 1363pub struct ActiveDiagnosticGroup {
 1364    pub active_range: Range<Anchor>,
 1365    pub active_message: String,
 1366    pub group_id: usize,
 1367    pub blocks: HashSet<CustomBlockId>,
 1368}
 1369
 1370#[derive(Debug, PartialEq, Eq)]
 1371
 1372pub(crate) enum ActiveDiagnostic {
 1373    None,
 1374    All,
 1375    Group(ActiveDiagnosticGroup),
 1376}
 1377
 1378#[derive(Serialize, Deserialize, Clone, Debug)]
 1379pub struct ClipboardSelection {
 1380    /// The number of bytes in this selection.
 1381    pub len: usize,
 1382    /// Whether this was a full-line selection.
 1383    pub is_entire_line: bool,
 1384    /// The indentation of the first line when this content was originally copied.
 1385    pub first_line_indent: u32,
 1386}
 1387
 1388// selections, scroll behavior, was newest selection reversed
 1389type SelectSyntaxNodeHistoryState = (
 1390    Box<[Selection<usize>]>,
 1391    SelectSyntaxNodeScrollBehavior,
 1392    bool,
 1393);
 1394
 1395#[derive(Default)]
 1396struct SelectSyntaxNodeHistory {
 1397    stack: Vec<SelectSyntaxNodeHistoryState>,
 1398    // disable temporarily to allow changing selections without losing the stack
 1399    pub disable_clearing: bool,
 1400}
 1401
 1402impl SelectSyntaxNodeHistory {
 1403    pub fn try_clear(&mut self) {
 1404        if !self.disable_clearing {
 1405            self.stack.clear();
 1406        }
 1407    }
 1408
 1409    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1410        self.stack.push(selection);
 1411    }
 1412
 1413    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1414        self.stack.pop()
 1415    }
 1416}
 1417
 1418enum SelectSyntaxNodeScrollBehavior {
 1419    CursorTop,
 1420    FitSelection,
 1421    CursorBottom,
 1422}
 1423
 1424#[derive(Debug)]
 1425pub(crate) struct NavigationData {
 1426    cursor_anchor: Anchor,
 1427    cursor_position: Point,
 1428    scroll_anchor: ScrollAnchor,
 1429    scroll_top_row: u32,
 1430}
 1431
 1432#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1433pub enum GotoDefinitionKind {
 1434    Symbol,
 1435    Declaration,
 1436    Type,
 1437    Implementation,
 1438}
 1439
 1440#[derive(Debug, Clone)]
 1441enum InlayHintRefreshReason {
 1442    ModifiersChanged(bool),
 1443    Toggle(bool),
 1444    SettingsChange(InlayHintSettings),
 1445    NewLinesShown,
 1446    BufferEdited(HashSet<Arc<Language>>),
 1447    RefreshRequested,
 1448    ExcerptsRemoved(Vec<ExcerptId>),
 1449}
 1450
 1451impl InlayHintRefreshReason {
 1452    fn description(&self) -> &'static str {
 1453        match self {
 1454            Self::ModifiersChanged(_) => "modifiers changed",
 1455            Self::Toggle(_) => "toggle",
 1456            Self::SettingsChange(_) => "settings change",
 1457            Self::NewLinesShown => "new lines shown",
 1458            Self::BufferEdited(_) => "buffer edited",
 1459            Self::RefreshRequested => "refresh requested",
 1460            Self::ExcerptsRemoved(_) => "excerpts removed",
 1461        }
 1462    }
 1463}
 1464
 1465pub enum FormatTarget {
 1466    Buffers,
 1467    Ranges(Vec<Range<MultiBufferPoint>>),
 1468}
 1469
 1470pub(crate) struct FocusedBlock {
 1471    id: BlockId,
 1472    focus_handle: WeakFocusHandle,
 1473}
 1474
 1475#[derive(Clone)]
 1476enum JumpData {
 1477    MultiBufferRow {
 1478        row: MultiBufferRow,
 1479        line_offset_from_top: u32,
 1480    },
 1481    MultiBufferPoint {
 1482        excerpt_id: ExcerptId,
 1483        position: Point,
 1484        anchor: text::Anchor,
 1485        line_offset_from_top: u32,
 1486    },
 1487}
 1488
 1489pub enum MultibufferSelectionMode {
 1490    First,
 1491    All,
 1492}
 1493
 1494#[derive(Clone, Copy, Debug, Default)]
 1495pub struct RewrapOptions {
 1496    pub override_language_settings: bool,
 1497    pub preserve_existing_whitespace: bool,
 1498}
 1499
 1500impl Editor {
 1501    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1502        let buffer = cx.new(|cx| Buffer::local("", cx));
 1503        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1504        Self::new(
 1505            EditorMode::SingleLine { auto_width: false },
 1506            buffer,
 1507            None,
 1508            window,
 1509            cx,
 1510        )
 1511    }
 1512
 1513    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1514        let buffer = cx.new(|cx| Buffer::local("", cx));
 1515        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1516        Self::new(EditorMode::full(), buffer, None, window, cx)
 1517    }
 1518
 1519    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1520        let buffer = cx.new(|cx| Buffer::local("", cx));
 1521        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1522        Self::new(
 1523            EditorMode::SingleLine { auto_width: true },
 1524            buffer,
 1525            None,
 1526            window,
 1527            cx,
 1528        )
 1529    }
 1530
 1531    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1532        let buffer = cx.new(|cx| Buffer::local("", cx));
 1533        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1534        Self::new(
 1535            EditorMode::AutoHeight { max_lines },
 1536            buffer,
 1537            None,
 1538            window,
 1539            cx,
 1540        )
 1541    }
 1542
 1543    pub fn for_buffer(
 1544        buffer: Entity<Buffer>,
 1545        project: Option<Entity<Project>>,
 1546        window: &mut Window,
 1547        cx: &mut Context<Self>,
 1548    ) -> Self {
 1549        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1550        Self::new(EditorMode::full(), buffer, project, window, cx)
 1551    }
 1552
 1553    pub fn for_multibuffer(
 1554        buffer: Entity<MultiBuffer>,
 1555        project: Option<Entity<Project>>,
 1556        window: &mut Window,
 1557        cx: &mut Context<Self>,
 1558    ) -> Self {
 1559        Self::new(EditorMode::full(), buffer, project, window, cx)
 1560    }
 1561
 1562    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1563        let mut clone = Self::new(
 1564            self.mode.clone(),
 1565            self.buffer.clone(),
 1566            self.project.clone(),
 1567            window,
 1568            cx,
 1569        );
 1570        self.display_map.update(cx, |display_map, cx| {
 1571            let snapshot = display_map.snapshot(cx);
 1572            clone.display_map.update(cx, |display_map, cx| {
 1573                display_map.set_state(&snapshot, cx);
 1574            });
 1575        });
 1576        clone.folds_did_change(cx);
 1577        clone.selections.clone_state(&self.selections);
 1578        clone.scroll_manager.clone_state(&self.scroll_manager);
 1579        clone.searchable = self.searchable;
 1580        clone.read_only = self.read_only;
 1581        clone
 1582    }
 1583
 1584    pub fn new(
 1585        mode: EditorMode,
 1586        buffer: Entity<MultiBuffer>,
 1587        project: Option<Entity<Project>>,
 1588        window: &mut Window,
 1589        cx: &mut Context<Self>,
 1590    ) -> Self {
 1591        Editor::new_internal(mode, buffer, project, None, window, cx)
 1592    }
 1593
 1594    fn new_internal(
 1595        mode: EditorMode,
 1596        buffer: Entity<MultiBuffer>,
 1597        project: Option<Entity<Project>>,
 1598        display_map: Option<Entity<DisplayMap>>,
 1599        window: &mut Window,
 1600        cx: &mut Context<Self>,
 1601    ) -> Self {
 1602        debug_assert!(
 1603            display_map.is_none() || mode.is_minimap(),
 1604            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1605        );
 1606
 1607        let full_mode = mode.is_full();
 1608        let diagnostics_max_severity = if full_mode {
 1609            EditorSettings::get_global(cx)
 1610                .diagnostics_max_severity
 1611                .unwrap_or(DiagnosticSeverity::Hint)
 1612        } else {
 1613            DiagnosticSeverity::Off
 1614        };
 1615        let style = window.text_style();
 1616        let font_size = style.font_size.to_pixels(window.rem_size());
 1617        let editor = cx.entity().downgrade();
 1618        let fold_placeholder = FoldPlaceholder {
 1619            constrain_width: true,
 1620            render: Arc::new(move |fold_id, fold_range, cx| {
 1621                let editor = editor.clone();
 1622                div()
 1623                    .id(fold_id)
 1624                    .bg(cx.theme().colors().ghost_element_background)
 1625                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1626                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1627                    .rounded_xs()
 1628                    .size_full()
 1629                    .cursor_pointer()
 1630                    .child("")
 1631                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1632                    .on_click(move |_, _window, cx| {
 1633                        editor
 1634                            .update(cx, |editor, cx| {
 1635                                editor.unfold_ranges(
 1636                                    &[fold_range.start..fold_range.end],
 1637                                    true,
 1638                                    false,
 1639                                    cx,
 1640                                );
 1641                                cx.stop_propagation();
 1642                            })
 1643                            .ok();
 1644                    })
 1645                    .into_any()
 1646            }),
 1647            merge_adjacent: true,
 1648            ..FoldPlaceholder::default()
 1649        };
 1650        let display_map = display_map.unwrap_or_else(|| {
 1651            cx.new(|cx| {
 1652                DisplayMap::new(
 1653                    buffer.clone(),
 1654                    style.font(),
 1655                    font_size,
 1656                    None,
 1657                    FILE_HEADER_HEIGHT,
 1658                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1659                    fold_placeholder,
 1660                    diagnostics_max_severity,
 1661                    cx,
 1662                )
 1663            })
 1664        });
 1665
 1666        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1667
 1668        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1669
 1670        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1671            .then(|| language_settings::SoftWrap::None);
 1672
 1673        let mut project_subscriptions = Vec::new();
 1674        if mode.is_full() {
 1675            if let Some(project) = project.as_ref() {
 1676                project_subscriptions.push(cx.subscribe_in(
 1677                    project,
 1678                    window,
 1679                    |editor, _, event, window, cx| match event {
 1680                        project::Event::RefreshCodeLens => {
 1681                            // we always query lens with actions, without storing them, always refreshing them
 1682                        }
 1683                        project::Event::RefreshInlayHints => {
 1684                            editor
 1685                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1686                        }
 1687                        project::Event::LanguageServerAdded(..)
 1688                        | project::Event::LanguageServerRemoved(..) => {
 1689                            if editor.tasks_update_task.is_none() {
 1690                                editor.tasks_update_task =
 1691                                    Some(editor.refresh_runnables(window, cx));
 1692                            }
 1693                        }
 1694                        project::Event::SnippetEdit(id, snippet_edits) => {
 1695                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1696                                let focus_handle = editor.focus_handle(cx);
 1697                                if focus_handle.is_focused(window) {
 1698                                    let snapshot = buffer.read(cx).snapshot();
 1699                                    for (range, snippet) in snippet_edits {
 1700                                        let editor_range =
 1701                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1702                                        editor
 1703                                            .insert_snippet(
 1704                                                &[editor_range],
 1705                                                snippet.clone(),
 1706                                                window,
 1707                                                cx,
 1708                                            )
 1709                                            .ok();
 1710                                    }
 1711                                }
 1712                            }
 1713                        }
 1714                        _ => {}
 1715                    },
 1716                ));
 1717                if let Some(task_inventory) = project
 1718                    .read(cx)
 1719                    .task_store()
 1720                    .read(cx)
 1721                    .task_inventory()
 1722                    .cloned()
 1723                {
 1724                    project_subscriptions.push(cx.observe_in(
 1725                        &task_inventory,
 1726                        window,
 1727                        |editor, _, window, cx| {
 1728                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1729                        },
 1730                    ));
 1731                };
 1732
 1733                project_subscriptions.push(cx.subscribe_in(
 1734                    &project.read(cx).breakpoint_store(),
 1735                    window,
 1736                    |editor, _, event, window, cx| match event {
 1737                        BreakpointStoreEvent::ClearDebugLines => {
 1738                            editor.clear_row_highlights::<ActiveDebugLine>();
 1739                            editor.refresh_inline_values(cx);
 1740                        }
 1741                        BreakpointStoreEvent::SetDebugLine => {
 1742                            if editor.go_to_active_debug_line(window, cx) {
 1743                                cx.stop_propagation();
 1744                            }
 1745
 1746                            editor.refresh_inline_values(cx);
 1747                        }
 1748                        _ => {}
 1749                    },
 1750                ));
 1751            }
 1752        }
 1753
 1754        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1755
 1756        let inlay_hint_settings =
 1757            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1758        let focus_handle = cx.focus_handle();
 1759        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1760            .detach();
 1761        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1762            .detach();
 1763        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1764            .detach();
 1765        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1766            .detach();
 1767
 1768        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1769            Some(false)
 1770        } else {
 1771            None
 1772        };
 1773
 1774        let breakpoint_store = match (&mode, project.as_ref()) {
 1775            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1776            _ => None,
 1777        };
 1778
 1779        let mut code_action_providers = Vec::new();
 1780        let mut load_uncommitted_diff = None;
 1781        if let Some(project) = project.clone() {
 1782            load_uncommitted_diff = Some(
 1783                update_uncommitted_diff_for_buffer(
 1784                    cx.entity(),
 1785                    &project,
 1786                    buffer.read(cx).all_buffers(),
 1787                    buffer.clone(),
 1788                    cx,
 1789                )
 1790                .shared(),
 1791            );
 1792            code_action_providers.push(Rc::new(project) as Rc<_>);
 1793        }
 1794
 1795        let mut this = Self {
 1796            focus_handle,
 1797            show_cursor_when_unfocused: false,
 1798            last_focused_descendant: None,
 1799            buffer: buffer.clone(),
 1800            display_map: display_map.clone(),
 1801            selections,
 1802            scroll_manager: ScrollManager::new(cx),
 1803            columnar_selection_tail: None,
 1804            columnar_display_point: None,
 1805            add_selections_state: None,
 1806            select_next_state: None,
 1807            select_prev_state: None,
 1808            selection_history: SelectionHistory::default(),
 1809            defer_selection_effects: false,
 1810            deferred_selection_effects_state: None,
 1811            autoclose_regions: Vec::new(),
 1812            snippet_stack: InvalidationStack::default(),
 1813            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1814            ime_transaction: None,
 1815            active_diagnostics: ActiveDiagnostic::None,
 1816            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1817            inline_diagnostics_update: Task::ready(()),
 1818            inline_diagnostics: Vec::new(),
 1819            soft_wrap_mode_override,
 1820            diagnostics_max_severity,
 1821            hard_wrap: None,
 1822            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1823            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1824            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1825            project,
 1826            blink_manager: blink_manager.clone(),
 1827            show_local_selections: true,
 1828            show_scrollbars: ScrollbarAxes {
 1829                horizontal: full_mode,
 1830                vertical: full_mode,
 1831            },
 1832            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1833            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1834            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1835            show_gutter: mode.is_full(),
 1836            show_line_numbers: None,
 1837            use_relative_line_numbers: None,
 1838            disable_expand_excerpt_buttons: false,
 1839            show_git_diff_gutter: None,
 1840            show_code_actions: None,
 1841            show_runnables: None,
 1842            show_breakpoints: None,
 1843            show_wrap_guides: None,
 1844            show_indent_guides,
 1845            placeholder_text: None,
 1846            highlight_order: 0,
 1847            highlighted_rows: HashMap::default(),
 1848            background_highlights: TreeMap::default(),
 1849            gutter_highlights: TreeMap::default(),
 1850            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1851            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1852            nav_history: None,
 1853            context_menu: RefCell::new(None),
 1854            context_menu_options: None,
 1855            mouse_context_menu: None,
 1856            completion_tasks: Vec::new(),
 1857            inline_blame_popover: None,
 1858            signature_help_state: SignatureHelpState::default(),
 1859            auto_signature_help: None,
 1860            find_all_references_task_sources: Vec::new(),
 1861            next_completion_id: 0,
 1862            next_inlay_id: 0,
 1863            code_action_providers,
 1864            available_code_actions: None,
 1865            code_actions_task: None,
 1866            quick_selection_highlight_task: None,
 1867            debounced_selection_highlight_task: None,
 1868            document_highlights_task: None,
 1869            linked_editing_range_task: None,
 1870            pending_rename: None,
 1871            searchable: true,
 1872            cursor_shape: EditorSettings::get_global(cx)
 1873                .cursor_shape
 1874                .unwrap_or_default(),
 1875            current_line_highlight: None,
 1876            autoindent_mode: Some(AutoindentMode::EachLine),
 1877            collapse_matches: false,
 1878            workspace: None,
 1879            input_enabled: true,
 1880            use_modal_editing: mode.is_full(),
 1881            read_only: mode.is_minimap(),
 1882            use_autoclose: true,
 1883            use_auto_surround: true,
 1884            auto_replace_emoji_shortcode: false,
 1885            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1886            leader_id: None,
 1887            remote_id: None,
 1888            hover_state: HoverState::default(),
 1889            pending_mouse_down: None,
 1890            hovered_link_state: None,
 1891            edit_prediction_provider: None,
 1892            active_inline_completion: None,
 1893            stale_inline_completion_in_menu: None,
 1894            edit_prediction_preview: EditPredictionPreview::Inactive {
 1895                released_too_fast: false,
 1896            },
 1897            inline_diagnostics_enabled: mode.is_full(),
 1898            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1899            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1900
 1901            gutter_hovered: false,
 1902            pixel_position_of_newest_cursor: None,
 1903            last_bounds: None,
 1904            last_position_map: None,
 1905            expect_bounds_change: None,
 1906            gutter_dimensions: GutterDimensions::default(),
 1907            style: None,
 1908            show_cursor_names: false,
 1909            hovered_cursors: HashMap::default(),
 1910            next_editor_action_id: EditorActionId::default(),
 1911            editor_actions: Rc::default(),
 1912            inline_completions_hidden_for_vim_mode: false,
 1913            show_inline_completions_override: None,
 1914            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1915            edit_prediction_settings: EditPredictionSettings::Disabled,
 1916            edit_prediction_indent_conflict: false,
 1917            edit_prediction_requires_modifier_in_indent_conflict: true,
 1918            custom_context_menu: None,
 1919            show_git_blame_gutter: false,
 1920            show_git_blame_inline: false,
 1921            show_selection_menu: None,
 1922            show_git_blame_inline_delay_task: None,
 1923            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1924            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1925            serialize_dirty_buffers: !mode.is_minimap()
 1926                && ProjectSettings::get_global(cx)
 1927                    .session
 1928                    .restore_unsaved_buffers,
 1929            blame: None,
 1930            blame_subscription: None,
 1931            tasks: BTreeMap::default(),
 1932
 1933            breakpoint_store,
 1934            gutter_breakpoint_indicator: (None, None),
 1935            _subscriptions: vec![
 1936                cx.observe(&buffer, Self::on_buffer_changed),
 1937                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1938                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1939                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1940                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1941                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1942                cx.observe_window_activation(window, |editor, window, cx| {
 1943                    let active = window.is_window_active();
 1944                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1945                        if active {
 1946                            blink_manager.enable(cx);
 1947                        } else {
 1948                            blink_manager.disable(cx);
 1949                        }
 1950                    });
 1951                    if active {
 1952                        editor.show_mouse_cursor();
 1953                    }
 1954                }),
 1955            ],
 1956            tasks_update_task: None,
 1957            linked_edit_ranges: Default::default(),
 1958            in_project_search: false,
 1959            previous_search_ranges: None,
 1960            breadcrumb_header: None,
 1961            focused_block: None,
 1962            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1963            addons: HashMap::default(),
 1964            registered_buffers: HashMap::default(),
 1965            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1966            selection_mark_mode: false,
 1967            toggle_fold_multiple_buffers: Task::ready(()),
 1968            serialize_selections: Task::ready(()),
 1969            serialize_folds: Task::ready(()),
 1970            text_style_refinement: None,
 1971            load_diff_task: load_uncommitted_diff,
 1972            temporary_diff_override: false,
 1973            mouse_cursor_hidden: false,
 1974            minimap: None,
 1975            hide_mouse_mode: EditorSettings::get_global(cx)
 1976                .hide_mouse
 1977                .unwrap_or_default(),
 1978            change_list: ChangeList::new(),
 1979            mode,
 1980        };
 1981        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1982            this._subscriptions
 1983                .push(cx.observe(breakpoints, |_, _, cx| {
 1984                    cx.notify();
 1985                }));
 1986        }
 1987        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1988        this._subscriptions.extend(project_subscriptions);
 1989
 1990        this._subscriptions.push(cx.subscribe_in(
 1991            &cx.entity(),
 1992            window,
 1993            |editor, _, e: &EditorEvent, window, cx| match e {
 1994                EditorEvent::ScrollPositionChanged { local, .. } => {
 1995                    if *local {
 1996                        let new_anchor = editor.scroll_manager.anchor();
 1997                        let snapshot = editor.snapshot(window, cx);
 1998                        editor.update_restoration_data(cx, move |data| {
 1999                            data.scroll_position = (
 2000                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2001                                new_anchor.offset,
 2002                            );
 2003                        });
 2004                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2005                        editor.inline_blame_popover.take();
 2006                    }
 2007                }
 2008                EditorEvent::Edited { .. } => {
 2009                    if !vim_enabled(cx) {
 2010                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2011                        let pop_state = editor
 2012                            .change_list
 2013                            .last()
 2014                            .map(|previous| {
 2015                                previous.len() == selections.len()
 2016                                    && previous.iter().enumerate().all(|(ix, p)| {
 2017                                        p.to_display_point(&map).row()
 2018                                            == selections[ix].head().row()
 2019                                    })
 2020                            })
 2021                            .unwrap_or(false);
 2022                        let new_positions = selections
 2023                            .into_iter()
 2024                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2025                            .collect();
 2026                        editor
 2027                            .change_list
 2028                            .push_to_change_list(pop_state, new_positions);
 2029                    }
 2030                }
 2031                _ => (),
 2032            },
 2033        ));
 2034
 2035        if let Some(dap_store) = this
 2036            .project
 2037            .as_ref()
 2038            .map(|project| project.read(cx).dap_store())
 2039        {
 2040            let weak_editor = cx.weak_entity();
 2041
 2042            this._subscriptions
 2043                .push(
 2044                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2045                        let session_entity = cx.entity();
 2046                        weak_editor
 2047                            .update(cx, |editor, cx| {
 2048                                editor._subscriptions.push(
 2049                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2050                                );
 2051                            })
 2052                            .ok();
 2053                    }),
 2054                );
 2055
 2056            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2057                this._subscriptions
 2058                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2059            }
 2060        }
 2061
 2062        this.end_selection(window, cx);
 2063        this.scroll_manager.show_scrollbars(window, cx);
 2064        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 2065
 2066        if full_mode {
 2067            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2068            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2069
 2070            if this.git_blame_inline_enabled {
 2071                this.start_git_blame_inline(false, window, cx);
 2072            }
 2073
 2074            this.go_to_active_debug_line(window, cx);
 2075
 2076            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2077                if let Some(project) = this.project.as_ref() {
 2078                    let handle = project.update(cx, |project, cx| {
 2079                        project.register_buffer_with_language_servers(&buffer, cx)
 2080                    });
 2081                    this.registered_buffers
 2082                        .insert(buffer.read(cx).remote_id(), handle);
 2083                }
 2084            }
 2085
 2086            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2087        }
 2088
 2089        this.report_editor_event("Editor Opened", None, cx);
 2090        this
 2091    }
 2092
 2093    pub fn deploy_mouse_context_menu(
 2094        &mut self,
 2095        position: gpui::Point<Pixels>,
 2096        context_menu: Entity<ContextMenu>,
 2097        window: &mut Window,
 2098        cx: &mut Context<Self>,
 2099    ) {
 2100        self.mouse_context_menu = Some(MouseContextMenu::new(
 2101            self,
 2102            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2103            context_menu,
 2104            window,
 2105            cx,
 2106        ));
 2107    }
 2108
 2109    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2110        self.mouse_context_menu
 2111            .as_ref()
 2112            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2113    }
 2114
 2115    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2116        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2117    }
 2118
 2119    fn key_context_internal(
 2120        &self,
 2121        has_active_edit_prediction: bool,
 2122        window: &Window,
 2123        cx: &App,
 2124    ) -> KeyContext {
 2125        let mut key_context = KeyContext::new_with_defaults();
 2126        key_context.add("Editor");
 2127        let mode = match self.mode {
 2128            EditorMode::SingleLine { .. } => "single_line",
 2129            EditorMode::AutoHeight { .. } => "auto_height",
 2130            EditorMode::Minimap { .. } => "minimap",
 2131            EditorMode::Full { .. } => "full",
 2132        };
 2133
 2134        if EditorSettings::jupyter_enabled(cx) {
 2135            key_context.add("jupyter");
 2136        }
 2137
 2138        key_context.set("mode", mode);
 2139        if self.pending_rename.is_some() {
 2140            key_context.add("renaming");
 2141        }
 2142
 2143        match self.context_menu.borrow().as_ref() {
 2144            Some(CodeContextMenu::Completions(_)) => {
 2145                key_context.add("menu");
 2146                key_context.add("showing_completions");
 2147            }
 2148            Some(CodeContextMenu::CodeActions(_)) => {
 2149                key_context.add("menu");
 2150                key_context.add("showing_code_actions")
 2151            }
 2152            None => {}
 2153        }
 2154
 2155        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2156        if !self.focus_handle(cx).contains_focused(window, cx)
 2157            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2158        {
 2159            for addon in self.addons.values() {
 2160                addon.extend_key_context(&mut key_context, cx)
 2161            }
 2162        }
 2163
 2164        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2165            if let Some(extension) = singleton_buffer
 2166                .read(cx)
 2167                .file()
 2168                .and_then(|file| file.path().extension()?.to_str())
 2169            {
 2170                key_context.set("extension", extension.to_string());
 2171            }
 2172        } else {
 2173            key_context.add("multibuffer");
 2174        }
 2175
 2176        if has_active_edit_prediction {
 2177            if self.edit_prediction_in_conflict() {
 2178                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2179            } else {
 2180                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2181                key_context.add("copilot_suggestion");
 2182            }
 2183        }
 2184
 2185        if self.selection_mark_mode {
 2186            key_context.add("selection_mode");
 2187        }
 2188
 2189        key_context
 2190    }
 2191
 2192    fn show_mouse_cursor(&mut self) {
 2193        self.mouse_cursor_hidden = false;
 2194    }
 2195
 2196    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2197        self.mouse_cursor_hidden = match origin {
 2198            HideMouseCursorOrigin::TypingAction => {
 2199                matches!(
 2200                    self.hide_mouse_mode,
 2201                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2202                )
 2203            }
 2204            HideMouseCursorOrigin::MovementAction => {
 2205                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2206            }
 2207        };
 2208    }
 2209
 2210    pub fn edit_prediction_in_conflict(&self) -> bool {
 2211        if !self.show_edit_predictions_in_menu() {
 2212            return false;
 2213        }
 2214
 2215        let showing_completions = self
 2216            .context_menu
 2217            .borrow()
 2218            .as_ref()
 2219            .map_or(false, |context| {
 2220                matches!(context, CodeContextMenu::Completions(_))
 2221            });
 2222
 2223        showing_completions
 2224            || self.edit_prediction_requires_modifier()
 2225            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2226            // bindings to insert tab characters.
 2227            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2228    }
 2229
 2230    pub fn accept_edit_prediction_keybind(
 2231        &self,
 2232        window: &Window,
 2233        cx: &App,
 2234    ) -> AcceptEditPredictionBinding {
 2235        let key_context = self.key_context_internal(true, window, cx);
 2236        let in_conflict = self.edit_prediction_in_conflict();
 2237
 2238        AcceptEditPredictionBinding(
 2239            window
 2240                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2241                .into_iter()
 2242                .filter(|binding| {
 2243                    !in_conflict
 2244                        || binding
 2245                            .keystrokes()
 2246                            .first()
 2247                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2248                })
 2249                .rev()
 2250                .min_by_key(|binding| {
 2251                    binding
 2252                        .keystrokes()
 2253                        .first()
 2254                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2255                }),
 2256        )
 2257    }
 2258
 2259    pub fn new_file(
 2260        workspace: &mut Workspace,
 2261        _: &workspace::NewFile,
 2262        window: &mut Window,
 2263        cx: &mut Context<Workspace>,
 2264    ) {
 2265        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2266            "Failed to create buffer",
 2267            window,
 2268            cx,
 2269            |e, _, _| match e.error_code() {
 2270                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2271                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2272                e.error_tag("required").unwrap_or("the latest version")
 2273            )),
 2274                _ => None,
 2275            },
 2276        );
 2277    }
 2278
 2279    pub fn new_in_workspace(
 2280        workspace: &mut Workspace,
 2281        window: &mut Window,
 2282        cx: &mut Context<Workspace>,
 2283    ) -> Task<Result<Entity<Editor>>> {
 2284        let project = workspace.project().clone();
 2285        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2286
 2287        cx.spawn_in(window, async move |workspace, cx| {
 2288            let buffer = create.await?;
 2289            workspace.update_in(cx, |workspace, window, cx| {
 2290                let editor =
 2291                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2292                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2293                editor
 2294            })
 2295        })
 2296    }
 2297
 2298    fn new_file_vertical(
 2299        workspace: &mut Workspace,
 2300        _: &workspace::NewFileSplitVertical,
 2301        window: &mut Window,
 2302        cx: &mut Context<Workspace>,
 2303    ) {
 2304        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2305    }
 2306
 2307    fn new_file_horizontal(
 2308        workspace: &mut Workspace,
 2309        _: &workspace::NewFileSplitHorizontal,
 2310        window: &mut Window,
 2311        cx: &mut Context<Workspace>,
 2312    ) {
 2313        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2314    }
 2315
 2316    fn new_file_in_direction(
 2317        workspace: &mut Workspace,
 2318        direction: SplitDirection,
 2319        window: &mut Window,
 2320        cx: &mut Context<Workspace>,
 2321    ) {
 2322        let project = workspace.project().clone();
 2323        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2324
 2325        cx.spawn_in(window, async move |workspace, cx| {
 2326            let buffer = create.await?;
 2327            workspace.update_in(cx, move |workspace, window, cx| {
 2328                workspace.split_item(
 2329                    direction,
 2330                    Box::new(
 2331                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2332                    ),
 2333                    window,
 2334                    cx,
 2335                )
 2336            })?;
 2337            anyhow::Ok(())
 2338        })
 2339        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2340            match e.error_code() {
 2341                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2342                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2343                e.error_tag("required").unwrap_or("the latest version")
 2344            )),
 2345                _ => None,
 2346            }
 2347        });
 2348    }
 2349
 2350    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2351        self.leader_id
 2352    }
 2353
 2354    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2355        &self.buffer
 2356    }
 2357
 2358    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2359        self.workspace.as_ref()?.0.upgrade()
 2360    }
 2361
 2362    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2363        self.buffer().read(cx).title(cx)
 2364    }
 2365
 2366    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2367        let git_blame_gutter_max_author_length = self
 2368            .render_git_blame_gutter(cx)
 2369            .then(|| {
 2370                if let Some(blame) = self.blame.as_ref() {
 2371                    let max_author_length =
 2372                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2373                    Some(max_author_length)
 2374                } else {
 2375                    None
 2376                }
 2377            })
 2378            .flatten();
 2379
 2380        EditorSnapshot {
 2381            mode: self.mode.clone(),
 2382            show_gutter: self.show_gutter,
 2383            show_line_numbers: self.show_line_numbers,
 2384            show_git_diff_gutter: self.show_git_diff_gutter,
 2385            show_code_actions: self.show_code_actions,
 2386            show_runnables: self.show_runnables,
 2387            show_breakpoints: self.show_breakpoints,
 2388            git_blame_gutter_max_author_length,
 2389            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2390            scroll_anchor: self.scroll_manager.anchor(),
 2391            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2392            placeholder_text: self.placeholder_text.clone(),
 2393            is_focused: self.focus_handle.is_focused(window),
 2394            current_line_highlight: self
 2395                .current_line_highlight
 2396                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2397            gutter_hovered: self.gutter_hovered,
 2398        }
 2399    }
 2400
 2401    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2402        self.buffer.read(cx).language_at(point, cx)
 2403    }
 2404
 2405    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2406        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2407    }
 2408
 2409    pub fn active_excerpt(
 2410        &self,
 2411        cx: &App,
 2412    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2413        self.buffer
 2414            .read(cx)
 2415            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2416    }
 2417
 2418    pub fn mode(&self) -> &EditorMode {
 2419        &self.mode
 2420    }
 2421
 2422    pub fn set_mode(&mut self, mode: EditorMode) {
 2423        self.mode = mode;
 2424    }
 2425
 2426    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2427        self.collaboration_hub.as_deref()
 2428    }
 2429
 2430    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2431        self.collaboration_hub = Some(hub);
 2432    }
 2433
 2434    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2435        self.in_project_search = in_project_search;
 2436    }
 2437
 2438    pub fn set_custom_context_menu(
 2439        &mut self,
 2440        f: impl 'static
 2441        + Fn(
 2442            &mut Self,
 2443            DisplayPoint,
 2444            &mut Window,
 2445            &mut Context<Self>,
 2446        ) -> Option<Entity<ui::ContextMenu>>,
 2447    ) {
 2448        self.custom_context_menu = Some(Box::new(f))
 2449    }
 2450
 2451    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2452        self.completion_provider = provider;
 2453    }
 2454
 2455    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2456        self.semantics_provider.clone()
 2457    }
 2458
 2459    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2460        self.semantics_provider = provider;
 2461    }
 2462
 2463    pub fn set_edit_prediction_provider<T>(
 2464        &mut self,
 2465        provider: Option<Entity<T>>,
 2466        window: &mut Window,
 2467        cx: &mut Context<Self>,
 2468    ) where
 2469        T: EditPredictionProvider,
 2470    {
 2471        self.edit_prediction_provider =
 2472            provider.map(|provider| RegisteredInlineCompletionProvider {
 2473                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2474                    if this.focus_handle.is_focused(window) {
 2475                        this.update_visible_inline_completion(window, cx);
 2476                    }
 2477                }),
 2478                provider: Arc::new(provider),
 2479            });
 2480        self.update_edit_prediction_settings(cx);
 2481        self.refresh_inline_completion(false, false, window, cx);
 2482    }
 2483
 2484    pub fn placeholder_text(&self) -> Option<&str> {
 2485        self.placeholder_text.as_deref()
 2486    }
 2487
 2488    pub fn set_placeholder_text(
 2489        &mut self,
 2490        placeholder_text: impl Into<Arc<str>>,
 2491        cx: &mut Context<Self>,
 2492    ) {
 2493        let placeholder_text = Some(placeholder_text.into());
 2494        if self.placeholder_text != placeholder_text {
 2495            self.placeholder_text = placeholder_text;
 2496            cx.notify();
 2497        }
 2498    }
 2499
 2500    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2501        self.cursor_shape = cursor_shape;
 2502
 2503        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2504        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2505
 2506        cx.notify();
 2507    }
 2508
 2509    pub fn set_current_line_highlight(
 2510        &mut self,
 2511        current_line_highlight: Option<CurrentLineHighlight>,
 2512    ) {
 2513        self.current_line_highlight = current_line_highlight;
 2514    }
 2515
 2516    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2517        self.collapse_matches = collapse_matches;
 2518    }
 2519
 2520    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2521        let buffers = self.buffer.read(cx).all_buffers();
 2522        let Some(project) = self.project.as_ref() else {
 2523            return;
 2524        };
 2525        project.update(cx, |project, cx| {
 2526            for buffer in buffers {
 2527                self.registered_buffers
 2528                    .entry(buffer.read(cx).remote_id())
 2529                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2530            }
 2531        })
 2532    }
 2533
 2534    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2535        if self.collapse_matches {
 2536            return range.start..range.start;
 2537        }
 2538        range.clone()
 2539    }
 2540
 2541    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2542        if self.display_map.read(cx).clip_at_line_ends != clip {
 2543            self.display_map
 2544                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2545        }
 2546    }
 2547
 2548    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2549        self.input_enabled = input_enabled;
 2550    }
 2551
 2552    pub fn set_inline_completions_hidden_for_vim_mode(
 2553        &mut self,
 2554        hidden: bool,
 2555        window: &mut Window,
 2556        cx: &mut Context<Self>,
 2557    ) {
 2558        if hidden != self.inline_completions_hidden_for_vim_mode {
 2559            self.inline_completions_hidden_for_vim_mode = hidden;
 2560            if hidden {
 2561                self.update_visible_inline_completion(window, cx);
 2562            } else {
 2563                self.refresh_inline_completion(true, false, window, cx);
 2564            }
 2565        }
 2566    }
 2567
 2568    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2569        self.menu_inline_completions_policy = value;
 2570    }
 2571
 2572    pub fn set_autoindent(&mut self, autoindent: bool) {
 2573        if autoindent {
 2574            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2575        } else {
 2576            self.autoindent_mode = None;
 2577        }
 2578    }
 2579
 2580    pub fn read_only(&self, cx: &App) -> bool {
 2581        self.read_only || self.buffer.read(cx).read_only()
 2582    }
 2583
 2584    pub fn set_read_only(&mut self, read_only: bool) {
 2585        self.read_only = read_only;
 2586    }
 2587
 2588    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2589        self.use_autoclose = autoclose;
 2590    }
 2591
 2592    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2593        self.use_auto_surround = auto_surround;
 2594    }
 2595
 2596    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2597        self.auto_replace_emoji_shortcode = auto_replace;
 2598    }
 2599
 2600    pub fn toggle_edit_predictions(
 2601        &mut self,
 2602        _: &ToggleEditPrediction,
 2603        window: &mut Window,
 2604        cx: &mut Context<Self>,
 2605    ) {
 2606        if self.show_inline_completions_override.is_some() {
 2607            self.set_show_edit_predictions(None, window, cx);
 2608        } else {
 2609            let show_edit_predictions = !self.edit_predictions_enabled();
 2610            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2611        }
 2612    }
 2613
 2614    pub fn set_show_edit_predictions(
 2615        &mut self,
 2616        show_edit_predictions: Option<bool>,
 2617        window: &mut Window,
 2618        cx: &mut Context<Self>,
 2619    ) {
 2620        self.show_inline_completions_override = show_edit_predictions;
 2621        self.update_edit_prediction_settings(cx);
 2622
 2623        if let Some(false) = show_edit_predictions {
 2624            self.discard_inline_completion(false, cx);
 2625        } else {
 2626            self.refresh_inline_completion(false, true, window, cx);
 2627        }
 2628    }
 2629
 2630    fn inline_completions_disabled_in_scope(
 2631        &self,
 2632        buffer: &Entity<Buffer>,
 2633        buffer_position: language::Anchor,
 2634        cx: &App,
 2635    ) -> bool {
 2636        let snapshot = buffer.read(cx).snapshot();
 2637        let settings = snapshot.settings_at(buffer_position, cx);
 2638
 2639        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2640            return false;
 2641        };
 2642
 2643        scope.override_name().map_or(false, |scope_name| {
 2644            settings
 2645                .edit_predictions_disabled_in
 2646                .iter()
 2647                .any(|s| s == scope_name)
 2648        })
 2649    }
 2650
 2651    pub fn set_use_modal_editing(&mut self, to: bool) {
 2652        self.use_modal_editing = to;
 2653    }
 2654
 2655    pub fn use_modal_editing(&self) -> bool {
 2656        self.use_modal_editing
 2657    }
 2658
 2659    fn selections_did_change(
 2660        &mut self,
 2661        local: bool,
 2662        old_cursor_position: &Anchor,
 2663        should_update_completions: bool,
 2664        window: &mut Window,
 2665        cx: &mut Context<Self>,
 2666    ) {
 2667        window.invalidate_character_coordinates();
 2668
 2669        // Copy selections to primary selection buffer
 2670        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2671        if local {
 2672            let selections = self.selections.all::<usize>(cx);
 2673            let buffer_handle = self.buffer.read(cx).read(cx);
 2674
 2675            let mut text = String::new();
 2676            for (index, selection) in selections.iter().enumerate() {
 2677                let text_for_selection = buffer_handle
 2678                    .text_for_range(selection.start..selection.end)
 2679                    .collect::<String>();
 2680
 2681                text.push_str(&text_for_selection);
 2682                if index != selections.len() - 1 {
 2683                    text.push('\n');
 2684                }
 2685            }
 2686
 2687            if !text.is_empty() {
 2688                cx.write_to_primary(ClipboardItem::new_string(text));
 2689            }
 2690        }
 2691
 2692        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2693            self.buffer.update(cx, |buffer, cx| {
 2694                buffer.set_active_selections(
 2695                    &self.selections.disjoint_anchors(),
 2696                    self.selections.line_mode,
 2697                    self.cursor_shape,
 2698                    cx,
 2699                )
 2700            });
 2701        }
 2702        let display_map = self
 2703            .display_map
 2704            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2705        let buffer = &display_map.buffer_snapshot;
 2706        self.add_selections_state = None;
 2707        self.select_next_state = None;
 2708        self.select_prev_state = None;
 2709        self.select_syntax_node_history.try_clear();
 2710        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2711        self.snippet_stack
 2712            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2713        self.take_rename(false, window, cx);
 2714
 2715        let new_cursor_position = self.selections.newest_anchor().head();
 2716
 2717        self.push_to_nav_history(
 2718            *old_cursor_position,
 2719            Some(new_cursor_position.to_point(buffer)),
 2720            false,
 2721            cx,
 2722        );
 2723
 2724        if local {
 2725            let new_cursor_position = self.selections.newest_anchor().head();
 2726
 2727            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2728                if !self.registered_buffers.contains_key(&buffer_id) {
 2729                    if let Some(project) = self.project.as_ref() {
 2730                        project.update(cx, |project, cx| {
 2731                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2732                                return;
 2733                            };
 2734                            self.registered_buffers.insert(
 2735                                buffer_id,
 2736                                project.register_buffer_with_language_servers(&buffer, cx),
 2737                            );
 2738                        })
 2739                    }
 2740                }
 2741            }
 2742
 2743            let mut context_menu = self.context_menu.borrow_mut();
 2744            let completion_menu = match context_menu.as_ref() {
 2745                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2746                Some(CodeContextMenu::CodeActions(_)) => {
 2747                    *context_menu = None;
 2748                    None
 2749                }
 2750                None => None,
 2751            };
 2752            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2753            drop(context_menu);
 2754
 2755            if should_update_completions {
 2756                if let Some(completion_position) = completion_position {
 2757                    let new_cursor_offset = new_cursor_position.to_offset(buffer);
 2758                    let position_matches =
 2759                        new_cursor_offset == completion_position.to_offset(buffer);
 2760                    let continue_showing = if position_matches {
 2761                        let (word_range, kind) = buffer.surrounding_word(new_cursor_offset, true);
 2762                        if let Some(CharKind::Word) = kind {
 2763                            word_range.start < new_cursor_offset
 2764                        } else {
 2765                            false
 2766                        }
 2767                    } else {
 2768                        false
 2769                    };
 2770
 2771                    if continue_showing {
 2772                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2773                    } else {
 2774                        self.hide_context_menu(window, cx);
 2775                    }
 2776                }
 2777            }
 2778
 2779            hide_hover(self, cx);
 2780
 2781            if old_cursor_position.to_display_point(&display_map).row()
 2782                != new_cursor_position.to_display_point(&display_map).row()
 2783            {
 2784                self.available_code_actions.take();
 2785            }
 2786            self.refresh_code_actions(window, cx);
 2787            self.refresh_document_highlights(cx);
 2788            self.refresh_selected_text_highlights(false, window, cx);
 2789            refresh_matching_bracket_highlights(self, window, cx);
 2790            self.update_visible_inline_completion(window, cx);
 2791            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2792            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2793            self.inline_blame_popover.take();
 2794            if self.git_blame_inline_enabled {
 2795                self.start_inline_blame_timer(window, cx);
 2796            }
 2797        }
 2798
 2799        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2800        cx.emit(EditorEvent::SelectionsChanged { local });
 2801
 2802        let selections = &self.selections.disjoint;
 2803        if selections.len() == 1 {
 2804            cx.emit(SearchEvent::ActiveMatchChanged)
 2805        }
 2806        if local {
 2807            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2808                let inmemory_selections = selections
 2809                    .iter()
 2810                    .map(|s| {
 2811                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2812                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2813                    })
 2814                    .collect();
 2815                self.update_restoration_data(cx, |data| {
 2816                    data.selections = inmemory_selections;
 2817                });
 2818
 2819                if WorkspaceSettings::get(None, cx).restore_on_startup
 2820                    != RestoreOnStartupBehavior::None
 2821                {
 2822                    if let Some(workspace_id) =
 2823                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2824                    {
 2825                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2826                        let selections = selections.clone();
 2827                        let background_executor = cx.background_executor().clone();
 2828                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2829                        self.serialize_selections = cx.background_spawn(async move {
 2830                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2831                    let db_selections = selections
 2832                        .iter()
 2833                        .map(|selection| {
 2834                            (
 2835                                selection.start.to_offset(&snapshot),
 2836                                selection.end.to_offset(&snapshot),
 2837                            )
 2838                        })
 2839                        .collect();
 2840
 2841                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2842                        .await
 2843                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2844                        .log_err();
 2845                });
 2846                    }
 2847                }
 2848            }
 2849        }
 2850
 2851        cx.notify();
 2852    }
 2853
 2854    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2855        use text::ToOffset as _;
 2856        use text::ToPoint as _;
 2857
 2858        if self.mode.is_minimap()
 2859            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2860        {
 2861            return;
 2862        }
 2863
 2864        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2865            return;
 2866        };
 2867
 2868        let snapshot = singleton.read(cx).snapshot();
 2869        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2870            let display_snapshot = display_map.snapshot(cx);
 2871
 2872            display_snapshot
 2873                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2874                .map(|fold| {
 2875                    fold.range.start.text_anchor.to_point(&snapshot)
 2876                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2877                })
 2878                .collect()
 2879        });
 2880        self.update_restoration_data(cx, |data| {
 2881            data.folds = inmemory_folds;
 2882        });
 2883
 2884        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2885            return;
 2886        };
 2887        let background_executor = cx.background_executor().clone();
 2888        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2889        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2890            display_map
 2891                .snapshot(cx)
 2892                .folds_in_range(0..snapshot.len())
 2893                .map(|fold| {
 2894                    (
 2895                        fold.range.start.text_anchor.to_offset(&snapshot),
 2896                        fold.range.end.text_anchor.to_offset(&snapshot),
 2897                    )
 2898                })
 2899                .collect()
 2900        });
 2901        self.serialize_folds = cx.background_spawn(async move {
 2902            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2903            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2904                .await
 2905                .with_context(|| {
 2906                    format!(
 2907                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2908                    )
 2909                })
 2910                .log_err();
 2911        });
 2912    }
 2913
 2914    pub fn sync_selections(
 2915        &mut self,
 2916        other: Entity<Editor>,
 2917        cx: &mut Context<Self>,
 2918    ) -> gpui::Subscription {
 2919        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2920        self.selections.change_with(cx, |selections| {
 2921            selections.select_anchors(other_selections);
 2922        });
 2923
 2924        let other_subscription =
 2925            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2926                EditorEvent::SelectionsChanged { local: true } => {
 2927                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2928                    if other_selections.is_empty() {
 2929                        return;
 2930                    }
 2931                    this.selections.change_with(cx, |selections| {
 2932                        selections.select_anchors(other_selections);
 2933                    });
 2934                }
 2935                _ => {}
 2936            });
 2937
 2938        let this_subscription =
 2939            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2940                EditorEvent::SelectionsChanged { local: true } => {
 2941                    let these_selections = this.selections.disjoint.to_vec();
 2942                    if these_selections.is_empty() {
 2943                        return;
 2944                    }
 2945                    other.update(cx, |other_editor, cx| {
 2946                        other_editor.selections.change_with(cx, |selections| {
 2947                            selections.select_anchors(these_selections);
 2948                        })
 2949                    });
 2950                }
 2951                _ => {}
 2952            });
 2953
 2954        Subscription::join(other_subscription, this_subscription)
 2955    }
 2956
 2957    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 2958    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 2959    /// effects of selection change occur at the end of the transaction.
 2960    pub fn change_selections<R>(
 2961        &mut self,
 2962        autoscroll: Option<Autoscroll>,
 2963        window: &mut Window,
 2964        cx: &mut Context<Self>,
 2965        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2966    ) -> R {
 2967        self.change_selections_inner(true, autoscroll, window, cx, change)
 2968    }
 2969
 2970    pub(crate) fn change_selections_without_updating_completions<R>(
 2971        &mut self,
 2972        autoscroll: Option<Autoscroll>,
 2973        window: &mut Window,
 2974        cx: &mut Context<Self>,
 2975        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2976    ) -> R {
 2977        self.change_selections_inner(false, autoscroll, window, cx, change)
 2978    }
 2979
 2980    fn change_selections_inner<R>(
 2981        &mut self,
 2982        should_update_completions: bool,
 2983        autoscroll: Option<Autoscroll>,
 2984        window: &mut Window,
 2985        cx: &mut Context<Self>,
 2986        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2987    ) -> R {
 2988        if let Some(state) = &mut self.deferred_selection_effects_state {
 2989            state.autoscroll = autoscroll.or(state.autoscroll);
 2990            state.should_update_completions = should_update_completions;
 2991            let (changed, result) = self.selections.change_with(cx, change);
 2992            state.changed |= changed;
 2993            return result;
 2994        }
 2995        let mut state = DeferredSelectionEffectsState {
 2996            changed: false,
 2997            should_update_completions,
 2998            autoscroll,
 2999            old_cursor_position: self.selections.newest_anchor().head(),
 3000            history_entry: SelectionHistoryEntry {
 3001                selections: self.selections.disjoint_anchors(),
 3002                select_next_state: self.select_next_state.clone(),
 3003                select_prev_state: self.select_prev_state.clone(),
 3004                add_selections_state: self.add_selections_state.clone(),
 3005            },
 3006        };
 3007        let (changed, result) = self.selections.change_with(cx, change);
 3008        state.changed = state.changed || changed;
 3009        if self.defer_selection_effects {
 3010            self.deferred_selection_effects_state = Some(state);
 3011        } else {
 3012            self.apply_selection_effects(state, window, cx);
 3013        }
 3014        result
 3015    }
 3016
 3017    /// Defers the effects of selection change, so that the effects of multiple calls to
 3018    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3019    /// to selection history and the state of popovers based on selection position aren't
 3020    /// erroneously updated.
 3021    pub fn with_selection_effects_deferred<R>(
 3022        &mut self,
 3023        window: &mut Window,
 3024        cx: &mut Context<Self>,
 3025        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3026    ) -> R {
 3027        let already_deferred = self.defer_selection_effects;
 3028        self.defer_selection_effects = true;
 3029        let result = update(self, window, cx);
 3030        if !already_deferred {
 3031            self.defer_selection_effects = false;
 3032            if let Some(state) = self.deferred_selection_effects_state.take() {
 3033                self.apply_selection_effects(state, window, cx);
 3034            }
 3035        }
 3036        result
 3037    }
 3038
 3039    fn apply_selection_effects(
 3040        &mut self,
 3041        state: DeferredSelectionEffectsState,
 3042        window: &mut Window,
 3043        cx: &mut Context<Self>,
 3044    ) {
 3045        if state.changed {
 3046            self.selection_history.push(state.history_entry);
 3047
 3048            if let Some(autoscroll) = state.autoscroll {
 3049                self.request_autoscroll(autoscroll, cx);
 3050            }
 3051
 3052            let old_cursor_position = &state.old_cursor_position;
 3053
 3054            self.selections_did_change(
 3055                true,
 3056                &old_cursor_position,
 3057                state.should_update_completions,
 3058                window,
 3059                cx,
 3060            );
 3061
 3062            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3063                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3064            }
 3065        }
 3066    }
 3067
 3068    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3069    where
 3070        I: IntoIterator<Item = (Range<S>, T)>,
 3071        S: ToOffset,
 3072        T: Into<Arc<str>>,
 3073    {
 3074        if self.read_only(cx) {
 3075            return;
 3076        }
 3077
 3078        self.buffer
 3079            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3080    }
 3081
 3082    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3083    where
 3084        I: IntoIterator<Item = (Range<S>, T)>,
 3085        S: ToOffset,
 3086        T: Into<Arc<str>>,
 3087    {
 3088        if self.read_only(cx) {
 3089            return;
 3090        }
 3091
 3092        self.buffer.update(cx, |buffer, cx| {
 3093            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3094        });
 3095    }
 3096
 3097    pub fn edit_with_block_indent<I, S, T>(
 3098        &mut self,
 3099        edits: I,
 3100        original_indent_columns: Vec<Option<u32>>,
 3101        cx: &mut Context<Self>,
 3102    ) where
 3103        I: IntoIterator<Item = (Range<S>, T)>,
 3104        S: ToOffset,
 3105        T: Into<Arc<str>>,
 3106    {
 3107        if self.read_only(cx) {
 3108            return;
 3109        }
 3110
 3111        self.buffer.update(cx, |buffer, cx| {
 3112            buffer.edit(
 3113                edits,
 3114                Some(AutoindentMode::Block {
 3115                    original_indent_columns,
 3116                }),
 3117                cx,
 3118            )
 3119        });
 3120    }
 3121
 3122    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3123        self.hide_context_menu(window, cx);
 3124
 3125        match phase {
 3126            SelectPhase::Begin {
 3127                position,
 3128                add,
 3129                click_count,
 3130            } => self.begin_selection(position, add, click_count, window, cx),
 3131            SelectPhase::BeginColumnar {
 3132                position,
 3133                goal_column,
 3134                reset,
 3135            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3136            SelectPhase::Extend {
 3137                position,
 3138                click_count,
 3139            } => self.extend_selection(position, click_count, window, cx),
 3140            SelectPhase::Update {
 3141                position,
 3142                goal_column,
 3143                scroll_delta,
 3144            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3145            SelectPhase::End => self.end_selection(window, cx),
 3146        }
 3147    }
 3148
 3149    fn extend_selection(
 3150        &mut self,
 3151        position: DisplayPoint,
 3152        click_count: usize,
 3153        window: &mut Window,
 3154        cx: &mut Context<Self>,
 3155    ) {
 3156        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3157        let tail = self.selections.newest::<usize>(cx).tail();
 3158        self.begin_selection(position, false, click_count, window, cx);
 3159
 3160        let position = position.to_offset(&display_map, Bias::Left);
 3161        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3162
 3163        let mut pending_selection = self
 3164            .selections
 3165            .pending_anchor()
 3166            .expect("extend_selection not called with pending selection");
 3167        if position >= tail {
 3168            pending_selection.start = tail_anchor;
 3169        } else {
 3170            pending_selection.end = tail_anchor;
 3171            pending_selection.reversed = true;
 3172        }
 3173
 3174        let mut pending_mode = self.selections.pending_mode().unwrap();
 3175        match &mut pending_mode {
 3176            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3177            _ => {}
 3178        }
 3179
 3180        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3181
 3182        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3183            s.set_pending(pending_selection, pending_mode)
 3184        });
 3185    }
 3186
 3187    fn begin_selection(
 3188        &mut self,
 3189        position: DisplayPoint,
 3190        add: bool,
 3191        click_count: usize,
 3192        window: &mut Window,
 3193        cx: &mut Context<Self>,
 3194    ) {
 3195        if !self.focus_handle.is_focused(window) {
 3196            self.last_focused_descendant = None;
 3197            window.focus(&self.focus_handle);
 3198        }
 3199
 3200        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3201        let buffer = &display_map.buffer_snapshot;
 3202        let position = display_map.clip_point(position, Bias::Left);
 3203
 3204        let start;
 3205        let end;
 3206        let mode;
 3207        let mut auto_scroll;
 3208        match click_count {
 3209            1 => {
 3210                start = buffer.anchor_before(position.to_point(&display_map));
 3211                end = start;
 3212                mode = SelectMode::Character;
 3213                auto_scroll = true;
 3214            }
 3215            2 => {
 3216                let range = movement::surrounding_word(&display_map, position);
 3217                start = buffer.anchor_before(range.start.to_point(&display_map));
 3218                end = buffer.anchor_before(range.end.to_point(&display_map));
 3219                mode = SelectMode::Word(start..end);
 3220                auto_scroll = true;
 3221            }
 3222            3 => {
 3223                let position = display_map
 3224                    .clip_point(position, Bias::Left)
 3225                    .to_point(&display_map);
 3226                let line_start = display_map.prev_line_boundary(position).0;
 3227                let next_line_start = buffer.clip_point(
 3228                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3229                    Bias::Left,
 3230                );
 3231                start = buffer.anchor_before(line_start);
 3232                end = buffer.anchor_before(next_line_start);
 3233                mode = SelectMode::Line(start..end);
 3234                auto_scroll = true;
 3235            }
 3236            _ => {
 3237                start = buffer.anchor_before(0);
 3238                end = buffer.anchor_before(buffer.len());
 3239                mode = SelectMode::All;
 3240                auto_scroll = false;
 3241            }
 3242        }
 3243        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3244
 3245        let point_to_delete: Option<usize> = {
 3246            let selected_points: Vec<Selection<Point>> =
 3247                self.selections.disjoint_in_range(start..end, cx);
 3248
 3249            if !add || click_count > 1 {
 3250                None
 3251            } else if !selected_points.is_empty() {
 3252                Some(selected_points[0].id)
 3253            } else {
 3254                let clicked_point_already_selected =
 3255                    self.selections.disjoint.iter().find(|selection| {
 3256                        selection.start.to_point(buffer) == start.to_point(buffer)
 3257                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3258                    });
 3259
 3260                clicked_point_already_selected.map(|selection| selection.id)
 3261            }
 3262        };
 3263
 3264        let selections_count = self.selections.count();
 3265
 3266        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3267            if let Some(point_to_delete) = point_to_delete {
 3268                s.delete(point_to_delete);
 3269
 3270                if selections_count == 1 {
 3271                    s.set_pending_anchor_range(start..end, mode);
 3272                }
 3273            } else {
 3274                if !add {
 3275                    s.clear_disjoint();
 3276                }
 3277
 3278                s.set_pending_anchor_range(start..end, mode);
 3279            }
 3280        });
 3281    }
 3282
 3283    fn begin_columnar_selection(
 3284        &mut self,
 3285        position: DisplayPoint,
 3286        goal_column: u32,
 3287        reset: bool,
 3288        window: &mut Window,
 3289        cx: &mut Context<Self>,
 3290    ) {
 3291        if !self.focus_handle.is_focused(window) {
 3292            self.last_focused_descendant = None;
 3293            window.focus(&self.focus_handle);
 3294        }
 3295
 3296        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3297
 3298        if reset {
 3299            let pointer_position = display_map
 3300                .buffer_snapshot
 3301                .anchor_before(position.to_point(&display_map));
 3302
 3303            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3304                s.clear_disjoint();
 3305                s.set_pending_anchor_range(
 3306                    pointer_position..pointer_position,
 3307                    SelectMode::Character,
 3308                );
 3309            });
 3310            if position.column() != goal_column {
 3311                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3312            } else {
 3313                self.columnar_display_point = None;
 3314            }
 3315        }
 3316
 3317        let tail = self.selections.newest::<Point>(cx).tail();
 3318        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3319
 3320        if !reset {
 3321            self.columnar_display_point = None;
 3322            self.select_columns(
 3323                tail.to_display_point(&display_map),
 3324                position,
 3325                goal_column,
 3326                &display_map,
 3327                window,
 3328                cx,
 3329            );
 3330        }
 3331    }
 3332
 3333    fn update_selection(
 3334        &mut self,
 3335        position: DisplayPoint,
 3336        goal_column: u32,
 3337        scroll_delta: gpui::Point<f32>,
 3338        window: &mut Window,
 3339        cx: &mut Context<Self>,
 3340    ) {
 3341        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3342
 3343        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3344            let tail = self
 3345                .columnar_display_point
 3346                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3347            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3348        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3349            let buffer = self.buffer.read(cx).snapshot(cx);
 3350            let head;
 3351            let tail;
 3352            let mode = self.selections.pending_mode().unwrap();
 3353            match &mode {
 3354                SelectMode::Character => {
 3355                    head = position.to_point(&display_map);
 3356                    tail = pending.tail().to_point(&buffer);
 3357                }
 3358                SelectMode::Word(original_range) => {
 3359                    let original_display_range = original_range.start.to_display_point(&display_map)
 3360                        ..original_range.end.to_display_point(&display_map);
 3361                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3362                        ..original_display_range.end.to_point(&display_map);
 3363                    if movement::is_inside_word(&display_map, position)
 3364                        || original_display_range.contains(&position)
 3365                    {
 3366                        let word_range = movement::surrounding_word(&display_map, position);
 3367                        if word_range.start < original_display_range.start {
 3368                            head = word_range.start.to_point(&display_map);
 3369                        } else {
 3370                            head = word_range.end.to_point(&display_map);
 3371                        }
 3372                    } else {
 3373                        head = position.to_point(&display_map);
 3374                    }
 3375
 3376                    if head <= original_buffer_range.start {
 3377                        tail = original_buffer_range.end;
 3378                    } else {
 3379                        tail = original_buffer_range.start;
 3380                    }
 3381                }
 3382                SelectMode::Line(original_range) => {
 3383                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3384
 3385                    let position = display_map
 3386                        .clip_point(position, Bias::Left)
 3387                        .to_point(&display_map);
 3388                    let line_start = display_map.prev_line_boundary(position).0;
 3389                    let next_line_start = buffer.clip_point(
 3390                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3391                        Bias::Left,
 3392                    );
 3393
 3394                    if line_start < original_range.start {
 3395                        head = line_start
 3396                    } else {
 3397                        head = next_line_start
 3398                    }
 3399
 3400                    if head <= original_range.start {
 3401                        tail = original_range.end;
 3402                    } else {
 3403                        tail = original_range.start;
 3404                    }
 3405                }
 3406                SelectMode::All => {
 3407                    return;
 3408                }
 3409            };
 3410
 3411            if head < tail {
 3412                pending.start = buffer.anchor_before(head);
 3413                pending.end = buffer.anchor_before(tail);
 3414                pending.reversed = true;
 3415            } else {
 3416                pending.start = buffer.anchor_before(tail);
 3417                pending.end = buffer.anchor_before(head);
 3418                pending.reversed = false;
 3419            }
 3420
 3421            self.change_selections(None, window, cx, |s| {
 3422                s.set_pending(pending, mode);
 3423            });
 3424        } else {
 3425            log::error!("update_selection dispatched with no pending selection");
 3426            return;
 3427        }
 3428
 3429        self.apply_scroll_delta(scroll_delta, window, cx);
 3430        cx.notify();
 3431    }
 3432
 3433    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3434        self.columnar_selection_tail.take();
 3435        if self.selections.pending_anchor().is_some() {
 3436            let selections = self.selections.all::<usize>(cx);
 3437            self.change_selections(None, window, cx, |s| {
 3438                s.select(selections);
 3439                s.clear_pending();
 3440            });
 3441        }
 3442    }
 3443
 3444    fn select_columns(
 3445        &mut self,
 3446        tail: DisplayPoint,
 3447        head: DisplayPoint,
 3448        goal_column: u32,
 3449        display_map: &DisplaySnapshot,
 3450        window: &mut Window,
 3451        cx: &mut Context<Self>,
 3452    ) {
 3453        let start_row = cmp::min(tail.row(), head.row());
 3454        let end_row = cmp::max(tail.row(), head.row());
 3455        let start_column = cmp::min(tail.column(), goal_column);
 3456        let end_column = cmp::max(tail.column(), goal_column);
 3457        let reversed = start_column < tail.column();
 3458
 3459        let selection_ranges = (start_row.0..=end_row.0)
 3460            .map(DisplayRow)
 3461            .filter_map(|row| {
 3462                if !display_map.is_block_line(row) {
 3463                    let start = display_map
 3464                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3465                        .to_point(display_map);
 3466                    let end = display_map
 3467                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3468                        .to_point(display_map);
 3469                    if reversed {
 3470                        Some(end..start)
 3471                    } else {
 3472                        Some(start..end)
 3473                    }
 3474                } else {
 3475                    None
 3476                }
 3477            })
 3478            .collect::<Vec<_>>();
 3479
 3480        let mut non_empty_ranges = selection_ranges
 3481            .iter()
 3482            .filter(|selection_range| selection_range.start != selection_range.end)
 3483            .peekable();
 3484
 3485        let ranges = if non_empty_ranges.peek().is_some() {
 3486            non_empty_ranges.cloned().collect()
 3487        } else {
 3488            selection_ranges
 3489        };
 3490
 3491        self.change_selections(None, window, cx, |s| {
 3492            s.select_ranges(ranges);
 3493        });
 3494        cx.notify();
 3495    }
 3496
 3497    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3498        self.selections
 3499            .all_adjusted(cx)
 3500            .iter()
 3501            .any(|selection| !selection.is_empty())
 3502    }
 3503
 3504    pub fn has_pending_nonempty_selection(&self) -> bool {
 3505        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3506            Some(Selection { start, end, .. }) => start != end,
 3507            None => false,
 3508        };
 3509
 3510        pending_nonempty_selection
 3511            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3512    }
 3513
 3514    pub fn has_pending_selection(&self) -> bool {
 3515        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3516    }
 3517
 3518    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3519        self.selection_mark_mode = false;
 3520
 3521        if self.clear_expanded_diff_hunks(cx) {
 3522            cx.notify();
 3523            return;
 3524        }
 3525        if self.dismiss_menus_and_popups(true, window, cx) {
 3526            return;
 3527        }
 3528
 3529        if self.mode.is_full()
 3530            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3531        {
 3532            return;
 3533        }
 3534
 3535        cx.propagate();
 3536    }
 3537
 3538    pub fn dismiss_menus_and_popups(
 3539        &mut self,
 3540        is_user_requested: bool,
 3541        window: &mut Window,
 3542        cx: &mut Context<Self>,
 3543    ) -> bool {
 3544        if self.take_rename(false, window, cx).is_some() {
 3545            return true;
 3546        }
 3547
 3548        if hide_hover(self, cx) {
 3549            return true;
 3550        }
 3551
 3552        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3553            return true;
 3554        }
 3555
 3556        if self.hide_context_menu(window, cx).is_some() {
 3557            return true;
 3558        }
 3559
 3560        if self.mouse_context_menu.take().is_some() {
 3561            return true;
 3562        }
 3563
 3564        if is_user_requested && self.discard_inline_completion(true, cx) {
 3565            return true;
 3566        }
 3567
 3568        if self.snippet_stack.pop().is_some() {
 3569            return true;
 3570        }
 3571
 3572        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3573            self.dismiss_diagnostics(cx);
 3574            return true;
 3575        }
 3576
 3577        false
 3578    }
 3579
 3580    fn linked_editing_ranges_for(
 3581        &self,
 3582        selection: Range<text::Anchor>,
 3583        cx: &App,
 3584    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3585        if self.linked_edit_ranges.is_empty() {
 3586            return None;
 3587        }
 3588        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3589            selection.end.buffer_id.and_then(|end_buffer_id| {
 3590                if selection.start.buffer_id != Some(end_buffer_id) {
 3591                    return None;
 3592                }
 3593                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3594                let snapshot = buffer.read(cx).snapshot();
 3595                self.linked_edit_ranges
 3596                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3597                    .map(|ranges| (ranges, snapshot, buffer))
 3598            })?;
 3599        use text::ToOffset as TO;
 3600        // find offset from the start of current range to current cursor position
 3601        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3602
 3603        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3604        let start_difference = start_offset - start_byte_offset;
 3605        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3606        let end_difference = end_offset - start_byte_offset;
 3607        // Current range has associated linked ranges.
 3608        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3609        for range in linked_ranges.iter() {
 3610            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3611            let end_offset = start_offset + end_difference;
 3612            let start_offset = start_offset + start_difference;
 3613            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3614                continue;
 3615            }
 3616            if self.selections.disjoint_anchor_ranges().any(|s| {
 3617                if s.start.buffer_id != selection.start.buffer_id
 3618                    || s.end.buffer_id != selection.end.buffer_id
 3619                {
 3620                    return false;
 3621                }
 3622                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3623                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3624            }) {
 3625                continue;
 3626            }
 3627            let start = buffer_snapshot.anchor_after(start_offset);
 3628            let end = buffer_snapshot.anchor_after(end_offset);
 3629            linked_edits
 3630                .entry(buffer.clone())
 3631                .or_default()
 3632                .push(start..end);
 3633        }
 3634        Some(linked_edits)
 3635    }
 3636
 3637    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3638        let text: Arc<str> = text.into();
 3639
 3640        if self.read_only(cx) {
 3641            return;
 3642        }
 3643
 3644        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3645
 3646        let selections = self.selections.all_adjusted(cx);
 3647        let mut bracket_inserted = false;
 3648        let mut edits = Vec::new();
 3649        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3650        let mut new_selections = Vec::with_capacity(selections.len());
 3651        let mut new_autoclose_regions = Vec::new();
 3652        let snapshot = self.buffer.read(cx).read(cx);
 3653        let mut clear_linked_edit_ranges = false;
 3654
 3655        for (selection, autoclose_region) in
 3656            self.selections_with_autoclose_regions(selections, &snapshot)
 3657        {
 3658            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3659                // Determine if the inserted text matches the opening or closing
 3660                // bracket of any of this language's bracket pairs.
 3661                let mut bracket_pair = None;
 3662                let mut is_bracket_pair_start = false;
 3663                let mut is_bracket_pair_end = false;
 3664                if !text.is_empty() {
 3665                    let mut bracket_pair_matching_end = None;
 3666                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3667                    //  and they are removing the character that triggered IME popup.
 3668                    for (pair, enabled) in scope.brackets() {
 3669                        if !pair.close && !pair.surround {
 3670                            continue;
 3671                        }
 3672
 3673                        if enabled && pair.start.ends_with(text.as_ref()) {
 3674                            let prefix_len = pair.start.len() - text.len();
 3675                            let preceding_text_matches_prefix = prefix_len == 0
 3676                                || (selection.start.column >= (prefix_len as u32)
 3677                                    && snapshot.contains_str_at(
 3678                                        Point::new(
 3679                                            selection.start.row,
 3680                                            selection.start.column - (prefix_len as u32),
 3681                                        ),
 3682                                        &pair.start[..prefix_len],
 3683                                    ));
 3684                            if preceding_text_matches_prefix {
 3685                                bracket_pair = Some(pair.clone());
 3686                                is_bracket_pair_start = true;
 3687                                break;
 3688                            }
 3689                        }
 3690                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3691                        {
 3692                            // take first bracket pair matching end, but don't break in case a later bracket
 3693                            // pair matches start
 3694                            bracket_pair_matching_end = Some(pair.clone());
 3695                        }
 3696                    }
 3697                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3698                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3699                        is_bracket_pair_end = true;
 3700                    }
 3701                }
 3702
 3703                if let Some(bracket_pair) = bracket_pair {
 3704                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3705                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3706                    let auto_surround =
 3707                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3708                    if selection.is_empty() {
 3709                        if is_bracket_pair_start {
 3710                            // If the inserted text is a suffix of an opening bracket and the
 3711                            // selection is preceded by the rest of the opening bracket, then
 3712                            // insert the closing bracket.
 3713                            let following_text_allows_autoclose = snapshot
 3714                                .chars_at(selection.start)
 3715                                .next()
 3716                                .map_or(true, |c| scope.should_autoclose_before(c));
 3717
 3718                            let preceding_text_allows_autoclose = selection.start.column == 0
 3719                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3720                                    true,
 3721                                    |c| {
 3722                                        bracket_pair.start != bracket_pair.end
 3723                                            || !snapshot
 3724                                                .char_classifier_at(selection.start)
 3725                                                .is_word(c)
 3726                                    },
 3727                                );
 3728
 3729                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3730                                && bracket_pair.start.len() == 1
 3731                            {
 3732                                let target = bracket_pair.start.chars().next().unwrap();
 3733                                let current_line_count = snapshot
 3734                                    .reversed_chars_at(selection.start)
 3735                                    .take_while(|&c| c != '\n')
 3736                                    .filter(|&c| c == target)
 3737                                    .count();
 3738                                current_line_count % 2 == 1
 3739                            } else {
 3740                                false
 3741                            };
 3742
 3743                            if autoclose
 3744                                && bracket_pair.close
 3745                                && following_text_allows_autoclose
 3746                                && preceding_text_allows_autoclose
 3747                                && !is_closing_quote
 3748                            {
 3749                                let anchor = snapshot.anchor_before(selection.end);
 3750                                new_selections.push((selection.map(|_| anchor), text.len()));
 3751                                new_autoclose_regions.push((
 3752                                    anchor,
 3753                                    text.len(),
 3754                                    selection.id,
 3755                                    bracket_pair.clone(),
 3756                                ));
 3757                                edits.push((
 3758                                    selection.range(),
 3759                                    format!("{}{}", text, bracket_pair.end).into(),
 3760                                ));
 3761                                bracket_inserted = true;
 3762                                continue;
 3763                            }
 3764                        }
 3765
 3766                        if let Some(region) = autoclose_region {
 3767                            // If the selection is followed by an auto-inserted closing bracket,
 3768                            // then don't insert that closing bracket again; just move the selection
 3769                            // past the closing bracket.
 3770                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3771                                && text.as_ref() == region.pair.end.as_str();
 3772                            if should_skip {
 3773                                let anchor = snapshot.anchor_after(selection.end);
 3774                                new_selections
 3775                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3776                                continue;
 3777                            }
 3778                        }
 3779
 3780                        let always_treat_brackets_as_autoclosed = snapshot
 3781                            .language_settings_at(selection.start, cx)
 3782                            .always_treat_brackets_as_autoclosed;
 3783                        if always_treat_brackets_as_autoclosed
 3784                            && is_bracket_pair_end
 3785                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3786                        {
 3787                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3788                            // and the inserted text is a closing bracket and the selection is followed
 3789                            // by the closing bracket then move the selection past the closing bracket.
 3790                            let anchor = snapshot.anchor_after(selection.end);
 3791                            new_selections.push((selection.map(|_| anchor), text.len()));
 3792                            continue;
 3793                        }
 3794                    }
 3795                    // If an opening bracket is 1 character long and is typed while
 3796                    // text is selected, then surround that text with the bracket pair.
 3797                    else if auto_surround
 3798                        && bracket_pair.surround
 3799                        && is_bracket_pair_start
 3800                        && bracket_pair.start.chars().count() == 1
 3801                    {
 3802                        edits.push((selection.start..selection.start, text.clone()));
 3803                        edits.push((
 3804                            selection.end..selection.end,
 3805                            bracket_pair.end.as_str().into(),
 3806                        ));
 3807                        bracket_inserted = true;
 3808                        new_selections.push((
 3809                            Selection {
 3810                                id: selection.id,
 3811                                start: snapshot.anchor_after(selection.start),
 3812                                end: snapshot.anchor_before(selection.end),
 3813                                reversed: selection.reversed,
 3814                                goal: selection.goal,
 3815                            },
 3816                            0,
 3817                        ));
 3818                        continue;
 3819                    }
 3820                }
 3821            }
 3822
 3823            if self.auto_replace_emoji_shortcode
 3824                && selection.is_empty()
 3825                && text.as_ref().ends_with(':')
 3826            {
 3827                if let Some(possible_emoji_short_code) =
 3828                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3829                {
 3830                    if !possible_emoji_short_code.is_empty() {
 3831                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3832                            let emoji_shortcode_start = Point::new(
 3833                                selection.start.row,
 3834                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3835                            );
 3836
 3837                            // Remove shortcode from buffer
 3838                            edits.push((
 3839                                emoji_shortcode_start..selection.start,
 3840                                "".to_string().into(),
 3841                            ));
 3842                            new_selections.push((
 3843                                Selection {
 3844                                    id: selection.id,
 3845                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3846                                    end: snapshot.anchor_before(selection.start),
 3847                                    reversed: selection.reversed,
 3848                                    goal: selection.goal,
 3849                                },
 3850                                0,
 3851                            ));
 3852
 3853                            // Insert emoji
 3854                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3855                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3856                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3857
 3858                            continue;
 3859                        }
 3860                    }
 3861                }
 3862            }
 3863
 3864            // If not handling any auto-close operation, then just replace the selected
 3865            // text with the given input and move the selection to the end of the
 3866            // newly inserted text.
 3867            let anchor = snapshot.anchor_after(selection.end);
 3868            if !self.linked_edit_ranges.is_empty() {
 3869                let start_anchor = snapshot.anchor_before(selection.start);
 3870
 3871                let is_word_char = text.chars().next().map_or(true, |char| {
 3872                    let classifier = snapshot
 3873                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3874                        .ignore_punctuation(true);
 3875                    classifier.is_word(char)
 3876                });
 3877
 3878                if is_word_char {
 3879                    if let Some(ranges) = self
 3880                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3881                    {
 3882                        for (buffer, edits) in ranges {
 3883                            linked_edits
 3884                                .entry(buffer.clone())
 3885                                .or_default()
 3886                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3887                        }
 3888                    }
 3889                } else {
 3890                    clear_linked_edit_ranges = true;
 3891                }
 3892            }
 3893
 3894            new_selections.push((selection.map(|_| anchor), 0));
 3895            edits.push((selection.start..selection.end, text.clone()));
 3896        }
 3897
 3898        drop(snapshot);
 3899
 3900        self.transact(window, cx, |this, window, cx| {
 3901            if clear_linked_edit_ranges {
 3902                this.linked_edit_ranges.clear();
 3903            }
 3904            let initial_buffer_versions =
 3905                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3906
 3907            this.buffer.update(cx, |buffer, cx| {
 3908                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3909            });
 3910            for (buffer, edits) in linked_edits {
 3911                buffer.update(cx, |buffer, cx| {
 3912                    let snapshot = buffer.snapshot();
 3913                    let edits = edits
 3914                        .into_iter()
 3915                        .map(|(range, text)| {
 3916                            use text::ToPoint as TP;
 3917                            let end_point = TP::to_point(&range.end, &snapshot);
 3918                            let start_point = TP::to_point(&range.start, &snapshot);
 3919                            (start_point..end_point, text)
 3920                        })
 3921                        .sorted_by_key(|(range, _)| range.start);
 3922                    buffer.edit(edits, None, cx);
 3923                })
 3924            }
 3925            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3926            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3927            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3928            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3929                .zip(new_selection_deltas)
 3930                .map(|(selection, delta)| Selection {
 3931                    id: selection.id,
 3932                    start: selection.start + delta,
 3933                    end: selection.end + delta,
 3934                    reversed: selection.reversed,
 3935                    goal: SelectionGoal::None,
 3936                })
 3937                .collect::<Vec<_>>();
 3938
 3939            let mut i = 0;
 3940            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3941                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3942                let start = map.buffer_snapshot.anchor_before(position);
 3943                let end = map.buffer_snapshot.anchor_after(position);
 3944                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3945                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3946                        Ordering::Less => i += 1,
 3947                        Ordering::Greater => break,
 3948                        Ordering::Equal => {
 3949                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3950                                Ordering::Less => i += 1,
 3951                                Ordering::Equal => break,
 3952                                Ordering::Greater => break,
 3953                            }
 3954                        }
 3955                    }
 3956                }
 3957                this.autoclose_regions.insert(
 3958                    i,
 3959                    AutocloseRegion {
 3960                        selection_id,
 3961                        range: start..end,
 3962                        pair,
 3963                    },
 3964                );
 3965            }
 3966
 3967            let had_active_inline_completion = this.has_active_inline_completion();
 3968            this.change_selections_without_updating_completions(
 3969                Some(Autoscroll::fit()),
 3970                window,
 3971                cx,
 3972                |s| s.select(new_selections),
 3973            );
 3974
 3975            if !bracket_inserted {
 3976                if let Some(on_type_format_task) =
 3977                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3978                {
 3979                    on_type_format_task.detach_and_log_err(cx);
 3980                }
 3981            }
 3982
 3983            let editor_settings = EditorSettings::get_global(cx);
 3984            if bracket_inserted
 3985                && (editor_settings.auto_signature_help
 3986                    || editor_settings.show_signature_help_after_edits)
 3987            {
 3988                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3989            }
 3990
 3991            let trigger_in_words =
 3992                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3993            if this.hard_wrap.is_some() {
 3994                let latest: Range<Point> = this.selections.newest(cx).range();
 3995                if latest.is_empty()
 3996                    && this
 3997                        .buffer()
 3998                        .read(cx)
 3999                        .snapshot(cx)
 4000                        .line_len(MultiBufferRow(latest.start.row))
 4001                        == latest.start.column
 4002                {
 4003                    this.rewrap_impl(
 4004                        RewrapOptions {
 4005                            override_language_settings: true,
 4006                            preserve_existing_whitespace: true,
 4007                        },
 4008                        cx,
 4009                    )
 4010                }
 4011            }
 4012            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4013            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4014            this.refresh_inline_completion(true, false, window, cx);
 4015            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4016        });
 4017    }
 4018
 4019    fn find_possible_emoji_shortcode_at_position(
 4020        snapshot: &MultiBufferSnapshot,
 4021        position: Point,
 4022    ) -> Option<String> {
 4023        let mut chars = Vec::new();
 4024        let mut found_colon = false;
 4025        for char in snapshot.reversed_chars_at(position).take(100) {
 4026            // Found a possible emoji shortcode in the middle of the buffer
 4027            if found_colon {
 4028                if char.is_whitespace() {
 4029                    chars.reverse();
 4030                    return Some(chars.iter().collect());
 4031                }
 4032                // If the previous character is not a whitespace, we are in the middle of a word
 4033                // and we only want to complete the shortcode if the word is made up of other emojis
 4034                let mut containing_word = String::new();
 4035                for ch in snapshot
 4036                    .reversed_chars_at(position)
 4037                    .skip(chars.len() + 1)
 4038                    .take(100)
 4039                {
 4040                    if ch.is_whitespace() {
 4041                        break;
 4042                    }
 4043                    containing_word.push(ch);
 4044                }
 4045                let containing_word = containing_word.chars().rev().collect::<String>();
 4046                if util::word_consists_of_emojis(containing_word.as_str()) {
 4047                    chars.reverse();
 4048                    return Some(chars.iter().collect());
 4049                }
 4050            }
 4051
 4052            if char.is_whitespace() || !char.is_ascii() {
 4053                return None;
 4054            }
 4055            if char == ':' {
 4056                found_colon = true;
 4057            } else {
 4058                chars.push(char);
 4059            }
 4060        }
 4061        // Found a possible emoji shortcode at the beginning of the buffer
 4062        chars.reverse();
 4063        Some(chars.iter().collect())
 4064    }
 4065
 4066    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4067        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4068        self.transact(window, cx, |this, window, cx| {
 4069            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4070                let selections = this.selections.all::<usize>(cx);
 4071                let multi_buffer = this.buffer.read(cx);
 4072                let buffer = multi_buffer.snapshot(cx);
 4073                selections
 4074                    .iter()
 4075                    .map(|selection| {
 4076                        let start_point = selection.start.to_point(&buffer);
 4077                        let mut existing_indent =
 4078                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4079                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4080                        let start = selection.start;
 4081                        let end = selection.end;
 4082                        let selection_is_empty = start == end;
 4083                        let language_scope = buffer.language_scope_at(start);
 4084                        let (
 4085                            comment_delimiter,
 4086                            doc_delimiter,
 4087                            insert_extra_newline,
 4088                            indent_on_newline,
 4089                            indent_on_extra_newline,
 4090                        ) = if let Some(language) = &language_scope {
 4091                            let mut insert_extra_newline =
 4092                                insert_extra_newline_brackets(&buffer, start..end, language)
 4093                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4094
 4095                            // Comment extension on newline is allowed only for cursor selections
 4096                            let comment_delimiter = maybe!({
 4097                                if !selection_is_empty {
 4098                                    return None;
 4099                                }
 4100
 4101                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4102                                    return None;
 4103                                }
 4104
 4105                                let delimiters = language.line_comment_prefixes();
 4106                                let max_len_of_delimiter =
 4107                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4108                                let (snapshot, range) =
 4109                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4110
 4111                                let num_of_whitespaces = snapshot
 4112                                    .chars_for_range(range.clone())
 4113                                    .take_while(|c| c.is_whitespace())
 4114                                    .count();
 4115                                let comment_candidate = snapshot
 4116                                    .chars_for_range(range)
 4117                                    .skip(num_of_whitespaces)
 4118                                    .take(max_len_of_delimiter)
 4119                                    .collect::<String>();
 4120                                let (delimiter, trimmed_len) = delimiters
 4121                                    .iter()
 4122                                    .filter_map(|delimiter| {
 4123                                        let prefix = delimiter.trim_end();
 4124                                        if comment_candidate.starts_with(prefix) {
 4125                                            Some((delimiter, prefix.len()))
 4126                                        } else {
 4127                                            None
 4128                                        }
 4129                                    })
 4130                                    .max_by_key(|(_, len)| *len)?;
 4131
 4132                                let cursor_is_placed_after_comment_marker =
 4133                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4134                                if cursor_is_placed_after_comment_marker {
 4135                                    Some(delimiter.clone())
 4136                                } else {
 4137                                    None
 4138                                }
 4139                            });
 4140
 4141                            let mut indent_on_newline = IndentSize::spaces(0);
 4142                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4143
 4144                            let doc_delimiter = maybe!({
 4145                                if !selection_is_empty {
 4146                                    return None;
 4147                                }
 4148
 4149                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4150                                    return None;
 4151                                }
 4152
 4153                                let DocumentationConfig {
 4154                                    start: start_tag,
 4155                                    end: end_tag,
 4156                                    prefix: delimiter,
 4157                                    tab_size: len,
 4158                                } = language.documentation()?;
 4159
 4160                                let is_within_block_comment = buffer
 4161                                    .language_scope_at(start_point)
 4162                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4163                                if !is_within_block_comment {
 4164                                    return None;
 4165                                }
 4166
 4167                                let (snapshot, range) =
 4168                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4169
 4170                                let num_of_whitespaces = snapshot
 4171                                    .chars_for_range(range.clone())
 4172                                    .take_while(|c| c.is_whitespace())
 4173                                    .count();
 4174
 4175                                // 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.
 4176                                let column = start_point.column;
 4177                                let cursor_is_after_start_tag = {
 4178                                    let start_tag_len = start_tag.len();
 4179                                    let start_tag_line = snapshot
 4180                                        .chars_for_range(range.clone())
 4181                                        .skip(num_of_whitespaces)
 4182                                        .take(start_tag_len)
 4183                                        .collect::<String>();
 4184                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4185                                        num_of_whitespaces + start_tag_len <= column as usize
 4186                                    } else {
 4187                                        false
 4188                                    }
 4189                                };
 4190
 4191                                let cursor_is_after_delimiter = {
 4192                                    let delimiter_trim = delimiter.trim_end();
 4193                                    let delimiter_line = snapshot
 4194                                        .chars_for_range(range.clone())
 4195                                        .skip(num_of_whitespaces)
 4196                                        .take(delimiter_trim.len())
 4197                                        .collect::<String>();
 4198                                    if delimiter_line.starts_with(delimiter_trim) {
 4199                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4200                                    } else {
 4201                                        false
 4202                                    }
 4203                                };
 4204
 4205                                let cursor_is_before_end_tag_if_exists = {
 4206                                    let mut char_position = 0u32;
 4207                                    let mut end_tag_offset = None;
 4208
 4209                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4210                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4211                                            let chars_before_match =
 4212                                                chunk[..byte_pos].chars().count() as u32;
 4213                                            end_tag_offset =
 4214                                                Some(char_position + chars_before_match);
 4215                                            break 'outer;
 4216                                        }
 4217                                        char_position += chunk.chars().count() as u32;
 4218                                    }
 4219
 4220                                    if let Some(end_tag_offset) = end_tag_offset {
 4221                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4222                                        if cursor_is_after_start_tag {
 4223                                            if cursor_is_before_end_tag {
 4224                                                insert_extra_newline = true;
 4225                                            }
 4226                                            let cursor_is_at_start_of_end_tag =
 4227                                                column == end_tag_offset;
 4228                                            if cursor_is_at_start_of_end_tag {
 4229                                                indent_on_extra_newline.len = (*len).into();
 4230                                            }
 4231                                        }
 4232                                        cursor_is_before_end_tag
 4233                                    } else {
 4234                                        true
 4235                                    }
 4236                                };
 4237
 4238                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4239                                    && cursor_is_before_end_tag_if_exists
 4240                                {
 4241                                    if cursor_is_after_start_tag {
 4242                                        indent_on_newline.len = (*len).into();
 4243                                    }
 4244                                    Some(delimiter.clone())
 4245                                } else {
 4246                                    None
 4247                                }
 4248                            });
 4249
 4250                            (
 4251                                comment_delimiter,
 4252                                doc_delimiter,
 4253                                insert_extra_newline,
 4254                                indent_on_newline,
 4255                                indent_on_extra_newline,
 4256                            )
 4257                        } else {
 4258                            (
 4259                                None,
 4260                                None,
 4261                                false,
 4262                                IndentSize::default(),
 4263                                IndentSize::default(),
 4264                            )
 4265                        };
 4266
 4267                        let prevent_auto_indent = doc_delimiter.is_some();
 4268                        let delimiter = comment_delimiter.or(doc_delimiter);
 4269
 4270                        let capacity_for_delimiter =
 4271                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4272                        let mut new_text = String::with_capacity(
 4273                            1 + capacity_for_delimiter
 4274                                + existing_indent.len as usize
 4275                                + indent_on_newline.len as usize
 4276                                + indent_on_extra_newline.len as usize,
 4277                        );
 4278                        new_text.push('\n');
 4279                        new_text.extend(existing_indent.chars());
 4280                        new_text.extend(indent_on_newline.chars());
 4281
 4282                        if let Some(delimiter) = &delimiter {
 4283                            new_text.push_str(delimiter);
 4284                        }
 4285
 4286                        if insert_extra_newline {
 4287                            new_text.push('\n');
 4288                            new_text.extend(existing_indent.chars());
 4289                            new_text.extend(indent_on_extra_newline.chars());
 4290                        }
 4291
 4292                        let anchor = buffer.anchor_after(end);
 4293                        let new_selection = selection.map(|_| anchor);
 4294                        (
 4295                            ((start..end, new_text), prevent_auto_indent),
 4296                            (insert_extra_newline, new_selection),
 4297                        )
 4298                    })
 4299                    .unzip()
 4300            };
 4301
 4302            let mut auto_indent_edits = Vec::new();
 4303            let mut edits = Vec::new();
 4304            for (edit, prevent_auto_indent) in edits_with_flags {
 4305                if prevent_auto_indent {
 4306                    edits.push(edit);
 4307                } else {
 4308                    auto_indent_edits.push(edit);
 4309                }
 4310            }
 4311            if !edits.is_empty() {
 4312                this.edit(edits, cx);
 4313            }
 4314            if !auto_indent_edits.is_empty() {
 4315                this.edit_with_autoindent(auto_indent_edits, cx);
 4316            }
 4317
 4318            let buffer = this.buffer.read(cx).snapshot(cx);
 4319            let new_selections = selection_info
 4320                .into_iter()
 4321                .map(|(extra_newline_inserted, new_selection)| {
 4322                    let mut cursor = new_selection.end.to_point(&buffer);
 4323                    if extra_newline_inserted {
 4324                        cursor.row -= 1;
 4325                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4326                    }
 4327                    new_selection.map(|_| cursor)
 4328                })
 4329                .collect();
 4330
 4331            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4332                s.select(new_selections)
 4333            });
 4334            this.refresh_inline_completion(true, false, window, cx);
 4335        });
 4336    }
 4337
 4338    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4339        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4340
 4341        let buffer = self.buffer.read(cx);
 4342        let snapshot = buffer.snapshot(cx);
 4343
 4344        let mut edits = Vec::new();
 4345        let mut rows = Vec::new();
 4346
 4347        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4348            let cursor = selection.head();
 4349            let row = cursor.row;
 4350
 4351            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4352
 4353            let newline = "\n".to_string();
 4354            edits.push((start_of_line..start_of_line, newline));
 4355
 4356            rows.push(row + rows_inserted as u32);
 4357        }
 4358
 4359        self.transact(window, cx, |editor, window, cx| {
 4360            editor.edit(edits, cx);
 4361
 4362            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4363                let mut index = 0;
 4364                s.move_cursors_with(|map, _, _| {
 4365                    let row = rows[index];
 4366                    index += 1;
 4367
 4368                    let point = Point::new(row, 0);
 4369                    let boundary = map.next_line_boundary(point).1;
 4370                    let clipped = map.clip_point(boundary, Bias::Left);
 4371
 4372                    (clipped, SelectionGoal::None)
 4373                });
 4374            });
 4375
 4376            let mut indent_edits = Vec::new();
 4377            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4378            for row in rows {
 4379                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4380                for (row, indent) in indents {
 4381                    if indent.len == 0 {
 4382                        continue;
 4383                    }
 4384
 4385                    let text = match indent.kind {
 4386                        IndentKind::Space => " ".repeat(indent.len as usize),
 4387                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4388                    };
 4389                    let point = Point::new(row.0, 0);
 4390                    indent_edits.push((point..point, text));
 4391                }
 4392            }
 4393            editor.edit(indent_edits, cx);
 4394        });
 4395    }
 4396
 4397    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4398        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4399
 4400        let buffer = self.buffer.read(cx);
 4401        let snapshot = buffer.snapshot(cx);
 4402
 4403        let mut edits = Vec::new();
 4404        let mut rows = Vec::new();
 4405        let mut rows_inserted = 0;
 4406
 4407        for selection in self.selections.all_adjusted(cx) {
 4408            let cursor = selection.head();
 4409            let row = cursor.row;
 4410
 4411            let point = Point::new(row + 1, 0);
 4412            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4413
 4414            let newline = "\n".to_string();
 4415            edits.push((start_of_line..start_of_line, newline));
 4416
 4417            rows_inserted += 1;
 4418            rows.push(row + rows_inserted);
 4419        }
 4420
 4421        self.transact(window, cx, |editor, window, cx| {
 4422            editor.edit(edits, cx);
 4423
 4424            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4425                let mut index = 0;
 4426                s.move_cursors_with(|map, _, _| {
 4427                    let row = rows[index];
 4428                    index += 1;
 4429
 4430                    let point = Point::new(row, 0);
 4431                    let boundary = map.next_line_boundary(point).1;
 4432                    let clipped = map.clip_point(boundary, Bias::Left);
 4433
 4434                    (clipped, SelectionGoal::None)
 4435                });
 4436            });
 4437
 4438            let mut indent_edits = Vec::new();
 4439            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4440            for row in rows {
 4441                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4442                for (row, indent) in indents {
 4443                    if indent.len == 0 {
 4444                        continue;
 4445                    }
 4446
 4447                    let text = match indent.kind {
 4448                        IndentKind::Space => " ".repeat(indent.len as usize),
 4449                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4450                    };
 4451                    let point = Point::new(row.0, 0);
 4452                    indent_edits.push((point..point, text));
 4453                }
 4454            }
 4455            editor.edit(indent_edits, cx);
 4456        });
 4457    }
 4458
 4459    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4460        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4461            original_indent_columns: Vec::new(),
 4462        });
 4463        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4464    }
 4465
 4466    fn insert_with_autoindent_mode(
 4467        &mut self,
 4468        text: &str,
 4469        autoindent_mode: Option<AutoindentMode>,
 4470        window: &mut Window,
 4471        cx: &mut Context<Self>,
 4472    ) {
 4473        if self.read_only(cx) {
 4474            return;
 4475        }
 4476
 4477        let text: Arc<str> = text.into();
 4478        self.transact(window, cx, |this, window, cx| {
 4479            let old_selections = this.selections.all_adjusted(cx);
 4480            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4481                let anchors = {
 4482                    let snapshot = buffer.read(cx);
 4483                    old_selections
 4484                        .iter()
 4485                        .map(|s| {
 4486                            let anchor = snapshot.anchor_after(s.head());
 4487                            s.map(|_| anchor)
 4488                        })
 4489                        .collect::<Vec<_>>()
 4490                };
 4491                buffer.edit(
 4492                    old_selections
 4493                        .iter()
 4494                        .map(|s| (s.start..s.end, text.clone())),
 4495                    autoindent_mode,
 4496                    cx,
 4497                );
 4498                anchors
 4499            });
 4500
 4501            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4502                s.select_anchors(selection_anchors);
 4503            });
 4504
 4505            cx.notify();
 4506        });
 4507    }
 4508
 4509    fn trigger_completion_on_input(
 4510        &mut self,
 4511        text: &str,
 4512        trigger_in_words: bool,
 4513        window: &mut Window,
 4514        cx: &mut Context<Self>,
 4515    ) {
 4516        let completions_source = self
 4517            .context_menu
 4518            .borrow()
 4519            .as_ref()
 4520            .and_then(|menu| match menu {
 4521                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4522                CodeContextMenu::CodeActions(_) => None,
 4523            });
 4524
 4525        match completions_source {
 4526            Some(CompletionsMenuSource::Words) => {
 4527                self.show_word_completions(&ShowWordCompletions, window, cx)
 4528            }
 4529            Some(CompletionsMenuSource::Normal)
 4530            | Some(CompletionsMenuSource::SnippetChoices)
 4531            | None
 4532                if self.is_completion_trigger(
 4533                    text,
 4534                    trigger_in_words,
 4535                    completions_source.is_some(),
 4536                    cx,
 4537                ) =>
 4538            {
 4539                self.show_completions(
 4540                    &ShowCompletions {
 4541                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4542                    },
 4543                    window,
 4544                    cx,
 4545                )
 4546            }
 4547            _ => {
 4548                self.hide_context_menu(window, cx);
 4549            }
 4550        }
 4551    }
 4552
 4553    fn is_completion_trigger(
 4554        &self,
 4555        text: &str,
 4556        trigger_in_words: bool,
 4557        menu_is_open: bool,
 4558        cx: &mut Context<Self>,
 4559    ) -> bool {
 4560        let position = self.selections.newest_anchor().head();
 4561        let multibuffer = self.buffer.read(cx);
 4562        let Some(buffer) = position
 4563            .buffer_id
 4564            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4565        else {
 4566            return false;
 4567        };
 4568
 4569        if let Some(completion_provider) = &self.completion_provider {
 4570            completion_provider.is_completion_trigger(
 4571                &buffer,
 4572                position.text_anchor,
 4573                text,
 4574                trigger_in_words,
 4575                menu_is_open,
 4576                cx,
 4577            )
 4578        } else {
 4579            false
 4580        }
 4581    }
 4582
 4583    /// If any empty selections is touching the start of its innermost containing autoclose
 4584    /// region, expand it to select the brackets.
 4585    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4586        let selections = self.selections.all::<usize>(cx);
 4587        let buffer = self.buffer.read(cx).read(cx);
 4588        let new_selections = self
 4589            .selections_with_autoclose_regions(selections, &buffer)
 4590            .map(|(mut selection, region)| {
 4591                if !selection.is_empty() {
 4592                    return selection;
 4593                }
 4594
 4595                if let Some(region) = region {
 4596                    let mut range = region.range.to_offset(&buffer);
 4597                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4598                        range.start -= region.pair.start.len();
 4599                        if buffer.contains_str_at(range.start, &region.pair.start)
 4600                            && buffer.contains_str_at(range.end, &region.pair.end)
 4601                        {
 4602                            range.end += region.pair.end.len();
 4603                            selection.start = range.start;
 4604                            selection.end = range.end;
 4605
 4606                            return selection;
 4607                        }
 4608                    }
 4609                }
 4610
 4611                let always_treat_brackets_as_autoclosed = buffer
 4612                    .language_settings_at(selection.start, cx)
 4613                    .always_treat_brackets_as_autoclosed;
 4614
 4615                if !always_treat_brackets_as_autoclosed {
 4616                    return selection;
 4617                }
 4618
 4619                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4620                    for (pair, enabled) in scope.brackets() {
 4621                        if !enabled || !pair.close {
 4622                            continue;
 4623                        }
 4624
 4625                        if buffer.contains_str_at(selection.start, &pair.end) {
 4626                            let pair_start_len = pair.start.len();
 4627                            if buffer.contains_str_at(
 4628                                selection.start.saturating_sub(pair_start_len),
 4629                                &pair.start,
 4630                            ) {
 4631                                selection.start -= pair_start_len;
 4632                                selection.end += pair.end.len();
 4633
 4634                                return selection;
 4635                            }
 4636                        }
 4637                    }
 4638                }
 4639
 4640                selection
 4641            })
 4642            .collect();
 4643
 4644        drop(buffer);
 4645        self.change_selections(None, window, cx, |selections| {
 4646            selections.select(new_selections)
 4647        });
 4648    }
 4649
 4650    /// Iterate the given selections, and for each one, find the smallest surrounding
 4651    /// autoclose region. This uses the ordering of the selections and the autoclose
 4652    /// regions to avoid repeated comparisons.
 4653    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4654        &'a self,
 4655        selections: impl IntoIterator<Item = Selection<D>>,
 4656        buffer: &'a MultiBufferSnapshot,
 4657    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4658        let mut i = 0;
 4659        let mut regions = self.autoclose_regions.as_slice();
 4660        selections.into_iter().map(move |selection| {
 4661            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4662
 4663            let mut enclosing = None;
 4664            while let Some(pair_state) = regions.get(i) {
 4665                if pair_state.range.end.to_offset(buffer) < range.start {
 4666                    regions = &regions[i + 1..];
 4667                    i = 0;
 4668                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4669                    break;
 4670                } else {
 4671                    if pair_state.selection_id == selection.id {
 4672                        enclosing = Some(pair_state);
 4673                    }
 4674                    i += 1;
 4675                }
 4676            }
 4677
 4678            (selection, enclosing)
 4679        })
 4680    }
 4681
 4682    /// Remove any autoclose regions that no longer contain their selection.
 4683    fn invalidate_autoclose_regions(
 4684        &mut self,
 4685        mut selections: &[Selection<Anchor>],
 4686        buffer: &MultiBufferSnapshot,
 4687    ) {
 4688        self.autoclose_regions.retain(|state| {
 4689            let mut i = 0;
 4690            while let Some(selection) = selections.get(i) {
 4691                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4692                    selections = &selections[1..];
 4693                    continue;
 4694                }
 4695                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4696                    break;
 4697                }
 4698                if selection.id == state.selection_id {
 4699                    return true;
 4700                } else {
 4701                    i += 1;
 4702                }
 4703            }
 4704            false
 4705        });
 4706    }
 4707
 4708    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4709        let offset = position.to_offset(buffer);
 4710        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4711        if offset > word_range.start && kind == Some(CharKind::Word) {
 4712            Some(
 4713                buffer
 4714                    .text_for_range(word_range.start..offset)
 4715                    .collect::<String>(),
 4716            )
 4717        } else {
 4718            None
 4719        }
 4720    }
 4721
 4722    pub fn toggle_inline_values(
 4723        &mut self,
 4724        _: &ToggleInlineValues,
 4725        _: &mut Window,
 4726        cx: &mut Context<Self>,
 4727    ) {
 4728        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4729
 4730        self.refresh_inline_values(cx);
 4731    }
 4732
 4733    pub fn toggle_inlay_hints(
 4734        &mut self,
 4735        _: &ToggleInlayHints,
 4736        _: &mut Window,
 4737        cx: &mut Context<Self>,
 4738    ) {
 4739        self.refresh_inlay_hints(
 4740            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4741            cx,
 4742        );
 4743    }
 4744
 4745    pub fn inlay_hints_enabled(&self) -> bool {
 4746        self.inlay_hint_cache.enabled
 4747    }
 4748
 4749    pub fn inline_values_enabled(&self) -> bool {
 4750        self.inline_value_cache.enabled
 4751    }
 4752
 4753    #[cfg(any(test, feature = "test-support"))]
 4754    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4755        self.display_map
 4756            .read(cx)
 4757            .current_inlays()
 4758            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4759            .cloned()
 4760            .collect()
 4761    }
 4762
 4763    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4764        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4765            return;
 4766        }
 4767
 4768        let reason_description = reason.description();
 4769        let ignore_debounce = matches!(
 4770            reason,
 4771            InlayHintRefreshReason::SettingsChange(_)
 4772                | InlayHintRefreshReason::Toggle(_)
 4773                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4774                | InlayHintRefreshReason::ModifiersChanged(_)
 4775        );
 4776        let (invalidate_cache, required_languages) = match reason {
 4777            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4778                match self.inlay_hint_cache.modifiers_override(enabled) {
 4779                    Some(enabled) => {
 4780                        if enabled {
 4781                            (InvalidationStrategy::RefreshRequested, None)
 4782                        } else {
 4783                            self.splice_inlays(
 4784                                &self
 4785                                    .visible_inlay_hints(cx)
 4786                                    .iter()
 4787                                    .map(|inlay| inlay.id)
 4788                                    .collect::<Vec<InlayId>>(),
 4789                                Vec::new(),
 4790                                cx,
 4791                            );
 4792                            return;
 4793                        }
 4794                    }
 4795                    None => return,
 4796                }
 4797            }
 4798            InlayHintRefreshReason::Toggle(enabled) => {
 4799                if self.inlay_hint_cache.toggle(enabled) {
 4800                    if enabled {
 4801                        (InvalidationStrategy::RefreshRequested, None)
 4802                    } else {
 4803                        self.splice_inlays(
 4804                            &self
 4805                                .visible_inlay_hints(cx)
 4806                                .iter()
 4807                                .map(|inlay| inlay.id)
 4808                                .collect::<Vec<InlayId>>(),
 4809                            Vec::new(),
 4810                            cx,
 4811                        );
 4812                        return;
 4813                    }
 4814                } else {
 4815                    return;
 4816                }
 4817            }
 4818            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4819                match self.inlay_hint_cache.update_settings(
 4820                    &self.buffer,
 4821                    new_settings,
 4822                    self.visible_inlay_hints(cx),
 4823                    cx,
 4824                ) {
 4825                    ControlFlow::Break(Some(InlaySplice {
 4826                        to_remove,
 4827                        to_insert,
 4828                    })) => {
 4829                        self.splice_inlays(&to_remove, to_insert, cx);
 4830                        return;
 4831                    }
 4832                    ControlFlow::Break(None) => return,
 4833                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4834                }
 4835            }
 4836            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4837                if let Some(InlaySplice {
 4838                    to_remove,
 4839                    to_insert,
 4840                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4841                {
 4842                    self.splice_inlays(&to_remove, to_insert, cx);
 4843                }
 4844                self.display_map.update(cx, |display_map, _| {
 4845                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4846                });
 4847                return;
 4848            }
 4849            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4850            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4851                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4852            }
 4853            InlayHintRefreshReason::RefreshRequested => {
 4854                (InvalidationStrategy::RefreshRequested, None)
 4855            }
 4856        };
 4857
 4858        if let Some(InlaySplice {
 4859            to_remove,
 4860            to_insert,
 4861        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4862            reason_description,
 4863            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4864            invalidate_cache,
 4865            ignore_debounce,
 4866            cx,
 4867        ) {
 4868            self.splice_inlays(&to_remove, to_insert, cx);
 4869        }
 4870    }
 4871
 4872    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4873        self.display_map
 4874            .read(cx)
 4875            .current_inlays()
 4876            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4877            .cloned()
 4878            .collect()
 4879    }
 4880
 4881    pub fn excerpts_for_inlay_hints_query(
 4882        &self,
 4883        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4884        cx: &mut Context<Editor>,
 4885    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4886        let Some(project) = self.project.as_ref() else {
 4887            return HashMap::default();
 4888        };
 4889        let project = project.read(cx);
 4890        let multi_buffer = self.buffer().read(cx);
 4891        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4892        let multi_buffer_visible_start = self
 4893            .scroll_manager
 4894            .anchor()
 4895            .anchor
 4896            .to_point(&multi_buffer_snapshot);
 4897        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4898            multi_buffer_visible_start
 4899                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4900            Bias::Left,
 4901        );
 4902        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4903        multi_buffer_snapshot
 4904            .range_to_buffer_ranges(multi_buffer_visible_range)
 4905            .into_iter()
 4906            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4907            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4908                let buffer_file = project::File::from_dyn(buffer.file())?;
 4909                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4910                let worktree_entry = buffer_worktree
 4911                    .read(cx)
 4912                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4913                if worktree_entry.is_ignored {
 4914                    return None;
 4915                }
 4916
 4917                let language = buffer.language()?;
 4918                if let Some(restrict_to_languages) = restrict_to_languages {
 4919                    if !restrict_to_languages.contains(language) {
 4920                        return None;
 4921                    }
 4922                }
 4923                Some((
 4924                    excerpt_id,
 4925                    (
 4926                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4927                        buffer.version().clone(),
 4928                        excerpt_visible_range,
 4929                    ),
 4930                ))
 4931            })
 4932            .collect()
 4933    }
 4934
 4935    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4936        TextLayoutDetails {
 4937            text_system: window.text_system().clone(),
 4938            editor_style: self.style.clone().unwrap(),
 4939            rem_size: window.rem_size(),
 4940            scroll_anchor: self.scroll_manager.anchor(),
 4941            visible_rows: self.visible_line_count(),
 4942            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4943        }
 4944    }
 4945
 4946    pub fn splice_inlays(
 4947        &self,
 4948        to_remove: &[InlayId],
 4949        to_insert: Vec<Inlay>,
 4950        cx: &mut Context<Self>,
 4951    ) {
 4952        self.display_map.update(cx, |display_map, cx| {
 4953            display_map.splice_inlays(to_remove, to_insert, cx)
 4954        });
 4955        cx.notify();
 4956    }
 4957
 4958    fn trigger_on_type_formatting(
 4959        &self,
 4960        input: String,
 4961        window: &mut Window,
 4962        cx: &mut Context<Self>,
 4963    ) -> Option<Task<Result<()>>> {
 4964        if input.len() != 1 {
 4965            return None;
 4966        }
 4967
 4968        let project = self.project.as_ref()?;
 4969        let position = self.selections.newest_anchor().head();
 4970        let (buffer, buffer_position) = self
 4971            .buffer
 4972            .read(cx)
 4973            .text_anchor_for_position(position, cx)?;
 4974
 4975        let settings = language_settings::language_settings(
 4976            buffer
 4977                .read(cx)
 4978                .language_at(buffer_position)
 4979                .map(|l| l.name()),
 4980            buffer.read(cx).file(),
 4981            cx,
 4982        );
 4983        if !settings.use_on_type_format {
 4984            return None;
 4985        }
 4986
 4987        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4988        // hence we do LSP request & edit on host side only — add formats to host's history.
 4989        let push_to_lsp_host_history = true;
 4990        // If this is not the host, append its history with new edits.
 4991        let push_to_client_history = project.read(cx).is_via_collab();
 4992
 4993        let on_type_formatting = project.update(cx, |project, cx| {
 4994            project.on_type_format(
 4995                buffer.clone(),
 4996                buffer_position,
 4997                input,
 4998                push_to_lsp_host_history,
 4999                cx,
 5000            )
 5001        });
 5002        Some(cx.spawn_in(window, async move |editor, cx| {
 5003            if let Some(transaction) = on_type_formatting.await? {
 5004                if push_to_client_history {
 5005                    buffer
 5006                        .update(cx, |buffer, _| {
 5007                            buffer.push_transaction(transaction, Instant::now());
 5008                            buffer.finalize_last_transaction();
 5009                        })
 5010                        .ok();
 5011                }
 5012                editor.update(cx, |editor, cx| {
 5013                    editor.refresh_document_highlights(cx);
 5014                })?;
 5015            }
 5016            Ok(())
 5017        }))
 5018    }
 5019
 5020    pub fn show_word_completions(
 5021        &mut self,
 5022        _: &ShowWordCompletions,
 5023        window: &mut Window,
 5024        cx: &mut Context<Self>,
 5025    ) {
 5026        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5027    }
 5028
 5029    pub fn show_completions(
 5030        &mut self,
 5031        options: &ShowCompletions,
 5032        window: &mut Window,
 5033        cx: &mut Context<Self>,
 5034    ) {
 5035        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5036    }
 5037
 5038    fn open_or_update_completions_menu(
 5039        &mut self,
 5040        requested_source: Option<CompletionsMenuSource>,
 5041        trigger: Option<&str>,
 5042        window: &mut Window,
 5043        cx: &mut Context<Self>,
 5044    ) {
 5045        if self.pending_rename.is_some() {
 5046            return;
 5047        }
 5048
 5049        let position = self.selections.newest_anchor().head();
 5050        if position.diff_base_anchor.is_some() {
 5051            return;
 5052        }
 5053        let (buffer, buffer_position) =
 5054            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5055                output
 5056            } else {
 5057                return;
 5058            };
 5059        let buffer_snapshot = buffer.read(cx).snapshot();
 5060
 5061        let query: Option<Arc<String>> =
 5062            Self::completion_query(&self.buffer.read(cx).read(cx), position)
 5063                .map(|query| query.into());
 5064
 5065        let provider = match requested_source {
 5066            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5067            Some(CompletionsMenuSource::Words) => None,
 5068            Some(CompletionsMenuSource::SnippetChoices) => {
 5069                log::error!("bug: SnippetChoices requested_source is not handled");
 5070                None
 5071            }
 5072        };
 5073
 5074        let sort_completions = provider
 5075            .as_ref()
 5076            .map_or(false, |provider| provider.sort_completions());
 5077
 5078        let filter_completions = provider
 5079            .as_ref()
 5080            .map_or(true, |provider| provider.filter_completions());
 5081
 5082        // When `is_incomplete` is false, can filter completions instead of re-querying when the
 5083        // current query is a suffix of the initial query.
 5084        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5085            if !menu.is_incomplete && filter_completions {
 5086                // If the new query is a suffix of the old query (typing more characters) and
 5087                // the previous result was complete, the existing completions can be filtered.
 5088                //
 5089                // Note that this is always true for snippet completions.
 5090                let query_matches = match (&menu.initial_query, &query) {
 5091                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5092                    (None, _) => true,
 5093                    _ => false,
 5094                };
 5095                if query_matches {
 5096                    let position_matches = if menu.initial_position == position {
 5097                        true
 5098                    } else {
 5099                        let snapshot = self.buffer.read(cx).read(cx);
 5100                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5101                    };
 5102                    if position_matches {
 5103                        menu.filter(query.clone(), provider.clone(), window, cx);
 5104                        return;
 5105                    }
 5106                }
 5107            }
 5108        };
 5109
 5110        let trigger_kind = match trigger {
 5111            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5112                CompletionTriggerKind::TRIGGER_CHARACTER
 5113            }
 5114            _ => CompletionTriggerKind::INVOKED,
 5115        };
 5116        let completion_context = CompletionContext {
 5117            trigger_character: trigger.and_then(|trigger| {
 5118                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5119                    Some(String::from(trigger))
 5120                } else {
 5121                    None
 5122                }
 5123            }),
 5124            trigger_kind,
 5125        };
 5126
 5127        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5128            buffer_snapshot.surrounding_word(buffer_position)
 5129        {
 5130            let word_to_exclude = buffer_snapshot
 5131                .text_for_range(word_range.clone())
 5132                .collect::<String>();
 5133            (
 5134                buffer_snapshot.anchor_before(word_range.start)
 5135                    ..buffer_snapshot.anchor_after(buffer_position),
 5136                Some(word_to_exclude),
 5137            )
 5138        } else {
 5139            (buffer_position..buffer_position, None)
 5140        };
 5141
 5142        let language = buffer_snapshot
 5143            .language_at(buffer_position)
 5144            .map(|language| language.name());
 5145
 5146        let completion_settings =
 5147            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5148
 5149        let show_completion_documentation = buffer_snapshot
 5150            .settings_at(buffer_position, cx)
 5151            .show_completion_documentation;
 5152
 5153        // The document can be large, so stay in reasonable bounds when searching for words,
 5154        // otherwise completion pop-up might be slow to appear.
 5155        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5156        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5157        let min_word_search = buffer_snapshot.clip_point(
 5158            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5159            Bias::Left,
 5160        );
 5161        let max_word_search = buffer_snapshot.clip_point(
 5162            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5163            Bias::Right,
 5164        );
 5165        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5166            ..buffer_snapshot.point_to_offset(max_word_search);
 5167
 5168        let skip_digits = query
 5169            .as_ref()
 5170            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5171
 5172        let (mut words, provider_responses) = match &provider {
 5173            Some(provider) => {
 5174                let provider_responses = provider.completions(
 5175                    position.excerpt_id,
 5176                    &buffer,
 5177                    buffer_position,
 5178                    completion_context,
 5179                    window,
 5180                    cx,
 5181                );
 5182
 5183                let words = match completion_settings.words {
 5184                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5185                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5186                        .background_spawn(async move {
 5187                            buffer_snapshot.words_in_range(WordsQuery {
 5188                                fuzzy_contents: None,
 5189                                range: word_search_range,
 5190                                skip_digits,
 5191                            })
 5192                        }),
 5193                };
 5194
 5195                (words, provider_responses)
 5196            }
 5197            None => (
 5198                cx.background_spawn(async move {
 5199                    buffer_snapshot.words_in_range(WordsQuery {
 5200                        fuzzy_contents: None,
 5201                        range: word_search_range,
 5202                        skip_digits,
 5203                    })
 5204                }),
 5205                Task::ready(Ok(Vec::new())),
 5206            ),
 5207        };
 5208
 5209        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5210
 5211        let id = post_inc(&mut self.next_completion_id);
 5212        let task = cx.spawn_in(window, async move |editor, cx| {
 5213            let Ok(()) = editor.update(cx, |this, _| {
 5214                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5215            }) else {
 5216                return;
 5217            };
 5218
 5219            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5220            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5221            let mut completions = Vec::new();
 5222            let mut is_incomplete = false;
 5223            if let Some(provider_responses) = provider_responses.await.log_err() {
 5224                if !provider_responses.is_empty() {
 5225                    for response in provider_responses {
 5226                        completions.extend(response.completions);
 5227                        is_incomplete = is_incomplete || response.is_incomplete;
 5228                    }
 5229                    if completion_settings.words == WordsCompletionMode::Fallback {
 5230                        words = Task::ready(BTreeMap::default());
 5231                    }
 5232                }
 5233            }
 5234
 5235            let mut words = words.await;
 5236            if let Some(word_to_exclude) = &word_to_exclude {
 5237                words.remove(word_to_exclude);
 5238            }
 5239            for lsp_completion in &completions {
 5240                words.remove(&lsp_completion.new_text);
 5241            }
 5242            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5243                replace_range: word_replace_range.clone(),
 5244                new_text: word.clone(),
 5245                label: CodeLabel::plain(word, None),
 5246                icon_path: None,
 5247                documentation: None,
 5248                source: CompletionSource::BufferWord {
 5249                    word_range,
 5250                    resolved: false,
 5251                },
 5252                insert_text_mode: Some(InsertTextMode::AS_IS),
 5253                confirm: None,
 5254            }));
 5255
 5256            let menu = if completions.is_empty() {
 5257                None
 5258            } else {
 5259                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5260                    let languages = editor
 5261                        .workspace
 5262                        .as_ref()
 5263                        .and_then(|(workspace, _)| workspace.upgrade())
 5264                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5265                    let menu = CompletionsMenu::new(
 5266                        id,
 5267                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5268                        sort_completions,
 5269                        show_completion_documentation,
 5270                        position,
 5271                        query.clone(),
 5272                        is_incomplete,
 5273                        buffer.clone(),
 5274                        completions.into(),
 5275                        snippet_sort_order,
 5276                        languages,
 5277                        language,
 5278                        cx,
 5279                    );
 5280
 5281                    let query = if filter_completions { query } else { None };
 5282                    let matches_task = if let Some(query) = query {
 5283                        menu.do_async_filtering(query, cx)
 5284                    } else {
 5285                        Task::ready(menu.unfiltered_matches())
 5286                    };
 5287                    (menu, matches_task)
 5288                }) else {
 5289                    return;
 5290                };
 5291
 5292                let matches = matches_task.await;
 5293
 5294                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5295                    // Newer menu already set, so exit.
 5296                    match editor.context_menu.borrow().as_ref() {
 5297                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5298                            if prev_menu.id > id {
 5299                                return;
 5300                            }
 5301                        }
 5302                        _ => {}
 5303                    };
 5304
 5305                    // Only valid to take prev_menu because it the new menu is immediately set
 5306                    // below, or the menu is hidden.
 5307                    match editor.context_menu.borrow_mut().take() {
 5308                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5309                            let position_matches =
 5310                                if prev_menu.initial_position == menu.initial_position {
 5311                                    true
 5312                                } else {
 5313                                    let snapshot = editor.buffer.read(cx).read(cx);
 5314                                    prev_menu.initial_position.to_offset(&snapshot)
 5315                                        == menu.initial_position.to_offset(&snapshot)
 5316                                };
 5317                            if position_matches {
 5318                                // Preserve markdown cache before `set_filter_results` because it will
 5319                                // try to populate the documentation cache.
 5320                                menu.preserve_markdown_cache(prev_menu);
 5321                            }
 5322                        }
 5323                        _ => {}
 5324                    };
 5325
 5326                    menu.set_filter_results(matches, provider, window, cx);
 5327                }) else {
 5328                    return;
 5329                };
 5330
 5331                menu.visible().then_some(menu)
 5332            };
 5333
 5334            editor
 5335                .update_in(cx, |editor, window, cx| {
 5336                    if editor.focus_handle.is_focused(window) {
 5337                        if let Some(menu) = menu {
 5338                            *editor.context_menu.borrow_mut() =
 5339                                Some(CodeContextMenu::Completions(menu));
 5340
 5341                            crate::hover_popover::hide_hover(editor, cx);
 5342                            if editor.show_edit_predictions_in_menu() {
 5343                                editor.update_visible_inline_completion(window, cx);
 5344                            } else {
 5345                                editor.discard_inline_completion(false, cx);
 5346                            }
 5347
 5348                            cx.notify();
 5349                            return;
 5350                        }
 5351                    }
 5352
 5353                    if editor.completion_tasks.len() <= 1 {
 5354                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5355                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5356                        // If it was already hidden and we don't show inline completions in the menu, we should
 5357                        // also show the inline-completion when available.
 5358                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5359                            editor.update_visible_inline_completion(window, cx);
 5360                        }
 5361                    }
 5362                })
 5363                .ok();
 5364        });
 5365
 5366        self.completion_tasks.push((id, task));
 5367    }
 5368
 5369    #[cfg(feature = "test-support")]
 5370    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5371        let menu = self.context_menu.borrow();
 5372        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5373            let completions = menu.completions.borrow();
 5374            Some(completions.to_vec())
 5375        } else {
 5376            None
 5377        }
 5378    }
 5379
 5380    pub fn with_completions_menu_matching_id<R>(
 5381        &self,
 5382        id: CompletionId,
 5383        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5384    ) -> R {
 5385        let mut context_menu = self.context_menu.borrow_mut();
 5386        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5387            return f(None);
 5388        };
 5389        if completions_menu.id != id {
 5390            return f(None);
 5391        }
 5392        f(Some(completions_menu))
 5393    }
 5394
 5395    pub fn confirm_completion(
 5396        &mut self,
 5397        action: &ConfirmCompletion,
 5398        window: &mut Window,
 5399        cx: &mut Context<Self>,
 5400    ) -> Option<Task<Result<()>>> {
 5401        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5402        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5403    }
 5404
 5405    pub fn confirm_completion_insert(
 5406        &mut self,
 5407        _: &ConfirmCompletionInsert,
 5408        window: &mut Window,
 5409        cx: &mut Context<Self>,
 5410    ) -> Option<Task<Result<()>>> {
 5411        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5412        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5413    }
 5414
 5415    pub fn confirm_completion_replace(
 5416        &mut self,
 5417        _: &ConfirmCompletionReplace,
 5418        window: &mut Window,
 5419        cx: &mut Context<Self>,
 5420    ) -> Option<Task<Result<()>>> {
 5421        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5422        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5423    }
 5424
 5425    pub fn compose_completion(
 5426        &mut self,
 5427        action: &ComposeCompletion,
 5428        window: &mut Window,
 5429        cx: &mut Context<Self>,
 5430    ) -> Option<Task<Result<()>>> {
 5431        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5432        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5433    }
 5434
 5435    fn do_completion(
 5436        &mut self,
 5437        item_ix: Option<usize>,
 5438        intent: CompletionIntent,
 5439        window: &mut Window,
 5440        cx: &mut Context<Editor>,
 5441    ) -> Option<Task<Result<()>>> {
 5442        use language::ToOffset as _;
 5443
 5444        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5445        else {
 5446            return None;
 5447        };
 5448
 5449        let candidate_id = {
 5450            let entries = completions_menu.entries.borrow();
 5451            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5452            if self.show_edit_predictions_in_menu() {
 5453                self.discard_inline_completion(true, cx);
 5454            }
 5455            mat.candidate_id
 5456        };
 5457
 5458        let completion = completions_menu
 5459            .completions
 5460            .borrow()
 5461            .get(candidate_id)?
 5462            .clone();
 5463        cx.stop_propagation();
 5464
 5465        let buffer_handle = completions_menu.buffer.clone();
 5466
 5467        let CompletionEdit {
 5468            new_text,
 5469            snippet,
 5470            replace_range,
 5471        } = process_completion_for_edit(
 5472            &completion,
 5473            intent,
 5474            &buffer_handle,
 5475            &completions_menu.initial_position.text_anchor,
 5476            cx,
 5477        );
 5478
 5479        let buffer = buffer_handle.read(cx);
 5480        let snapshot = self.buffer.read(cx).snapshot(cx);
 5481        let newest_anchor = self.selections.newest_anchor();
 5482        let replace_range_multibuffer = {
 5483            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5484            let multibuffer_anchor = snapshot
 5485                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5486                .unwrap()
 5487                ..snapshot
 5488                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5489                    .unwrap();
 5490            multibuffer_anchor.start.to_offset(&snapshot)
 5491                ..multibuffer_anchor.end.to_offset(&snapshot)
 5492        };
 5493        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5494            return None;
 5495        }
 5496
 5497        let old_text = buffer
 5498            .text_for_range(replace_range.clone())
 5499            .collect::<String>();
 5500        let lookbehind = newest_anchor
 5501            .start
 5502            .text_anchor
 5503            .to_offset(buffer)
 5504            .saturating_sub(replace_range.start);
 5505        let lookahead = replace_range
 5506            .end
 5507            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5508        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5509        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5510
 5511        let selections = self.selections.all::<usize>(cx);
 5512        let mut ranges = Vec::new();
 5513        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5514
 5515        for selection in &selections {
 5516            let range = if selection.id == newest_anchor.id {
 5517                replace_range_multibuffer.clone()
 5518            } else {
 5519                let mut range = selection.range();
 5520
 5521                // if prefix is present, don't duplicate it
 5522                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5523                    range.start = range.start.saturating_sub(lookbehind);
 5524
 5525                    // if suffix is also present, mimic the newest cursor and replace it
 5526                    if selection.id != newest_anchor.id
 5527                        && snapshot.contains_str_at(range.end, suffix)
 5528                    {
 5529                        range.end += lookahead;
 5530                    }
 5531                }
 5532                range
 5533            };
 5534
 5535            ranges.push(range.clone());
 5536
 5537            if !self.linked_edit_ranges.is_empty() {
 5538                let start_anchor = snapshot.anchor_before(range.start);
 5539                let end_anchor = snapshot.anchor_after(range.end);
 5540                if let Some(ranges) = self
 5541                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5542                {
 5543                    for (buffer, edits) in ranges {
 5544                        linked_edits
 5545                            .entry(buffer.clone())
 5546                            .or_default()
 5547                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5548                    }
 5549                }
 5550            }
 5551        }
 5552
 5553        let common_prefix_len = old_text
 5554            .chars()
 5555            .zip(new_text.chars())
 5556            .take_while(|(a, b)| a == b)
 5557            .map(|(a, _)| a.len_utf8())
 5558            .sum::<usize>();
 5559
 5560        cx.emit(EditorEvent::InputHandled {
 5561            utf16_range_to_replace: None,
 5562            text: new_text[common_prefix_len..].into(),
 5563        });
 5564
 5565        self.transact(window, cx, |this, window, cx| {
 5566            if let Some(mut snippet) = snippet {
 5567                snippet.text = new_text.to_string();
 5568                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5569            } else {
 5570                this.buffer.update(cx, |buffer, cx| {
 5571                    let auto_indent = match completion.insert_text_mode {
 5572                        Some(InsertTextMode::AS_IS) => None,
 5573                        _ => this.autoindent_mode.clone(),
 5574                    };
 5575                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5576                    buffer.edit(edits, auto_indent, cx);
 5577                });
 5578            }
 5579            for (buffer, edits) in linked_edits {
 5580                buffer.update(cx, |buffer, cx| {
 5581                    let snapshot = buffer.snapshot();
 5582                    let edits = edits
 5583                        .into_iter()
 5584                        .map(|(range, text)| {
 5585                            use text::ToPoint as TP;
 5586                            let end_point = TP::to_point(&range.end, &snapshot);
 5587                            let start_point = TP::to_point(&range.start, &snapshot);
 5588                            (start_point..end_point, text)
 5589                        })
 5590                        .sorted_by_key(|(range, _)| range.start);
 5591                    buffer.edit(edits, None, cx);
 5592                })
 5593            }
 5594
 5595            this.refresh_inline_completion(true, false, window, cx);
 5596        });
 5597
 5598        let show_new_completions_on_confirm = completion
 5599            .confirm
 5600            .as_ref()
 5601            .map_or(false, |confirm| confirm(intent, window, cx));
 5602        if show_new_completions_on_confirm {
 5603            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5604        }
 5605
 5606        let provider = self.completion_provider.as_ref()?;
 5607        drop(completion);
 5608        let apply_edits = provider.apply_additional_edits_for_completion(
 5609            buffer_handle,
 5610            completions_menu.completions.clone(),
 5611            candidate_id,
 5612            true,
 5613            cx,
 5614        );
 5615
 5616        let editor_settings = EditorSettings::get_global(cx);
 5617        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5618            // After the code completion is finished, users often want to know what signatures are needed.
 5619            // so we should automatically call signature_help
 5620            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5621        }
 5622
 5623        Some(cx.foreground_executor().spawn(async move {
 5624            apply_edits.await?;
 5625            Ok(())
 5626        }))
 5627    }
 5628
 5629    pub fn toggle_code_actions(
 5630        &mut self,
 5631        action: &ToggleCodeActions,
 5632        window: &mut Window,
 5633        cx: &mut Context<Self>,
 5634    ) {
 5635        let quick_launch = action.quick_launch;
 5636        let mut context_menu = self.context_menu.borrow_mut();
 5637        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5638            if code_actions.deployed_from == action.deployed_from {
 5639                // Toggle if we're selecting the same one
 5640                *context_menu = None;
 5641                cx.notify();
 5642                return;
 5643            } else {
 5644                // Otherwise, clear it and start a new one
 5645                *context_menu = None;
 5646                cx.notify();
 5647            }
 5648        }
 5649        drop(context_menu);
 5650        let snapshot = self.snapshot(window, cx);
 5651        let deployed_from = action.deployed_from.clone();
 5652        let mut task = self.code_actions_task.take();
 5653        let action = action.clone();
 5654        cx.spawn_in(window, async move |editor, cx| {
 5655            while let Some(prev_task) = task {
 5656                prev_task.await.log_err();
 5657                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5658            }
 5659
 5660            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5661                if editor.focus_handle.is_focused(window) {
 5662                    let multibuffer_point = match &action.deployed_from {
 5663                        Some(CodeActionSource::Indicator(row)) => {
 5664                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5665                        }
 5666                        _ => editor.selections.newest::<Point>(cx).head(),
 5667                    };
 5668                    let (buffer, buffer_row) = snapshot
 5669                        .buffer_snapshot
 5670                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5671                        .and_then(|(buffer_snapshot, range)| {
 5672                            editor
 5673                                .buffer
 5674                                .read(cx)
 5675                                .buffer(buffer_snapshot.remote_id())
 5676                                .map(|buffer| (buffer, range.start.row))
 5677                        })?;
 5678                    let (_, code_actions) = editor
 5679                        .available_code_actions
 5680                        .clone()
 5681                        .and_then(|(location, code_actions)| {
 5682                            let snapshot = location.buffer.read(cx).snapshot();
 5683                            let point_range = location.range.to_point(&snapshot);
 5684                            let point_range = point_range.start.row..=point_range.end.row;
 5685                            if point_range.contains(&buffer_row) {
 5686                                Some((location, code_actions))
 5687                            } else {
 5688                                None
 5689                            }
 5690                        })
 5691                        .unzip();
 5692                    let buffer_id = buffer.read(cx).remote_id();
 5693                    let tasks = editor
 5694                        .tasks
 5695                        .get(&(buffer_id, buffer_row))
 5696                        .map(|t| Arc::new(t.to_owned()));
 5697                    if tasks.is_none() && code_actions.is_none() {
 5698                        return None;
 5699                    }
 5700
 5701                    editor.completion_tasks.clear();
 5702                    editor.discard_inline_completion(false, cx);
 5703                    let task_context =
 5704                        tasks
 5705                            .as_ref()
 5706                            .zip(editor.project.clone())
 5707                            .map(|(tasks, project)| {
 5708                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5709                            });
 5710
 5711                    Some(cx.spawn_in(window, async move |editor, cx| {
 5712                        let task_context = match task_context {
 5713                            Some(task_context) => task_context.await,
 5714                            None => None,
 5715                        };
 5716                        let resolved_tasks =
 5717                            tasks
 5718                                .zip(task_context.clone())
 5719                                .map(|(tasks, task_context)| ResolvedTasks {
 5720                                    templates: tasks.resolve(&task_context).collect(),
 5721                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5722                                        multibuffer_point.row,
 5723                                        tasks.column,
 5724                                    )),
 5725                                });
 5726                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5727                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5728                                maybe!({
 5729                                    let project = editor.project.as_ref()?;
 5730                                    let dap_store = project.read(cx).dap_store();
 5731                                    let mut scenarios = vec![];
 5732                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5733                                    let buffer = buffer.read(cx);
 5734                                    let language = buffer.language()?;
 5735                                    let file = buffer.file();
 5736                                    let debug_adapter =
 5737                                        language_settings(language.name().into(), file, cx)
 5738                                            .debuggers
 5739                                            .first()
 5740                                            .map(SharedString::from)
 5741                                            .or_else(|| {
 5742                                                language
 5743                                                    .config()
 5744                                                    .debuggers
 5745                                                    .first()
 5746                                                    .map(SharedString::from)
 5747                                            })?;
 5748
 5749                                    dap_store.update(cx, |dap_store, cx| {
 5750                                        for (_, task) in &resolved_tasks.templates {
 5751                                            if let Some(scenario) = dap_store
 5752                                                .debug_scenario_for_build_task(
 5753                                                    task.original_task().clone(),
 5754                                                    debug_adapter.clone().into(),
 5755                                                    task.display_label().to_owned().into(),
 5756                                                    cx,
 5757                                                )
 5758                                            {
 5759                                                scenarios.push(scenario);
 5760                                            }
 5761                                        }
 5762                                    });
 5763                                    Some(scenarios)
 5764                                })
 5765                                .unwrap_or_default()
 5766                            } else {
 5767                                vec![]
 5768                            }
 5769                        })?;
 5770                        let spawn_straight_away = quick_launch
 5771                            && resolved_tasks
 5772                                .as_ref()
 5773                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5774                            && code_actions
 5775                                .as_ref()
 5776                                .map_or(true, |actions| actions.is_empty())
 5777                            && debug_scenarios.is_empty();
 5778                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5779                            crate::hover_popover::hide_hover(editor, cx);
 5780                            *editor.context_menu.borrow_mut() =
 5781                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5782                                    buffer,
 5783                                    actions: CodeActionContents::new(
 5784                                        resolved_tasks,
 5785                                        code_actions,
 5786                                        debug_scenarios,
 5787                                        task_context.unwrap_or_default(),
 5788                                    ),
 5789                                    selected_item: Default::default(),
 5790                                    scroll_handle: UniformListScrollHandle::default(),
 5791                                    deployed_from,
 5792                                }));
 5793                            if spawn_straight_away {
 5794                                if let Some(task) = editor.confirm_code_action(
 5795                                    &ConfirmCodeAction { item_ix: Some(0) },
 5796                                    window,
 5797                                    cx,
 5798                                ) {
 5799                                    cx.notify();
 5800                                    return task;
 5801                                }
 5802                            }
 5803                            cx.notify();
 5804                            Task::ready(Ok(()))
 5805                        }) {
 5806                            task.await
 5807                        } else {
 5808                            Ok(())
 5809                        }
 5810                    }))
 5811                } else {
 5812                    Some(Task::ready(Ok(())))
 5813                }
 5814            })?;
 5815            if let Some(task) = spawned_test_task {
 5816                task.await?;
 5817            }
 5818
 5819            anyhow::Ok(())
 5820        })
 5821        .detach_and_log_err(cx);
 5822    }
 5823
 5824    pub fn confirm_code_action(
 5825        &mut self,
 5826        action: &ConfirmCodeAction,
 5827        window: &mut Window,
 5828        cx: &mut Context<Self>,
 5829    ) -> Option<Task<Result<()>>> {
 5830        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5831
 5832        let actions_menu =
 5833            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5834                menu
 5835            } else {
 5836                return None;
 5837            };
 5838
 5839        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5840        let action = actions_menu.actions.get(action_ix)?;
 5841        let title = action.label();
 5842        let buffer = actions_menu.buffer;
 5843        let workspace = self.workspace()?;
 5844
 5845        match action {
 5846            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5847                workspace.update(cx, |workspace, cx| {
 5848                    workspace.schedule_resolved_task(
 5849                        task_source_kind,
 5850                        resolved_task,
 5851                        false,
 5852                        window,
 5853                        cx,
 5854                    );
 5855
 5856                    Some(Task::ready(Ok(())))
 5857                })
 5858            }
 5859            CodeActionsItem::CodeAction {
 5860                excerpt_id,
 5861                action,
 5862                provider,
 5863            } => {
 5864                let apply_code_action =
 5865                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5866                let workspace = workspace.downgrade();
 5867                Some(cx.spawn_in(window, async move |editor, cx| {
 5868                    let project_transaction = apply_code_action.await?;
 5869                    Self::open_project_transaction(
 5870                        &editor,
 5871                        workspace,
 5872                        project_transaction,
 5873                        title,
 5874                        cx,
 5875                    )
 5876                    .await
 5877                }))
 5878            }
 5879            CodeActionsItem::DebugScenario(scenario) => {
 5880                let context = actions_menu.actions.context.clone();
 5881
 5882                workspace.update(cx, |workspace, cx| {
 5883                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5884                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5885                });
 5886                Some(Task::ready(Ok(())))
 5887            }
 5888        }
 5889    }
 5890
 5891    pub async fn open_project_transaction(
 5892        this: &WeakEntity<Editor>,
 5893        workspace: WeakEntity<Workspace>,
 5894        transaction: ProjectTransaction,
 5895        title: String,
 5896        cx: &mut AsyncWindowContext,
 5897    ) -> Result<()> {
 5898        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5899        cx.update(|_, cx| {
 5900            entries.sort_unstable_by_key(|(buffer, _)| {
 5901                buffer.read(cx).file().map(|f| f.path().clone())
 5902            });
 5903        })?;
 5904
 5905        // If the project transaction's edits are all contained within this editor, then
 5906        // avoid opening a new editor to display them.
 5907
 5908        if let Some((buffer, transaction)) = entries.first() {
 5909            if entries.len() == 1 {
 5910                let excerpt = this.update(cx, |editor, cx| {
 5911                    editor
 5912                        .buffer()
 5913                        .read(cx)
 5914                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5915                })?;
 5916                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5917                    if excerpted_buffer == *buffer {
 5918                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5919                            let excerpt_range = excerpt_range.to_offset(buffer);
 5920                            buffer
 5921                                .edited_ranges_for_transaction::<usize>(transaction)
 5922                                .all(|range| {
 5923                                    excerpt_range.start <= range.start
 5924                                        && excerpt_range.end >= range.end
 5925                                })
 5926                        })?;
 5927
 5928                        if all_edits_within_excerpt {
 5929                            return Ok(());
 5930                        }
 5931                    }
 5932                }
 5933            }
 5934        } else {
 5935            return Ok(());
 5936        }
 5937
 5938        let mut ranges_to_highlight = Vec::new();
 5939        let excerpt_buffer = cx.new(|cx| {
 5940            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5941            for (buffer_handle, transaction) in &entries {
 5942                let edited_ranges = buffer_handle
 5943                    .read(cx)
 5944                    .edited_ranges_for_transaction::<Point>(transaction)
 5945                    .collect::<Vec<_>>();
 5946                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5947                    PathKey::for_buffer(buffer_handle, cx),
 5948                    buffer_handle.clone(),
 5949                    edited_ranges,
 5950                    DEFAULT_MULTIBUFFER_CONTEXT,
 5951                    cx,
 5952                );
 5953
 5954                ranges_to_highlight.extend(ranges);
 5955            }
 5956            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5957            multibuffer
 5958        })?;
 5959
 5960        workspace.update_in(cx, |workspace, window, cx| {
 5961            let project = workspace.project().clone();
 5962            let editor =
 5963                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5964            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5965            editor.update(cx, |editor, cx| {
 5966                editor.highlight_background::<Self>(
 5967                    &ranges_to_highlight,
 5968                    |theme| theme.editor_highlighted_line_background,
 5969                    cx,
 5970                );
 5971            });
 5972        })?;
 5973
 5974        Ok(())
 5975    }
 5976
 5977    pub fn clear_code_action_providers(&mut self) {
 5978        self.code_action_providers.clear();
 5979        self.available_code_actions.take();
 5980    }
 5981
 5982    pub fn add_code_action_provider(
 5983        &mut self,
 5984        provider: Rc<dyn CodeActionProvider>,
 5985        window: &mut Window,
 5986        cx: &mut Context<Self>,
 5987    ) {
 5988        if self
 5989            .code_action_providers
 5990            .iter()
 5991            .any(|existing_provider| existing_provider.id() == provider.id())
 5992        {
 5993            return;
 5994        }
 5995
 5996        self.code_action_providers.push(provider);
 5997        self.refresh_code_actions(window, cx);
 5998    }
 5999
 6000    pub fn remove_code_action_provider(
 6001        &mut self,
 6002        id: Arc<str>,
 6003        window: &mut Window,
 6004        cx: &mut Context<Self>,
 6005    ) {
 6006        self.code_action_providers
 6007            .retain(|provider| provider.id() != id);
 6008        self.refresh_code_actions(window, cx);
 6009    }
 6010
 6011    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6012        !self.code_action_providers.is_empty()
 6013            && EditorSettings::get_global(cx).toolbar.code_actions
 6014    }
 6015
 6016    pub fn has_available_code_actions(&self) -> bool {
 6017        self.available_code_actions
 6018            .as_ref()
 6019            .is_some_and(|(_, actions)| !actions.is_empty())
 6020    }
 6021
 6022    fn render_inline_code_actions(
 6023        &self,
 6024        icon_size: ui::IconSize,
 6025        display_row: DisplayRow,
 6026        is_active: bool,
 6027        cx: &mut Context<Self>,
 6028    ) -> AnyElement {
 6029        let show_tooltip = !self.context_menu_visible();
 6030        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6031            .icon_size(icon_size)
 6032            .shape(ui::IconButtonShape::Square)
 6033            .style(ButtonStyle::Transparent)
 6034            .icon_color(ui::Color::Hidden)
 6035            .toggle_state(is_active)
 6036            .when(show_tooltip, |this| {
 6037                this.tooltip({
 6038                    let focus_handle = self.focus_handle.clone();
 6039                    move |window, cx| {
 6040                        Tooltip::for_action_in(
 6041                            "Toggle Code Actions",
 6042                            &ToggleCodeActions {
 6043                                deployed_from: None,
 6044                                quick_launch: false,
 6045                            },
 6046                            &focus_handle,
 6047                            window,
 6048                            cx,
 6049                        )
 6050                    }
 6051                })
 6052            })
 6053            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6054                window.focus(&editor.focus_handle(cx));
 6055                editor.toggle_code_actions(
 6056                    &crate::actions::ToggleCodeActions {
 6057                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6058                            display_row,
 6059                        )),
 6060                        quick_launch: false,
 6061                    },
 6062                    window,
 6063                    cx,
 6064                );
 6065            }))
 6066            .into_any_element()
 6067    }
 6068
 6069    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6070        &self.context_menu
 6071    }
 6072
 6073    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6074        let newest_selection = self.selections.newest_anchor().clone();
 6075        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6076        let buffer = self.buffer.read(cx);
 6077        if newest_selection.head().diff_base_anchor.is_some() {
 6078            return None;
 6079        }
 6080        let (start_buffer, start) =
 6081            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6082        let (end_buffer, end) =
 6083            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6084        if start_buffer != end_buffer {
 6085            return None;
 6086        }
 6087
 6088        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6089            cx.background_executor()
 6090                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6091                .await;
 6092
 6093            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6094                let providers = this.code_action_providers.clone();
 6095                let tasks = this
 6096                    .code_action_providers
 6097                    .iter()
 6098                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6099                    .collect::<Vec<_>>();
 6100                (providers, tasks)
 6101            })?;
 6102
 6103            let mut actions = Vec::new();
 6104            for (provider, provider_actions) in
 6105                providers.into_iter().zip(future::join_all(tasks).await)
 6106            {
 6107                if let Some(provider_actions) = provider_actions.log_err() {
 6108                    actions.extend(provider_actions.into_iter().map(|action| {
 6109                        AvailableCodeAction {
 6110                            excerpt_id: newest_selection.start.excerpt_id,
 6111                            action,
 6112                            provider: provider.clone(),
 6113                        }
 6114                    }));
 6115                }
 6116            }
 6117
 6118            this.update(cx, |this, cx| {
 6119                this.available_code_actions = if actions.is_empty() {
 6120                    None
 6121                } else {
 6122                    Some((
 6123                        Location {
 6124                            buffer: start_buffer,
 6125                            range: start..end,
 6126                        },
 6127                        actions.into(),
 6128                    ))
 6129                };
 6130                cx.notify();
 6131            })
 6132        }));
 6133        None
 6134    }
 6135
 6136    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6137        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6138            self.show_git_blame_inline = false;
 6139
 6140            self.show_git_blame_inline_delay_task =
 6141                Some(cx.spawn_in(window, async move |this, cx| {
 6142                    cx.background_executor().timer(delay).await;
 6143
 6144                    this.update(cx, |this, cx| {
 6145                        this.show_git_blame_inline = true;
 6146                        cx.notify();
 6147                    })
 6148                    .log_err();
 6149                }));
 6150        }
 6151    }
 6152
 6153    fn show_blame_popover(
 6154        &mut self,
 6155        blame_entry: &BlameEntry,
 6156        position: gpui::Point<Pixels>,
 6157        cx: &mut Context<Self>,
 6158    ) {
 6159        if let Some(state) = &mut self.inline_blame_popover {
 6160            state.hide_task.take();
 6161            cx.notify();
 6162        } else {
 6163            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6164            let show_task = cx.spawn(async move |editor, cx| {
 6165                cx.background_executor()
 6166                    .timer(std::time::Duration::from_millis(delay))
 6167                    .await;
 6168                editor
 6169                    .update(cx, |editor, cx| {
 6170                        if let Some(state) = &mut editor.inline_blame_popover {
 6171                            state.show_task = None;
 6172                            cx.notify();
 6173                        }
 6174                    })
 6175                    .ok();
 6176            });
 6177            let Some(blame) = self.blame.as_ref() else {
 6178                return;
 6179            };
 6180            let blame = blame.read(cx);
 6181            let details = blame.details_for_entry(&blame_entry);
 6182            let markdown = cx.new(|cx| {
 6183                Markdown::new(
 6184                    details
 6185                        .as_ref()
 6186                        .map(|message| message.message.clone())
 6187                        .unwrap_or_default(),
 6188                    None,
 6189                    None,
 6190                    cx,
 6191                )
 6192            });
 6193            self.inline_blame_popover = Some(InlineBlamePopover {
 6194                position,
 6195                show_task: Some(show_task),
 6196                hide_task: None,
 6197                popover_bounds: None,
 6198                popover_state: InlineBlamePopoverState {
 6199                    scroll_handle: ScrollHandle::new(),
 6200                    commit_message: details,
 6201                    markdown,
 6202                },
 6203            });
 6204        }
 6205    }
 6206
 6207    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6208        if let Some(state) = &mut self.inline_blame_popover {
 6209            if state.show_task.is_some() {
 6210                self.inline_blame_popover.take();
 6211                cx.notify();
 6212            } else {
 6213                let hide_task = cx.spawn(async move |editor, cx| {
 6214                    cx.background_executor()
 6215                        .timer(std::time::Duration::from_millis(100))
 6216                        .await;
 6217                    editor
 6218                        .update(cx, |editor, cx| {
 6219                            editor.inline_blame_popover.take();
 6220                            cx.notify();
 6221                        })
 6222                        .ok();
 6223                });
 6224                state.hide_task = Some(hide_task);
 6225            }
 6226        }
 6227    }
 6228
 6229    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6230        if self.pending_rename.is_some() {
 6231            return None;
 6232        }
 6233
 6234        let provider = self.semantics_provider.clone()?;
 6235        let buffer = self.buffer.read(cx);
 6236        let newest_selection = self.selections.newest_anchor().clone();
 6237        let cursor_position = newest_selection.head();
 6238        let (cursor_buffer, cursor_buffer_position) =
 6239            buffer.text_anchor_for_position(cursor_position, cx)?;
 6240        let (tail_buffer, tail_buffer_position) =
 6241            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6242        if cursor_buffer != tail_buffer {
 6243            return None;
 6244        }
 6245
 6246        let snapshot = cursor_buffer.read(cx).snapshot();
 6247        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6248        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6249        if start_word_range != end_word_range {
 6250            self.document_highlights_task.take();
 6251            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6252            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6253            return None;
 6254        }
 6255
 6256        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6257        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6258            cx.background_executor()
 6259                .timer(Duration::from_millis(debounce))
 6260                .await;
 6261
 6262            let highlights = if let Some(highlights) = cx
 6263                .update(|cx| {
 6264                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6265                })
 6266                .ok()
 6267                .flatten()
 6268            {
 6269                highlights.await.log_err()
 6270            } else {
 6271                None
 6272            };
 6273
 6274            if let Some(highlights) = highlights {
 6275                this.update(cx, |this, cx| {
 6276                    if this.pending_rename.is_some() {
 6277                        return;
 6278                    }
 6279
 6280                    let buffer_id = cursor_position.buffer_id;
 6281                    let buffer = this.buffer.read(cx);
 6282                    if !buffer
 6283                        .text_anchor_for_position(cursor_position, cx)
 6284                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6285                    {
 6286                        return;
 6287                    }
 6288
 6289                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6290                    let mut write_ranges = Vec::new();
 6291                    let mut read_ranges = Vec::new();
 6292                    for highlight in highlights {
 6293                        for (excerpt_id, excerpt_range) in
 6294                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6295                        {
 6296                            let start = highlight
 6297                                .range
 6298                                .start
 6299                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6300                            let end = highlight
 6301                                .range
 6302                                .end
 6303                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6304                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6305                                continue;
 6306                            }
 6307
 6308                            let range = Anchor {
 6309                                buffer_id,
 6310                                excerpt_id,
 6311                                text_anchor: start,
 6312                                diff_base_anchor: None,
 6313                            }..Anchor {
 6314                                buffer_id,
 6315                                excerpt_id,
 6316                                text_anchor: end,
 6317                                diff_base_anchor: None,
 6318                            };
 6319                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6320                                write_ranges.push(range);
 6321                            } else {
 6322                                read_ranges.push(range);
 6323                            }
 6324                        }
 6325                    }
 6326
 6327                    this.highlight_background::<DocumentHighlightRead>(
 6328                        &read_ranges,
 6329                        |theme| theme.editor_document_highlight_read_background,
 6330                        cx,
 6331                    );
 6332                    this.highlight_background::<DocumentHighlightWrite>(
 6333                        &write_ranges,
 6334                        |theme| theme.editor_document_highlight_write_background,
 6335                        cx,
 6336                    );
 6337                    cx.notify();
 6338                })
 6339                .log_err();
 6340            }
 6341        }));
 6342        None
 6343    }
 6344
 6345    fn prepare_highlight_query_from_selection(
 6346        &mut self,
 6347        cx: &mut Context<Editor>,
 6348    ) -> Option<(String, Range<Anchor>)> {
 6349        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6350            return None;
 6351        }
 6352        if !EditorSettings::get_global(cx).selection_highlight {
 6353            return None;
 6354        }
 6355        if self.selections.count() != 1 || self.selections.line_mode {
 6356            return None;
 6357        }
 6358        let selection = self.selections.newest::<Point>(cx);
 6359        if selection.is_empty() || selection.start.row != selection.end.row {
 6360            return None;
 6361        }
 6362        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6363        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6364        let query = multi_buffer_snapshot
 6365            .text_for_range(selection_anchor_range.clone())
 6366            .collect::<String>();
 6367        if query.trim().is_empty() {
 6368            return None;
 6369        }
 6370        Some((query, selection_anchor_range))
 6371    }
 6372
 6373    fn update_selection_occurrence_highlights(
 6374        &mut self,
 6375        query_text: String,
 6376        query_range: Range<Anchor>,
 6377        multi_buffer_range_to_query: Range<Point>,
 6378        use_debounce: bool,
 6379        window: &mut Window,
 6380        cx: &mut Context<Editor>,
 6381    ) -> Task<()> {
 6382        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6383        cx.spawn_in(window, async move |editor, cx| {
 6384            if use_debounce {
 6385                cx.background_executor()
 6386                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6387                    .await;
 6388            }
 6389            let match_task = cx.background_spawn(async move {
 6390                let buffer_ranges = multi_buffer_snapshot
 6391                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6392                    .into_iter()
 6393                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6394                let mut match_ranges = Vec::new();
 6395                let Ok(regex) = project::search::SearchQuery::text(
 6396                    query_text.clone(),
 6397                    false,
 6398                    false,
 6399                    false,
 6400                    Default::default(),
 6401                    Default::default(),
 6402                    false,
 6403                    None,
 6404                ) else {
 6405                    return Vec::default();
 6406                };
 6407                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6408                    match_ranges.extend(
 6409                        regex
 6410                            .search(&buffer_snapshot, Some(search_range.clone()))
 6411                            .await
 6412                            .into_iter()
 6413                            .filter_map(|match_range| {
 6414                                let match_start = buffer_snapshot
 6415                                    .anchor_after(search_range.start + match_range.start);
 6416                                let match_end = buffer_snapshot
 6417                                    .anchor_before(search_range.start + match_range.end);
 6418                                let match_anchor_range = Anchor::range_in_buffer(
 6419                                    excerpt_id,
 6420                                    buffer_snapshot.remote_id(),
 6421                                    match_start..match_end,
 6422                                );
 6423                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6424                            }),
 6425                    );
 6426                }
 6427                match_ranges
 6428            });
 6429            let match_ranges = match_task.await;
 6430            editor
 6431                .update_in(cx, |editor, _, cx| {
 6432                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6433                    if !match_ranges.is_empty() {
 6434                        editor.highlight_background::<SelectedTextHighlight>(
 6435                            &match_ranges,
 6436                            |theme| theme.editor_document_highlight_bracket_background,
 6437                            cx,
 6438                        )
 6439                    }
 6440                })
 6441                .log_err();
 6442        })
 6443    }
 6444
 6445    fn refresh_selected_text_highlights(
 6446        &mut self,
 6447        on_buffer_edit: bool,
 6448        window: &mut Window,
 6449        cx: &mut Context<Editor>,
 6450    ) {
 6451        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6452        else {
 6453            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6454            self.quick_selection_highlight_task.take();
 6455            self.debounced_selection_highlight_task.take();
 6456            return;
 6457        };
 6458        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6459        if on_buffer_edit
 6460            || self
 6461                .quick_selection_highlight_task
 6462                .as_ref()
 6463                .map_or(true, |(prev_anchor_range, _)| {
 6464                    prev_anchor_range != &query_range
 6465                })
 6466        {
 6467            let multi_buffer_visible_start = self
 6468                .scroll_manager
 6469                .anchor()
 6470                .anchor
 6471                .to_point(&multi_buffer_snapshot);
 6472            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6473                multi_buffer_visible_start
 6474                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6475                Bias::Left,
 6476            );
 6477            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6478            self.quick_selection_highlight_task = Some((
 6479                query_range.clone(),
 6480                self.update_selection_occurrence_highlights(
 6481                    query_text.clone(),
 6482                    query_range.clone(),
 6483                    multi_buffer_visible_range,
 6484                    false,
 6485                    window,
 6486                    cx,
 6487                ),
 6488            ));
 6489        }
 6490        if on_buffer_edit
 6491            || self
 6492                .debounced_selection_highlight_task
 6493                .as_ref()
 6494                .map_or(true, |(prev_anchor_range, _)| {
 6495                    prev_anchor_range != &query_range
 6496                })
 6497        {
 6498            let multi_buffer_start = multi_buffer_snapshot
 6499                .anchor_before(0)
 6500                .to_point(&multi_buffer_snapshot);
 6501            let multi_buffer_end = multi_buffer_snapshot
 6502                .anchor_after(multi_buffer_snapshot.len())
 6503                .to_point(&multi_buffer_snapshot);
 6504            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6505            self.debounced_selection_highlight_task = Some((
 6506                query_range.clone(),
 6507                self.update_selection_occurrence_highlights(
 6508                    query_text,
 6509                    query_range,
 6510                    multi_buffer_full_range,
 6511                    true,
 6512                    window,
 6513                    cx,
 6514                ),
 6515            ));
 6516        }
 6517    }
 6518
 6519    pub fn refresh_inline_completion(
 6520        &mut self,
 6521        debounce: bool,
 6522        user_requested: bool,
 6523        window: &mut Window,
 6524        cx: &mut Context<Self>,
 6525    ) -> Option<()> {
 6526        let provider = self.edit_prediction_provider()?;
 6527        let cursor = self.selections.newest_anchor().head();
 6528        let (buffer, cursor_buffer_position) =
 6529            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6530
 6531        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6532            self.discard_inline_completion(false, cx);
 6533            return None;
 6534        }
 6535
 6536        if !user_requested
 6537            && (!self.should_show_edit_predictions()
 6538                || !self.is_focused(window)
 6539                || buffer.read(cx).is_empty())
 6540        {
 6541            self.discard_inline_completion(false, cx);
 6542            return None;
 6543        }
 6544
 6545        self.update_visible_inline_completion(window, cx);
 6546        provider.refresh(
 6547            self.project.clone(),
 6548            buffer,
 6549            cursor_buffer_position,
 6550            debounce,
 6551            cx,
 6552        );
 6553        Some(())
 6554    }
 6555
 6556    fn show_edit_predictions_in_menu(&self) -> bool {
 6557        match self.edit_prediction_settings {
 6558            EditPredictionSettings::Disabled => false,
 6559            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6560        }
 6561    }
 6562
 6563    pub fn edit_predictions_enabled(&self) -> bool {
 6564        match self.edit_prediction_settings {
 6565            EditPredictionSettings::Disabled => false,
 6566            EditPredictionSettings::Enabled { .. } => true,
 6567        }
 6568    }
 6569
 6570    fn edit_prediction_requires_modifier(&self) -> bool {
 6571        match self.edit_prediction_settings {
 6572            EditPredictionSettings::Disabled => false,
 6573            EditPredictionSettings::Enabled {
 6574                preview_requires_modifier,
 6575                ..
 6576            } => preview_requires_modifier,
 6577        }
 6578    }
 6579
 6580    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6581        if self.edit_prediction_provider.is_none() {
 6582            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6583        } else {
 6584            let selection = self.selections.newest_anchor();
 6585            let cursor = selection.head();
 6586
 6587            if let Some((buffer, cursor_buffer_position)) =
 6588                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6589            {
 6590                self.edit_prediction_settings =
 6591                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6592            }
 6593        }
 6594    }
 6595
 6596    fn edit_prediction_settings_at_position(
 6597        &self,
 6598        buffer: &Entity<Buffer>,
 6599        buffer_position: language::Anchor,
 6600        cx: &App,
 6601    ) -> EditPredictionSettings {
 6602        if !self.mode.is_full()
 6603            || !self.show_inline_completions_override.unwrap_or(true)
 6604            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6605        {
 6606            return EditPredictionSettings::Disabled;
 6607        }
 6608
 6609        let buffer = buffer.read(cx);
 6610
 6611        let file = buffer.file();
 6612
 6613        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6614            return EditPredictionSettings::Disabled;
 6615        };
 6616
 6617        let by_provider = matches!(
 6618            self.menu_inline_completions_policy,
 6619            MenuInlineCompletionsPolicy::ByProvider
 6620        );
 6621
 6622        let show_in_menu = by_provider
 6623            && self
 6624                .edit_prediction_provider
 6625                .as_ref()
 6626                .map_or(false, |provider| {
 6627                    provider.provider.show_completions_in_menu()
 6628                });
 6629
 6630        let preview_requires_modifier =
 6631            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6632
 6633        EditPredictionSettings::Enabled {
 6634            show_in_menu,
 6635            preview_requires_modifier,
 6636        }
 6637    }
 6638
 6639    fn should_show_edit_predictions(&self) -> bool {
 6640        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6641    }
 6642
 6643    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6644        matches!(
 6645            self.edit_prediction_preview,
 6646            EditPredictionPreview::Active { .. }
 6647        )
 6648    }
 6649
 6650    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6651        let cursor = self.selections.newest_anchor().head();
 6652        if let Some((buffer, cursor_position)) =
 6653            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6654        {
 6655            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6656        } else {
 6657            false
 6658        }
 6659    }
 6660
 6661    pub fn supports_minimap(&self, cx: &App) -> bool {
 6662        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6663    }
 6664
 6665    fn edit_predictions_enabled_in_buffer(
 6666        &self,
 6667        buffer: &Entity<Buffer>,
 6668        buffer_position: language::Anchor,
 6669        cx: &App,
 6670    ) -> bool {
 6671        maybe!({
 6672            if self.read_only(cx) {
 6673                return Some(false);
 6674            }
 6675            let provider = self.edit_prediction_provider()?;
 6676            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6677                return Some(false);
 6678            }
 6679            let buffer = buffer.read(cx);
 6680            let Some(file) = buffer.file() else {
 6681                return Some(true);
 6682            };
 6683            let settings = all_language_settings(Some(file), cx);
 6684            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6685        })
 6686        .unwrap_or(false)
 6687    }
 6688
 6689    fn cycle_inline_completion(
 6690        &mut self,
 6691        direction: Direction,
 6692        window: &mut Window,
 6693        cx: &mut Context<Self>,
 6694    ) -> Option<()> {
 6695        let provider = self.edit_prediction_provider()?;
 6696        let cursor = self.selections.newest_anchor().head();
 6697        let (buffer, cursor_buffer_position) =
 6698            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6699        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6700            return None;
 6701        }
 6702
 6703        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6704        self.update_visible_inline_completion(window, cx);
 6705
 6706        Some(())
 6707    }
 6708
 6709    pub fn show_inline_completion(
 6710        &mut self,
 6711        _: &ShowEditPrediction,
 6712        window: &mut Window,
 6713        cx: &mut Context<Self>,
 6714    ) {
 6715        if !self.has_active_inline_completion() {
 6716            self.refresh_inline_completion(false, true, window, cx);
 6717            return;
 6718        }
 6719
 6720        self.update_visible_inline_completion(window, cx);
 6721    }
 6722
 6723    pub fn display_cursor_names(
 6724        &mut self,
 6725        _: &DisplayCursorNames,
 6726        window: &mut Window,
 6727        cx: &mut Context<Self>,
 6728    ) {
 6729        self.show_cursor_names(window, cx);
 6730    }
 6731
 6732    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6733        self.show_cursor_names = true;
 6734        cx.notify();
 6735        cx.spawn_in(window, async move |this, cx| {
 6736            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6737            this.update(cx, |this, cx| {
 6738                this.show_cursor_names = false;
 6739                cx.notify()
 6740            })
 6741            .ok()
 6742        })
 6743        .detach();
 6744    }
 6745
 6746    pub fn next_edit_prediction(
 6747        &mut self,
 6748        _: &NextEditPrediction,
 6749        window: &mut Window,
 6750        cx: &mut Context<Self>,
 6751    ) {
 6752        if self.has_active_inline_completion() {
 6753            self.cycle_inline_completion(Direction::Next, window, cx);
 6754        } else {
 6755            let is_copilot_disabled = self
 6756                .refresh_inline_completion(false, true, window, cx)
 6757                .is_none();
 6758            if is_copilot_disabled {
 6759                cx.propagate();
 6760            }
 6761        }
 6762    }
 6763
 6764    pub fn previous_edit_prediction(
 6765        &mut self,
 6766        _: &PreviousEditPrediction,
 6767        window: &mut Window,
 6768        cx: &mut Context<Self>,
 6769    ) {
 6770        if self.has_active_inline_completion() {
 6771            self.cycle_inline_completion(Direction::Prev, window, cx);
 6772        } else {
 6773            let is_copilot_disabled = self
 6774                .refresh_inline_completion(false, true, window, cx)
 6775                .is_none();
 6776            if is_copilot_disabled {
 6777                cx.propagate();
 6778            }
 6779        }
 6780    }
 6781
 6782    pub fn accept_edit_prediction(
 6783        &mut self,
 6784        _: &AcceptEditPrediction,
 6785        window: &mut Window,
 6786        cx: &mut Context<Self>,
 6787    ) {
 6788        if self.show_edit_predictions_in_menu() {
 6789            self.hide_context_menu(window, cx);
 6790        }
 6791
 6792        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6793            return;
 6794        };
 6795
 6796        self.report_inline_completion_event(
 6797            active_inline_completion.completion_id.clone(),
 6798            true,
 6799            cx,
 6800        );
 6801
 6802        match &active_inline_completion.completion {
 6803            InlineCompletion::Move { target, .. } => {
 6804                let target = *target;
 6805
 6806                if let Some(position_map) = &self.last_position_map {
 6807                    if position_map
 6808                        .visible_row_range
 6809                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6810                        || !self.edit_prediction_requires_modifier()
 6811                    {
 6812                        self.unfold_ranges(&[target..target], true, false, cx);
 6813                        // Note that this is also done in vim's handler of the Tab action.
 6814                        self.change_selections(
 6815                            Some(Autoscroll::newest()),
 6816                            window,
 6817                            cx,
 6818                            |selections| {
 6819                                selections.select_anchor_ranges([target..target]);
 6820                            },
 6821                        );
 6822                        self.clear_row_highlights::<EditPredictionPreview>();
 6823
 6824                        self.edit_prediction_preview
 6825                            .set_previous_scroll_position(None);
 6826                    } else {
 6827                        self.edit_prediction_preview
 6828                            .set_previous_scroll_position(Some(
 6829                                position_map.snapshot.scroll_anchor,
 6830                            ));
 6831
 6832                        self.highlight_rows::<EditPredictionPreview>(
 6833                            target..target,
 6834                            cx.theme().colors().editor_highlighted_line_background,
 6835                            RowHighlightOptions {
 6836                                autoscroll: true,
 6837                                ..Default::default()
 6838                            },
 6839                            cx,
 6840                        );
 6841                        self.request_autoscroll(Autoscroll::fit(), cx);
 6842                    }
 6843                }
 6844            }
 6845            InlineCompletion::Edit { edits, .. } => {
 6846                if let Some(provider) = self.edit_prediction_provider() {
 6847                    provider.accept(cx);
 6848                }
 6849
 6850                // Store the transaction ID and selections before applying the edit
 6851                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6852
 6853                let snapshot = self.buffer.read(cx).snapshot(cx);
 6854                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6855
 6856                self.buffer.update(cx, |buffer, cx| {
 6857                    buffer.edit(edits.iter().cloned(), None, cx)
 6858                });
 6859
 6860                self.change_selections(None, window, cx, |s| {
 6861                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6862                });
 6863
 6864                let selections = self.selections.disjoint_anchors();
 6865                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6866                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6867                    if has_new_transaction {
 6868                        self.selection_history
 6869                            .insert_transaction(transaction_id_now, selections);
 6870                    }
 6871                }
 6872
 6873                self.update_visible_inline_completion(window, cx);
 6874                if self.active_inline_completion.is_none() {
 6875                    self.refresh_inline_completion(true, true, window, cx);
 6876                }
 6877
 6878                cx.notify();
 6879            }
 6880        }
 6881
 6882        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6883    }
 6884
 6885    pub fn accept_partial_inline_completion(
 6886        &mut self,
 6887        _: &AcceptPartialEditPrediction,
 6888        window: &mut Window,
 6889        cx: &mut Context<Self>,
 6890    ) {
 6891        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6892            return;
 6893        };
 6894        if self.selections.count() != 1 {
 6895            return;
 6896        }
 6897
 6898        self.report_inline_completion_event(
 6899            active_inline_completion.completion_id.clone(),
 6900            true,
 6901            cx,
 6902        );
 6903
 6904        match &active_inline_completion.completion {
 6905            InlineCompletion::Move { target, .. } => {
 6906                let target = *target;
 6907                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6908                    selections.select_anchor_ranges([target..target]);
 6909                });
 6910            }
 6911            InlineCompletion::Edit { edits, .. } => {
 6912                // Find an insertion that starts at the cursor position.
 6913                let snapshot = self.buffer.read(cx).snapshot(cx);
 6914                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6915                let insertion = edits.iter().find_map(|(range, text)| {
 6916                    let range = range.to_offset(&snapshot);
 6917                    if range.is_empty() && range.start == cursor_offset {
 6918                        Some(text)
 6919                    } else {
 6920                        None
 6921                    }
 6922                });
 6923
 6924                if let Some(text) = insertion {
 6925                    let mut partial_completion = text
 6926                        .chars()
 6927                        .by_ref()
 6928                        .take_while(|c| c.is_alphabetic())
 6929                        .collect::<String>();
 6930                    if partial_completion.is_empty() {
 6931                        partial_completion = text
 6932                            .chars()
 6933                            .by_ref()
 6934                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6935                            .collect::<String>();
 6936                    }
 6937
 6938                    cx.emit(EditorEvent::InputHandled {
 6939                        utf16_range_to_replace: None,
 6940                        text: partial_completion.clone().into(),
 6941                    });
 6942
 6943                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6944
 6945                    self.refresh_inline_completion(true, true, window, cx);
 6946                    cx.notify();
 6947                } else {
 6948                    self.accept_edit_prediction(&Default::default(), window, cx);
 6949                }
 6950            }
 6951        }
 6952    }
 6953
 6954    fn discard_inline_completion(
 6955        &mut self,
 6956        should_report_inline_completion_event: bool,
 6957        cx: &mut Context<Self>,
 6958    ) -> bool {
 6959        if should_report_inline_completion_event {
 6960            let completion_id = self
 6961                .active_inline_completion
 6962                .as_ref()
 6963                .and_then(|active_completion| active_completion.completion_id.clone());
 6964
 6965            self.report_inline_completion_event(completion_id, false, cx);
 6966        }
 6967
 6968        if let Some(provider) = self.edit_prediction_provider() {
 6969            provider.discard(cx);
 6970        }
 6971
 6972        self.take_active_inline_completion(cx)
 6973    }
 6974
 6975    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6976        let Some(provider) = self.edit_prediction_provider() else {
 6977            return;
 6978        };
 6979
 6980        let Some((_, buffer, _)) = self
 6981            .buffer
 6982            .read(cx)
 6983            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6984        else {
 6985            return;
 6986        };
 6987
 6988        let extension = buffer
 6989            .read(cx)
 6990            .file()
 6991            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6992
 6993        let event_type = match accepted {
 6994            true => "Edit Prediction Accepted",
 6995            false => "Edit Prediction Discarded",
 6996        };
 6997        telemetry::event!(
 6998            event_type,
 6999            provider = provider.name(),
 7000            prediction_id = id,
 7001            suggestion_accepted = accepted,
 7002            file_extension = extension,
 7003        );
 7004    }
 7005
 7006    pub fn has_active_inline_completion(&self) -> bool {
 7007        self.active_inline_completion.is_some()
 7008    }
 7009
 7010    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7011        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7012            return false;
 7013        };
 7014
 7015        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7016        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7017        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7018        true
 7019    }
 7020
 7021    /// Returns true when we're displaying the edit prediction popover below the cursor
 7022    /// like we are not previewing and the LSP autocomplete menu is visible
 7023    /// or we are in `when_holding_modifier` mode.
 7024    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7025        if self.edit_prediction_preview_is_active()
 7026            || !self.show_edit_predictions_in_menu()
 7027            || !self.edit_predictions_enabled()
 7028        {
 7029            return false;
 7030        }
 7031
 7032        if self.has_visible_completions_menu() {
 7033            return true;
 7034        }
 7035
 7036        has_completion && self.edit_prediction_requires_modifier()
 7037    }
 7038
 7039    fn handle_modifiers_changed(
 7040        &mut self,
 7041        modifiers: Modifiers,
 7042        position_map: &PositionMap,
 7043        window: &mut Window,
 7044        cx: &mut Context<Self>,
 7045    ) {
 7046        if self.show_edit_predictions_in_menu() {
 7047            self.update_edit_prediction_preview(&modifiers, window, cx);
 7048        }
 7049
 7050        self.update_selection_mode(&modifiers, position_map, window, cx);
 7051
 7052        let mouse_position = window.mouse_position();
 7053        if !position_map.text_hitbox.is_hovered(window) {
 7054            return;
 7055        }
 7056
 7057        self.update_hovered_link(
 7058            position_map.point_for_position(mouse_position),
 7059            &position_map.snapshot,
 7060            modifiers,
 7061            window,
 7062            cx,
 7063        )
 7064    }
 7065
 7066    fn update_selection_mode(
 7067        &mut self,
 7068        modifiers: &Modifiers,
 7069        position_map: &PositionMap,
 7070        window: &mut Window,
 7071        cx: &mut Context<Self>,
 7072    ) {
 7073        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 7074            return;
 7075        }
 7076
 7077        let mouse_position = window.mouse_position();
 7078        let point_for_position = position_map.point_for_position(mouse_position);
 7079        let position = point_for_position.previous_valid;
 7080
 7081        self.select(
 7082            SelectPhase::BeginColumnar {
 7083                position,
 7084                reset: false,
 7085                goal_column: point_for_position.exact_unclipped.column(),
 7086            },
 7087            window,
 7088            cx,
 7089        );
 7090    }
 7091
 7092    fn update_edit_prediction_preview(
 7093        &mut self,
 7094        modifiers: &Modifiers,
 7095        window: &mut Window,
 7096        cx: &mut Context<Self>,
 7097    ) {
 7098        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 7099        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 7100            return;
 7101        };
 7102
 7103        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 7104            if matches!(
 7105                self.edit_prediction_preview,
 7106                EditPredictionPreview::Inactive { .. }
 7107            ) {
 7108                self.edit_prediction_preview = EditPredictionPreview::Active {
 7109                    previous_scroll_position: None,
 7110                    since: Instant::now(),
 7111                };
 7112
 7113                self.update_visible_inline_completion(window, cx);
 7114                cx.notify();
 7115            }
 7116        } else if let EditPredictionPreview::Active {
 7117            previous_scroll_position,
 7118            since,
 7119        } = self.edit_prediction_preview
 7120        {
 7121            if let (Some(previous_scroll_position), Some(position_map)) =
 7122                (previous_scroll_position, self.last_position_map.as_ref())
 7123            {
 7124                self.set_scroll_position(
 7125                    previous_scroll_position
 7126                        .scroll_position(&position_map.snapshot.display_snapshot),
 7127                    window,
 7128                    cx,
 7129                );
 7130            }
 7131
 7132            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7133                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7134            };
 7135            self.clear_row_highlights::<EditPredictionPreview>();
 7136            self.update_visible_inline_completion(window, cx);
 7137            cx.notify();
 7138        }
 7139    }
 7140
 7141    fn update_visible_inline_completion(
 7142        &mut self,
 7143        _window: &mut Window,
 7144        cx: &mut Context<Self>,
 7145    ) -> Option<()> {
 7146        let selection = self.selections.newest_anchor();
 7147        let cursor = selection.head();
 7148        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7149        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7150        let excerpt_id = cursor.excerpt_id;
 7151
 7152        let show_in_menu = self.show_edit_predictions_in_menu();
 7153        let completions_menu_has_precedence = !show_in_menu
 7154            && (self.context_menu.borrow().is_some()
 7155                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7156
 7157        if completions_menu_has_precedence
 7158            || !offset_selection.is_empty()
 7159            || self
 7160                .active_inline_completion
 7161                .as_ref()
 7162                .map_or(false, |completion| {
 7163                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7164                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7165                    !invalidation_range.contains(&offset_selection.head())
 7166                })
 7167        {
 7168            self.discard_inline_completion(false, cx);
 7169            return None;
 7170        }
 7171
 7172        self.take_active_inline_completion(cx);
 7173        let Some(provider) = self.edit_prediction_provider() else {
 7174            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7175            return None;
 7176        };
 7177
 7178        let (buffer, cursor_buffer_position) =
 7179            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7180
 7181        self.edit_prediction_settings =
 7182            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7183
 7184        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7185
 7186        if self.edit_prediction_indent_conflict {
 7187            let cursor_point = cursor.to_point(&multibuffer);
 7188
 7189            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7190
 7191            if let Some((_, indent)) = indents.iter().next() {
 7192                if indent.len == cursor_point.column {
 7193                    self.edit_prediction_indent_conflict = false;
 7194                }
 7195            }
 7196        }
 7197
 7198        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7199        let edits = inline_completion
 7200            .edits
 7201            .into_iter()
 7202            .flat_map(|(range, new_text)| {
 7203                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7204                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7205                Some((start..end, new_text))
 7206            })
 7207            .collect::<Vec<_>>();
 7208        if edits.is_empty() {
 7209            return None;
 7210        }
 7211
 7212        let first_edit_start = edits.first().unwrap().0.start;
 7213        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7214        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7215
 7216        let last_edit_end = edits.last().unwrap().0.end;
 7217        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7218        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7219
 7220        let cursor_row = cursor.to_point(&multibuffer).row;
 7221
 7222        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7223
 7224        let mut inlay_ids = Vec::new();
 7225        let invalidation_row_range;
 7226        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7227            Some(cursor_row..edit_end_row)
 7228        } else if cursor_row > edit_end_row {
 7229            Some(edit_start_row..cursor_row)
 7230        } else {
 7231            None
 7232        };
 7233        let is_move =
 7234            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7235        let completion = if is_move {
 7236            invalidation_row_range =
 7237                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7238            let target = first_edit_start;
 7239            InlineCompletion::Move { target, snapshot }
 7240        } else {
 7241            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7242                && !self.inline_completions_hidden_for_vim_mode;
 7243
 7244            if show_completions_in_buffer {
 7245                if edits
 7246                    .iter()
 7247                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7248                {
 7249                    let mut inlays = Vec::new();
 7250                    for (range, new_text) in &edits {
 7251                        let inlay = Inlay::inline_completion(
 7252                            post_inc(&mut self.next_inlay_id),
 7253                            range.start,
 7254                            new_text.as_str(),
 7255                        );
 7256                        inlay_ids.push(inlay.id);
 7257                        inlays.push(inlay);
 7258                    }
 7259
 7260                    self.splice_inlays(&[], inlays, cx);
 7261                } else {
 7262                    let background_color = cx.theme().status().deleted_background;
 7263                    self.highlight_text::<InlineCompletionHighlight>(
 7264                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7265                        HighlightStyle {
 7266                            background_color: Some(background_color),
 7267                            ..Default::default()
 7268                        },
 7269                        cx,
 7270                    );
 7271                }
 7272            }
 7273
 7274            invalidation_row_range = edit_start_row..edit_end_row;
 7275
 7276            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7277                if provider.show_tab_accept_marker() {
 7278                    EditDisplayMode::TabAccept
 7279                } else {
 7280                    EditDisplayMode::Inline
 7281                }
 7282            } else {
 7283                EditDisplayMode::DiffPopover
 7284            };
 7285
 7286            InlineCompletion::Edit {
 7287                edits,
 7288                edit_preview: inline_completion.edit_preview,
 7289                display_mode,
 7290                snapshot,
 7291            }
 7292        };
 7293
 7294        let invalidation_range = multibuffer
 7295            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7296            ..multibuffer.anchor_after(Point::new(
 7297                invalidation_row_range.end,
 7298                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7299            ));
 7300
 7301        self.stale_inline_completion_in_menu = None;
 7302        self.active_inline_completion = Some(InlineCompletionState {
 7303            inlay_ids,
 7304            completion,
 7305            completion_id: inline_completion.id,
 7306            invalidation_range,
 7307        });
 7308
 7309        cx.notify();
 7310
 7311        Some(())
 7312    }
 7313
 7314    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7315        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7316    }
 7317
 7318    fn clear_tasks(&mut self) {
 7319        self.tasks.clear()
 7320    }
 7321
 7322    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7323        if self.tasks.insert(key, value).is_some() {
 7324            // This case should hopefully be rare, but just in case...
 7325            log::error!(
 7326                "multiple different run targets found on a single line, only the last target will be rendered"
 7327            )
 7328        }
 7329    }
 7330
 7331    /// Get all display points of breakpoints that will be rendered within editor
 7332    ///
 7333    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7334    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7335    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7336    fn active_breakpoints(
 7337        &self,
 7338        range: Range<DisplayRow>,
 7339        window: &mut Window,
 7340        cx: &mut Context<Self>,
 7341    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7342        let mut breakpoint_display_points = HashMap::default();
 7343
 7344        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7345            return breakpoint_display_points;
 7346        };
 7347
 7348        let snapshot = self.snapshot(window, cx);
 7349
 7350        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7351        let Some(project) = self.project.as_ref() else {
 7352            return breakpoint_display_points;
 7353        };
 7354
 7355        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7356            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7357
 7358        for (buffer_snapshot, range, excerpt_id) in
 7359            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7360        {
 7361            let Some(buffer) = project
 7362                .read(cx)
 7363                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7364            else {
 7365                continue;
 7366            };
 7367            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7368                &buffer,
 7369                Some(
 7370                    buffer_snapshot.anchor_before(range.start)
 7371                        ..buffer_snapshot.anchor_after(range.end),
 7372                ),
 7373                buffer_snapshot,
 7374                cx,
 7375            );
 7376            for (breakpoint, state) in breakpoints {
 7377                let multi_buffer_anchor =
 7378                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7379                let position = multi_buffer_anchor
 7380                    .to_point(&multi_buffer_snapshot)
 7381                    .to_display_point(&snapshot);
 7382
 7383                breakpoint_display_points.insert(
 7384                    position.row(),
 7385                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7386                );
 7387            }
 7388        }
 7389
 7390        breakpoint_display_points
 7391    }
 7392
 7393    fn breakpoint_context_menu(
 7394        &self,
 7395        anchor: Anchor,
 7396        window: &mut Window,
 7397        cx: &mut Context<Self>,
 7398    ) -> Entity<ui::ContextMenu> {
 7399        let weak_editor = cx.weak_entity();
 7400        let focus_handle = self.focus_handle(cx);
 7401
 7402        let row = self
 7403            .buffer
 7404            .read(cx)
 7405            .snapshot(cx)
 7406            .summary_for_anchor::<Point>(&anchor)
 7407            .row;
 7408
 7409        let breakpoint = self
 7410            .breakpoint_at_row(row, window, cx)
 7411            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7412
 7413        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7414            "Edit Log Breakpoint"
 7415        } else {
 7416            "Set Log Breakpoint"
 7417        };
 7418
 7419        let condition_breakpoint_msg = if breakpoint
 7420            .as_ref()
 7421            .is_some_and(|bp| bp.1.condition.is_some())
 7422        {
 7423            "Edit Condition Breakpoint"
 7424        } else {
 7425            "Set Condition Breakpoint"
 7426        };
 7427
 7428        let hit_condition_breakpoint_msg = if breakpoint
 7429            .as_ref()
 7430            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7431        {
 7432            "Edit Hit Condition Breakpoint"
 7433        } else {
 7434            "Set Hit Condition Breakpoint"
 7435        };
 7436
 7437        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7438            "Unset Breakpoint"
 7439        } else {
 7440            "Set Breakpoint"
 7441        };
 7442
 7443        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7444            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7445
 7446        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7447            BreakpointState::Enabled => Some("Disable"),
 7448            BreakpointState::Disabled => Some("Enable"),
 7449        });
 7450
 7451        let (anchor, breakpoint) =
 7452            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7453
 7454        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7455            menu.on_blur_subscription(Subscription::new(|| {}))
 7456                .context(focus_handle)
 7457                .when(run_to_cursor, |this| {
 7458                    let weak_editor = weak_editor.clone();
 7459                    this.entry("Run to cursor", None, move |window, cx| {
 7460                        weak_editor
 7461                            .update(cx, |editor, cx| {
 7462                                editor.change_selections(None, window, cx, |s| {
 7463                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7464                                });
 7465                            })
 7466                            .ok();
 7467
 7468                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7469                    })
 7470                    .separator()
 7471                })
 7472                .when_some(toggle_state_msg, |this, msg| {
 7473                    this.entry(msg, None, {
 7474                        let weak_editor = weak_editor.clone();
 7475                        let breakpoint = breakpoint.clone();
 7476                        move |_window, cx| {
 7477                            weak_editor
 7478                                .update(cx, |this, cx| {
 7479                                    this.edit_breakpoint_at_anchor(
 7480                                        anchor,
 7481                                        breakpoint.as_ref().clone(),
 7482                                        BreakpointEditAction::InvertState,
 7483                                        cx,
 7484                                    );
 7485                                })
 7486                                .log_err();
 7487                        }
 7488                    })
 7489                })
 7490                .entry(set_breakpoint_msg, None, {
 7491                    let weak_editor = weak_editor.clone();
 7492                    let breakpoint = breakpoint.clone();
 7493                    move |_window, cx| {
 7494                        weak_editor
 7495                            .update(cx, |this, cx| {
 7496                                this.edit_breakpoint_at_anchor(
 7497                                    anchor,
 7498                                    breakpoint.as_ref().clone(),
 7499                                    BreakpointEditAction::Toggle,
 7500                                    cx,
 7501                                );
 7502                            })
 7503                            .log_err();
 7504                    }
 7505                })
 7506                .entry(log_breakpoint_msg, None, {
 7507                    let breakpoint = breakpoint.clone();
 7508                    let weak_editor = weak_editor.clone();
 7509                    move |window, cx| {
 7510                        weak_editor
 7511                            .update(cx, |this, cx| {
 7512                                this.add_edit_breakpoint_block(
 7513                                    anchor,
 7514                                    breakpoint.as_ref(),
 7515                                    BreakpointPromptEditAction::Log,
 7516                                    window,
 7517                                    cx,
 7518                                );
 7519                            })
 7520                            .log_err();
 7521                    }
 7522                })
 7523                .entry(condition_breakpoint_msg, None, {
 7524                    let breakpoint = breakpoint.clone();
 7525                    let weak_editor = weak_editor.clone();
 7526                    move |window, cx| {
 7527                        weak_editor
 7528                            .update(cx, |this, cx| {
 7529                                this.add_edit_breakpoint_block(
 7530                                    anchor,
 7531                                    breakpoint.as_ref(),
 7532                                    BreakpointPromptEditAction::Condition,
 7533                                    window,
 7534                                    cx,
 7535                                );
 7536                            })
 7537                            .log_err();
 7538                    }
 7539                })
 7540                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7541                    weak_editor
 7542                        .update(cx, |this, cx| {
 7543                            this.add_edit_breakpoint_block(
 7544                                anchor,
 7545                                breakpoint.as_ref(),
 7546                                BreakpointPromptEditAction::HitCondition,
 7547                                window,
 7548                                cx,
 7549                            );
 7550                        })
 7551                        .log_err();
 7552                })
 7553        })
 7554    }
 7555
 7556    fn render_breakpoint(
 7557        &self,
 7558        position: Anchor,
 7559        row: DisplayRow,
 7560        breakpoint: &Breakpoint,
 7561        state: Option<BreakpointSessionState>,
 7562        cx: &mut Context<Self>,
 7563    ) -> IconButton {
 7564        let is_rejected = state.is_some_and(|s| !s.verified);
 7565        // Is it a breakpoint that shows up when hovering over gutter?
 7566        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7567            (false, false),
 7568            |PhantomBreakpointIndicator {
 7569                 is_active,
 7570                 display_row,
 7571                 collides_with_existing_breakpoint,
 7572             }| {
 7573                (
 7574                    is_active && display_row == row,
 7575                    collides_with_existing_breakpoint,
 7576                )
 7577            },
 7578        );
 7579
 7580        let (color, icon) = {
 7581            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7582                (false, false) => ui::IconName::DebugBreakpoint,
 7583                (true, false) => ui::IconName::DebugLogBreakpoint,
 7584                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7585                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7586            };
 7587
 7588            let color = if is_phantom {
 7589                Color::Hint
 7590            } else if is_rejected {
 7591                Color::Disabled
 7592            } else {
 7593                Color::Debugger
 7594            };
 7595
 7596            (color, icon)
 7597        };
 7598
 7599        let breakpoint = Arc::from(breakpoint.clone());
 7600
 7601        let alt_as_text = gpui::Keystroke {
 7602            modifiers: Modifiers::secondary_key(),
 7603            ..Default::default()
 7604        };
 7605        let primary_action_text = if breakpoint.is_disabled() {
 7606            "Enable breakpoint"
 7607        } else if is_phantom && !collides_with_existing {
 7608            "Set breakpoint"
 7609        } else {
 7610            "Unset breakpoint"
 7611        };
 7612        let focus_handle = self.focus_handle.clone();
 7613
 7614        let meta = if is_rejected {
 7615            SharedString::from("No executable code is associated with this line.")
 7616        } else if collides_with_existing && !breakpoint.is_disabled() {
 7617            SharedString::from(format!(
 7618                "{alt_as_text}-click to disable,\nright-click for more options."
 7619            ))
 7620        } else {
 7621            SharedString::from("Right-click for more options.")
 7622        };
 7623        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7624            .icon_size(IconSize::XSmall)
 7625            .size(ui::ButtonSize::None)
 7626            .when(is_rejected, |this| {
 7627                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7628            })
 7629            .icon_color(color)
 7630            .style(ButtonStyle::Transparent)
 7631            .on_click(cx.listener({
 7632                let breakpoint = breakpoint.clone();
 7633
 7634                move |editor, event: &ClickEvent, window, cx| {
 7635                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7636                        BreakpointEditAction::InvertState
 7637                    } else {
 7638                        BreakpointEditAction::Toggle
 7639                    };
 7640
 7641                    window.focus(&editor.focus_handle(cx));
 7642                    editor.edit_breakpoint_at_anchor(
 7643                        position,
 7644                        breakpoint.as_ref().clone(),
 7645                        edit_action,
 7646                        cx,
 7647                    );
 7648                }
 7649            }))
 7650            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7651                editor.set_breakpoint_context_menu(
 7652                    row,
 7653                    Some(position),
 7654                    event.down.position,
 7655                    window,
 7656                    cx,
 7657                );
 7658            }))
 7659            .tooltip(move |window, cx| {
 7660                Tooltip::with_meta_in(
 7661                    primary_action_text,
 7662                    Some(&ToggleBreakpoint),
 7663                    meta.clone(),
 7664                    &focus_handle,
 7665                    window,
 7666                    cx,
 7667                )
 7668            })
 7669    }
 7670
 7671    fn build_tasks_context(
 7672        project: &Entity<Project>,
 7673        buffer: &Entity<Buffer>,
 7674        buffer_row: u32,
 7675        tasks: &Arc<RunnableTasks>,
 7676        cx: &mut Context<Self>,
 7677    ) -> Task<Option<task::TaskContext>> {
 7678        let position = Point::new(buffer_row, tasks.column);
 7679        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7680        let location = Location {
 7681            buffer: buffer.clone(),
 7682            range: range_start..range_start,
 7683        };
 7684        // Fill in the environmental variables from the tree-sitter captures
 7685        let mut captured_task_variables = TaskVariables::default();
 7686        for (capture_name, value) in tasks.extra_variables.clone() {
 7687            captured_task_variables.insert(
 7688                task::VariableName::Custom(capture_name.into()),
 7689                value.clone(),
 7690            );
 7691        }
 7692        project.update(cx, |project, cx| {
 7693            project.task_store().update(cx, |task_store, cx| {
 7694                task_store.task_context_for_location(captured_task_variables, location, cx)
 7695            })
 7696        })
 7697    }
 7698
 7699    pub fn spawn_nearest_task(
 7700        &mut self,
 7701        action: &SpawnNearestTask,
 7702        window: &mut Window,
 7703        cx: &mut Context<Self>,
 7704    ) {
 7705        let Some((workspace, _)) = self.workspace.clone() else {
 7706            return;
 7707        };
 7708        let Some(project) = self.project.clone() else {
 7709            return;
 7710        };
 7711
 7712        // Try to find a closest, enclosing node using tree-sitter that has a
 7713        // task
 7714        let Some((buffer, buffer_row, tasks)) = self
 7715            .find_enclosing_node_task(cx)
 7716            // Or find the task that's closest in row-distance.
 7717            .or_else(|| self.find_closest_task(cx))
 7718        else {
 7719            return;
 7720        };
 7721
 7722        let reveal_strategy = action.reveal;
 7723        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7724        cx.spawn_in(window, async move |_, cx| {
 7725            let context = task_context.await?;
 7726            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7727
 7728            let resolved = &mut resolved_task.resolved;
 7729            resolved.reveal = reveal_strategy;
 7730
 7731            workspace
 7732                .update_in(cx, |workspace, window, cx| {
 7733                    workspace.schedule_resolved_task(
 7734                        task_source_kind,
 7735                        resolved_task,
 7736                        false,
 7737                        window,
 7738                        cx,
 7739                    );
 7740                })
 7741                .ok()
 7742        })
 7743        .detach();
 7744    }
 7745
 7746    fn find_closest_task(
 7747        &mut self,
 7748        cx: &mut Context<Self>,
 7749    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7750        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7751
 7752        let ((buffer_id, row), tasks) = self
 7753            .tasks
 7754            .iter()
 7755            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7756
 7757        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7758        let tasks = Arc::new(tasks.to_owned());
 7759        Some((buffer, *row, tasks))
 7760    }
 7761
 7762    fn find_enclosing_node_task(
 7763        &mut self,
 7764        cx: &mut Context<Self>,
 7765    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7766        let snapshot = self.buffer.read(cx).snapshot(cx);
 7767        let offset = self.selections.newest::<usize>(cx).head();
 7768        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7769        let buffer_id = excerpt.buffer().remote_id();
 7770
 7771        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7772        let mut cursor = layer.node().walk();
 7773
 7774        while cursor.goto_first_child_for_byte(offset).is_some() {
 7775            if cursor.node().end_byte() == offset {
 7776                cursor.goto_next_sibling();
 7777            }
 7778        }
 7779
 7780        // Ascend to the smallest ancestor that contains the range and has a task.
 7781        loop {
 7782            let node = cursor.node();
 7783            let node_range = node.byte_range();
 7784            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7785
 7786            // Check if this node contains our offset
 7787            if node_range.start <= offset && node_range.end >= offset {
 7788                // If it contains offset, check for task
 7789                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7790                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7791                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7792                }
 7793            }
 7794
 7795            if !cursor.goto_parent() {
 7796                break;
 7797            }
 7798        }
 7799        None
 7800    }
 7801
 7802    fn render_run_indicator(
 7803        &self,
 7804        _style: &EditorStyle,
 7805        is_active: bool,
 7806        row: DisplayRow,
 7807        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7808        cx: &mut Context<Self>,
 7809    ) -> IconButton {
 7810        let color = Color::Muted;
 7811        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7812
 7813        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7814            .shape(ui::IconButtonShape::Square)
 7815            .icon_size(IconSize::XSmall)
 7816            .icon_color(color)
 7817            .toggle_state(is_active)
 7818            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7819                let quick_launch = e.down.button == MouseButton::Left;
 7820                window.focus(&editor.focus_handle(cx));
 7821                editor.toggle_code_actions(
 7822                    &ToggleCodeActions {
 7823                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7824                        quick_launch,
 7825                    },
 7826                    window,
 7827                    cx,
 7828                );
 7829            }))
 7830            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7831                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7832            }))
 7833    }
 7834
 7835    pub fn context_menu_visible(&self) -> bool {
 7836        !self.edit_prediction_preview_is_active()
 7837            && self
 7838                .context_menu
 7839                .borrow()
 7840                .as_ref()
 7841                .map_or(false, |menu| menu.visible())
 7842    }
 7843
 7844    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7845        self.context_menu
 7846            .borrow()
 7847            .as_ref()
 7848            .map(|menu| menu.origin())
 7849    }
 7850
 7851    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7852        self.context_menu_options = Some(options);
 7853    }
 7854
 7855    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7856    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7857
 7858    fn render_edit_prediction_popover(
 7859        &mut self,
 7860        text_bounds: &Bounds<Pixels>,
 7861        content_origin: gpui::Point<Pixels>,
 7862        right_margin: Pixels,
 7863        editor_snapshot: &EditorSnapshot,
 7864        visible_row_range: Range<DisplayRow>,
 7865        scroll_top: f32,
 7866        scroll_bottom: f32,
 7867        line_layouts: &[LineWithInvisibles],
 7868        line_height: Pixels,
 7869        scroll_pixel_position: gpui::Point<Pixels>,
 7870        newest_selection_head: Option<DisplayPoint>,
 7871        editor_width: Pixels,
 7872        style: &EditorStyle,
 7873        window: &mut Window,
 7874        cx: &mut App,
 7875    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7876        if self.mode().is_minimap() {
 7877            return None;
 7878        }
 7879        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7880
 7881        if self.edit_prediction_visible_in_cursor_popover(true) {
 7882            return None;
 7883        }
 7884
 7885        match &active_inline_completion.completion {
 7886            InlineCompletion::Move { target, .. } => {
 7887                let target_display_point = target.to_display_point(editor_snapshot);
 7888
 7889                if self.edit_prediction_requires_modifier() {
 7890                    if !self.edit_prediction_preview_is_active() {
 7891                        return None;
 7892                    }
 7893
 7894                    self.render_edit_prediction_modifier_jump_popover(
 7895                        text_bounds,
 7896                        content_origin,
 7897                        visible_row_range,
 7898                        line_layouts,
 7899                        line_height,
 7900                        scroll_pixel_position,
 7901                        newest_selection_head,
 7902                        target_display_point,
 7903                        window,
 7904                        cx,
 7905                    )
 7906                } else {
 7907                    self.render_edit_prediction_eager_jump_popover(
 7908                        text_bounds,
 7909                        content_origin,
 7910                        editor_snapshot,
 7911                        visible_row_range,
 7912                        scroll_top,
 7913                        scroll_bottom,
 7914                        line_height,
 7915                        scroll_pixel_position,
 7916                        target_display_point,
 7917                        editor_width,
 7918                        window,
 7919                        cx,
 7920                    )
 7921                }
 7922            }
 7923            InlineCompletion::Edit {
 7924                display_mode: EditDisplayMode::Inline,
 7925                ..
 7926            } => None,
 7927            InlineCompletion::Edit {
 7928                display_mode: EditDisplayMode::TabAccept,
 7929                edits,
 7930                ..
 7931            } => {
 7932                let range = &edits.first()?.0;
 7933                let target_display_point = range.end.to_display_point(editor_snapshot);
 7934
 7935                self.render_edit_prediction_end_of_line_popover(
 7936                    "Accept",
 7937                    editor_snapshot,
 7938                    visible_row_range,
 7939                    target_display_point,
 7940                    line_height,
 7941                    scroll_pixel_position,
 7942                    content_origin,
 7943                    editor_width,
 7944                    window,
 7945                    cx,
 7946                )
 7947            }
 7948            InlineCompletion::Edit {
 7949                edits,
 7950                edit_preview,
 7951                display_mode: EditDisplayMode::DiffPopover,
 7952                snapshot,
 7953            } => self.render_edit_prediction_diff_popover(
 7954                text_bounds,
 7955                content_origin,
 7956                right_margin,
 7957                editor_snapshot,
 7958                visible_row_range,
 7959                line_layouts,
 7960                line_height,
 7961                scroll_pixel_position,
 7962                newest_selection_head,
 7963                editor_width,
 7964                style,
 7965                edits,
 7966                edit_preview,
 7967                snapshot,
 7968                window,
 7969                cx,
 7970            ),
 7971        }
 7972    }
 7973
 7974    fn render_edit_prediction_modifier_jump_popover(
 7975        &mut self,
 7976        text_bounds: &Bounds<Pixels>,
 7977        content_origin: gpui::Point<Pixels>,
 7978        visible_row_range: Range<DisplayRow>,
 7979        line_layouts: &[LineWithInvisibles],
 7980        line_height: Pixels,
 7981        scroll_pixel_position: gpui::Point<Pixels>,
 7982        newest_selection_head: Option<DisplayPoint>,
 7983        target_display_point: DisplayPoint,
 7984        window: &mut Window,
 7985        cx: &mut App,
 7986    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7987        let scrolled_content_origin =
 7988            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7989
 7990        const SCROLL_PADDING_Y: Pixels = px(12.);
 7991
 7992        if target_display_point.row() < visible_row_range.start {
 7993            return self.render_edit_prediction_scroll_popover(
 7994                |_| SCROLL_PADDING_Y,
 7995                IconName::ArrowUp,
 7996                visible_row_range,
 7997                line_layouts,
 7998                newest_selection_head,
 7999                scrolled_content_origin,
 8000                window,
 8001                cx,
 8002            );
 8003        } else if target_display_point.row() >= visible_row_range.end {
 8004            return self.render_edit_prediction_scroll_popover(
 8005                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8006                IconName::ArrowDown,
 8007                visible_row_range,
 8008                line_layouts,
 8009                newest_selection_head,
 8010                scrolled_content_origin,
 8011                window,
 8012                cx,
 8013            );
 8014        }
 8015
 8016        const POLE_WIDTH: Pixels = px(2.);
 8017
 8018        let line_layout =
 8019            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8020        let target_column = target_display_point.column() as usize;
 8021
 8022        let target_x = line_layout.x_for_index(target_column);
 8023        let target_y =
 8024            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8025
 8026        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8027
 8028        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8029        border_color.l += 0.001;
 8030
 8031        let mut element = v_flex()
 8032            .items_end()
 8033            .when(flag_on_right, |el| el.items_start())
 8034            .child(if flag_on_right {
 8035                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8036                    .rounded_bl(px(0.))
 8037                    .rounded_tl(px(0.))
 8038                    .border_l_2()
 8039                    .border_color(border_color)
 8040            } else {
 8041                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8042                    .rounded_br(px(0.))
 8043                    .rounded_tr(px(0.))
 8044                    .border_r_2()
 8045                    .border_color(border_color)
 8046            })
 8047            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8048            .into_any();
 8049
 8050        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8051
 8052        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8053            - point(
 8054                if flag_on_right {
 8055                    POLE_WIDTH
 8056                } else {
 8057                    size.width - POLE_WIDTH
 8058                },
 8059                size.height - line_height,
 8060            );
 8061
 8062        origin.x = origin.x.max(content_origin.x);
 8063
 8064        element.prepaint_at(origin, window, cx);
 8065
 8066        Some((element, origin))
 8067    }
 8068
 8069    fn render_edit_prediction_scroll_popover(
 8070        &mut self,
 8071        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8072        scroll_icon: IconName,
 8073        visible_row_range: Range<DisplayRow>,
 8074        line_layouts: &[LineWithInvisibles],
 8075        newest_selection_head: Option<DisplayPoint>,
 8076        scrolled_content_origin: gpui::Point<Pixels>,
 8077        window: &mut Window,
 8078        cx: &mut App,
 8079    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8080        let mut element = self
 8081            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8082            .into_any();
 8083
 8084        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8085
 8086        let cursor = newest_selection_head?;
 8087        let cursor_row_layout =
 8088            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8089        let cursor_column = cursor.column() as usize;
 8090
 8091        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8092
 8093        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8094
 8095        element.prepaint_at(origin, window, cx);
 8096        Some((element, origin))
 8097    }
 8098
 8099    fn render_edit_prediction_eager_jump_popover(
 8100        &mut self,
 8101        text_bounds: &Bounds<Pixels>,
 8102        content_origin: gpui::Point<Pixels>,
 8103        editor_snapshot: &EditorSnapshot,
 8104        visible_row_range: Range<DisplayRow>,
 8105        scroll_top: f32,
 8106        scroll_bottom: f32,
 8107        line_height: Pixels,
 8108        scroll_pixel_position: gpui::Point<Pixels>,
 8109        target_display_point: DisplayPoint,
 8110        editor_width: Pixels,
 8111        window: &mut Window,
 8112        cx: &mut App,
 8113    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8114        if target_display_point.row().as_f32() < scroll_top {
 8115            let mut element = self
 8116                .render_edit_prediction_line_popover(
 8117                    "Jump to Edit",
 8118                    Some(IconName::ArrowUp),
 8119                    window,
 8120                    cx,
 8121                )?
 8122                .into_any();
 8123
 8124            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8125            let offset = point(
 8126                (text_bounds.size.width - size.width) / 2.,
 8127                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8128            );
 8129
 8130            let origin = text_bounds.origin + offset;
 8131            element.prepaint_at(origin, window, cx);
 8132            Some((element, origin))
 8133        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8134            let mut element = self
 8135                .render_edit_prediction_line_popover(
 8136                    "Jump to Edit",
 8137                    Some(IconName::ArrowDown),
 8138                    window,
 8139                    cx,
 8140                )?
 8141                .into_any();
 8142
 8143            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8144            let offset = point(
 8145                (text_bounds.size.width - size.width) / 2.,
 8146                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8147            );
 8148
 8149            let origin = text_bounds.origin + offset;
 8150            element.prepaint_at(origin, window, cx);
 8151            Some((element, origin))
 8152        } else {
 8153            self.render_edit_prediction_end_of_line_popover(
 8154                "Jump to Edit",
 8155                editor_snapshot,
 8156                visible_row_range,
 8157                target_display_point,
 8158                line_height,
 8159                scroll_pixel_position,
 8160                content_origin,
 8161                editor_width,
 8162                window,
 8163                cx,
 8164            )
 8165        }
 8166    }
 8167
 8168    fn render_edit_prediction_end_of_line_popover(
 8169        self: &mut Editor,
 8170        label: &'static str,
 8171        editor_snapshot: &EditorSnapshot,
 8172        visible_row_range: Range<DisplayRow>,
 8173        target_display_point: DisplayPoint,
 8174        line_height: Pixels,
 8175        scroll_pixel_position: gpui::Point<Pixels>,
 8176        content_origin: gpui::Point<Pixels>,
 8177        editor_width: Pixels,
 8178        window: &mut Window,
 8179        cx: &mut App,
 8180    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8181        let target_line_end = DisplayPoint::new(
 8182            target_display_point.row(),
 8183            editor_snapshot.line_len(target_display_point.row()),
 8184        );
 8185
 8186        let mut element = self
 8187            .render_edit_prediction_line_popover(label, None, window, cx)?
 8188            .into_any();
 8189
 8190        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8191
 8192        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8193
 8194        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8195        let mut origin = start_point
 8196            + line_origin
 8197            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8198        origin.x = origin.x.max(content_origin.x);
 8199
 8200        let max_x = content_origin.x + editor_width - size.width;
 8201
 8202        if origin.x > max_x {
 8203            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8204
 8205            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8206                origin.y += offset;
 8207                IconName::ArrowUp
 8208            } else {
 8209                origin.y -= offset;
 8210                IconName::ArrowDown
 8211            };
 8212
 8213            element = self
 8214                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8215                .into_any();
 8216
 8217            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8218
 8219            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8220        }
 8221
 8222        element.prepaint_at(origin, window, cx);
 8223        Some((element, origin))
 8224    }
 8225
 8226    fn render_edit_prediction_diff_popover(
 8227        self: &Editor,
 8228        text_bounds: &Bounds<Pixels>,
 8229        content_origin: gpui::Point<Pixels>,
 8230        right_margin: Pixels,
 8231        editor_snapshot: &EditorSnapshot,
 8232        visible_row_range: Range<DisplayRow>,
 8233        line_layouts: &[LineWithInvisibles],
 8234        line_height: Pixels,
 8235        scroll_pixel_position: gpui::Point<Pixels>,
 8236        newest_selection_head: Option<DisplayPoint>,
 8237        editor_width: Pixels,
 8238        style: &EditorStyle,
 8239        edits: &Vec<(Range<Anchor>, String)>,
 8240        edit_preview: &Option<language::EditPreview>,
 8241        snapshot: &language::BufferSnapshot,
 8242        window: &mut Window,
 8243        cx: &mut App,
 8244    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8245        let edit_start = edits
 8246            .first()
 8247            .unwrap()
 8248            .0
 8249            .start
 8250            .to_display_point(editor_snapshot);
 8251        let edit_end = edits
 8252            .last()
 8253            .unwrap()
 8254            .0
 8255            .end
 8256            .to_display_point(editor_snapshot);
 8257
 8258        let is_visible = visible_row_range.contains(&edit_start.row())
 8259            || visible_row_range.contains(&edit_end.row());
 8260        if !is_visible {
 8261            return None;
 8262        }
 8263
 8264        let highlighted_edits =
 8265            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8266
 8267        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8268        let line_count = highlighted_edits.text.lines().count();
 8269
 8270        const BORDER_WIDTH: Pixels = px(1.);
 8271
 8272        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8273        let has_keybind = keybind.is_some();
 8274
 8275        let mut element = h_flex()
 8276            .items_start()
 8277            .child(
 8278                h_flex()
 8279                    .bg(cx.theme().colors().editor_background)
 8280                    .border(BORDER_WIDTH)
 8281                    .shadow_sm()
 8282                    .border_color(cx.theme().colors().border)
 8283                    .rounded_l_lg()
 8284                    .when(line_count > 1, |el| el.rounded_br_lg())
 8285                    .pr_1()
 8286                    .child(styled_text),
 8287            )
 8288            .child(
 8289                h_flex()
 8290                    .h(line_height + BORDER_WIDTH * 2.)
 8291                    .px_1p5()
 8292                    .gap_1()
 8293                    // Workaround: For some reason, there's a gap if we don't do this
 8294                    .ml(-BORDER_WIDTH)
 8295                    .shadow(vec![gpui::BoxShadow {
 8296                        color: gpui::black().opacity(0.05),
 8297                        offset: point(px(1.), px(1.)),
 8298                        blur_radius: px(2.),
 8299                        spread_radius: px(0.),
 8300                    }])
 8301                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8302                    .border(BORDER_WIDTH)
 8303                    .border_color(cx.theme().colors().border)
 8304                    .rounded_r_lg()
 8305                    .id("edit_prediction_diff_popover_keybind")
 8306                    .when(!has_keybind, |el| {
 8307                        let status_colors = cx.theme().status();
 8308
 8309                        el.bg(status_colors.error_background)
 8310                            .border_color(status_colors.error.opacity(0.6))
 8311                            .child(Icon::new(IconName::Info).color(Color::Error))
 8312                            .cursor_default()
 8313                            .hoverable_tooltip(move |_window, cx| {
 8314                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8315                            })
 8316                    })
 8317                    .children(keybind),
 8318            )
 8319            .into_any();
 8320
 8321        let longest_row =
 8322            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8323        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8324            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8325        } else {
 8326            layout_line(
 8327                longest_row,
 8328                editor_snapshot,
 8329                style,
 8330                editor_width,
 8331                |_| false,
 8332                window,
 8333                cx,
 8334            )
 8335            .width
 8336        };
 8337
 8338        let viewport_bounds =
 8339            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8340                right: -right_margin,
 8341                ..Default::default()
 8342            });
 8343
 8344        let x_after_longest =
 8345            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8346                - scroll_pixel_position.x;
 8347
 8348        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8349
 8350        // Fully visible if it can be displayed within the window (allow overlapping other
 8351        // panes). However, this is only allowed if the popover starts within text_bounds.
 8352        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8353            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8354
 8355        let mut origin = if can_position_to_the_right {
 8356            point(
 8357                x_after_longest,
 8358                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8359                    - scroll_pixel_position.y,
 8360            )
 8361        } else {
 8362            let cursor_row = newest_selection_head.map(|head| head.row());
 8363            let above_edit = edit_start
 8364                .row()
 8365                .0
 8366                .checked_sub(line_count as u32)
 8367                .map(DisplayRow);
 8368            let below_edit = Some(edit_end.row() + 1);
 8369            let above_cursor =
 8370                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8371            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8372
 8373            // Place the edit popover adjacent to the edit if there is a location
 8374            // available that is onscreen and does not obscure the cursor. Otherwise,
 8375            // place it adjacent to the cursor.
 8376            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8377                .into_iter()
 8378                .flatten()
 8379                .find(|&start_row| {
 8380                    let end_row = start_row + line_count as u32;
 8381                    visible_row_range.contains(&start_row)
 8382                        && visible_row_range.contains(&end_row)
 8383                        && cursor_row.map_or(true, |cursor_row| {
 8384                            !((start_row..end_row).contains(&cursor_row))
 8385                        })
 8386                })?;
 8387
 8388            content_origin
 8389                + point(
 8390                    -scroll_pixel_position.x,
 8391                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8392                )
 8393        };
 8394
 8395        origin.x -= BORDER_WIDTH;
 8396
 8397        window.defer_draw(element, origin, 1);
 8398
 8399        // Do not return an element, since it will already be drawn due to defer_draw.
 8400        None
 8401    }
 8402
 8403    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8404        px(30.)
 8405    }
 8406
 8407    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8408        if self.read_only(cx) {
 8409            cx.theme().players().read_only()
 8410        } else {
 8411            self.style.as_ref().unwrap().local_player
 8412        }
 8413    }
 8414
 8415    fn render_edit_prediction_accept_keybind(
 8416        &self,
 8417        window: &mut Window,
 8418        cx: &App,
 8419    ) -> Option<AnyElement> {
 8420        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8421        let accept_keystroke = accept_binding.keystroke()?;
 8422
 8423        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8424
 8425        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8426            Color::Accent
 8427        } else {
 8428            Color::Muted
 8429        };
 8430
 8431        h_flex()
 8432            .px_0p5()
 8433            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8434            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8435            .text_size(TextSize::XSmall.rems(cx))
 8436            .child(h_flex().children(ui::render_modifiers(
 8437                &accept_keystroke.modifiers,
 8438                PlatformStyle::platform(),
 8439                Some(modifiers_color),
 8440                Some(IconSize::XSmall.rems().into()),
 8441                true,
 8442            )))
 8443            .when(is_platform_style_mac, |parent| {
 8444                parent.child(accept_keystroke.key.clone())
 8445            })
 8446            .when(!is_platform_style_mac, |parent| {
 8447                parent.child(
 8448                    Key::new(
 8449                        util::capitalize(&accept_keystroke.key),
 8450                        Some(Color::Default),
 8451                    )
 8452                    .size(Some(IconSize::XSmall.rems().into())),
 8453                )
 8454            })
 8455            .into_any()
 8456            .into()
 8457    }
 8458
 8459    fn render_edit_prediction_line_popover(
 8460        &self,
 8461        label: impl Into<SharedString>,
 8462        icon: Option<IconName>,
 8463        window: &mut Window,
 8464        cx: &App,
 8465    ) -> Option<Stateful<Div>> {
 8466        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8467
 8468        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8469        let has_keybind = keybind.is_some();
 8470
 8471        let result = h_flex()
 8472            .id("ep-line-popover")
 8473            .py_0p5()
 8474            .pl_1()
 8475            .pr(padding_right)
 8476            .gap_1()
 8477            .rounded_md()
 8478            .border_1()
 8479            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8480            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8481            .shadow_sm()
 8482            .when(!has_keybind, |el| {
 8483                let status_colors = cx.theme().status();
 8484
 8485                el.bg(status_colors.error_background)
 8486                    .border_color(status_colors.error.opacity(0.6))
 8487                    .pl_2()
 8488                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8489                    .cursor_default()
 8490                    .hoverable_tooltip(move |_window, cx| {
 8491                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8492                    })
 8493            })
 8494            .children(keybind)
 8495            .child(
 8496                Label::new(label)
 8497                    .size(LabelSize::Small)
 8498                    .when(!has_keybind, |el| {
 8499                        el.color(cx.theme().status().error.into()).strikethrough()
 8500                    }),
 8501            )
 8502            .when(!has_keybind, |el| {
 8503                el.child(
 8504                    h_flex().ml_1().child(
 8505                        Icon::new(IconName::Info)
 8506                            .size(IconSize::Small)
 8507                            .color(cx.theme().status().error.into()),
 8508                    ),
 8509                )
 8510            })
 8511            .when_some(icon, |element, icon| {
 8512                element.child(
 8513                    div()
 8514                        .mt(px(1.5))
 8515                        .child(Icon::new(icon).size(IconSize::Small)),
 8516                )
 8517            });
 8518
 8519        Some(result)
 8520    }
 8521
 8522    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8523        let accent_color = cx.theme().colors().text_accent;
 8524        let editor_bg_color = cx.theme().colors().editor_background;
 8525        editor_bg_color.blend(accent_color.opacity(0.1))
 8526    }
 8527
 8528    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8529        let accent_color = cx.theme().colors().text_accent;
 8530        let editor_bg_color = cx.theme().colors().editor_background;
 8531        editor_bg_color.blend(accent_color.opacity(0.6))
 8532    }
 8533
 8534    fn render_edit_prediction_cursor_popover(
 8535        &self,
 8536        min_width: Pixels,
 8537        max_width: Pixels,
 8538        cursor_point: Point,
 8539        style: &EditorStyle,
 8540        accept_keystroke: Option<&gpui::Keystroke>,
 8541        _window: &Window,
 8542        cx: &mut Context<Editor>,
 8543    ) -> Option<AnyElement> {
 8544        let provider = self.edit_prediction_provider.as_ref()?;
 8545
 8546        if provider.provider.needs_terms_acceptance(cx) {
 8547            return Some(
 8548                h_flex()
 8549                    .min_w(min_width)
 8550                    .flex_1()
 8551                    .px_2()
 8552                    .py_1()
 8553                    .gap_3()
 8554                    .elevation_2(cx)
 8555                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8556                    .id("accept-terms")
 8557                    .cursor_pointer()
 8558                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8559                    .on_click(cx.listener(|this, _event, window, cx| {
 8560                        cx.stop_propagation();
 8561                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8562                        window.dispatch_action(
 8563                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8564                            cx,
 8565                        );
 8566                    }))
 8567                    .child(
 8568                        h_flex()
 8569                            .flex_1()
 8570                            .gap_2()
 8571                            .child(Icon::new(IconName::ZedPredict))
 8572                            .child(Label::new("Accept Terms of Service"))
 8573                            .child(div().w_full())
 8574                            .child(
 8575                                Icon::new(IconName::ArrowUpRight)
 8576                                    .color(Color::Muted)
 8577                                    .size(IconSize::Small),
 8578                            )
 8579                            .into_any_element(),
 8580                    )
 8581                    .into_any(),
 8582            );
 8583        }
 8584
 8585        let is_refreshing = provider.provider.is_refreshing(cx);
 8586
 8587        fn pending_completion_container() -> Div {
 8588            h_flex()
 8589                .h_full()
 8590                .flex_1()
 8591                .gap_2()
 8592                .child(Icon::new(IconName::ZedPredict))
 8593        }
 8594
 8595        let completion = match &self.active_inline_completion {
 8596            Some(prediction) => {
 8597                if !self.has_visible_completions_menu() {
 8598                    const RADIUS: Pixels = px(6.);
 8599                    const BORDER_WIDTH: Pixels = px(1.);
 8600
 8601                    return Some(
 8602                        h_flex()
 8603                            .elevation_2(cx)
 8604                            .border(BORDER_WIDTH)
 8605                            .border_color(cx.theme().colors().border)
 8606                            .when(accept_keystroke.is_none(), |el| {
 8607                                el.border_color(cx.theme().status().error)
 8608                            })
 8609                            .rounded(RADIUS)
 8610                            .rounded_tl(px(0.))
 8611                            .overflow_hidden()
 8612                            .child(div().px_1p5().child(match &prediction.completion {
 8613                                InlineCompletion::Move { target, snapshot } => {
 8614                                    use text::ToPoint as _;
 8615                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8616                                    {
 8617                                        Icon::new(IconName::ZedPredictDown)
 8618                                    } else {
 8619                                        Icon::new(IconName::ZedPredictUp)
 8620                                    }
 8621                                }
 8622                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8623                            }))
 8624                            .child(
 8625                                h_flex()
 8626                                    .gap_1()
 8627                                    .py_1()
 8628                                    .px_2()
 8629                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8630                                    .border_l_1()
 8631                                    .border_color(cx.theme().colors().border)
 8632                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8633                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8634                                        el.child(
 8635                                            Label::new("Hold")
 8636                                                .size(LabelSize::Small)
 8637                                                .when(accept_keystroke.is_none(), |el| {
 8638                                                    el.strikethrough()
 8639                                                })
 8640                                                .line_height_style(LineHeightStyle::UiLabel),
 8641                                        )
 8642                                    })
 8643                                    .id("edit_prediction_cursor_popover_keybind")
 8644                                    .when(accept_keystroke.is_none(), |el| {
 8645                                        let status_colors = cx.theme().status();
 8646
 8647                                        el.bg(status_colors.error_background)
 8648                                            .border_color(status_colors.error.opacity(0.6))
 8649                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8650                                            .cursor_default()
 8651                                            .hoverable_tooltip(move |_window, cx| {
 8652                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8653                                                    .into()
 8654                                            })
 8655                                    })
 8656                                    .when_some(
 8657                                        accept_keystroke.as_ref(),
 8658                                        |el, accept_keystroke| {
 8659                                            el.child(h_flex().children(ui::render_modifiers(
 8660                                                &accept_keystroke.modifiers,
 8661                                                PlatformStyle::platform(),
 8662                                                Some(Color::Default),
 8663                                                Some(IconSize::XSmall.rems().into()),
 8664                                                false,
 8665                                            )))
 8666                                        },
 8667                                    ),
 8668                            )
 8669                            .into_any(),
 8670                    );
 8671                }
 8672
 8673                self.render_edit_prediction_cursor_popover_preview(
 8674                    prediction,
 8675                    cursor_point,
 8676                    style,
 8677                    cx,
 8678                )?
 8679            }
 8680
 8681            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8682                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8683                    stale_completion,
 8684                    cursor_point,
 8685                    style,
 8686                    cx,
 8687                )?,
 8688
 8689                None => {
 8690                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8691                }
 8692            },
 8693
 8694            None => pending_completion_container().child(Label::new("No Prediction")),
 8695        };
 8696
 8697        let completion = if is_refreshing {
 8698            completion
 8699                .with_animation(
 8700                    "loading-completion",
 8701                    Animation::new(Duration::from_secs(2))
 8702                        .repeat()
 8703                        .with_easing(pulsating_between(0.4, 0.8)),
 8704                    |label, delta| label.opacity(delta),
 8705                )
 8706                .into_any_element()
 8707        } else {
 8708            completion.into_any_element()
 8709        };
 8710
 8711        let has_completion = self.active_inline_completion.is_some();
 8712
 8713        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8714        Some(
 8715            h_flex()
 8716                .min_w(min_width)
 8717                .max_w(max_width)
 8718                .flex_1()
 8719                .elevation_2(cx)
 8720                .border_color(cx.theme().colors().border)
 8721                .child(
 8722                    div()
 8723                        .flex_1()
 8724                        .py_1()
 8725                        .px_2()
 8726                        .overflow_hidden()
 8727                        .child(completion),
 8728                )
 8729                .when_some(accept_keystroke, |el, accept_keystroke| {
 8730                    if !accept_keystroke.modifiers.modified() {
 8731                        return el;
 8732                    }
 8733
 8734                    el.child(
 8735                        h_flex()
 8736                            .h_full()
 8737                            .border_l_1()
 8738                            .rounded_r_lg()
 8739                            .border_color(cx.theme().colors().border)
 8740                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8741                            .gap_1()
 8742                            .py_1()
 8743                            .px_2()
 8744                            .child(
 8745                                h_flex()
 8746                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8747                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8748                                    .child(h_flex().children(ui::render_modifiers(
 8749                                        &accept_keystroke.modifiers,
 8750                                        PlatformStyle::platform(),
 8751                                        Some(if !has_completion {
 8752                                            Color::Muted
 8753                                        } else {
 8754                                            Color::Default
 8755                                        }),
 8756                                        None,
 8757                                        false,
 8758                                    ))),
 8759                            )
 8760                            .child(Label::new("Preview").into_any_element())
 8761                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8762                    )
 8763                })
 8764                .into_any(),
 8765        )
 8766    }
 8767
 8768    fn render_edit_prediction_cursor_popover_preview(
 8769        &self,
 8770        completion: &InlineCompletionState,
 8771        cursor_point: Point,
 8772        style: &EditorStyle,
 8773        cx: &mut Context<Editor>,
 8774    ) -> Option<Div> {
 8775        use text::ToPoint as _;
 8776
 8777        fn render_relative_row_jump(
 8778            prefix: impl Into<String>,
 8779            current_row: u32,
 8780            target_row: u32,
 8781        ) -> Div {
 8782            let (row_diff, arrow) = if target_row < current_row {
 8783                (current_row - target_row, IconName::ArrowUp)
 8784            } else {
 8785                (target_row - current_row, IconName::ArrowDown)
 8786            };
 8787
 8788            h_flex()
 8789                .child(
 8790                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8791                        .color(Color::Muted)
 8792                        .size(LabelSize::Small),
 8793                )
 8794                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8795        }
 8796
 8797        match &completion.completion {
 8798            InlineCompletion::Move {
 8799                target, snapshot, ..
 8800            } => Some(
 8801                h_flex()
 8802                    .px_2()
 8803                    .gap_2()
 8804                    .flex_1()
 8805                    .child(
 8806                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8807                            Icon::new(IconName::ZedPredictDown)
 8808                        } else {
 8809                            Icon::new(IconName::ZedPredictUp)
 8810                        },
 8811                    )
 8812                    .child(Label::new("Jump to Edit")),
 8813            ),
 8814
 8815            InlineCompletion::Edit {
 8816                edits,
 8817                edit_preview,
 8818                snapshot,
 8819                display_mode: _,
 8820            } => {
 8821                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8822
 8823                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8824                    &snapshot,
 8825                    &edits,
 8826                    edit_preview.as_ref()?,
 8827                    true,
 8828                    cx,
 8829                )
 8830                .first_line_preview();
 8831
 8832                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8833                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8834
 8835                let preview = h_flex()
 8836                    .gap_1()
 8837                    .min_w_16()
 8838                    .child(styled_text)
 8839                    .when(has_more_lines, |parent| parent.child(""));
 8840
 8841                let left = if first_edit_row != cursor_point.row {
 8842                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8843                        .into_any_element()
 8844                } else {
 8845                    Icon::new(IconName::ZedPredict).into_any_element()
 8846                };
 8847
 8848                Some(
 8849                    h_flex()
 8850                        .h_full()
 8851                        .flex_1()
 8852                        .gap_2()
 8853                        .pr_1()
 8854                        .overflow_x_hidden()
 8855                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8856                        .child(left)
 8857                        .child(preview),
 8858                )
 8859            }
 8860        }
 8861    }
 8862
 8863    pub fn render_context_menu(
 8864        &self,
 8865        style: &EditorStyle,
 8866        max_height_in_lines: u32,
 8867        window: &mut Window,
 8868        cx: &mut Context<Editor>,
 8869    ) -> Option<AnyElement> {
 8870        let menu = self.context_menu.borrow();
 8871        let menu = menu.as_ref()?;
 8872        if !menu.visible() {
 8873            return None;
 8874        };
 8875        Some(menu.render(style, max_height_in_lines, window, cx))
 8876    }
 8877
 8878    fn render_context_menu_aside(
 8879        &mut self,
 8880        max_size: Size<Pixels>,
 8881        window: &mut Window,
 8882        cx: &mut Context<Editor>,
 8883    ) -> Option<AnyElement> {
 8884        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8885            if menu.visible() {
 8886                menu.render_aside(max_size, window, cx)
 8887            } else {
 8888                None
 8889            }
 8890        })
 8891    }
 8892
 8893    fn hide_context_menu(
 8894        &mut self,
 8895        window: &mut Window,
 8896        cx: &mut Context<Self>,
 8897    ) -> Option<CodeContextMenu> {
 8898        cx.notify();
 8899        self.completion_tasks.clear();
 8900        let context_menu = self.context_menu.borrow_mut().take();
 8901        self.stale_inline_completion_in_menu.take();
 8902        self.update_visible_inline_completion(window, cx);
 8903        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8904            if let Some(completion_provider) = &self.completion_provider {
 8905                completion_provider.selection_changed(None, window, cx);
 8906            }
 8907        }
 8908        context_menu
 8909    }
 8910
 8911    fn show_snippet_choices(
 8912        &mut self,
 8913        choices: &Vec<String>,
 8914        selection: Range<Anchor>,
 8915        cx: &mut Context<Self>,
 8916    ) {
 8917        if selection.start.buffer_id.is_none() {
 8918            return;
 8919        }
 8920        let buffer_id = selection.start.buffer_id.unwrap();
 8921        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8922        let id = post_inc(&mut self.next_completion_id);
 8923        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8924
 8925        if let Some(buffer) = buffer {
 8926            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8927                CompletionsMenu::new_snippet_choices(
 8928                    id,
 8929                    true,
 8930                    choices,
 8931                    selection,
 8932                    buffer,
 8933                    snippet_sort_order,
 8934                ),
 8935            ));
 8936        }
 8937    }
 8938
 8939    pub fn insert_snippet(
 8940        &mut self,
 8941        insertion_ranges: &[Range<usize>],
 8942        snippet: Snippet,
 8943        window: &mut Window,
 8944        cx: &mut Context<Self>,
 8945    ) -> Result<()> {
 8946        struct Tabstop<T> {
 8947            is_end_tabstop: bool,
 8948            ranges: Vec<Range<T>>,
 8949            choices: Option<Vec<String>>,
 8950        }
 8951
 8952        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8953            let snippet_text: Arc<str> = snippet.text.clone().into();
 8954            let edits = insertion_ranges
 8955                .iter()
 8956                .cloned()
 8957                .map(|range| (range, snippet_text.clone()));
 8958            let autoindent_mode = AutoindentMode::Block {
 8959                original_indent_columns: Vec::new(),
 8960            };
 8961            buffer.edit(edits, Some(autoindent_mode), cx);
 8962
 8963            let snapshot = &*buffer.read(cx);
 8964            let snippet = &snippet;
 8965            snippet
 8966                .tabstops
 8967                .iter()
 8968                .map(|tabstop| {
 8969                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8970                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8971                    });
 8972                    let mut tabstop_ranges = tabstop
 8973                        .ranges
 8974                        .iter()
 8975                        .flat_map(|tabstop_range| {
 8976                            let mut delta = 0_isize;
 8977                            insertion_ranges.iter().map(move |insertion_range| {
 8978                                let insertion_start = insertion_range.start as isize + delta;
 8979                                delta +=
 8980                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8981
 8982                                let start = ((insertion_start + tabstop_range.start) as usize)
 8983                                    .min(snapshot.len());
 8984                                let end = ((insertion_start + tabstop_range.end) as usize)
 8985                                    .min(snapshot.len());
 8986                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8987                            })
 8988                        })
 8989                        .collect::<Vec<_>>();
 8990                    // Sort in reverse order so that the first range is the newest created
 8991                    // selection. Completions will use it and autoscroll will prioritize it.
 8992                    tabstop_ranges.sort_unstable_by(|a, b| b.start.cmp(&a.start, snapshot));
 8993
 8994                    Tabstop {
 8995                        is_end_tabstop,
 8996                        ranges: tabstop_ranges,
 8997                        choices: tabstop.choices.clone(),
 8998                    }
 8999                })
 9000                .collect::<Vec<_>>()
 9001        });
 9002        if let Some(tabstop) = tabstops.first() {
 9003            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9004                s.select_ranges(tabstop.ranges.iter().cloned());
 9005            });
 9006
 9007            if let Some(choices) = &tabstop.choices {
 9008                if let Some(selection) = tabstop.ranges.first() {
 9009                    self.show_snippet_choices(choices, selection.clone(), cx)
 9010                }
 9011            }
 9012
 9013            // If we're already at the last tabstop and it's at the end of the snippet,
 9014            // we're done, we don't need to keep the state around.
 9015            if !tabstop.is_end_tabstop {
 9016                let choices = tabstops
 9017                    .iter()
 9018                    .map(|tabstop| tabstop.choices.clone())
 9019                    .collect();
 9020
 9021                let ranges = tabstops
 9022                    .into_iter()
 9023                    .map(|tabstop| tabstop.ranges)
 9024                    .collect::<Vec<_>>();
 9025
 9026                self.snippet_stack.push(SnippetState {
 9027                    active_index: 0,
 9028                    ranges,
 9029                    choices,
 9030                });
 9031            }
 9032
 9033            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9034            if self.autoclose_regions.is_empty() {
 9035                let snapshot = self.buffer.read(cx).snapshot(cx);
 9036                for selection in &mut self.selections.all::<Point>(cx) {
 9037                    let selection_head = selection.head();
 9038                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9039                        continue;
 9040                    };
 9041
 9042                    let mut bracket_pair = None;
 9043                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9044                    let prev_chars = snapshot
 9045                        .reversed_chars_at(selection_head)
 9046                        .collect::<String>();
 9047                    for (pair, enabled) in scope.brackets() {
 9048                        if enabled
 9049                            && pair.close
 9050                            && prev_chars.starts_with(pair.start.as_str())
 9051                            && next_chars.starts_with(pair.end.as_str())
 9052                        {
 9053                            bracket_pair = Some(pair.clone());
 9054                            break;
 9055                        }
 9056                    }
 9057                    if let Some(pair) = bracket_pair {
 9058                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9059                        let autoclose_enabled =
 9060                            self.use_autoclose && snapshot_settings.use_autoclose;
 9061                        if autoclose_enabled {
 9062                            let start = snapshot.anchor_after(selection_head);
 9063                            let end = snapshot.anchor_after(selection_head);
 9064                            self.autoclose_regions.push(AutocloseRegion {
 9065                                selection_id: selection.id,
 9066                                range: start..end,
 9067                                pair,
 9068                            });
 9069                        }
 9070                    }
 9071                }
 9072            }
 9073        }
 9074        Ok(())
 9075    }
 9076
 9077    pub fn move_to_next_snippet_tabstop(
 9078        &mut self,
 9079        window: &mut Window,
 9080        cx: &mut Context<Self>,
 9081    ) -> bool {
 9082        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9083    }
 9084
 9085    pub fn move_to_prev_snippet_tabstop(
 9086        &mut self,
 9087        window: &mut Window,
 9088        cx: &mut Context<Self>,
 9089    ) -> bool {
 9090        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9091    }
 9092
 9093    pub fn move_to_snippet_tabstop(
 9094        &mut self,
 9095        bias: Bias,
 9096        window: &mut Window,
 9097        cx: &mut Context<Self>,
 9098    ) -> bool {
 9099        if let Some(mut snippet) = self.snippet_stack.pop() {
 9100            match bias {
 9101                Bias::Left => {
 9102                    if snippet.active_index > 0 {
 9103                        snippet.active_index -= 1;
 9104                    } else {
 9105                        self.snippet_stack.push(snippet);
 9106                        return false;
 9107                    }
 9108                }
 9109                Bias::Right => {
 9110                    if snippet.active_index + 1 < snippet.ranges.len() {
 9111                        snippet.active_index += 1;
 9112                    } else {
 9113                        self.snippet_stack.push(snippet);
 9114                        return false;
 9115                    }
 9116                }
 9117            }
 9118            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9119                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9120                    s.select_ranges(current_ranges.iter().cloned())
 9121                });
 9122
 9123                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9124                    if let Some(selection) = current_ranges.first() {
 9125                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9126                    }
 9127                }
 9128
 9129                // If snippet state is not at the last tabstop, push it back on the stack
 9130                if snippet.active_index + 1 < snippet.ranges.len() {
 9131                    self.snippet_stack.push(snippet);
 9132                }
 9133                return true;
 9134            }
 9135        }
 9136
 9137        false
 9138    }
 9139
 9140    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9141        self.transact(window, cx, |this, window, cx| {
 9142            this.select_all(&SelectAll, window, cx);
 9143            this.insert("", window, cx);
 9144        });
 9145    }
 9146
 9147    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9148        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9149        self.transact(window, cx, |this, window, cx| {
 9150            this.select_autoclose_pair(window, cx);
 9151            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9152            if !this.linked_edit_ranges.is_empty() {
 9153                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9154                let snapshot = this.buffer.read(cx).snapshot(cx);
 9155
 9156                for selection in selections.iter() {
 9157                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9158                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9159                    if selection_start.buffer_id != selection_end.buffer_id {
 9160                        continue;
 9161                    }
 9162                    if let Some(ranges) =
 9163                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9164                    {
 9165                        for (buffer, entries) in ranges {
 9166                            linked_ranges.entry(buffer).or_default().extend(entries);
 9167                        }
 9168                    }
 9169                }
 9170            }
 9171
 9172            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9173            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9174            for selection in &mut selections {
 9175                if selection.is_empty() {
 9176                    let old_head = selection.head();
 9177                    let mut new_head =
 9178                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9179                            .to_point(&display_map);
 9180                    if let Some((buffer, line_buffer_range)) = display_map
 9181                        .buffer_snapshot
 9182                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9183                    {
 9184                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9185                        let indent_len = match indent_size.kind {
 9186                            IndentKind::Space => {
 9187                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9188                            }
 9189                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9190                        };
 9191                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9192                            let indent_len = indent_len.get();
 9193                            new_head = cmp::min(
 9194                                new_head,
 9195                                MultiBufferPoint::new(
 9196                                    old_head.row,
 9197                                    ((old_head.column - 1) / indent_len) * indent_len,
 9198                                ),
 9199                            );
 9200                        }
 9201                    }
 9202
 9203                    selection.set_head(new_head, SelectionGoal::None);
 9204                }
 9205            }
 9206
 9207            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9208                s.select(selections)
 9209            });
 9210            this.insert("", window, cx);
 9211            let empty_str: Arc<str> = Arc::from("");
 9212            for (buffer, edits) in linked_ranges {
 9213                let snapshot = buffer.read(cx).snapshot();
 9214                use text::ToPoint as TP;
 9215
 9216                let edits = edits
 9217                    .into_iter()
 9218                    .map(|range| {
 9219                        let end_point = TP::to_point(&range.end, &snapshot);
 9220                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9221
 9222                        if end_point == start_point {
 9223                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9224                                .saturating_sub(1);
 9225                            start_point =
 9226                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9227                        };
 9228
 9229                        (start_point..end_point, empty_str.clone())
 9230                    })
 9231                    .sorted_by_key(|(range, _)| range.start)
 9232                    .collect::<Vec<_>>();
 9233                buffer.update(cx, |this, cx| {
 9234                    this.edit(edits, None, cx);
 9235                })
 9236            }
 9237            this.refresh_inline_completion(true, false, window, cx);
 9238            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9239        });
 9240    }
 9241
 9242    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9243        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9244        self.transact(window, cx, |this, window, cx| {
 9245            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9246                s.move_with(|map, selection| {
 9247                    if selection.is_empty() {
 9248                        let cursor = movement::right(map, selection.head());
 9249                        selection.end = cursor;
 9250                        selection.reversed = true;
 9251                        selection.goal = SelectionGoal::None;
 9252                    }
 9253                })
 9254            });
 9255            this.insert("", window, cx);
 9256            this.refresh_inline_completion(true, false, window, cx);
 9257        });
 9258    }
 9259
 9260    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9261        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9262        if self.move_to_prev_snippet_tabstop(window, cx) {
 9263            return;
 9264        }
 9265        self.outdent(&Outdent, window, cx);
 9266    }
 9267
 9268    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9269        if self.move_to_next_snippet_tabstop(window, cx) {
 9270            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9271            return;
 9272        }
 9273        if self.read_only(cx) {
 9274            return;
 9275        }
 9276        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9277        let mut selections = self.selections.all_adjusted(cx);
 9278        let buffer = self.buffer.read(cx);
 9279        let snapshot = buffer.snapshot(cx);
 9280        let rows_iter = selections.iter().map(|s| s.head().row);
 9281        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9282
 9283        let has_some_cursor_in_whitespace = selections
 9284            .iter()
 9285            .filter(|selection| selection.is_empty())
 9286            .any(|selection| {
 9287                let cursor = selection.head();
 9288                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9289                cursor.column < current_indent.len
 9290            });
 9291
 9292        let mut edits = Vec::new();
 9293        let mut prev_edited_row = 0;
 9294        let mut row_delta = 0;
 9295        for selection in &mut selections {
 9296            if selection.start.row != prev_edited_row {
 9297                row_delta = 0;
 9298            }
 9299            prev_edited_row = selection.end.row;
 9300
 9301            // If the selection is non-empty, then increase the indentation of the selected lines.
 9302            if !selection.is_empty() {
 9303                row_delta =
 9304                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9305                continue;
 9306            }
 9307
 9308            let cursor = selection.head();
 9309            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9310            if let Some(suggested_indent) =
 9311                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9312            {
 9313                // Don't do anything if already at suggested indent
 9314                // and there is any other cursor which is not
 9315                if has_some_cursor_in_whitespace
 9316                    && cursor.column == current_indent.len
 9317                    && current_indent.len == suggested_indent.len
 9318                {
 9319                    continue;
 9320                }
 9321
 9322                // Adjust line and move cursor to suggested indent
 9323                // if cursor is not at suggested indent
 9324                if cursor.column < suggested_indent.len
 9325                    && cursor.column <= current_indent.len
 9326                    && current_indent.len <= suggested_indent.len
 9327                {
 9328                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9329                    selection.end = selection.start;
 9330                    if row_delta == 0 {
 9331                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9332                            cursor.row,
 9333                            current_indent,
 9334                            suggested_indent,
 9335                        ));
 9336                        row_delta = suggested_indent.len - current_indent.len;
 9337                    }
 9338                    continue;
 9339                }
 9340
 9341                // If current indent is more than suggested indent
 9342                // only move cursor to current indent and skip indent
 9343                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9344                    selection.start = Point::new(cursor.row, current_indent.len);
 9345                    selection.end = selection.start;
 9346                    continue;
 9347                }
 9348            }
 9349
 9350            // Otherwise, insert a hard or soft tab.
 9351            let settings = buffer.language_settings_at(cursor, cx);
 9352            let tab_size = if settings.hard_tabs {
 9353                IndentSize::tab()
 9354            } else {
 9355                let tab_size = settings.tab_size.get();
 9356                let indent_remainder = snapshot
 9357                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9358                    .flat_map(str::chars)
 9359                    .fold(row_delta % tab_size, |counter: u32, c| {
 9360                        if c == '\t' {
 9361                            0
 9362                        } else {
 9363                            (counter + 1) % tab_size
 9364                        }
 9365                    });
 9366
 9367                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9368                IndentSize::spaces(chars_to_next_tab_stop)
 9369            };
 9370            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9371            selection.end = selection.start;
 9372            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9373            row_delta += tab_size.len;
 9374        }
 9375
 9376        self.transact(window, cx, |this, window, cx| {
 9377            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9378            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9379                s.select(selections)
 9380            });
 9381            this.refresh_inline_completion(true, false, window, cx);
 9382        });
 9383    }
 9384
 9385    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9386        if self.read_only(cx) {
 9387            return;
 9388        }
 9389        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9390        let mut selections = self.selections.all::<Point>(cx);
 9391        let mut prev_edited_row = 0;
 9392        let mut row_delta = 0;
 9393        let mut edits = Vec::new();
 9394        let buffer = self.buffer.read(cx);
 9395        let snapshot = buffer.snapshot(cx);
 9396        for selection in &mut selections {
 9397            if selection.start.row != prev_edited_row {
 9398                row_delta = 0;
 9399            }
 9400            prev_edited_row = selection.end.row;
 9401
 9402            row_delta =
 9403                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9404        }
 9405
 9406        self.transact(window, cx, |this, window, cx| {
 9407            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9408            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9409                s.select(selections)
 9410            });
 9411        });
 9412    }
 9413
 9414    fn indent_selection(
 9415        buffer: &MultiBuffer,
 9416        snapshot: &MultiBufferSnapshot,
 9417        selection: &mut Selection<Point>,
 9418        edits: &mut Vec<(Range<Point>, String)>,
 9419        delta_for_start_row: u32,
 9420        cx: &App,
 9421    ) -> u32 {
 9422        let settings = buffer.language_settings_at(selection.start, cx);
 9423        let tab_size = settings.tab_size.get();
 9424        let indent_kind = if settings.hard_tabs {
 9425            IndentKind::Tab
 9426        } else {
 9427            IndentKind::Space
 9428        };
 9429        let mut start_row = selection.start.row;
 9430        let mut end_row = selection.end.row + 1;
 9431
 9432        // If a selection ends at the beginning of a line, don't indent
 9433        // that last line.
 9434        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9435            end_row -= 1;
 9436        }
 9437
 9438        // Avoid re-indenting a row that has already been indented by a
 9439        // previous selection, but still update this selection's column
 9440        // to reflect that indentation.
 9441        if delta_for_start_row > 0 {
 9442            start_row += 1;
 9443            selection.start.column += delta_for_start_row;
 9444            if selection.end.row == selection.start.row {
 9445                selection.end.column += delta_for_start_row;
 9446            }
 9447        }
 9448
 9449        let mut delta_for_end_row = 0;
 9450        let has_multiple_rows = start_row + 1 != end_row;
 9451        for row in start_row..end_row {
 9452            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9453            let indent_delta = match (current_indent.kind, indent_kind) {
 9454                (IndentKind::Space, IndentKind::Space) => {
 9455                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9456                    IndentSize::spaces(columns_to_next_tab_stop)
 9457                }
 9458                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9459                (_, IndentKind::Tab) => IndentSize::tab(),
 9460            };
 9461
 9462            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9463                0
 9464            } else {
 9465                selection.start.column
 9466            };
 9467            let row_start = Point::new(row, start);
 9468            edits.push((
 9469                row_start..row_start,
 9470                indent_delta.chars().collect::<String>(),
 9471            ));
 9472
 9473            // Update this selection's endpoints to reflect the indentation.
 9474            if row == selection.start.row {
 9475                selection.start.column += indent_delta.len;
 9476            }
 9477            if row == selection.end.row {
 9478                selection.end.column += indent_delta.len;
 9479                delta_for_end_row = indent_delta.len;
 9480            }
 9481        }
 9482
 9483        if selection.start.row == selection.end.row {
 9484            delta_for_start_row + delta_for_end_row
 9485        } else {
 9486            delta_for_end_row
 9487        }
 9488    }
 9489
 9490    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9491        if self.read_only(cx) {
 9492            return;
 9493        }
 9494        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9495        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9496        let selections = self.selections.all::<Point>(cx);
 9497        let mut deletion_ranges = Vec::new();
 9498        let mut last_outdent = None;
 9499        {
 9500            let buffer = self.buffer.read(cx);
 9501            let snapshot = buffer.snapshot(cx);
 9502            for selection in &selections {
 9503                let settings = buffer.language_settings_at(selection.start, cx);
 9504                let tab_size = settings.tab_size.get();
 9505                let mut rows = selection.spanned_rows(false, &display_map);
 9506
 9507                // Avoid re-outdenting a row that has already been outdented by a
 9508                // previous selection.
 9509                if let Some(last_row) = last_outdent {
 9510                    if last_row == rows.start {
 9511                        rows.start = rows.start.next_row();
 9512                    }
 9513                }
 9514                let has_multiple_rows = rows.len() > 1;
 9515                for row in rows.iter_rows() {
 9516                    let indent_size = snapshot.indent_size_for_line(row);
 9517                    if indent_size.len > 0 {
 9518                        let deletion_len = match indent_size.kind {
 9519                            IndentKind::Space => {
 9520                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9521                                if columns_to_prev_tab_stop == 0 {
 9522                                    tab_size
 9523                                } else {
 9524                                    columns_to_prev_tab_stop
 9525                                }
 9526                            }
 9527                            IndentKind::Tab => 1,
 9528                        };
 9529                        let start = if has_multiple_rows
 9530                            || deletion_len > selection.start.column
 9531                            || indent_size.len < selection.start.column
 9532                        {
 9533                            0
 9534                        } else {
 9535                            selection.start.column - deletion_len
 9536                        };
 9537                        deletion_ranges.push(
 9538                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9539                        );
 9540                        last_outdent = Some(row);
 9541                    }
 9542                }
 9543            }
 9544        }
 9545
 9546        self.transact(window, cx, |this, window, cx| {
 9547            this.buffer.update(cx, |buffer, cx| {
 9548                let empty_str: Arc<str> = Arc::default();
 9549                buffer.edit(
 9550                    deletion_ranges
 9551                        .into_iter()
 9552                        .map(|range| (range, empty_str.clone())),
 9553                    None,
 9554                    cx,
 9555                );
 9556            });
 9557            let selections = this.selections.all::<usize>(cx);
 9558            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9559                s.select(selections)
 9560            });
 9561        });
 9562    }
 9563
 9564    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9565        if self.read_only(cx) {
 9566            return;
 9567        }
 9568        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9569        let selections = self
 9570            .selections
 9571            .all::<usize>(cx)
 9572            .into_iter()
 9573            .map(|s| s.range());
 9574
 9575        self.transact(window, cx, |this, window, cx| {
 9576            this.buffer.update(cx, |buffer, cx| {
 9577                buffer.autoindent_ranges(selections, cx);
 9578            });
 9579            let selections = this.selections.all::<usize>(cx);
 9580            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9581                s.select(selections)
 9582            });
 9583        });
 9584    }
 9585
 9586    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9587        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9588        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9589        let selections = self.selections.all::<Point>(cx);
 9590
 9591        let mut new_cursors = Vec::new();
 9592        let mut edit_ranges = Vec::new();
 9593        let mut selections = selections.iter().peekable();
 9594        while let Some(selection) = selections.next() {
 9595            let mut rows = selection.spanned_rows(false, &display_map);
 9596            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9597
 9598            // Accumulate contiguous regions of rows that we want to delete.
 9599            while let Some(next_selection) = selections.peek() {
 9600                let next_rows = next_selection.spanned_rows(false, &display_map);
 9601                if next_rows.start <= rows.end {
 9602                    rows.end = next_rows.end;
 9603                    selections.next().unwrap();
 9604                } else {
 9605                    break;
 9606                }
 9607            }
 9608
 9609            let buffer = &display_map.buffer_snapshot;
 9610            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9611            let edit_end;
 9612            let cursor_buffer_row;
 9613            if buffer.max_point().row >= rows.end.0 {
 9614                // If there's a line after the range, delete the \n from the end of the row range
 9615                // and position the cursor on the next line.
 9616                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9617                cursor_buffer_row = rows.end;
 9618            } else {
 9619                // If there isn't a line after the range, delete the \n from the line before the
 9620                // start of the row range and position the cursor there.
 9621                edit_start = edit_start.saturating_sub(1);
 9622                edit_end = buffer.len();
 9623                cursor_buffer_row = rows.start.previous_row();
 9624            }
 9625
 9626            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9627            *cursor.column_mut() =
 9628                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9629
 9630            new_cursors.push((
 9631                selection.id,
 9632                buffer.anchor_after(cursor.to_point(&display_map)),
 9633            ));
 9634            edit_ranges.push(edit_start..edit_end);
 9635        }
 9636
 9637        self.transact(window, cx, |this, window, cx| {
 9638            let buffer = this.buffer.update(cx, |buffer, cx| {
 9639                let empty_str: Arc<str> = Arc::default();
 9640                buffer.edit(
 9641                    edit_ranges
 9642                        .into_iter()
 9643                        .map(|range| (range, empty_str.clone())),
 9644                    None,
 9645                    cx,
 9646                );
 9647                buffer.snapshot(cx)
 9648            });
 9649            let new_selections = new_cursors
 9650                .into_iter()
 9651                .map(|(id, cursor)| {
 9652                    let cursor = cursor.to_point(&buffer);
 9653                    Selection {
 9654                        id,
 9655                        start: cursor,
 9656                        end: cursor,
 9657                        reversed: false,
 9658                        goal: SelectionGoal::None,
 9659                    }
 9660                })
 9661                .collect();
 9662
 9663            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9664                s.select(new_selections);
 9665            });
 9666        });
 9667    }
 9668
 9669    pub fn join_lines_impl(
 9670        &mut self,
 9671        insert_whitespace: bool,
 9672        window: &mut Window,
 9673        cx: &mut Context<Self>,
 9674    ) {
 9675        if self.read_only(cx) {
 9676            return;
 9677        }
 9678        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9679        for selection in self.selections.all::<Point>(cx) {
 9680            let start = MultiBufferRow(selection.start.row);
 9681            // Treat single line selections as if they include the next line. Otherwise this action
 9682            // would do nothing for single line selections individual cursors.
 9683            let end = if selection.start.row == selection.end.row {
 9684                MultiBufferRow(selection.start.row + 1)
 9685            } else {
 9686                MultiBufferRow(selection.end.row)
 9687            };
 9688
 9689            if let Some(last_row_range) = row_ranges.last_mut() {
 9690                if start <= last_row_range.end {
 9691                    last_row_range.end = end;
 9692                    continue;
 9693                }
 9694            }
 9695            row_ranges.push(start..end);
 9696        }
 9697
 9698        let snapshot = self.buffer.read(cx).snapshot(cx);
 9699        let mut cursor_positions = Vec::new();
 9700        for row_range in &row_ranges {
 9701            let anchor = snapshot.anchor_before(Point::new(
 9702                row_range.end.previous_row().0,
 9703                snapshot.line_len(row_range.end.previous_row()),
 9704            ));
 9705            cursor_positions.push(anchor..anchor);
 9706        }
 9707
 9708        self.transact(window, cx, |this, window, cx| {
 9709            for row_range in row_ranges.into_iter().rev() {
 9710                for row in row_range.iter_rows().rev() {
 9711                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9712                    let next_line_row = row.next_row();
 9713                    let indent = snapshot.indent_size_for_line(next_line_row);
 9714                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9715
 9716                    let replace =
 9717                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9718                            " "
 9719                        } else {
 9720                            ""
 9721                        };
 9722
 9723                    this.buffer.update(cx, |buffer, cx| {
 9724                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9725                    });
 9726                }
 9727            }
 9728
 9729            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9730                s.select_anchor_ranges(cursor_positions)
 9731            });
 9732        });
 9733    }
 9734
 9735    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9736        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9737        self.join_lines_impl(true, window, cx);
 9738    }
 9739
 9740    pub fn sort_lines_case_sensitive(
 9741        &mut self,
 9742        _: &SortLinesCaseSensitive,
 9743        window: &mut Window,
 9744        cx: &mut Context<Self>,
 9745    ) {
 9746        self.manipulate_lines(window, cx, |lines| lines.sort())
 9747    }
 9748
 9749    pub fn sort_lines_case_insensitive(
 9750        &mut self,
 9751        _: &SortLinesCaseInsensitive,
 9752        window: &mut Window,
 9753        cx: &mut Context<Self>,
 9754    ) {
 9755        self.manipulate_lines(window, cx, |lines| {
 9756            lines.sort_by_key(|line| line.to_lowercase())
 9757        })
 9758    }
 9759
 9760    pub fn unique_lines_case_insensitive(
 9761        &mut self,
 9762        _: &UniqueLinesCaseInsensitive,
 9763        window: &mut Window,
 9764        cx: &mut Context<Self>,
 9765    ) {
 9766        self.manipulate_lines(window, cx, |lines| {
 9767            let mut seen = HashSet::default();
 9768            lines.retain(|line| seen.insert(line.to_lowercase()));
 9769        })
 9770    }
 9771
 9772    pub fn unique_lines_case_sensitive(
 9773        &mut self,
 9774        _: &UniqueLinesCaseSensitive,
 9775        window: &mut Window,
 9776        cx: &mut Context<Self>,
 9777    ) {
 9778        self.manipulate_lines(window, cx, |lines| {
 9779            let mut seen = HashSet::default();
 9780            lines.retain(|line| seen.insert(*line));
 9781        })
 9782    }
 9783
 9784    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9785        let Some(project) = self.project.clone() else {
 9786            return;
 9787        };
 9788        self.reload(project, window, cx)
 9789            .detach_and_notify_err(window, cx);
 9790    }
 9791
 9792    pub fn restore_file(
 9793        &mut self,
 9794        _: &::git::RestoreFile,
 9795        window: &mut Window,
 9796        cx: &mut Context<Self>,
 9797    ) {
 9798        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9799        let mut buffer_ids = HashSet::default();
 9800        let snapshot = self.buffer().read(cx).snapshot(cx);
 9801        for selection in self.selections.all::<usize>(cx) {
 9802            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9803        }
 9804
 9805        let buffer = self.buffer().read(cx);
 9806        let ranges = buffer_ids
 9807            .into_iter()
 9808            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9809            .collect::<Vec<_>>();
 9810
 9811        self.restore_hunks_in_ranges(ranges, window, cx);
 9812    }
 9813
 9814    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9815        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9816        let selections = self
 9817            .selections
 9818            .all(cx)
 9819            .into_iter()
 9820            .map(|s| s.range())
 9821            .collect();
 9822        self.restore_hunks_in_ranges(selections, window, cx);
 9823    }
 9824
 9825    pub fn restore_hunks_in_ranges(
 9826        &mut self,
 9827        ranges: Vec<Range<Point>>,
 9828        window: &mut Window,
 9829        cx: &mut Context<Editor>,
 9830    ) {
 9831        let mut revert_changes = HashMap::default();
 9832        let chunk_by = self
 9833            .snapshot(window, cx)
 9834            .hunks_for_ranges(ranges)
 9835            .into_iter()
 9836            .chunk_by(|hunk| hunk.buffer_id);
 9837        for (buffer_id, hunks) in &chunk_by {
 9838            let hunks = hunks.collect::<Vec<_>>();
 9839            for hunk in &hunks {
 9840                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9841            }
 9842            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9843        }
 9844        drop(chunk_by);
 9845        if !revert_changes.is_empty() {
 9846            self.transact(window, cx, |editor, window, cx| {
 9847                editor.restore(revert_changes, window, cx);
 9848            });
 9849        }
 9850    }
 9851
 9852    pub fn open_active_item_in_terminal(
 9853        &mut self,
 9854        _: &OpenInTerminal,
 9855        window: &mut Window,
 9856        cx: &mut Context<Self>,
 9857    ) {
 9858        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9859            let project_path = buffer.read(cx).project_path(cx)?;
 9860            let project = self.project.as_ref()?.read(cx);
 9861            let entry = project.entry_for_path(&project_path, cx)?;
 9862            let parent = match &entry.canonical_path {
 9863                Some(canonical_path) => canonical_path.to_path_buf(),
 9864                None => project.absolute_path(&project_path, cx)?,
 9865            }
 9866            .parent()?
 9867            .to_path_buf();
 9868            Some(parent)
 9869        }) {
 9870            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9871        }
 9872    }
 9873
 9874    fn set_breakpoint_context_menu(
 9875        &mut self,
 9876        display_row: DisplayRow,
 9877        position: Option<Anchor>,
 9878        clicked_point: gpui::Point<Pixels>,
 9879        window: &mut Window,
 9880        cx: &mut Context<Self>,
 9881    ) {
 9882        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9883            return;
 9884        }
 9885        let source = self
 9886            .buffer
 9887            .read(cx)
 9888            .snapshot(cx)
 9889            .anchor_before(Point::new(display_row.0, 0u32));
 9890
 9891        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9892
 9893        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9894            self,
 9895            source,
 9896            clicked_point,
 9897            context_menu,
 9898            window,
 9899            cx,
 9900        );
 9901    }
 9902
 9903    fn add_edit_breakpoint_block(
 9904        &mut self,
 9905        anchor: Anchor,
 9906        breakpoint: &Breakpoint,
 9907        edit_action: BreakpointPromptEditAction,
 9908        window: &mut Window,
 9909        cx: &mut Context<Self>,
 9910    ) {
 9911        let weak_editor = cx.weak_entity();
 9912        let bp_prompt = cx.new(|cx| {
 9913            BreakpointPromptEditor::new(
 9914                weak_editor,
 9915                anchor,
 9916                breakpoint.clone(),
 9917                edit_action,
 9918                window,
 9919                cx,
 9920            )
 9921        });
 9922
 9923        let height = bp_prompt.update(cx, |this, cx| {
 9924            this.prompt
 9925                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9926        });
 9927        let cloned_prompt = bp_prompt.clone();
 9928        let blocks = vec![BlockProperties {
 9929            style: BlockStyle::Sticky,
 9930            placement: BlockPlacement::Above(anchor),
 9931            height: Some(height),
 9932            render: Arc::new(move |cx| {
 9933                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9934                cloned_prompt.clone().into_any_element()
 9935            }),
 9936            priority: 0,
 9937            render_in_minimap: true,
 9938        }];
 9939
 9940        let focus_handle = bp_prompt.focus_handle(cx);
 9941        window.focus(&focus_handle);
 9942
 9943        let block_ids = self.insert_blocks(blocks, None, cx);
 9944        bp_prompt.update(cx, |prompt, _| {
 9945            prompt.add_block_ids(block_ids);
 9946        });
 9947    }
 9948
 9949    pub(crate) fn breakpoint_at_row(
 9950        &self,
 9951        row: u32,
 9952        window: &mut Window,
 9953        cx: &mut Context<Self>,
 9954    ) -> Option<(Anchor, Breakpoint)> {
 9955        let snapshot = self.snapshot(window, cx);
 9956        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9957
 9958        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9959    }
 9960
 9961    pub(crate) fn breakpoint_at_anchor(
 9962        &self,
 9963        breakpoint_position: Anchor,
 9964        snapshot: &EditorSnapshot,
 9965        cx: &mut Context<Self>,
 9966    ) -> Option<(Anchor, Breakpoint)> {
 9967        let project = self.project.clone()?;
 9968
 9969        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9970            snapshot
 9971                .buffer_snapshot
 9972                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9973        })?;
 9974
 9975        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9976        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
 9977        let buffer_snapshot = buffer.read(cx).snapshot();
 9978
 9979        let row = buffer_snapshot
 9980            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9981            .row;
 9982
 9983        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9984        let anchor_end = snapshot
 9985            .buffer_snapshot
 9986            .anchor_after(Point::new(row, line_len));
 9987
 9988        let bp = self
 9989            .breakpoint_store
 9990            .as_ref()?
 9991            .read_with(cx, |breakpoint_store, cx| {
 9992                breakpoint_store
 9993                    .breakpoints(
 9994                        &buffer,
 9995                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9996                        &buffer_snapshot,
 9997                        cx,
 9998                    )
 9999                    .next()
10000                    .and_then(|(bp, _)| {
10001                        let breakpoint_row = buffer_snapshot
10002                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10003                            .row;
10004
10005                        if breakpoint_row == row {
10006                            snapshot
10007                                .buffer_snapshot
10008                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10009                                .map(|position| (position, bp.bp.clone()))
10010                        } else {
10011                            None
10012                        }
10013                    })
10014            });
10015        bp
10016    }
10017
10018    pub fn edit_log_breakpoint(
10019        &mut self,
10020        _: &EditLogBreakpoint,
10021        window: &mut Window,
10022        cx: &mut Context<Self>,
10023    ) {
10024        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10025            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10026                message: None,
10027                state: BreakpointState::Enabled,
10028                condition: None,
10029                hit_condition: None,
10030            });
10031
10032            self.add_edit_breakpoint_block(
10033                anchor,
10034                &breakpoint,
10035                BreakpointPromptEditAction::Log,
10036                window,
10037                cx,
10038            );
10039        }
10040    }
10041
10042    fn breakpoints_at_cursors(
10043        &self,
10044        window: &mut Window,
10045        cx: &mut Context<Self>,
10046    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10047        let snapshot = self.snapshot(window, cx);
10048        let cursors = self
10049            .selections
10050            .disjoint_anchors()
10051            .into_iter()
10052            .map(|selection| {
10053                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10054
10055                let breakpoint_position = self
10056                    .breakpoint_at_row(cursor_position.row, window, cx)
10057                    .map(|bp| bp.0)
10058                    .unwrap_or_else(|| {
10059                        snapshot
10060                            .display_snapshot
10061                            .buffer_snapshot
10062                            .anchor_after(Point::new(cursor_position.row, 0))
10063                    });
10064
10065                let breakpoint = self
10066                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10067                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10068
10069                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10070            })
10071            // 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.
10072            .collect::<HashMap<Anchor, _>>();
10073
10074        cursors.into_iter().collect()
10075    }
10076
10077    pub fn enable_breakpoint(
10078        &mut self,
10079        _: &crate::actions::EnableBreakpoint,
10080        window: &mut Window,
10081        cx: &mut Context<Self>,
10082    ) {
10083        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10084            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10085                continue;
10086            };
10087            self.edit_breakpoint_at_anchor(
10088                anchor,
10089                breakpoint,
10090                BreakpointEditAction::InvertState,
10091                cx,
10092            );
10093        }
10094    }
10095
10096    pub fn disable_breakpoint(
10097        &mut self,
10098        _: &crate::actions::DisableBreakpoint,
10099        window: &mut Window,
10100        cx: &mut Context<Self>,
10101    ) {
10102        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10103            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10104                continue;
10105            };
10106            self.edit_breakpoint_at_anchor(
10107                anchor,
10108                breakpoint,
10109                BreakpointEditAction::InvertState,
10110                cx,
10111            );
10112        }
10113    }
10114
10115    pub fn toggle_breakpoint(
10116        &mut self,
10117        _: &crate::actions::ToggleBreakpoint,
10118        window: &mut Window,
10119        cx: &mut Context<Self>,
10120    ) {
10121        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10122            if let Some(breakpoint) = breakpoint {
10123                self.edit_breakpoint_at_anchor(
10124                    anchor,
10125                    breakpoint,
10126                    BreakpointEditAction::Toggle,
10127                    cx,
10128                );
10129            } else {
10130                self.edit_breakpoint_at_anchor(
10131                    anchor,
10132                    Breakpoint::new_standard(),
10133                    BreakpointEditAction::Toggle,
10134                    cx,
10135                );
10136            }
10137        }
10138    }
10139
10140    pub fn edit_breakpoint_at_anchor(
10141        &mut self,
10142        breakpoint_position: Anchor,
10143        breakpoint: Breakpoint,
10144        edit_action: BreakpointEditAction,
10145        cx: &mut Context<Self>,
10146    ) {
10147        let Some(breakpoint_store) = &self.breakpoint_store else {
10148            return;
10149        };
10150
10151        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10152            if breakpoint_position == Anchor::min() {
10153                self.buffer()
10154                    .read(cx)
10155                    .excerpt_buffer_ids()
10156                    .into_iter()
10157                    .next()
10158            } else {
10159                None
10160            }
10161        }) else {
10162            return;
10163        };
10164
10165        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10166            return;
10167        };
10168
10169        breakpoint_store.update(cx, |breakpoint_store, cx| {
10170            breakpoint_store.toggle_breakpoint(
10171                buffer,
10172                BreakpointWithPosition {
10173                    position: breakpoint_position.text_anchor,
10174                    bp: breakpoint,
10175                },
10176                edit_action,
10177                cx,
10178            );
10179        });
10180
10181        cx.notify();
10182    }
10183
10184    #[cfg(any(test, feature = "test-support"))]
10185    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10186        self.breakpoint_store.clone()
10187    }
10188
10189    pub fn prepare_restore_change(
10190        &self,
10191        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10192        hunk: &MultiBufferDiffHunk,
10193        cx: &mut App,
10194    ) -> Option<()> {
10195        if hunk.is_created_file() {
10196            return None;
10197        }
10198        let buffer = self.buffer.read(cx);
10199        let diff = buffer.diff_for(hunk.buffer_id)?;
10200        let buffer = buffer.buffer(hunk.buffer_id)?;
10201        let buffer = buffer.read(cx);
10202        let original_text = diff
10203            .read(cx)
10204            .base_text()
10205            .as_rope()
10206            .slice(hunk.diff_base_byte_range.clone());
10207        let buffer_snapshot = buffer.snapshot();
10208        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10209        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10210            probe
10211                .0
10212                .start
10213                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10214                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10215        }) {
10216            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10217            Some(())
10218        } else {
10219            None
10220        }
10221    }
10222
10223    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10224        self.manipulate_lines(window, cx, |lines| lines.reverse())
10225    }
10226
10227    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10228        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10229    }
10230
10231    fn manipulate_lines<Fn>(
10232        &mut self,
10233        window: &mut Window,
10234        cx: &mut Context<Self>,
10235        mut callback: Fn,
10236    ) where
10237        Fn: FnMut(&mut Vec<&str>),
10238    {
10239        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10240
10241        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10242        let buffer = self.buffer.read(cx).snapshot(cx);
10243
10244        let mut edits = Vec::new();
10245
10246        let selections = self.selections.all::<Point>(cx);
10247        let mut selections = selections.iter().peekable();
10248        let mut contiguous_row_selections = Vec::new();
10249        let mut new_selections = Vec::new();
10250        let mut added_lines = 0;
10251        let mut removed_lines = 0;
10252
10253        while let Some(selection) = selections.next() {
10254            let (start_row, end_row) = consume_contiguous_rows(
10255                &mut contiguous_row_selections,
10256                selection,
10257                &display_map,
10258                &mut selections,
10259            );
10260
10261            let start_point = Point::new(start_row.0, 0);
10262            let end_point = Point::new(
10263                end_row.previous_row().0,
10264                buffer.line_len(end_row.previous_row()),
10265            );
10266            let text = buffer
10267                .text_for_range(start_point..end_point)
10268                .collect::<String>();
10269
10270            let mut lines = text.split('\n').collect_vec();
10271
10272            let lines_before = lines.len();
10273            callback(&mut lines);
10274            let lines_after = lines.len();
10275
10276            edits.push((start_point..end_point, lines.join("\n")));
10277
10278            // Selections must change based on added and removed line count
10279            let start_row =
10280                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10281            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10282            new_selections.push(Selection {
10283                id: selection.id,
10284                start: start_row,
10285                end: end_row,
10286                goal: SelectionGoal::None,
10287                reversed: selection.reversed,
10288            });
10289
10290            if lines_after > lines_before {
10291                added_lines += lines_after - lines_before;
10292            } else if lines_before > lines_after {
10293                removed_lines += lines_before - lines_after;
10294            }
10295        }
10296
10297        self.transact(window, cx, |this, window, cx| {
10298            let buffer = this.buffer.update(cx, |buffer, cx| {
10299                buffer.edit(edits, None, cx);
10300                buffer.snapshot(cx)
10301            });
10302
10303            // Recalculate offsets on newly edited buffer
10304            let new_selections = new_selections
10305                .iter()
10306                .map(|s| {
10307                    let start_point = Point::new(s.start.0, 0);
10308                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10309                    Selection {
10310                        id: s.id,
10311                        start: buffer.point_to_offset(start_point),
10312                        end: buffer.point_to_offset(end_point),
10313                        goal: s.goal,
10314                        reversed: s.reversed,
10315                    }
10316                })
10317                .collect();
10318
10319            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10320                s.select(new_selections);
10321            });
10322
10323            this.request_autoscroll(Autoscroll::fit(), cx);
10324        });
10325    }
10326
10327    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10328        self.manipulate_text(window, cx, |text| {
10329            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10330            if has_upper_case_characters {
10331                text.to_lowercase()
10332            } else {
10333                text.to_uppercase()
10334            }
10335        })
10336    }
10337
10338    pub fn convert_to_upper_case(
10339        &mut self,
10340        _: &ConvertToUpperCase,
10341        window: &mut Window,
10342        cx: &mut Context<Self>,
10343    ) {
10344        self.manipulate_text(window, cx, |text| text.to_uppercase())
10345    }
10346
10347    pub fn convert_to_lower_case(
10348        &mut self,
10349        _: &ConvertToLowerCase,
10350        window: &mut Window,
10351        cx: &mut Context<Self>,
10352    ) {
10353        self.manipulate_text(window, cx, |text| text.to_lowercase())
10354    }
10355
10356    pub fn convert_to_title_case(
10357        &mut self,
10358        _: &ConvertToTitleCase,
10359        window: &mut Window,
10360        cx: &mut Context<Self>,
10361    ) {
10362        self.manipulate_text(window, cx, |text| {
10363            text.split('\n')
10364                .map(|line| line.to_case(Case::Title))
10365                .join("\n")
10366        })
10367    }
10368
10369    pub fn convert_to_snake_case(
10370        &mut self,
10371        _: &ConvertToSnakeCase,
10372        window: &mut Window,
10373        cx: &mut Context<Self>,
10374    ) {
10375        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10376    }
10377
10378    pub fn convert_to_kebab_case(
10379        &mut self,
10380        _: &ConvertToKebabCase,
10381        window: &mut Window,
10382        cx: &mut Context<Self>,
10383    ) {
10384        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10385    }
10386
10387    pub fn convert_to_upper_camel_case(
10388        &mut self,
10389        _: &ConvertToUpperCamelCase,
10390        window: &mut Window,
10391        cx: &mut Context<Self>,
10392    ) {
10393        self.manipulate_text(window, cx, |text| {
10394            text.split('\n')
10395                .map(|line| line.to_case(Case::UpperCamel))
10396                .join("\n")
10397        })
10398    }
10399
10400    pub fn convert_to_lower_camel_case(
10401        &mut self,
10402        _: &ConvertToLowerCamelCase,
10403        window: &mut Window,
10404        cx: &mut Context<Self>,
10405    ) {
10406        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10407    }
10408
10409    pub fn convert_to_opposite_case(
10410        &mut self,
10411        _: &ConvertToOppositeCase,
10412        window: &mut Window,
10413        cx: &mut Context<Self>,
10414    ) {
10415        self.manipulate_text(window, cx, |text| {
10416            text.chars()
10417                .fold(String::with_capacity(text.len()), |mut t, c| {
10418                    if c.is_uppercase() {
10419                        t.extend(c.to_lowercase());
10420                    } else {
10421                        t.extend(c.to_uppercase());
10422                    }
10423                    t
10424                })
10425        })
10426    }
10427
10428    pub fn convert_to_rot13(
10429        &mut self,
10430        _: &ConvertToRot13,
10431        window: &mut Window,
10432        cx: &mut Context<Self>,
10433    ) {
10434        self.manipulate_text(window, cx, |text| {
10435            text.chars()
10436                .map(|c| match c {
10437                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10438                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10439                    _ => c,
10440                })
10441                .collect()
10442        })
10443    }
10444
10445    pub fn convert_to_rot47(
10446        &mut self,
10447        _: &ConvertToRot47,
10448        window: &mut Window,
10449        cx: &mut Context<Self>,
10450    ) {
10451        self.manipulate_text(window, cx, |text| {
10452            text.chars()
10453                .map(|c| {
10454                    let code_point = c as u32;
10455                    if code_point >= 33 && code_point <= 126 {
10456                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10457                    }
10458                    c
10459                })
10460                .collect()
10461        })
10462    }
10463
10464    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10465    where
10466        Fn: FnMut(&str) -> String,
10467    {
10468        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10469        let buffer = self.buffer.read(cx).snapshot(cx);
10470
10471        let mut new_selections = Vec::new();
10472        let mut edits = Vec::new();
10473        let mut selection_adjustment = 0i32;
10474
10475        for selection in self.selections.all::<usize>(cx) {
10476            let selection_is_empty = selection.is_empty();
10477
10478            let (start, end) = if selection_is_empty {
10479                let word_range = movement::surrounding_word(
10480                    &display_map,
10481                    selection.start.to_display_point(&display_map),
10482                );
10483                let start = word_range.start.to_offset(&display_map, Bias::Left);
10484                let end = word_range.end.to_offset(&display_map, Bias::Left);
10485                (start, end)
10486            } else {
10487                (selection.start, selection.end)
10488            };
10489
10490            let text = buffer.text_for_range(start..end).collect::<String>();
10491            let old_length = text.len() as i32;
10492            let text = callback(&text);
10493
10494            new_selections.push(Selection {
10495                start: (start as i32 - selection_adjustment) as usize,
10496                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10497                goal: SelectionGoal::None,
10498                ..selection
10499            });
10500
10501            selection_adjustment += old_length - text.len() as i32;
10502
10503            edits.push((start..end, text));
10504        }
10505
10506        self.transact(window, cx, |this, window, cx| {
10507            this.buffer.update(cx, |buffer, cx| {
10508                buffer.edit(edits, None, cx);
10509            });
10510
10511            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10512                s.select(new_selections);
10513            });
10514
10515            this.request_autoscroll(Autoscroll::fit(), cx);
10516        });
10517    }
10518
10519    pub fn duplicate(
10520        &mut self,
10521        upwards: bool,
10522        whole_lines: bool,
10523        window: &mut Window,
10524        cx: &mut Context<Self>,
10525    ) {
10526        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10527
10528        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10529        let buffer = &display_map.buffer_snapshot;
10530        let selections = self.selections.all::<Point>(cx);
10531
10532        let mut edits = Vec::new();
10533        let mut selections_iter = selections.iter().peekable();
10534        while let Some(selection) = selections_iter.next() {
10535            let mut rows = selection.spanned_rows(false, &display_map);
10536            // duplicate line-wise
10537            if whole_lines || selection.start == selection.end {
10538                // Avoid duplicating the same lines twice.
10539                while let Some(next_selection) = selections_iter.peek() {
10540                    let next_rows = next_selection.spanned_rows(false, &display_map);
10541                    if next_rows.start < rows.end {
10542                        rows.end = next_rows.end;
10543                        selections_iter.next().unwrap();
10544                    } else {
10545                        break;
10546                    }
10547                }
10548
10549                // Copy the text from the selected row region and splice it either at the start
10550                // or end of the region.
10551                let start = Point::new(rows.start.0, 0);
10552                let end = Point::new(
10553                    rows.end.previous_row().0,
10554                    buffer.line_len(rows.end.previous_row()),
10555                );
10556                let text = buffer
10557                    .text_for_range(start..end)
10558                    .chain(Some("\n"))
10559                    .collect::<String>();
10560                let insert_location = if upwards {
10561                    Point::new(rows.end.0, 0)
10562                } else {
10563                    start
10564                };
10565                edits.push((insert_location..insert_location, text));
10566            } else {
10567                // duplicate character-wise
10568                let start = selection.start;
10569                let end = selection.end;
10570                let text = buffer.text_for_range(start..end).collect::<String>();
10571                edits.push((selection.end..selection.end, text));
10572            }
10573        }
10574
10575        self.transact(window, cx, |this, _, cx| {
10576            this.buffer.update(cx, |buffer, cx| {
10577                buffer.edit(edits, None, cx);
10578            });
10579
10580            this.request_autoscroll(Autoscroll::fit(), cx);
10581        });
10582    }
10583
10584    pub fn duplicate_line_up(
10585        &mut self,
10586        _: &DuplicateLineUp,
10587        window: &mut Window,
10588        cx: &mut Context<Self>,
10589    ) {
10590        self.duplicate(true, true, window, cx);
10591    }
10592
10593    pub fn duplicate_line_down(
10594        &mut self,
10595        _: &DuplicateLineDown,
10596        window: &mut Window,
10597        cx: &mut Context<Self>,
10598    ) {
10599        self.duplicate(false, true, window, cx);
10600    }
10601
10602    pub fn duplicate_selection(
10603        &mut self,
10604        _: &DuplicateSelection,
10605        window: &mut Window,
10606        cx: &mut Context<Self>,
10607    ) {
10608        self.duplicate(false, false, window, cx);
10609    }
10610
10611    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10612        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10613
10614        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10615        let buffer = self.buffer.read(cx).snapshot(cx);
10616
10617        let mut edits = Vec::new();
10618        let mut unfold_ranges = Vec::new();
10619        let mut refold_creases = Vec::new();
10620
10621        let selections = self.selections.all::<Point>(cx);
10622        let mut selections = selections.iter().peekable();
10623        let mut contiguous_row_selections = Vec::new();
10624        let mut new_selections = Vec::new();
10625
10626        while let Some(selection) = selections.next() {
10627            // Find all the selections that span a contiguous row range
10628            let (start_row, end_row) = consume_contiguous_rows(
10629                &mut contiguous_row_selections,
10630                selection,
10631                &display_map,
10632                &mut selections,
10633            );
10634
10635            // Move the text spanned by the row range to be before the line preceding the row range
10636            if start_row.0 > 0 {
10637                let range_to_move = Point::new(
10638                    start_row.previous_row().0,
10639                    buffer.line_len(start_row.previous_row()),
10640                )
10641                    ..Point::new(
10642                        end_row.previous_row().0,
10643                        buffer.line_len(end_row.previous_row()),
10644                    );
10645                let insertion_point = display_map
10646                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10647                    .0;
10648
10649                // Don't move lines across excerpts
10650                if buffer
10651                    .excerpt_containing(insertion_point..range_to_move.end)
10652                    .is_some()
10653                {
10654                    let text = buffer
10655                        .text_for_range(range_to_move.clone())
10656                        .flat_map(|s| s.chars())
10657                        .skip(1)
10658                        .chain(['\n'])
10659                        .collect::<String>();
10660
10661                    edits.push((
10662                        buffer.anchor_after(range_to_move.start)
10663                            ..buffer.anchor_before(range_to_move.end),
10664                        String::new(),
10665                    ));
10666                    let insertion_anchor = buffer.anchor_after(insertion_point);
10667                    edits.push((insertion_anchor..insertion_anchor, text));
10668
10669                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10670
10671                    // Move selections up
10672                    new_selections.extend(contiguous_row_selections.drain(..).map(
10673                        |mut selection| {
10674                            selection.start.row -= row_delta;
10675                            selection.end.row -= row_delta;
10676                            selection
10677                        },
10678                    ));
10679
10680                    // Move folds up
10681                    unfold_ranges.push(range_to_move.clone());
10682                    for fold in display_map.folds_in_range(
10683                        buffer.anchor_before(range_to_move.start)
10684                            ..buffer.anchor_after(range_to_move.end),
10685                    ) {
10686                        let mut start = fold.range.start.to_point(&buffer);
10687                        let mut end = fold.range.end.to_point(&buffer);
10688                        start.row -= row_delta;
10689                        end.row -= row_delta;
10690                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10691                    }
10692                }
10693            }
10694
10695            // If we didn't move line(s), preserve the existing selections
10696            new_selections.append(&mut contiguous_row_selections);
10697        }
10698
10699        self.transact(window, cx, |this, window, cx| {
10700            this.unfold_ranges(&unfold_ranges, true, true, cx);
10701            this.buffer.update(cx, |buffer, cx| {
10702                for (range, text) in edits {
10703                    buffer.edit([(range, text)], None, cx);
10704                }
10705            });
10706            this.fold_creases(refold_creases, true, window, cx);
10707            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10708                s.select(new_selections);
10709            })
10710        });
10711    }
10712
10713    pub fn move_line_down(
10714        &mut self,
10715        _: &MoveLineDown,
10716        window: &mut Window,
10717        cx: &mut Context<Self>,
10718    ) {
10719        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10720
10721        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10722        let buffer = self.buffer.read(cx).snapshot(cx);
10723
10724        let mut edits = Vec::new();
10725        let mut unfold_ranges = Vec::new();
10726        let mut refold_creases = Vec::new();
10727
10728        let selections = self.selections.all::<Point>(cx);
10729        let mut selections = selections.iter().peekable();
10730        let mut contiguous_row_selections = Vec::new();
10731        let mut new_selections = Vec::new();
10732
10733        while let Some(selection) = selections.next() {
10734            // Find all the selections that span a contiguous row range
10735            let (start_row, end_row) = consume_contiguous_rows(
10736                &mut contiguous_row_selections,
10737                selection,
10738                &display_map,
10739                &mut selections,
10740            );
10741
10742            // Move the text spanned by the row range to be after the last line of the row range
10743            if end_row.0 <= buffer.max_point().row {
10744                let range_to_move =
10745                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10746                let insertion_point = display_map
10747                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10748                    .0;
10749
10750                // Don't move lines across excerpt boundaries
10751                if buffer
10752                    .excerpt_containing(range_to_move.start..insertion_point)
10753                    .is_some()
10754                {
10755                    let mut text = String::from("\n");
10756                    text.extend(buffer.text_for_range(range_to_move.clone()));
10757                    text.pop(); // Drop trailing newline
10758                    edits.push((
10759                        buffer.anchor_after(range_to_move.start)
10760                            ..buffer.anchor_before(range_to_move.end),
10761                        String::new(),
10762                    ));
10763                    let insertion_anchor = buffer.anchor_after(insertion_point);
10764                    edits.push((insertion_anchor..insertion_anchor, text));
10765
10766                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10767
10768                    // Move selections down
10769                    new_selections.extend(contiguous_row_selections.drain(..).map(
10770                        |mut selection| {
10771                            selection.start.row += row_delta;
10772                            selection.end.row += row_delta;
10773                            selection
10774                        },
10775                    ));
10776
10777                    // Move folds down
10778                    unfold_ranges.push(range_to_move.clone());
10779                    for fold in display_map.folds_in_range(
10780                        buffer.anchor_before(range_to_move.start)
10781                            ..buffer.anchor_after(range_to_move.end),
10782                    ) {
10783                        let mut start = fold.range.start.to_point(&buffer);
10784                        let mut end = fold.range.end.to_point(&buffer);
10785                        start.row += row_delta;
10786                        end.row += row_delta;
10787                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10788                    }
10789                }
10790            }
10791
10792            // If we didn't move line(s), preserve the existing selections
10793            new_selections.append(&mut contiguous_row_selections);
10794        }
10795
10796        self.transact(window, cx, |this, window, cx| {
10797            this.unfold_ranges(&unfold_ranges, true, true, cx);
10798            this.buffer.update(cx, |buffer, cx| {
10799                for (range, text) in edits {
10800                    buffer.edit([(range, text)], None, cx);
10801                }
10802            });
10803            this.fold_creases(refold_creases, true, window, cx);
10804            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10805                s.select(new_selections)
10806            });
10807        });
10808    }
10809
10810    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10811        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10812        let text_layout_details = &self.text_layout_details(window);
10813        self.transact(window, cx, |this, window, cx| {
10814            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10815                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10816                s.move_with(|display_map, selection| {
10817                    if !selection.is_empty() {
10818                        return;
10819                    }
10820
10821                    let mut head = selection.head();
10822                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10823                    if head.column() == display_map.line_len(head.row()) {
10824                        transpose_offset = display_map
10825                            .buffer_snapshot
10826                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10827                    }
10828
10829                    if transpose_offset == 0 {
10830                        return;
10831                    }
10832
10833                    *head.column_mut() += 1;
10834                    head = display_map.clip_point(head, Bias::Right);
10835                    let goal = SelectionGoal::HorizontalPosition(
10836                        display_map
10837                            .x_for_display_point(head, text_layout_details)
10838                            .into(),
10839                    );
10840                    selection.collapse_to(head, goal);
10841
10842                    let transpose_start = display_map
10843                        .buffer_snapshot
10844                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10845                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10846                        let transpose_end = display_map
10847                            .buffer_snapshot
10848                            .clip_offset(transpose_offset + 1, Bias::Right);
10849                        if let Some(ch) =
10850                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10851                        {
10852                            edits.push((transpose_start..transpose_offset, String::new()));
10853                            edits.push((transpose_end..transpose_end, ch.to_string()));
10854                        }
10855                    }
10856                });
10857                edits
10858            });
10859            this.buffer
10860                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10861            let selections = this.selections.all::<usize>(cx);
10862            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10863                s.select(selections);
10864            });
10865        });
10866    }
10867
10868    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10869        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10870        self.rewrap_impl(RewrapOptions::default(), cx)
10871    }
10872
10873    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10874        let buffer = self.buffer.read(cx).snapshot(cx);
10875        let selections = self.selections.all::<Point>(cx);
10876        let mut selections = selections.iter().peekable();
10877
10878        let mut edits = Vec::new();
10879        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10880
10881        while let Some(selection) = selections.next() {
10882            let mut start_row = selection.start.row;
10883            let mut end_row = selection.end.row;
10884
10885            // Skip selections that overlap with a range that has already been rewrapped.
10886            let selection_range = start_row..end_row;
10887            if rewrapped_row_ranges
10888                .iter()
10889                .any(|range| range.overlaps(&selection_range))
10890            {
10891                continue;
10892            }
10893
10894            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10895
10896            // Since not all lines in the selection may be at the same indent
10897            // level, choose the indent size that is the most common between all
10898            // of the lines.
10899            //
10900            // If there is a tie, we use the deepest indent.
10901            let (indent_size, indent_end) = {
10902                let mut indent_size_occurrences = HashMap::default();
10903                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10904
10905                for row in start_row..=end_row {
10906                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10907                    rows_by_indent_size.entry(indent).or_default().push(row);
10908                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10909                }
10910
10911                let indent_size = indent_size_occurrences
10912                    .into_iter()
10913                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10914                    .map(|(indent, _)| indent)
10915                    .unwrap_or_default();
10916                let row = rows_by_indent_size[&indent_size][0];
10917                let indent_end = Point::new(row, indent_size.len);
10918
10919                (indent_size, indent_end)
10920            };
10921
10922            let mut line_prefix = indent_size.chars().collect::<String>();
10923
10924            let mut inside_comment = false;
10925            if let Some(comment_prefix) =
10926                buffer
10927                    .language_scope_at(selection.head())
10928                    .and_then(|language| {
10929                        language
10930                            .line_comment_prefixes()
10931                            .iter()
10932                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10933                            .cloned()
10934                    })
10935            {
10936                line_prefix.push_str(&comment_prefix);
10937                inside_comment = true;
10938            }
10939
10940            let language_settings = buffer.language_settings_at(selection.head(), cx);
10941            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10942                RewrapBehavior::InComments => inside_comment,
10943                RewrapBehavior::InSelections => !selection.is_empty(),
10944                RewrapBehavior::Anywhere => true,
10945            };
10946
10947            let should_rewrap = options.override_language_settings
10948                || allow_rewrap_based_on_language
10949                || self.hard_wrap.is_some();
10950            if !should_rewrap {
10951                continue;
10952            }
10953
10954            if selection.is_empty() {
10955                'expand_upwards: while start_row > 0 {
10956                    let prev_row = start_row - 1;
10957                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10958                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10959                    {
10960                        start_row = prev_row;
10961                    } else {
10962                        break 'expand_upwards;
10963                    }
10964                }
10965
10966                'expand_downwards: while end_row < buffer.max_point().row {
10967                    let next_row = end_row + 1;
10968                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10969                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10970                    {
10971                        end_row = next_row;
10972                    } else {
10973                        break 'expand_downwards;
10974                    }
10975                }
10976            }
10977
10978            let start = Point::new(start_row, 0);
10979            let start_offset = start.to_offset(&buffer);
10980            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10981            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10982            let Some(lines_without_prefixes) = selection_text
10983                .lines()
10984                .map(|line| {
10985                    line.strip_prefix(&line_prefix)
10986                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10987                        .with_context(|| {
10988                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10989                        })
10990                })
10991                .collect::<Result<Vec<_>, _>>()
10992                .log_err()
10993            else {
10994                continue;
10995            };
10996
10997            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10998                buffer
10999                    .language_settings_at(Point::new(start_row, 0), cx)
11000                    .preferred_line_length as usize
11001            });
11002            let wrapped_text = wrap_with_prefix(
11003                line_prefix,
11004                lines_without_prefixes.join("\n"),
11005                wrap_column,
11006                tab_size,
11007                options.preserve_existing_whitespace,
11008            );
11009
11010            // TODO: should always use char-based diff while still supporting cursor behavior that
11011            // matches vim.
11012            let mut diff_options = DiffOptions::default();
11013            if options.override_language_settings {
11014                diff_options.max_word_diff_len = 0;
11015                diff_options.max_word_diff_line_count = 0;
11016            } else {
11017                diff_options.max_word_diff_len = usize::MAX;
11018                diff_options.max_word_diff_line_count = usize::MAX;
11019            }
11020
11021            for (old_range, new_text) in
11022                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11023            {
11024                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11025                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11026                edits.push((edit_start..edit_end, new_text));
11027            }
11028
11029            rewrapped_row_ranges.push(start_row..=end_row);
11030        }
11031
11032        self.buffer
11033            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11034    }
11035
11036    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11037        let mut text = String::new();
11038        let buffer = self.buffer.read(cx).snapshot(cx);
11039        let mut selections = self.selections.all::<Point>(cx);
11040        let mut clipboard_selections = Vec::with_capacity(selections.len());
11041        {
11042            let max_point = buffer.max_point();
11043            let mut is_first = true;
11044            for selection in &mut selections {
11045                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11046                if is_entire_line {
11047                    selection.start = Point::new(selection.start.row, 0);
11048                    if !selection.is_empty() && selection.end.column == 0 {
11049                        selection.end = cmp::min(max_point, selection.end);
11050                    } else {
11051                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11052                    }
11053                    selection.goal = SelectionGoal::None;
11054                }
11055                if is_first {
11056                    is_first = false;
11057                } else {
11058                    text += "\n";
11059                }
11060                let mut len = 0;
11061                for chunk in buffer.text_for_range(selection.start..selection.end) {
11062                    text.push_str(chunk);
11063                    len += chunk.len();
11064                }
11065                clipboard_selections.push(ClipboardSelection {
11066                    len,
11067                    is_entire_line,
11068                    first_line_indent: buffer
11069                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11070                        .len,
11071                });
11072            }
11073        }
11074
11075        self.transact(window, cx, |this, window, cx| {
11076            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11077                s.select(selections);
11078            });
11079            this.insert("", window, cx);
11080        });
11081        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11082    }
11083
11084    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11085        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11086        let item = self.cut_common(window, cx);
11087        cx.write_to_clipboard(item);
11088    }
11089
11090    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11091        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11092        self.change_selections(None, window, cx, |s| {
11093            s.move_with(|snapshot, sel| {
11094                if sel.is_empty() {
11095                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11096                }
11097            });
11098        });
11099        let item = self.cut_common(window, cx);
11100        cx.set_global(KillRing(item))
11101    }
11102
11103    pub fn kill_ring_yank(
11104        &mut self,
11105        _: &KillRingYank,
11106        window: &mut Window,
11107        cx: &mut Context<Self>,
11108    ) {
11109        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11110        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11111            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11112                (kill_ring.text().to_string(), kill_ring.metadata_json())
11113            } else {
11114                return;
11115            }
11116        } else {
11117            return;
11118        };
11119        self.do_paste(&text, metadata, false, window, cx);
11120    }
11121
11122    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11123        self.do_copy(true, cx);
11124    }
11125
11126    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11127        self.do_copy(false, cx);
11128    }
11129
11130    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11131        let selections = self.selections.all::<Point>(cx);
11132        let buffer = self.buffer.read(cx).read(cx);
11133        let mut text = String::new();
11134
11135        let mut clipboard_selections = Vec::with_capacity(selections.len());
11136        {
11137            let max_point = buffer.max_point();
11138            let mut is_first = true;
11139            for selection in &selections {
11140                let mut start = selection.start;
11141                let mut end = selection.end;
11142                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11143                if is_entire_line {
11144                    start = Point::new(start.row, 0);
11145                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11146                }
11147
11148                let mut trimmed_selections = Vec::new();
11149                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11150                    let row = MultiBufferRow(start.row);
11151                    let first_indent = buffer.indent_size_for_line(row);
11152                    if first_indent.len == 0 || start.column > first_indent.len {
11153                        trimmed_selections.push(start..end);
11154                    } else {
11155                        trimmed_selections.push(
11156                            Point::new(row.0, first_indent.len)
11157                                ..Point::new(row.0, buffer.line_len(row)),
11158                        );
11159                        for row in start.row + 1..=end.row {
11160                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11161                            if row == end.row {
11162                                line_len = end.column;
11163                            }
11164                            if line_len == 0 {
11165                                trimmed_selections
11166                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11167                                continue;
11168                            }
11169                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11170                            if row_indent_size.len >= first_indent.len {
11171                                trimmed_selections.push(
11172                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11173                                );
11174                            } else {
11175                                trimmed_selections.clear();
11176                                trimmed_selections.push(start..end);
11177                                break;
11178                            }
11179                        }
11180                    }
11181                } else {
11182                    trimmed_selections.push(start..end);
11183                }
11184
11185                for trimmed_range in trimmed_selections {
11186                    if is_first {
11187                        is_first = false;
11188                    } else {
11189                        text += "\n";
11190                    }
11191                    let mut len = 0;
11192                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11193                        text.push_str(chunk);
11194                        len += chunk.len();
11195                    }
11196                    clipboard_selections.push(ClipboardSelection {
11197                        len,
11198                        is_entire_line,
11199                        first_line_indent: buffer
11200                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11201                            .len,
11202                    });
11203                }
11204            }
11205        }
11206
11207        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11208            text,
11209            clipboard_selections,
11210        ));
11211    }
11212
11213    pub fn do_paste(
11214        &mut self,
11215        text: &String,
11216        clipboard_selections: Option<Vec<ClipboardSelection>>,
11217        handle_entire_lines: bool,
11218        window: &mut Window,
11219        cx: &mut Context<Self>,
11220    ) {
11221        if self.read_only(cx) {
11222            return;
11223        }
11224
11225        let clipboard_text = Cow::Borrowed(text);
11226
11227        self.transact(window, cx, |this, window, cx| {
11228            if let Some(mut clipboard_selections) = clipboard_selections {
11229                let old_selections = this.selections.all::<usize>(cx);
11230                let all_selections_were_entire_line =
11231                    clipboard_selections.iter().all(|s| s.is_entire_line);
11232                let first_selection_indent_column =
11233                    clipboard_selections.first().map(|s| s.first_line_indent);
11234                if clipboard_selections.len() != old_selections.len() {
11235                    clipboard_selections.drain(..);
11236                }
11237                let cursor_offset = this.selections.last::<usize>(cx).head();
11238                let mut auto_indent_on_paste = true;
11239
11240                this.buffer.update(cx, |buffer, cx| {
11241                    let snapshot = buffer.read(cx);
11242                    auto_indent_on_paste = snapshot
11243                        .language_settings_at(cursor_offset, cx)
11244                        .auto_indent_on_paste;
11245
11246                    let mut start_offset = 0;
11247                    let mut edits = Vec::new();
11248                    let mut original_indent_columns = Vec::new();
11249                    for (ix, selection) in old_selections.iter().enumerate() {
11250                        let to_insert;
11251                        let entire_line;
11252                        let original_indent_column;
11253                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11254                            let end_offset = start_offset + clipboard_selection.len;
11255                            to_insert = &clipboard_text[start_offset..end_offset];
11256                            entire_line = clipboard_selection.is_entire_line;
11257                            start_offset = end_offset + 1;
11258                            original_indent_column = Some(clipboard_selection.first_line_indent);
11259                        } else {
11260                            to_insert = clipboard_text.as_str();
11261                            entire_line = all_selections_were_entire_line;
11262                            original_indent_column = first_selection_indent_column
11263                        }
11264
11265                        // If the corresponding selection was empty when this slice of the
11266                        // clipboard text was written, then the entire line containing the
11267                        // selection was copied. If this selection is also currently empty,
11268                        // then paste the line before the current line of the buffer.
11269                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11270                            let column = selection.start.to_point(&snapshot).column as usize;
11271                            let line_start = selection.start - column;
11272                            line_start..line_start
11273                        } else {
11274                            selection.range()
11275                        };
11276
11277                        edits.push((range, to_insert));
11278                        original_indent_columns.push(original_indent_column);
11279                    }
11280                    drop(snapshot);
11281
11282                    buffer.edit(
11283                        edits,
11284                        if auto_indent_on_paste {
11285                            Some(AutoindentMode::Block {
11286                                original_indent_columns,
11287                            })
11288                        } else {
11289                            None
11290                        },
11291                        cx,
11292                    );
11293                });
11294
11295                let selections = this.selections.all::<usize>(cx);
11296                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11297                    s.select(selections)
11298                });
11299            } else {
11300                this.insert(&clipboard_text, window, cx);
11301            }
11302        });
11303    }
11304
11305    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11306        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11307        if let Some(item) = cx.read_from_clipboard() {
11308            let entries = item.entries();
11309
11310            match entries.first() {
11311                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11312                // of all the pasted entries.
11313                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11314                    .do_paste(
11315                        clipboard_string.text(),
11316                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11317                        true,
11318                        window,
11319                        cx,
11320                    ),
11321                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11322            }
11323        }
11324    }
11325
11326    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11327        if self.read_only(cx) {
11328            return;
11329        }
11330
11331        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11332
11333        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11334            if let Some((selections, _)) =
11335                self.selection_history.transaction(transaction_id).cloned()
11336            {
11337                self.change_selections(None, window, cx, |s| {
11338                    s.select_anchors(selections.to_vec());
11339                });
11340            } else {
11341                log::error!(
11342                    "No entry in selection_history found for undo. \
11343                     This may correspond to a bug where undo does not update the selection. \
11344                     If this is occurring, please add details to \
11345                     https://github.com/zed-industries/zed/issues/22692"
11346                );
11347            }
11348            self.request_autoscroll(Autoscroll::fit(), cx);
11349            self.unmark_text(window, cx);
11350            self.refresh_inline_completion(true, false, window, cx);
11351            cx.emit(EditorEvent::Edited { transaction_id });
11352            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11353        }
11354    }
11355
11356    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11357        if self.read_only(cx) {
11358            return;
11359        }
11360
11361        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11362
11363        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11364            if let Some((_, Some(selections))) =
11365                self.selection_history.transaction(transaction_id).cloned()
11366            {
11367                self.change_selections(None, window, cx, |s| {
11368                    s.select_anchors(selections.to_vec());
11369                });
11370            } else {
11371                log::error!(
11372                    "No entry in selection_history found for redo. \
11373                     This may correspond to a bug where undo does not update the selection. \
11374                     If this is occurring, please add details to \
11375                     https://github.com/zed-industries/zed/issues/22692"
11376                );
11377            }
11378            self.request_autoscroll(Autoscroll::fit(), cx);
11379            self.unmark_text(window, cx);
11380            self.refresh_inline_completion(true, false, window, cx);
11381            cx.emit(EditorEvent::Edited { transaction_id });
11382        }
11383    }
11384
11385    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11386        self.buffer
11387            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11388    }
11389
11390    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11391        self.buffer
11392            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11393    }
11394
11395    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11396        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11397        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11398            s.move_with(|map, selection| {
11399                let cursor = if selection.is_empty() {
11400                    movement::left(map, selection.start)
11401                } else {
11402                    selection.start
11403                };
11404                selection.collapse_to(cursor, SelectionGoal::None);
11405            });
11406        })
11407    }
11408
11409    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11410        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11411        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11412            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11413        })
11414    }
11415
11416    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11417        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11418        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11419            s.move_with(|map, selection| {
11420                let cursor = if selection.is_empty() {
11421                    movement::right(map, selection.end)
11422                } else {
11423                    selection.end
11424                };
11425                selection.collapse_to(cursor, SelectionGoal::None)
11426            });
11427        })
11428    }
11429
11430    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11431        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11432        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11433            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11434        })
11435    }
11436
11437    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11438        if self.take_rename(true, window, cx).is_some() {
11439            return;
11440        }
11441
11442        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11443            cx.propagate();
11444            return;
11445        }
11446
11447        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11448
11449        let text_layout_details = &self.text_layout_details(window);
11450        let selection_count = self.selections.count();
11451        let first_selection = self.selections.first_anchor();
11452
11453        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11454            s.move_with(|map, selection| {
11455                if !selection.is_empty() {
11456                    selection.goal = SelectionGoal::None;
11457                }
11458                let (cursor, goal) = movement::up(
11459                    map,
11460                    selection.start,
11461                    selection.goal,
11462                    false,
11463                    text_layout_details,
11464                );
11465                selection.collapse_to(cursor, goal);
11466            });
11467        });
11468
11469        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11470        {
11471            cx.propagate();
11472        }
11473    }
11474
11475    pub fn move_up_by_lines(
11476        &mut self,
11477        action: &MoveUpByLines,
11478        window: &mut Window,
11479        cx: &mut Context<Self>,
11480    ) {
11481        if self.take_rename(true, window, cx).is_some() {
11482            return;
11483        }
11484
11485        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11486            cx.propagate();
11487            return;
11488        }
11489
11490        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11491
11492        let text_layout_details = &self.text_layout_details(window);
11493
11494        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11495            s.move_with(|map, selection| {
11496                if !selection.is_empty() {
11497                    selection.goal = SelectionGoal::None;
11498                }
11499                let (cursor, goal) = movement::up_by_rows(
11500                    map,
11501                    selection.start,
11502                    action.lines,
11503                    selection.goal,
11504                    false,
11505                    text_layout_details,
11506                );
11507                selection.collapse_to(cursor, goal);
11508            });
11509        })
11510    }
11511
11512    pub fn move_down_by_lines(
11513        &mut self,
11514        action: &MoveDownByLines,
11515        window: &mut Window,
11516        cx: &mut Context<Self>,
11517    ) {
11518        if self.take_rename(true, window, cx).is_some() {
11519            return;
11520        }
11521
11522        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11523            cx.propagate();
11524            return;
11525        }
11526
11527        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11528
11529        let text_layout_details = &self.text_layout_details(window);
11530
11531        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11532            s.move_with(|map, selection| {
11533                if !selection.is_empty() {
11534                    selection.goal = SelectionGoal::None;
11535                }
11536                let (cursor, goal) = movement::down_by_rows(
11537                    map,
11538                    selection.start,
11539                    action.lines,
11540                    selection.goal,
11541                    false,
11542                    text_layout_details,
11543                );
11544                selection.collapse_to(cursor, goal);
11545            });
11546        })
11547    }
11548
11549    pub fn select_down_by_lines(
11550        &mut self,
11551        action: &SelectDownByLines,
11552        window: &mut Window,
11553        cx: &mut Context<Self>,
11554    ) {
11555        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11556        let text_layout_details = &self.text_layout_details(window);
11557        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11558            s.move_heads_with(|map, head, goal| {
11559                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11560            })
11561        })
11562    }
11563
11564    pub fn select_up_by_lines(
11565        &mut self,
11566        action: &SelectUpByLines,
11567        window: &mut Window,
11568        cx: &mut Context<Self>,
11569    ) {
11570        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11571        let text_layout_details = &self.text_layout_details(window);
11572        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11573            s.move_heads_with(|map, head, goal| {
11574                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11575            })
11576        })
11577    }
11578
11579    pub fn select_page_up(
11580        &mut self,
11581        _: &SelectPageUp,
11582        window: &mut Window,
11583        cx: &mut Context<Self>,
11584    ) {
11585        let Some(row_count) = self.visible_row_count() else {
11586            return;
11587        };
11588
11589        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11590
11591        let text_layout_details = &self.text_layout_details(window);
11592
11593        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11594            s.move_heads_with(|map, head, goal| {
11595                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11596            })
11597        })
11598    }
11599
11600    pub fn move_page_up(
11601        &mut self,
11602        action: &MovePageUp,
11603        window: &mut Window,
11604        cx: &mut Context<Self>,
11605    ) {
11606        if self.take_rename(true, window, cx).is_some() {
11607            return;
11608        }
11609
11610        if self
11611            .context_menu
11612            .borrow_mut()
11613            .as_mut()
11614            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11615            .unwrap_or(false)
11616        {
11617            return;
11618        }
11619
11620        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11621            cx.propagate();
11622            return;
11623        }
11624
11625        let Some(row_count) = self.visible_row_count() else {
11626            return;
11627        };
11628
11629        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11630
11631        let autoscroll = if action.center_cursor {
11632            Autoscroll::center()
11633        } else {
11634            Autoscroll::fit()
11635        };
11636
11637        let text_layout_details = &self.text_layout_details(window);
11638
11639        self.change_selections(Some(autoscroll), window, cx, |s| {
11640            s.move_with(|map, selection| {
11641                if !selection.is_empty() {
11642                    selection.goal = SelectionGoal::None;
11643                }
11644                let (cursor, goal) = movement::up_by_rows(
11645                    map,
11646                    selection.end,
11647                    row_count,
11648                    selection.goal,
11649                    false,
11650                    text_layout_details,
11651                );
11652                selection.collapse_to(cursor, goal);
11653            });
11654        });
11655    }
11656
11657    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11658        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11659        let text_layout_details = &self.text_layout_details(window);
11660        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11661            s.move_heads_with(|map, head, goal| {
11662                movement::up(map, head, goal, false, text_layout_details)
11663            })
11664        })
11665    }
11666
11667    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11668        self.take_rename(true, window, cx);
11669
11670        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11671            cx.propagate();
11672            return;
11673        }
11674
11675        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11676
11677        let text_layout_details = &self.text_layout_details(window);
11678        let selection_count = self.selections.count();
11679        let first_selection = self.selections.first_anchor();
11680
11681        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11682            s.move_with(|map, selection| {
11683                if !selection.is_empty() {
11684                    selection.goal = SelectionGoal::None;
11685                }
11686                let (cursor, goal) = movement::down(
11687                    map,
11688                    selection.end,
11689                    selection.goal,
11690                    false,
11691                    text_layout_details,
11692                );
11693                selection.collapse_to(cursor, goal);
11694            });
11695        });
11696
11697        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11698        {
11699            cx.propagate();
11700        }
11701    }
11702
11703    pub fn select_page_down(
11704        &mut self,
11705        _: &SelectPageDown,
11706        window: &mut Window,
11707        cx: &mut Context<Self>,
11708    ) {
11709        let Some(row_count) = self.visible_row_count() else {
11710            return;
11711        };
11712
11713        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11714
11715        let text_layout_details = &self.text_layout_details(window);
11716
11717        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11718            s.move_heads_with(|map, head, goal| {
11719                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11720            })
11721        })
11722    }
11723
11724    pub fn move_page_down(
11725        &mut self,
11726        action: &MovePageDown,
11727        window: &mut Window,
11728        cx: &mut Context<Self>,
11729    ) {
11730        if self.take_rename(true, window, cx).is_some() {
11731            return;
11732        }
11733
11734        if self
11735            .context_menu
11736            .borrow_mut()
11737            .as_mut()
11738            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11739            .unwrap_or(false)
11740        {
11741            return;
11742        }
11743
11744        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11745            cx.propagate();
11746            return;
11747        }
11748
11749        let Some(row_count) = self.visible_row_count() else {
11750            return;
11751        };
11752
11753        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11754
11755        let autoscroll = if action.center_cursor {
11756            Autoscroll::center()
11757        } else {
11758            Autoscroll::fit()
11759        };
11760
11761        let text_layout_details = &self.text_layout_details(window);
11762        self.change_selections(Some(autoscroll), window, cx, |s| {
11763            s.move_with(|map, selection| {
11764                if !selection.is_empty() {
11765                    selection.goal = SelectionGoal::None;
11766                }
11767                let (cursor, goal) = movement::down_by_rows(
11768                    map,
11769                    selection.end,
11770                    row_count,
11771                    selection.goal,
11772                    false,
11773                    text_layout_details,
11774                );
11775                selection.collapse_to(cursor, goal);
11776            });
11777        });
11778    }
11779
11780    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11781        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11782        let text_layout_details = &self.text_layout_details(window);
11783        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11784            s.move_heads_with(|map, head, goal| {
11785                movement::down(map, head, goal, false, text_layout_details)
11786            })
11787        });
11788    }
11789
11790    pub fn context_menu_first(
11791        &mut self,
11792        _: &ContextMenuFirst,
11793        window: &mut Window,
11794        cx: &mut Context<Self>,
11795    ) {
11796        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11797            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11798        }
11799    }
11800
11801    pub fn context_menu_prev(
11802        &mut self,
11803        _: &ContextMenuPrevious,
11804        window: &mut Window,
11805        cx: &mut Context<Self>,
11806    ) {
11807        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11808            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11809        }
11810    }
11811
11812    pub fn context_menu_next(
11813        &mut self,
11814        _: &ContextMenuNext,
11815        window: &mut Window,
11816        cx: &mut Context<Self>,
11817    ) {
11818        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11819            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11820        }
11821    }
11822
11823    pub fn context_menu_last(
11824        &mut self,
11825        _: &ContextMenuLast,
11826        window: &mut Window,
11827        cx: &mut Context<Self>,
11828    ) {
11829        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11830            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11831        }
11832    }
11833
11834    pub fn move_to_previous_word_start(
11835        &mut self,
11836        _: &MoveToPreviousWordStart,
11837        window: &mut Window,
11838        cx: &mut Context<Self>,
11839    ) {
11840        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11841        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11842            s.move_cursors_with(|map, head, _| {
11843                (
11844                    movement::previous_word_start(map, head),
11845                    SelectionGoal::None,
11846                )
11847            });
11848        })
11849    }
11850
11851    pub fn move_to_previous_subword_start(
11852        &mut self,
11853        _: &MoveToPreviousSubwordStart,
11854        window: &mut Window,
11855        cx: &mut Context<Self>,
11856    ) {
11857        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11858        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11859            s.move_cursors_with(|map, head, _| {
11860                (
11861                    movement::previous_subword_start(map, head),
11862                    SelectionGoal::None,
11863                )
11864            });
11865        })
11866    }
11867
11868    pub fn select_to_previous_word_start(
11869        &mut self,
11870        _: &SelectToPreviousWordStart,
11871        window: &mut Window,
11872        cx: &mut Context<Self>,
11873    ) {
11874        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11875        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11876            s.move_heads_with(|map, head, _| {
11877                (
11878                    movement::previous_word_start(map, head),
11879                    SelectionGoal::None,
11880                )
11881            });
11882        })
11883    }
11884
11885    pub fn select_to_previous_subword_start(
11886        &mut self,
11887        _: &SelectToPreviousSubwordStart,
11888        window: &mut Window,
11889        cx: &mut Context<Self>,
11890    ) {
11891        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11892        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11893            s.move_heads_with(|map, head, _| {
11894                (
11895                    movement::previous_subword_start(map, head),
11896                    SelectionGoal::None,
11897                )
11898            });
11899        })
11900    }
11901
11902    pub fn delete_to_previous_word_start(
11903        &mut self,
11904        action: &DeleteToPreviousWordStart,
11905        window: &mut Window,
11906        cx: &mut Context<Self>,
11907    ) {
11908        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11909        self.transact(window, cx, |this, window, cx| {
11910            this.select_autoclose_pair(window, cx);
11911            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11912                s.move_with(|map, selection| {
11913                    if selection.is_empty() {
11914                        let cursor = if action.ignore_newlines {
11915                            movement::previous_word_start(map, selection.head())
11916                        } else {
11917                            movement::previous_word_start_or_newline(map, selection.head())
11918                        };
11919                        selection.set_head(cursor, SelectionGoal::None);
11920                    }
11921                });
11922            });
11923            this.insert("", window, cx);
11924        });
11925    }
11926
11927    pub fn delete_to_previous_subword_start(
11928        &mut self,
11929        _: &DeleteToPreviousSubwordStart,
11930        window: &mut Window,
11931        cx: &mut Context<Self>,
11932    ) {
11933        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11934        self.transact(window, cx, |this, window, cx| {
11935            this.select_autoclose_pair(window, cx);
11936            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11937                s.move_with(|map, selection| {
11938                    if selection.is_empty() {
11939                        let cursor = movement::previous_subword_start(map, selection.head());
11940                        selection.set_head(cursor, SelectionGoal::None);
11941                    }
11942                });
11943            });
11944            this.insert("", window, cx);
11945        });
11946    }
11947
11948    pub fn move_to_next_word_end(
11949        &mut self,
11950        _: &MoveToNextWordEnd,
11951        window: &mut Window,
11952        cx: &mut Context<Self>,
11953    ) {
11954        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11955        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11956            s.move_cursors_with(|map, head, _| {
11957                (movement::next_word_end(map, head), SelectionGoal::None)
11958            });
11959        })
11960    }
11961
11962    pub fn move_to_next_subword_end(
11963        &mut self,
11964        _: &MoveToNextSubwordEnd,
11965        window: &mut Window,
11966        cx: &mut Context<Self>,
11967    ) {
11968        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11969        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11970            s.move_cursors_with(|map, head, _| {
11971                (movement::next_subword_end(map, head), SelectionGoal::None)
11972            });
11973        })
11974    }
11975
11976    pub fn select_to_next_word_end(
11977        &mut self,
11978        _: &SelectToNextWordEnd,
11979        window: &mut Window,
11980        cx: &mut Context<Self>,
11981    ) {
11982        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11983        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11984            s.move_heads_with(|map, head, _| {
11985                (movement::next_word_end(map, head), SelectionGoal::None)
11986            });
11987        })
11988    }
11989
11990    pub fn select_to_next_subword_end(
11991        &mut self,
11992        _: &SelectToNextSubwordEnd,
11993        window: &mut Window,
11994        cx: &mut Context<Self>,
11995    ) {
11996        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11997        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11998            s.move_heads_with(|map, head, _| {
11999                (movement::next_subword_end(map, head), SelectionGoal::None)
12000            });
12001        })
12002    }
12003
12004    pub fn delete_to_next_word_end(
12005        &mut self,
12006        action: &DeleteToNextWordEnd,
12007        window: &mut Window,
12008        cx: &mut Context<Self>,
12009    ) {
12010        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12011        self.transact(window, cx, |this, window, cx| {
12012            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12013                s.move_with(|map, selection| {
12014                    if selection.is_empty() {
12015                        let cursor = if action.ignore_newlines {
12016                            movement::next_word_end(map, selection.head())
12017                        } else {
12018                            movement::next_word_end_or_newline(map, selection.head())
12019                        };
12020                        selection.set_head(cursor, SelectionGoal::None);
12021                    }
12022                });
12023            });
12024            this.insert("", window, cx);
12025        });
12026    }
12027
12028    pub fn delete_to_next_subword_end(
12029        &mut self,
12030        _: &DeleteToNextSubwordEnd,
12031        window: &mut Window,
12032        cx: &mut Context<Self>,
12033    ) {
12034        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12035        self.transact(window, cx, |this, window, cx| {
12036            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12037                s.move_with(|map, selection| {
12038                    if selection.is_empty() {
12039                        let cursor = movement::next_subword_end(map, selection.head());
12040                        selection.set_head(cursor, SelectionGoal::None);
12041                    }
12042                });
12043            });
12044            this.insert("", window, cx);
12045        });
12046    }
12047
12048    pub fn move_to_beginning_of_line(
12049        &mut self,
12050        action: &MoveToBeginningOfLine,
12051        window: &mut Window,
12052        cx: &mut Context<Self>,
12053    ) {
12054        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12055        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12056            s.move_cursors_with(|map, head, _| {
12057                (
12058                    movement::indented_line_beginning(
12059                        map,
12060                        head,
12061                        action.stop_at_soft_wraps,
12062                        action.stop_at_indent,
12063                    ),
12064                    SelectionGoal::None,
12065                )
12066            });
12067        })
12068    }
12069
12070    pub fn select_to_beginning_of_line(
12071        &mut self,
12072        action: &SelectToBeginningOfLine,
12073        window: &mut Window,
12074        cx: &mut Context<Self>,
12075    ) {
12076        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12077        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12078            s.move_heads_with(|map, head, _| {
12079                (
12080                    movement::indented_line_beginning(
12081                        map,
12082                        head,
12083                        action.stop_at_soft_wraps,
12084                        action.stop_at_indent,
12085                    ),
12086                    SelectionGoal::None,
12087                )
12088            });
12089        });
12090    }
12091
12092    pub fn delete_to_beginning_of_line(
12093        &mut self,
12094        action: &DeleteToBeginningOfLine,
12095        window: &mut Window,
12096        cx: &mut Context<Self>,
12097    ) {
12098        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12099        self.transact(window, cx, |this, window, cx| {
12100            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12101                s.move_with(|_, selection| {
12102                    selection.reversed = true;
12103                });
12104            });
12105
12106            this.select_to_beginning_of_line(
12107                &SelectToBeginningOfLine {
12108                    stop_at_soft_wraps: false,
12109                    stop_at_indent: action.stop_at_indent,
12110                },
12111                window,
12112                cx,
12113            );
12114            this.backspace(&Backspace, window, cx);
12115        });
12116    }
12117
12118    pub fn move_to_end_of_line(
12119        &mut self,
12120        action: &MoveToEndOfLine,
12121        window: &mut Window,
12122        cx: &mut Context<Self>,
12123    ) {
12124        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12125        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12126            s.move_cursors_with(|map, head, _| {
12127                (
12128                    movement::line_end(map, head, action.stop_at_soft_wraps),
12129                    SelectionGoal::None,
12130                )
12131            });
12132        })
12133    }
12134
12135    pub fn select_to_end_of_line(
12136        &mut self,
12137        action: &SelectToEndOfLine,
12138        window: &mut Window,
12139        cx: &mut Context<Self>,
12140    ) {
12141        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12142        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12143            s.move_heads_with(|map, head, _| {
12144                (
12145                    movement::line_end(map, head, action.stop_at_soft_wraps),
12146                    SelectionGoal::None,
12147                )
12148            });
12149        })
12150    }
12151
12152    pub fn delete_to_end_of_line(
12153        &mut self,
12154        _: &DeleteToEndOfLine,
12155        window: &mut Window,
12156        cx: &mut Context<Self>,
12157    ) {
12158        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12159        self.transact(window, cx, |this, window, cx| {
12160            this.select_to_end_of_line(
12161                &SelectToEndOfLine {
12162                    stop_at_soft_wraps: false,
12163                },
12164                window,
12165                cx,
12166            );
12167            this.delete(&Delete, window, cx);
12168        });
12169    }
12170
12171    pub fn cut_to_end_of_line(
12172        &mut self,
12173        _: &CutToEndOfLine,
12174        window: &mut Window,
12175        cx: &mut Context<Self>,
12176    ) {
12177        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12178        self.transact(window, cx, |this, window, cx| {
12179            this.select_to_end_of_line(
12180                &SelectToEndOfLine {
12181                    stop_at_soft_wraps: false,
12182                },
12183                window,
12184                cx,
12185            );
12186            this.cut(&Cut, window, cx);
12187        });
12188    }
12189
12190    pub fn move_to_start_of_paragraph(
12191        &mut self,
12192        _: &MoveToStartOfParagraph,
12193        window: &mut Window,
12194        cx: &mut Context<Self>,
12195    ) {
12196        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12197            cx.propagate();
12198            return;
12199        }
12200        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12201        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12202            s.move_with(|map, selection| {
12203                selection.collapse_to(
12204                    movement::start_of_paragraph(map, selection.head(), 1),
12205                    SelectionGoal::None,
12206                )
12207            });
12208        })
12209    }
12210
12211    pub fn move_to_end_of_paragraph(
12212        &mut self,
12213        _: &MoveToEndOfParagraph,
12214        window: &mut Window,
12215        cx: &mut Context<Self>,
12216    ) {
12217        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12218            cx.propagate();
12219            return;
12220        }
12221        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12222        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12223            s.move_with(|map, selection| {
12224                selection.collapse_to(
12225                    movement::end_of_paragraph(map, selection.head(), 1),
12226                    SelectionGoal::None,
12227                )
12228            });
12229        })
12230    }
12231
12232    pub fn select_to_start_of_paragraph(
12233        &mut self,
12234        _: &SelectToStartOfParagraph,
12235        window: &mut Window,
12236        cx: &mut Context<Self>,
12237    ) {
12238        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12239            cx.propagate();
12240            return;
12241        }
12242        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12243        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12244            s.move_heads_with(|map, head, _| {
12245                (
12246                    movement::start_of_paragraph(map, head, 1),
12247                    SelectionGoal::None,
12248                )
12249            });
12250        })
12251    }
12252
12253    pub fn select_to_end_of_paragraph(
12254        &mut self,
12255        _: &SelectToEndOfParagraph,
12256        window: &mut Window,
12257        cx: &mut Context<Self>,
12258    ) {
12259        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12260            cx.propagate();
12261            return;
12262        }
12263        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12264        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12265            s.move_heads_with(|map, head, _| {
12266                (
12267                    movement::end_of_paragraph(map, head, 1),
12268                    SelectionGoal::None,
12269                )
12270            });
12271        })
12272    }
12273
12274    pub fn move_to_start_of_excerpt(
12275        &mut self,
12276        _: &MoveToStartOfExcerpt,
12277        window: &mut Window,
12278        cx: &mut Context<Self>,
12279    ) {
12280        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12281            cx.propagate();
12282            return;
12283        }
12284        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12285        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12286            s.move_with(|map, selection| {
12287                selection.collapse_to(
12288                    movement::start_of_excerpt(
12289                        map,
12290                        selection.head(),
12291                        workspace::searchable::Direction::Prev,
12292                    ),
12293                    SelectionGoal::None,
12294                )
12295            });
12296        })
12297    }
12298
12299    pub fn move_to_start_of_next_excerpt(
12300        &mut self,
12301        _: &MoveToStartOfNextExcerpt,
12302        window: &mut Window,
12303        cx: &mut Context<Self>,
12304    ) {
12305        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12306            cx.propagate();
12307            return;
12308        }
12309
12310        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12311            s.move_with(|map, selection| {
12312                selection.collapse_to(
12313                    movement::start_of_excerpt(
12314                        map,
12315                        selection.head(),
12316                        workspace::searchable::Direction::Next,
12317                    ),
12318                    SelectionGoal::None,
12319                )
12320            });
12321        })
12322    }
12323
12324    pub fn move_to_end_of_excerpt(
12325        &mut self,
12326        _: &MoveToEndOfExcerpt,
12327        window: &mut Window,
12328        cx: &mut Context<Self>,
12329    ) {
12330        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12331            cx.propagate();
12332            return;
12333        }
12334        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12335        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12336            s.move_with(|map, selection| {
12337                selection.collapse_to(
12338                    movement::end_of_excerpt(
12339                        map,
12340                        selection.head(),
12341                        workspace::searchable::Direction::Next,
12342                    ),
12343                    SelectionGoal::None,
12344                )
12345            });
12346        })
12347    }
12348
12349    pub fn move_to_end_of_previous_excerpt(
12350        &mut self,
12351        _: &MoveToEndOfPreviousExcerpt,
12352        window: &mut Window,
12353        cx: &mut Context<Self>,
12354    ) {
12355        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12356            cx.propagate();
12357            return;
12358        }
12359        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12360        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12361            s.move_with(|map, selection| {
12362                selection.collapse_to(
12363                    movement::end_of_excerpt(
12364                        map,
12365                        selection.head(),
12366                        workspace::searchable::Direction::Prev,
12367                    ),
12368                    SelectionGoal::None,
12369                )
12370            });
12371        })
12372    }
12373
12374    pub fn select_to_start_of_excerpt(
12375        &mut self,
12376        _: &SelectToStartOfExcerpt,
12377        window: &mut Window,
12378        cx: &mut Context<Self>,
12379    ) {
12380        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12381            cx.propagate();
12382            return;
12383        }
12384        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12385        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12386            s.move_heads_with(|map, head, _| {
12387                (
12388                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12389                    SelectionGoal::None,
12390                )
12391            });
12392        })
12393    }
12394
12395    pub fn select_to_start_of_next_excerpt(
12396        &mut self,
12397        _: &SelectToStartOfNextExcerpt,
12398        window: &mut Window,
12399        cx: &mut Context<Self>,
12400    ) {
12401        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12402            cx.propagate();
12403            return;
12404        }
12405        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12406        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12407            s.move_heads_with(|map, head, _| {
12408                (
12409                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12410                    SelectionGoal::None,
12411                )
12412            });
12413        })
12414    }
12415
12416    pub fn select_to_end_of_excerpt(
12417        &mut self,
12418        _: &SelectToEndOfExcerpt,
12419        window: &mut Window,
12420        cx: &mut Context<Self>,
12421    ) {
12422        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12423            cx.propagate();
12424            return;
12425        }
12426        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12427        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12428            s.move_heads_with(|map, head, _| {
12429                (
12430                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12431                    SelectionGoal::None,
12432                )
12433            });
12434        })
12435    }
12436
12437    pub fn select_to_end_of_previous_excerpt(
12438        &mut self,
12439        _: &SelectToEndOfPreviousExcerpt,
12440        window: &mut Window,
12441        cx: &mut Context<Self>,
12442    ) {
12443        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12444            cx.propagate();
12445            return;
12446        }
12447        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12448        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12449            s.move_heads_with(|map, head, _| {
12450                (
12451                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12452                    SelectionGoal::None,
12453                )
12454            });
12455        })
12456    }
12457
12458    pub fn move_to_beginning(
12459        &mut self,
12460        _: &MoveToBeginning,
12461        window: &mut Window,
12462        cx: &mut Context<Self>,
12463    ) {
12464        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12465            cx.propagate();
12466            return;
12467        }
12468        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12469        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12470            s.select_ranges(vec![0..0]);
12471        });
12472    }
12473
12474    pub fn select_to_beginning(
12475        &mut self,
12476        _: &SelectToBeginning,
12477        window: &mut Window,
12478        cx: &mut Context<Self>,
12479    ) {
12480        let mut selection = self.selections.last::<Point>(cx);
12481        selection.set_head(Point::zero(), SelectionGoal::None);
12482        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12483        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12484            s.select(vec![selection]);
12485        });
12486    }
12487
12488    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12489        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12490            cx.propagate();
12491            return;
12492        }
12493        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12494        let cursor = self.buffer.read(cx).read(cx).len();
12495        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12496            s.select_ranges(vec![cursor..cursor])
12497        });
12498    }
12499
12500    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12501        self.nav_history = nav_history;
12502    }
12503
12504    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12505        self.nav_history.as_ref()
12506    }
12507
12508    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12509        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12510    }
12511
12512    fn push_to_nav_history(
12513        &mut self,
12514        cursor_anchor: Anchor,
12515        new_position: Option<Point>,
12516        is_deactivate: bool,
12517        cx: &mut Context<Self>,
12518    ) {
12519        if let Some(nav_history) = self.nav_history.as_mut() {
12520            let buffer = self.buffer.read(cx).read(cx);
12521            let cursor_position = cursor_anchor.to_point(&buffer);
12522            let scroll_state = self.scroll_manager.anchor();
12523            let scroll_top_row = scroll_state.top_row(&buffer);
12524            drop(buffer);
12525
12526            if let Some(new_position) = new_position {
12527                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12528                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12529                    return;
12530                }
12531            }
12532
12533            nav_history.push(
12534                Some(NavigationData {
12535                    cursor_anchor,
12536                    cursor_position,
12537                    scroll_anchor: scroll_state,
12538                    scroll_top_row,
12539                }),
12540                cx,
12541            );
12542            cx.emit(EditorEvent::PushedToNavHistory {
12543                anchor: cursor_anchor,
12544                is_deactivate,
12545            })
12546        }
12547    }
12548
12549    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12550        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12551        let buffer = self.buffer.read(cx).snapshot(cx);
12552        let mut selection = self.selections.first::<usize>(cx);
12553        selection.set_head(buffer.len(), SelectionGoal::None);
12554        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12555            s.select(vec![selection]);
12556        });
12557    }
12558
12559    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12560        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12561        let end = self.buffer.read(cx).read(cx).len();
12562        self.change_selections(None, window, cx, |s| {
12563            s.select_ranges(vec![0..end]);
12564        });
12565    }
12566
12567    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12568        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12569        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12570        let mut selections = self.selections.all::<Point>(cx);
12571        let max_point = display_map.buffer_snapshot.max_point();
12572        for selection in &mut selections {
12573            let rows = selection.spanned_rows(true, &display_map);
12574            selection.start = Point::new(rows.start.0, 0);
12575            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12576            selection.reversed = false;
12577        }
12578        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12579            s.select(selections);
12580        });
12581    }
12582
12583    pub fn split_selection_into_lines(
12584        &mut self,
12585        _: &SplitSelectionIntoLines,
12586        window: &mut Window,
12587        cx: &mut Context<Self>,
12588    ) {
12589        let selections = self
12590            .selections
12591            .all::<Point>(cx)
12592            .into_iter()
12593            .map(|selection| selection.start..selection.end)
12594            .collect::<Vec<_>>();
12595        self.unfold_ranges(&selections, true, true, cx);
12596
12597        let mut new_selection_ranges = Vec::new();
12598        {
12599            let buffer = self.buffer.read(cx).read(cx);
12600            for selection in selections {
12601                for row in selection.start.row..selection.end.row {
12602                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12603                    new_selection_ranges.push(cursor..cursor);
12604                }
12605
12606                let is_multiline_selection = selection.start.row != selection.end.row;
12607                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12608                // so this action feels more ergonomic when paired with other selection operations
12609                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12610                if !should_skip_last {
12611                    new_selection_ranges.push(selection.end..selection.end);
12612                }
12613            }
12614        }
12615        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12616            s.select_ranges(new_selection_ranges);
12617        });
12618    }
12619
12620    pub fn add_selection_above(
12621        &mut self,
12622        _: &AddSelectionAbove,
12623        window: &mut Window,
12624        cx: &mut Context<Self>,
12625    ) {
12626        self.add_selection(true, window, cx);
12627    }
12628
12629    pub fn add_selection_below(
12630        &mut self,
12631        _: &AddSelectionBelow,
12632        window: &mut Window,
12633        cx: &mut Context<Self>,
12634    ) {
12635        self.add_selection(false, window, cx);
12636    }
12637
12638    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12639        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12640
12641        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12642        let mut selections = self.selections.all::<Point>(cx);
12643        let text_layout_details = self.text_layout_details(window);
12644        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12645            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12646            let range = oldest_selection.display_range(&display_map).sorted();
12647
12648            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12649            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12650            let positions = start_x.min(end_x)..start_x.max(end_x);
12651
12652            selections.clear();
12653            let mut stack = Vec::new();
12654            for row in range.start.row().0..=range.end.row().0 {
12655                if let Some(selection) = self.selections.build_columnar_selection(
12656                    &display_map,
12657                    DisplayRow(row),
12658                    &positions,
12659                    oldest_selection.reversed,
12660                    &text_layout_details,
12661                ) {
12662                    stack.push(selection.id);
12663                    selections.push(selection);
12664                }
12665            }
12666
12667            if above {
12668                stack.reverse();
12669            }
12670
12671            AddSelectionsState { above, stack }
12672        });
12673
12674        let last_added_selection = *state.stack.last().unwrap();
12675        let mut new_selections = Vec::new();
12676        if above == state.above {
12677            let end_row = if above {
12678                DisplayRow(0)
12679            } else {
12680                display_map.max_point().row()
12681            };
12682
12683            'outer: for selection in selections {
12684                if selection.id == last_added_selection {
12685                    let range = selection.display_range(&display_map).sorted();
12686                    debug_assert_eq!(range.start.row(), range.end.row());
12687                    let mut row = range.start.row();
12688                    let positions =
12689                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12690                            px(start)..px(end)
12691                        } else {
12692                            let start_x =
12693                                display_map.x_for_display_point(range.start, &text_layout_details);
12694                            let end_x =
12695                                display_map.x_for_display_point(range.end, &text_layout_details);
12696                            start_x.min(end_x)..start_x.max(end_x)
12697                        };
12698
12699                    while row != end_row {
12700                        if above {
12701                            row.0 -= 1;
12702                        } else {
12703                            row.0 += 1;
12704                        }
12705
12706                        if let Some(new_selection) = self.selections.build_columnar_selection(
12707                            &display_map,
12708                            row,
12709                            &positions,
12710                            selection.reversed,
12711                            &text_layout_details,
12712                        ) {
12713                            state.stack.push(new_selection.id);
12714                            if above {
12715                                new_selections.push(new_selection);
12716                                new_selections.push(selection);
12717                            } else {
12718                                new_selections.push(selection);
12719                                new_selections.push(new_selection);
12720                            }
12721
12722                            continue 'outer;
12723                        }
12724                    }
12725                }
12726
12727                new_selections.push(selection);
12728            }
12729        } else {
12730            new_selections = selections;
12731            new_selections.retain(|s| s.id != last_added_selection);
12732            state.stack.pop();
12733        }
12734
12735        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12736            s.select(new_selections);
12737        });
12738        if state.stack.len() > 1 {
12739            self.add_selections_state = Some(state);
12740        }
12741    }
12742
12743    fn select_match_ranges(
12744        &mut self,
12745        range: Range<usize>,
12746        reversed: bool,
12747        replace_newest: bool,
12748        auto_scroll: Option<Autoscroll>,
12749        window: &mut Window,
12750        cx: &mut Context<Editor>,
12751    ) {
12752        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12753        self.change_selections(auto_scroll, window, cx, |s| {
12754            if replace_newest {
12755                s.delete(s.newest_anchor().id);
12756            }
12757            if reversed {
12758                s.insert_range(range.end..range.start);
12759            } else {
12760                s.insert_range(range);
12761            }
12762        });
12763    }
12764
12765    pub fn select_next_match_internal(
12766        &mut self,
12767        display_map: &DisplaySnapshot,
12768        replace_newest: bool,
12769        autoscroll: Option<Autoscroll>,
12770        window: &mut Window,
12771        cx: &mut Context<Self>,
12772    ) -> Result<()> {
12773        let buffer = &display_map.buffer_snapshot;
12774        let mut selections = self.selections.all::<usize>(cx);
12775        if let Some(mut select_next_state) = self.select_next_state.take() {
12776            let query = &select_next_state.query;
12777            if !select_next_state.done {
12778                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12779                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12780                let mut next_selected_range = None;
12781
12782                let bytes_after_last_selection =
12783                    buffer.bytes_in_range(last_selection.end..buffer.len());
12784                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12785                let query_matches = query
12786                    .stream_find_iter(bytes_after_last_selection)
12787                    .map(|result| (last_selection.end, result))
12788                    .chain(
12789                        query
12790                            .stream_find_iter(bytes_before_first_selection)
12791                            .map(|result| (0, result)),
12792                    );
12793
12794                for (start_offset, query_match) in query_matches {
12795                    let query_match = query_match.unwrap(); // can only fail due to I/O
12796                    let offset_range =
12797                        start_offset + query_match.start()..start_offset + query_match.end();
12798                    let display_range = offset_range.start.to_display_point(display_map)
12799                        ..offset_range.end.to_display_point(display_map);
12800
12801                    if !select_next_state.wordwise
12802                        || (!movement::is_inside_word(display_map, display_range.start)
12803                            && !movement::is_inside_word(display_map, display_range.end))
12804                    {
12805                        // TODO: This is n^2, because we might check all the selections
12806                        if !selections
12807                            .iter()
12808                            .any(|selection| selection.range().overlaps(&offset_range))
12809                        {
12810                            next_selected_range = Some(offset_range);
12811                            break;
12812                        }
12813                    }
12814                }
12815
12816                if let Some(next_selected_range) = next_selected_range {
12817                    self.select_match_ranges(
12818                        next_selected_range,
12819                        last_selection.reversed,
12820                        replace_newest,
12821                        autoscroll,
12822                        window,
12823                        cx,
12824                    );
12825                } else {
12826                    select_next_state.done = true;
12827                }
12828            }
12829
12830            self.select_next_state = Some(select_next_state);
12831        } else {
12832            let mut only_carets = true;
12833            let mut same_text_selected = true;
12834            let mut selected_text = None;
12835
12836            let mut selections_iter = selections.iter().peekable();
12837            while let Some(selection) = selections_iter.next() {
12838                if selection.start != selection.end {
12839                    only_carets = false;
12840                }
12841
12842                if same_text_selected {
12843                    if selected_text.is_none() {
12844                        selected_text =
12845                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12846                    }
12847
12848                    if let Some(next_selection) = selections_iter.peek() {
12849                        if next_selection.range().len() == selection.range().len() {
12850                            let next_selected_text = buffer
12851                                .text_for_range(next_selection.range())
12852                                .collect::<String>();
12853                            if Some(next_selected_text) != selected_text {
12854                                same_text_selected = false;
12855                                selected_text = None;
12856                            }
12857                        } else {
12858                            same_text_selected = false;
12859                            selected_text = None;
12860                        }
12861                    }
12862                }
12863            }
12864
12865            if only_carets {
12866                for selection in &mut selections {
12867                    let word_range = movement::surrounding_word(
12868                        display_map,
12869                        selection.start.to_display_point(display_map),
12870                    );
12871                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12872                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12873                    selection.goal = SelectionGoal::None;
12874                    selection.reversed = false;
12875                    self.select_match_ranges(
12876                        selection.start..selection.end,
12877                        selection.reversed,
12878                        replace_newest,
12879                        autoscroll,
12880                        window,
12881                        cx,
12882                    );
12883                }
12884
12885                if selections.len() == 1 {
12886                    let selection = selections
12887                        .last()
12888                        .expect("ensured that there's only one selection");
12889                    let query = buffer
12890                        .text_for_range(selection.start..selection.end)
12891                        .collect::<String>();
12892                    let is_empty = query.is_empty();
12893                    let select_state = SelectNextState {
12894                        query: AhoCorasick::new(&[query])?,
12895                        wordwise: true,
12896                        done: is_empty,
12897                    };
12898                    self.select_next_state = Some(select_state);
12899                } else {
12900                    self.select_next_state = None;
12901                }
12902            } else if let Some(selected_text) = selected_text {
12903                self.select_next_state = Some(SelectNextState {
12904                    query: AhoCorasick::new(&[selected_text])?,
12905                    wordwise: false,
12906                    done: false,
12907                });
12908                self.select_next_match_internal(
12909                    display_map,
12910                    replace_newest,
12911                    autoscroll,
12912                    window,
12913                    cx,
12914                )?;
12915            }
12916        }
12917        Ok(())
12918    }
12919
12920    pub fn select_all_matches(
12921        &mut self,
12922        _action: &SelectAllMatches,
12923        window: &mut Window,
12924        cx: &mut Context<Self>,
12925    ) -> Result<()> {
12926        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12927
12928        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12929
12930        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12931        let Some(select_next_state) = self.select_next_state.as_mut() else {
12932            return Ok(());
12933        };
12934        if select_next_state.done {
12935            return Ok(());
12936        }
12937
12938        let mut new_selections = Vec::new();
12939
12940        let reversed = self.selections.oldest::<usize>(cx).reversed;
12941        let buffer = &display_map.buffer_snapshot;
12942        let query_matches = select_next_state
12943            .query
12944            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12945
12946        for query_match in query_matches.into_iter() {
12947            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12948            let offset_range = if reversed {
12949                query_match.end()..query_match.start()
12950            } else {
12951                query_match.start()..query_match.end()
12952            };
12953            let display_range = offset_range.start.to_display_point(&display_map)
12954                ..offset_range.end.to_display_point(&display_map);
12955
12956            if !select_next_state.wordwise
12957                || (!movement::is_inside_word(&display_map, display_range.start)
12958                    && !movement::is_inside_word(&display_map, display_range.end))
12959            {
12960                new_selections.push(offset_range.start..offset_range.end);
12961            }
12962        }
12963
12964        select_next_state.done = true;
12965        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12966        self.change_selections(None, window, cx, |selections| {
12967            selections.select_ranges(new_selections)
12968        });
12969
12970        Ok(())
12971    }
12972
12973    pub fn select_next(
12974        &mut self,
12975        action: &SelectNext,
12976        window: &mut Window,
12977        cx: &mut Context<Self>,
12978    ) -> Result<()> {
12979        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12980        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12981        self.select_next_match_internal(
12982            &display_map,
12983            action.replace_newest,
12984            Some(Autoscroll::newest()),
12985            window,
12986            cx,
12987        )?;
12988        Ok(())
12989    }
12990
12991    pub fn select_previous(
12992        &mut self,
12993        action: &SelectPrevious,
12994        window: &mut Window,
12995        cx: &mut Context<Self>,
12996    ) -> Result<()> {
12997        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12998        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12999        let buffer = &display_map.buffer_snapshot;
13000        let mut selections = self.selections.all::<usize>(cx);
13001        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13002            let query = &select_prev_state.query;
13003            if !select_prev_state.done {
13004                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13005                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13006                let mut next_selected_range = None;
13007                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13008                let bytes_before_last_selection =
13009                    buffer.reversed_bytes_in_range(0..last_selection.start);
13010                let bytes_after_first_selection =
13011                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13012                let query_matches = query
13013                    .stream_find_iter(bytes_before_last_selection)
13014                    .map(|result| (last_selection.start, result))
13015                    .chain(
13016                        query
13017                            .stream_find_iter(bytes_after_first_selection)
13018                            .map(|result| (buffer.len(), result)),
13019                    );
13020                for (end_offset, query_match) in query_matches {
13021                    let query_match = query_match.unwrap(); // can only fail due to I/O
13022                    let offset_range =
13023                        end_offset - query_match.end()..end_offset - query_match.start();
13024                    let display_range = offset_range.start.to_display_point(&display_map)
13025                        ..offset_range.end.to_display_point(&display_map);
13026
13027                    if !select_prev_state.wordwise
13028                        || (!movement::is_inside_word(&display_map, display_range.start)
13029                            && !movement::is_inside_word(&display_map, display_range.end))
13030                    {
13031                        next_selected_range = Some(offset_range);
13032                        break;
13033                    }
13034                }
13035
13036                if let Some(next_selected_range) = next_selected_range {
13037                    self.select_match_ranges(
13038                        next_selected_range,
13039                        last_selection.reversed,
13040                        action.replace_newest,
13041                        Some(Autoscroll::newest()),
13042                        window,
13043                        cx,
13044                    );
13045                } else {
13046                    select_prev_state.done = true;
13047                }
13048            }
13049
13050            self.select_prev_state = Some(select_prev_state);
13051        } else {
13052            let mut only_carets = true;
13053            let mut same_text_selected = true;
13054            let mut selected_text = None;
13055
13056            let mut selections_iter = selections.iter().peekable();
13057            while let Some(selection) = selections_iter.next() {
13058                if selection.start != selection.end {
13059                    only_carets = false;
13060                }
13061
13062                if same_text_selected {
13063                    if selected_text.is_none() {
13064                        selected_text =
13065                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13066                    }
13067
13068                    if let Some(next_selection) = selections_iter.peek() {
13069                        if next_selection.range().len() == selection.range().len() {
13070                            let next_selected_text = buffer
13071                                .text_for_range(next_selection.range())
13072                                .collect::<String>();
13073                            if Some(next_selected_text) != selected_text {
13074                                same_text_selected = false;
13075                                selected_text = None;
13076                            }
13077                        } else {
13078                            same_text_selected = false;
13079                            selected_text = None;
13080                        }
13081                    }
13082                }
13083            }
13084
13085            if only_carets {
13086                for selection in &mut selections {
13087                    let word_range = movement::surrounding_word(
13088                        &display_map,
13089                        selection.start.to_display_point(&display_map),
13090                    );
13091                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13092                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13093                    selection.goal = SelectionGoal::None;
13094                    selection.reversed = false;
13095                    self.select_match_ranges(
13096                        selection.start..selection.end,
13097                        selection.reversed,
13098                        action.replace_newest,
13099                        Some(Autoscroll::newest()),
13100                        window,
13101                        cx,
13102                    );
13103                }
13104                if selections.len() == 1 {
13105                    let selection = selections
13106                        .last()
13107                        .expect("ensured that there's only one selection");
13108                    let query = buffer
13109                        .text_for_range(selection.start..selection.end)
13110                        .collect::<String>();
13111                    let is_empty = query.is_empty();
13112                    let select_state = SelectNextState {
13113                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13114                        wordwise: true,
13115                        done: is_empty,
13116                    };
13117                    self.select_prev_state = Some(select_state);
13118                } else {
13119                    self.select_prev_state = None;
13120                }
13121            } else if let Some(selected_text) = selected_text {
13122                self.select_prev_state = Some(SelectNextState {
13123                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13124                    wordwise: false,
13125                    done: false,
13126                });
13127                self.select_previous(action, window, cx)?;
13128            }
13129        }
13130        Ok(())
13131    }
13132
13133    pub fn find_next_match(
13134        &mut self,
13135        _: &FindNextMatch,
13136        window: &mut Window,
13137        cx: &mut Context<Self>,
13138    ) -> Result<()> {
13139        let selections = self.selections.disjoint_anchors();
13140        match selections.first() {
13141            Some(first) if selections.len() >= 2 => {
13142                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13143                    s.select_ranges([first.range()]);
13144                });
13145            }
13146            _ => self.select_next(
13147                &SelectNext {
13148                    replace_newest: true,
13149                },
13150                window,
13151                cx,
13152            )?,
13153        }
13154        Ok(())
13155    }
13156
13157    pub fn find_previous_match(
13158        &mut self,
13159        _: &FindPreviousMatch,
13160        window: &mut Window,
13161        cx: &mut Context<Self>,
13162    ) -> Result<()> {
13163        let selections = self.selections.disjoint_anchors();
13164        match selections.last() {
13165            Some(last) if selections.len() >= 2 => {
13166                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13167                    s.select_ranges([last.range()]);
13168                });
13169            }
13170            _ => self.select_previous(
13171                &SelectPrevious {
13172                    replace_newest: true,
13173                },
13174                window,
13175                cx,
13176            )?,
13177        }
13178        Ok(())
13179    }
13180
13181    pub fn toggle_comments(
13182        &mut self,
13183        action: &ToggleComments,
13184        window: &mut Window,
13185        cx: &mut Context<Self>,
13186    ) {
13187        if self.read_only(cx) {
13188            return;
13189        }
13190        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13191        let text_layout_details = &self.text_layout_details(window);
13192        self.transact(window, cx, |this, window, cx| {
13193            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13194            let mut edits = Vec::new();
13195            let mut selection_edit_ranges = Vec::new();
13196            let mut last_toggled_row = None;
13197            let snapshot = this.buffer.read(cx).read(cx);
13198            let empty_str: Arc<str> = Arc::default();
13199            let mut suffixes_inserted = Vec::new();
13200            let ignore_indent = action.ignore_indent;
13201
13202            fn comment_prefix_range(
13203                snapshot: &MultiBufferSnapshot,
13204                row: MultiBufferRow,
13205                comment_prefix: &str,
13206                comment_prefix_whitespace: &str,
13207                ignore_indent: bool,
13208            ) -> Range<Point> {
13209                let indent_size = if ignore_indent {
13210                    0
13211                } else {
13212                    snapshot.indent_size_for_line(row).len
13213                };
13214
13215                let start = Point::new(row.0, indent_size);
13216
13217                let mut line_bytes = snapshot
13218                    .bytes_in_range(start..snapshot.max_point())
13219                    .flatten()
13220                    .copied();
13221
13222                // If this line currently begins with the line comment prefix, then record
13223                // the range containing the prefix.
13224                if line_bytes
13225                    .by_ref()
13226                    .take(comment_prefix.len())
13227                    .eq(comment_prefix.bytes())
13228                {
13229                    // Include any whitespace that matches the comment prefix.
13230                    let matching_whitespace_len = line_bytes
13231                        .zip(comment_prefix_whitespace.bytes())
13232                        .take_while(|(a, b)| a == b)
13233                        .count() as u32;
13234                    let end = Point::new(
13235                        start.row,
13236                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13237                    );
13238                    start..end
13239                } else {
13240                    start..start
13241                }
13242            }
13243
13244            fn comment_suffix_range(
13245                snapshot: &MultiBufferSnapshot,
13246                row: MultiBufferRow,
13247                comment_suffix: &str,
13248                comment_suffix_has_leading_space: bool,
13249            ) -> Range<Point> {
13250                let end = Point::new(row.0, snapshot.line_len(row));
13251                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13252
13253                let mut line_end_bytes = snapshot
13254                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13255                    .flatten()
13256                    .copied();
13257
13258                let leading_space_len = if suffix_start_column > 0
13259                    && line_end_bytes.next() == Some(b' ')
13260                    && comment_suffix_has_leading_space
13261                {
13262                    1
13263                } else {
13264                    0
13265                };
13266
13267                // If this line currently begins with the line comment prefix, then record
13268                // the range containing the prefix.
13269                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13270                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13271                    start..end
13272                } else {
13273                    end..end
13274                }
13275            }
13276
13277            // TODO: Handle selections that cross excerpts
13278            for selection in &mut selections {
13279                let start_column = snapshot
13280                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13281                    .len;
13282                let language = if let Some(language) =
13283                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13284                {
13285                    language
13286                } else {
13287                    continue;
13288                };
13289
13290                selection_edit_ranges.clear();
13291
13292                // If multiple selections contain a given row, avoid processing that
13293                // row more than once.
13294                let mut start_row = MultiBufferRow(selection.start.row);
13295                if last_toggled_row == Some(start_row) {
13296                    start_row = start_row.next_row();
13297                }
13298                let end_row =
13299                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13300                        MultiBufferRow(selection.end.row - 1)
13301                    } else {
13302                        MultiBufferRow(selection.end.row)
13303                    };
13304                last_toggled_row = Some(end_row);
13305
13306                if start_row > end_row {
13307                    continue;
13308                }
13309
13310                // If the language has line comments, toggle those.
13311                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13312
13313                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13314                if ignore_indent {
13315                    full_comment_prefixes = full_comment_prefixes
13316                        .into_iter()
13317                        .map(|s| Arc::from(s.trim_end()))
13318                        .collect();
13319                }
13320
13321                if !full_comment_prefixes.is_empty() {
13322                    let first_prefix = full_comment_prefixes
13323                        .first()
13324                        .expect("prefixes is non-empty");
13325                    let prefix_trimmed_lengths = full_comment_prefixes
13326                        .iter()
13327                        .map(|p| p.trim_end_matches(' ').len())
13328                        .collect::<SmallVec<[usize; 4]>>();
13329
13330                    let mut all_selection_lines_are_comments = true;
13331
13332                    for row in start_row.0..=end_row.0 {
13333                        let row = MultiBufferRow(row);
13334                        if start_row < end_row && snapshot.is_line_blank(row) {
13335                            continue;
13336                        }
13337
13338                        let prefix_range = full_comment_prefixes
13339                            .iter()
13340                            .zip(prefix_trimmed_lengths.iter().copied())
13341                            .map(|(prefix, trimmed_prefix_len)| {
13342                                comment_prefix_range(
13343                                    snapshot.deref(),
13344                                    row,
13345                                    &prefix[..trimmed_prefix_len],
13346                                    &prefix[trimmed_prefix_len..],
13347                                    ignore_indent,
13348                                )
13349                            })
13350                            .max_by_key(|range| range.end.column - range.start.column)
13351                            .expect("prefixes is non-empty");
13352
13353                        if prefix_range.is_empty() {
13354                            all_selection_lines_are_comments = false;
13355                        }
13356
13357                        selection_edit_ranges.push(prefix_range);
13358                    }
13359
13360                    if all_selection_lines_are_comments {
13361                        edits.extend(
13362                            selection_edit_ranges
13363                                .iter()
13364                                .cloned()
13365                                .map(|range| (range, empty_str.clone())),
13366                        );
13367                    } else {
13368                        let min_column = selection_edit_ranges
13369                            .iter()
13370                            .map(|range| range.start.column)
13371                            .min()
13372                            .unwrap_or(0);
13373                        edits.extend(selection_edit_ranges.iter().map(|range| {
13374                            let position = Point::new(range.start.row, min_column);
13375                            (position..position, first_prefix.clone())
13376                        }));
13377                    }
13378                } else if let Some((full_comment_prefix, comment_suffix)) =
13379                    language.block_comment_delimiters()
13380                {
13381                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13382                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13383                    let prefix_range = comment_prefix_range(
13384                        snapshot.deref(),
13385                        start_row,
13386                        comment_prefix,
13387                        comment_prefix_whitespace,
13388                        ignore_indent,
13389                    );
13390                    let suffix_range = comment_suffix_range(
13391                        snapshot.deref(),
13392                        end_row,
13393                        comment_suffix.trim_start_matches(' '),
13394                        comment_suffix.starts_with(' '),
13395                    );
13396
13397                    if prefix_range.is_empty() || suffix_range.is_empty() {
13398                        edits.push((
13399                            prefix_range.start..prefix_range.start,
13400                            full_comment_prefix.clone(),
13401                        ));
13402                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13403                        suffixes_inserted.push((end_row, comment_suffix.len()));
13404                    } else {
13405                        edits.push((prefix_range, empty_str.clone()));
13406                        edits.push((suffix_range, empty_str.clone()));
13407                    }
13408                } else {
13409                    continue;
13410                }
13411            }
13412
13413            drop(snapshot);
13414            this.buffer.update(cx, |buffer, cx| {
13415                buffer.edit(edits, None, cx);
13416            });
13417
13418            // Adjust selections so that they end before any comment suffixes that
13419            // were inserted.
13420            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13421            let mut selections = this.selections.all::<Point>(cx);
13422            let snapshot = this.buffer.read(cx).read(cx);
13423            for selection in &mut selections {
13424                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13425                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13426                        Ordering::Less => {
13427                            suffixes_inserted.next();
13428                            continue;
13429                        }
13430                        Ordering::Greater => break,
13431                        Ordering::Equal => {
13432                            if selection.end.column == snapshot.line_len(row) {
13433                                if selection.is_empty() {
13434                                    selection.start.column -= suffix_len as u32;
13435                                }
13436                                selection.end.column -= suffix_len as u32;
13437                            }
13438                            break;
13439                        }
13440                    }
13441                }
13442            }
13443
13444            drop(snapshot);
13445            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13446                s.select(selections)
13447            });
13448
13449            let selections = this.selections.all::<Point>(cx);
13450            let selections_on_single_row = selections.windows(2).all(|selections| {
13451                selections[0].start.row == selections[1].start.row
13452                    && selections[0].end.row == selections[1].end.row
13453                    && selections[0].start.row == selections[0].end.row
13454            });
13455            let selections_selecting = selections
13456                .iter()
13457                .any(|selection| selection.start != selection.end);
13458            let advance_downwards = action.advance_downwards
13459                && selections_on_single_row
13460                && !selections_selecting
13461                && !matches!(this.mode, EditorMode::SingleLine { .. });
13462
13463            if advance_downwards {
13464                let snapshot = this.buffer.read(cx).snapshot(cx);
13465
13466                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13467                    s.move_cursors_with(|display_snapshot, display_point, _| {
13468                        let mut point = display_point.to_point(display_snapshot);
13469                        point.row += 1;
13470                        point = snapshot.clip_point(point, Bias::Left);
13471                        let display_point = point.to_display_point(display_snapshot);
13472                        let goal = SelectionGoal::HorizontalPosition(
13473                            display_snapshot
13474                                .x_for_display_point(display_point, text_layout_details)
13475                                .into(),
13476                        );
13477                        (display_point, goal)
13478                    })
13479                });
13480            }
13481        });
13482    }
13483
13484    pub fn select_enclosing_symbol(
13485        &mut self,
13486        _: &SelectEnclosingSymbol,
13487        window: &mut Window,
13488        cx: &mut Context<Self>,
13489    ) {
13490        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13491
13492        let buffer = self.buffer.read(cx).snapshot(cx);
13493        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13494
13495        fn update_selection(
13496            selection: &Selection<usize>,
13497            buffer_snap: &MultiBufferSnapshot,
13498        ) -> Option<Selection<usize>> {
13499            let cursor = selection.head();
13500            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13501            for symbol in symbols.iter().rev() {
13502                let start = symbol.range.start.to_offset(buffer_snap);
13503                let end = symbol.range.end.to_offset(buffer_snap);
13504                let new_range = start..end;
13505                if start < selection.start || end > selection.end {
13506                    return Some(Selection {
13507                        id: selection.id,
13508                        start: new_range.start,
13509                        end: new_range.end,
13510                        goal: SelectionGoal::None,
13511                        reversed: selection.reversed,
13512                    });
13513                }
13514            }
13515            None
13516        }
13517
13518        let mut selected_larger_symbol = false;
13519        let new_selections = old_selections
13520            .iter()
13521            .map(|selection| match update_selection(selection, &buffer) {
13522                Some(new_selection) => {
13523                    if new_selection.range() != selection.range() {
13524                        selected_larger_symbol = true;
13525                    }
13526                    new_selection
13527                }
13528                None => selection.clone(),
13529            })
13530            .collect::<Vec<_>>();
13531
13532        if selected_larger_symbol {
13533            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13534                s.select(new_selections);
13535            });
13536        }
13537    }
13538
13539    pub fn select_larger_syntax_node(
13540        &mut self,
13541        _: &SelectLargerSyntaxNode,
13542        window: &mut Window,
13543        cx: &mut Context<Self>,
13544    ) {
13545        let Some(visible_row_count) = self.visible_row_count() else {
13546            return;
13547        };
13548        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13549        if old_selections.is_empty() {
13550            return;
13551        }
13552
13553        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13554
13555        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13556        let buffer = self.buffer.read(cx).snapshot(cx);
13557
13558        let mut selected_larger_node = false;
13559        let mut new_selections = old_selections
13560            .iter()
13561            .map(|selection| {
13562                let old_range = selection.start..selection.end;
13563
13564                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13565                    // manually select word at selection
13566                    if ["string_content", "inline"].contains(&node.kind()) {
13567                        let word_range = {
13568                            let display_point = buffer
13569                                .offset_to_point(old_range.start)
13570                                .to_display_point(&display_map);
13571                            let Range { start, end } =
13572                                movement::surrounding_word(&display_map, display_point);
13573                            start.to_point(&display_map).to_offset(&buffer)
13574                                ..end.to_point(&display_map).to_offset(&buffer)
13575                        };
13576                        // ignore if word is already selected
13577                        if !word_range.is_empty() && old_range != word_range {
13578                            let last_word_range = {
13579                                let display_point = buffer
13580                                    .offset_to_point(old_range.end)
13581                                    .to_display_point(&display_map);
13582                                let Range { start, end } =
13583                                    movement::surrounding_word(&display_map, display_point);
13584                                start.to_point(&display_map).to_offset(&buffer)
13585                                    ..end.to_point(&display_map).to_offset(&buffer)
13586                            };
13587                            // only select word if start and end point belongs to same word
13588                            if word_range == last_word_range {
13589                                selected_larger_node = true;
13590                                return Selection {
13591                                    id: selection.id,
13592                                    start: word_range.start,
13593                                    end: word_range.end,
13594                                    goal: SelectionGoal::None,
13595                                    reversed: selection.reversed,
13596                                };
13597                            }
13598                        }
13599                    }
13600                }
13601
13602                let mut new_range = old_range.clone();
13603                while let Some((_node, containing_range)) =
13604                    buffer.syntax_ancestor(new_range.clone())
13605                {
13606                    new_range = match containing_range {
13607                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13608                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13609                    };
13610                    if !display_map.intersects_fold(new_range.start)
13611                        && !display_map.intersects_fold(new_range.end)
13612                    {
13613                        break;
13614                    }
13615                }
13616
13617                selected_larger_node |= new_range != old_range;
13618                Selection {
13619                    id: selection.id,
13620                    start: new_range.start,
13621                    end: new_range.end,
13622                    goal: SelectionGoal::None,
13623                    reversed: selection.reversed,
13624                }
13625            })
13626            .collect::<Vec<_>>();
13627
13628        if !selected_larger_node {
13629            return; // don't put this call in the history
13630        }
13631
13632        // scroll based on transformation done to the last selection created by the user
13633        let (last_old, last_new) = old_selections
13634            .last()
13635            .zip(new_selections.last().cloned())
13636            .expect("old_selections isn't empty");
13637
13638        // revert selection
13639        let is_selection_reversed = {
13640            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13641            new_selections.last_mut().expect("checked above").reversed =
13642                should_newest_selection_be_reversed;
13643            should_newest_selection_be_reversed
13644        };
13645
13646        if selected_larger_node {
13647            self.select_syntax_node_history.disable_clearing = true;
13648            self.change_selections(None, window, cx, |s| {
13649                s.select(new_selections.clone());
13650            });
13651            self.select_syntax_node_history.disable_clearing = false;
13652        }
13653
13654        let start_row = last_new.start.to_display_point(&display_map).row().0;
13655        let end_row = last_new.end.to_display_point(&display_map).row().0;
13656        let selection_height = end_row - start_row + 1;
13657        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13658
13659        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13660        let scroll_behavior = if fits_on_the_screen {
13661            self.request_autoscroll(Autoscroll::fit(), cx);
13662            SelectSyntaxNodeScrollBehavior::FitSelection
13663        } else if is_selection_reversed {
13664            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13665            SelectSyntaxNodeScrollBehavior::CursorTop
13666        } else {
13667            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13668            SelectSyntaxNodeScrollBehavior::CursorBottom
13669        };
13670
13671        self.select_syntax_node_history.push((
13672            old_selections,
13673            scroll_behavior,
13674            is_selection_reversed,
13675        ));
13676    }
13677
13678    pub fn select_smaller_syntax_node(
13679        &mut self,
13680        _: &SelectSmallerSyntaxNode,
13681        window: &mut Window,
13682        cx: &mut Context<Self>,
13683    ) {
13684        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13685
13686        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13687            self.select_syntax_node_history.pop()
13688        {
13689            if let Some(selection) = selections.last_mut() {
13690                selection.reversed = is_selection_reversed;
13691            }
13692
13693            self.select_syntax_node_history.disable_clearing = true;
13694            self.change_selections(None, window, cx, |s| {
13695                s.select(selections.to_vec());
13696            });
13697            self.select_syntax_node_history.disable_clearing = false;
13698
13699            match scroll_behavior {
13700                SelectSyntaxNodeScrollBehavior::CursorTop => {
13701                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13702                }
13703                SelectSyntaxNodeScrollBehavior::FitSelection => {
13704                    self.request_autoscroll(Autoscroll::fit(), cx);
13705                }
13706                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13707                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13708                }
13709            }
13710        }
13711    }
13712
13713    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13714        if !EditorSettings::get_global(cx).gutter.runnables {
13715            self.clear_tasks();
13716            return Task::ready(());
13717        }
13718        let project = self.project.as_ref().map(Entity::downgrade);
13719        let task_sources = self.lsp_task_sources(cx);
13720        let multi_buffer = self.buffer.downgrade();
13721        cx.spawn_in(window, async move |editor, cx| {
13722            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13723            let Some(project) = project.and_then(|p| p.upgrade()) else {
13724                return;
13725            };
13726            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13727                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13728            }) else {
13729                return;
13730            };
13731
13732            let hide_runnables = project
13733                .update(cx, |project, cx| {
13734                    // Do not display any test indicators in non-dev server remote projects.
13735                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13736                })
13737                .unwrap_or(true);
13738            if hide_runnables {
13739                return;
13740            }
13741            let new_rows =
13742                cx.background_spawn({
13743                    let snapshot = display_snapshot.clone();
13744                    async move {
13745                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13746                    }
13747                })
13748                    .await;
13749            let Ok(lsp_tasks) =
13750                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13751            else {
13752                return;
13753            };
13754            let lsp_tasks = lsp_tasks.await;
13755
13756            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13757                lsp_tasks
13758                    .into_iter()
13759                    .flat_map(|(kind, tasks)| {
13760                        tasks.into_iter().filter_map(move |(location, task)| {
13761                            Some((kind.clone(), location?, task))
13762                        })
13763                    })
13764                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13765                        let buffer = location.target.buffer;
13766                        let buffer_snapshot = buffer.read(cx).snapshot();
13767                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13768                            |(excerpt_id, snapshot, _)| {
13769                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13770                                    display_snapshot
13771                                        .buffer_snapshot
13772                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13773                                } else {
13774                                    None
13775                                }
13776                            },
13777                        );
13778                        if let Some(offset) = offset {
13779                            let task_buffer_range =
13780                                location.target.range.to_point(&buffer_snapshot);
13781                            let context_buffer_range =
13782                                task_buffer_range.to_offset(&buffer_snapshot);
13783                            let context_range = BufferOffset(context_buffer_range.start)
13784                                ..BufferOffset(context_buffer_range.end);
13785
13786                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13787                                .or_insert_with(|| RunnableTasks {
13788                                    templates: Vec::new(),
13789                                    offset,
13790                                    column: task_buffer_range.start.column,
13791                                    extra_variables: HashMap::default(),
13792                                    context_range,
13793                                })
13794                                .templates
13795                                .push((kind, task.original_task().clone()));
13796                        }
13797
13798                        acc
13799                    })
13800            }) else {
13801                return;
13802            };
13803
13804            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
13805                buffer.language_settings(cx).tasks.prefer_lsp
13806            }) else {
13807                return;
13808            };
13809
13810            let rows = Self::runnable_rows(
13811                project,
13812                display_snapshot,
13813                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
13814                new_rows,
13815                cx.clone(),
13816            );
13817            editor
13818                .update(cx, |editor, _| {
13819                    editor.clear_tasks();
13820                    for (key, mut value) in rows {
13821                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13822                            value.templates.extend(lsp_tasks.templates);
13823                        }
13824
13825                        editor.insert_tasks(key, value);
13826                    }
13827                    for (key, value) in lsp_tasks_by_rows {
13828                        editor.insert_tasks(key, value);
13829                    }
13830                })
13831                .ok();
13832        })
13833    }
13834    fn fetch_runnable_ranges(
13835        snapshot: &DisplaySnapshot,
13836        range: Range<Anchor>,
13837    ) -> Vec<language::RunnableRange> {
13838        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13839    }
13840
13841    fn runnable_rows(
13842        project: Entity<Project>,
13843        snapshot: DisplaySnapshot,
13844        prefer_lsp: bool,
13845        runnable_ranges: Vec<RunnableRange>,
13846        mut cx: AsyncWindowContext,
13847    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13848        runnable_ranges
13849            .into_iter()
13850            .filter_map(|mut runnable| {
13851                let mut tasks = cx
13852                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13853                    .ok()?;
13854                if prefer_lsp {
13855                    tasks.retain(|(task_kind, _)| {
13856                        !matches!(task_kind, TaskSourceKind::Language { .. })
13857                    });
13858                }
13859                if tasks.is_empty() {
13860                    return None;
13861                }
13862
13863                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13864
13865                let row = snapshot
13866                    .buffer_snapshot
13867                    .buffer_line_for_row(MultiBufferRow(point.row))?
13868                    .1
13869                    .start
13870                    .row;
13871
13872                let context_range =
13873                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13874                Some((
13875                    (runnable.buffer_id, row),
13876                    RunnableTasks {
13877                        templates: tasks,
13878                        offset: snapshot
13879                            .buffer_snapshot
13880                            .anchor_before(runnable.run_range.start),
13881                        context_range,
13882                        column: point.column,
13883                        extra_variables: runnable.extra_captures,
13884                    },
13885                ))
13886            })
13887            .collect()
13888    }
13889
13890    fn templates_with_tags(
13891        project: &Entity<Project>,
13892        runnable: &mut Runnable,
13893        cx: &mut App,
13894    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13895        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13896            let (worktree_id, file) = project
13897                .buffer_for_id(runnable.buffer, cx)
13898                .and_then(|buffer| buffer.read(cx).file())
13899                .map(|file| (file.worktree_id(cx), file.clone()))
13900                .unzip();
13901
13902            (
13903                project.task_store().read(cx).task_inventory().cloned(),
13904                worktree_id,
13905                file,
13906            )
13907        });
13908
13909        let mut templates_with_tags = mem::take(&mut runnable.tags)
13910            .into_iter()
13911            .flat_map(|RunnableTag(tag)| {
13912                inventory
13913                    .as_ref()
13914                    .into_iter()
13915                    .flat_map(|inventory| {
13916                        inventory.read(cx).list_tasks(
13917                            file.clone(),
13918                            Some(runnable.language.clone()),
13919                            worktree_id,
13920                            cx,
13921                        )
13922                    })
13923                    .filter(move |(_, template)| {
13924                        template.tags.iter().any(|source_tag| source_tag == &tag)
13925                    })
13926            })
13927            .sorted_by_key(|(kind, _)| kind.to_owned())
13928            .collect::<Vec<_>>();
13929        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13930            // Strongest source wins; if we have worktree tag binding, prefer that to
13931            // global and language bindings;
13932            // if we have a global binding, prefer that to language binding.
13933            let first_mismatch = templates_with_tags
13934                .iter()
13935                .position(|(tag_source, _)| tag_source != leading_tag_source);
13936            if let Some(index) = first_mismatch {
13937                templates_with_tags.truncate(index);
13938            }
13939        }
13940
13941        templates_with_tags
13942    }
13943
13944    pub fn move_to_enclosing_bracket(
13945        &mut self,
13946        _: &MoveToEnclosingBracket,
13947        window: &mut Window,
13948        cx: &mut Context<Self>,
13949    ) {
13950        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13951        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13952            s.move_offsets_with(|snapshot, selection| {
13953                let Some(enclosing_bracket_ranges) =
13954                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13955                else {
13956                    return;
13957                };
13958
13959                let mut best_length = usize::MAX;
13960                let mut best_inside = false;
13961                let mut best_in_bracket_range = false;
13962                let mut best_destination = None;
13963                for (open, close) in enclosing_bracket_ranges {
13964                    let close = close.to_inclusive();
13965                    let length = close.end() - open.start;
13966                    let inside = selection.start >= open.end && selection.end <= *close.start();
13967                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13968                        || close.contains(&selection.head());
13969
13970                    // If best is next to a bracket and current isn't, skip
13971                    if !in_bracket_range && best_in_bracket_range {
13972                        continue;
13973                    }
13974
13975                    // Prefer smaller lengths unless best is inside and current isn't
13976                    if length > best_length && (best_inside || !inside) {
13977                        continue;
13978                    }
13979
13980                    best_length = length;
13981                    best_inside = inside;
13982                    best_in_bracket_range = in_bracket_range;
13983                    best_destination = Some(
13984                        if close.contains(&selection.start) && close.contains(&selection.end) {
13985                            if inside { open.end } else { open.start }
13986                        } else if inside {
13987                            *close.start()
13988                        } else {
13989                            *close.end()
13990                        },
13991                    );
13992                }
13993
13994                if let Some(destination) = best_destination {
13995                    selection.collapse_to(destination, SelectionGoal::None);
13996                }
13997            })
13998        });
13999    }
14000
14001    pub fn undo_selection(
14002        &mut self,
14003        _: &UndoSelection,
14004        window: &mut Window,
14005        cx: &mut Context<Self>,
14006    ) {
14007        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14008        self.end_selection(window, cx);
14009        self.selection_history.mode = SelectionHistoryMode::Undoing;
14010        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14011            self.change_selections(None, window, cx, |s| {
14012                s.select_anchors(entry.selections.to_vec())
14013            });
14014            self.select_next_state = entry.select_next_state;
14015            self.select_prev_state = entry.select_prev_state;
14016            self.add_selections_state = entry.add_selections_state;
14017            self.request_autoscroll(Autoscroll::newest(), cx);
14018        }
14019        self.selection_history.mode = SelectionHistoryMode::Normal;
14020    }
14021
14022    pub fn redo_selection(
14023        &mut self,
14024        _: &RedoSelection,
14025        window: &mut Window,
14026        cx: &mut Context<Self>,
14027    ) {
14028        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14029        self.end_selection(window, cx);
14030        self.selection_history.mode = SelectionHistoryMode::Redoing;
14031        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14032            self.change_selections(None, window, cx, |s| {
14033                s.select_anchors(entry.selections.to_vec())
14034            });
14035            self.select_next_state = entry.select_next_state;
14036            self.select_prev_state = entry.select_prev_state;
14037            self.add_selections_state = entry.add_selections_state;
14038            self.request_autoscroll(Autoscroll::newest(), cx);
14039        }
14040        self.selection_history.mode = SelectionHistoryMode::Normal;
14041    }
14042
14043    pub fn expand_excerpts(
14044        &mut self,
14045        action: &ExpandExcerpts,
14046        _: &mut Window,
14047        cx: &mut Context<Self>,
14048    ) {
14049        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14050    }
14051
14052    pub fn expand_excerpts_down(
14053        &mut self,
14054        action: &ExpandExcerptsDown,
14055        _: &mut Window,
14056        cx: &mut Context<Self>,
14057    ) {
14058        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14059    }
14060
14061    pub fn expand_excerpts_up(
14062        &mut self,
14063        action: &ExpandExcerptsUp,
14064        _: &mut Window,
14065        cx: &mut Context<Self>,
14066    ) {
14067        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14068    }
14069
14070    pub fn expand_excerpts_for_direction(
14071        &mut self,
14072        lines: u32,
14073        direction: ExpandExcerptDirection,
14074
14075        cx: &mut Context<Self>,
14076    ) {
14077        let selections = self.selections.disjoint_anchors();
14078
14079        let lines = if lines == 0 {
14080            EditorSettings::get_global(cx).expand_excerpt_lines
14081        } else {
14082            lines
14083        };
14084
14085        self.buffer.update(cx, |buffer, cx| {
14086            let snapshot = buffer.snapshot(cx);
14087            let mut excerpt_ids = selections
14088                .iter()
14089                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14090                .collect::<Vec<_>>();
14091            excerpt_ids.sort();
14092            excerpt_ids.dedup();
14093            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14094        })
14095    }
14096
14097    pub fn expand_excerpt(
14098        &mut self,
14099        excerpt: ExcerptId,
14100        direction: ExpandExcerptDirection,
14101        window: &mut Window,
14102        cx: &mut Context<Self>,
14103    ) {
14104        let current_scroll_position = self.scroll_position(cx);
14105        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14106        let mut should_scroll_up = false;
14107
14108        if direction == ExpandExcerptDirection::Down {
14109            let multi_buffer = self.buffer.read(cx);
14110            let snapshot = multi_buffer.snapshot(cx);
14111            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14112                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14113                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14114                        let buffer_snapshot = buffer.read(cx).snapshot();
14115                        let excerpt_end_row =
14116                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14117                        let last_row = buffer_snapshot.max_point().row;
14118                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14119                        should_scroll_up = lines_below >= lines_to_expand;
14120                    }
14121                }
14122            }
14123        }
14124
14125        self.buffer.update(cx, |buffer, cx| {
14126            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14127        });
14128
14129        if should_scroll_up {
14130            let new_scroll_position =
14131                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14132            self.set_scroll_position(new_scroll_position, window, cx);
14133        }
14134    }
14135
14136    pub fn go_to_singleton_buffer_point(
14137        &mut self,
14138        point: Point,
14139        window: &mut Window,
14140        cx: &mut Context<Self>,
14141    ) {
14142        self.go_to_singleton_buffer_range(point..point, window, cx);
14143    }
14144
14145    pub fn go_to_singleton_buffer_range(
14146        &mut self,
14147        range: Range<Point>,
14148        window: &mut Window,
14149        cx: &mut Context<Self>,
14150    ) {
14151        let multibuffer = self.buffer().read(cx);
14152        let Some(buffer) = multibuffer.as_singleton() else {
14153            return;
14154        };
14155        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14156            return;
14157        };
14158        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14159            return;
14160        };
14161        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14162            s.select_anchor_ranges([start..end])
14163        });
14164    }
14165
14166    pub fn go_to_diagnostic(
14167        &mut self,
14168        _: &GoToDiagnostic,
14169        window: &mut Window,
14170        cx: &mut Context<Self>,
14171    ) {
14172        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14173        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14174    }
14175
14176    pub fn go_to_prev_diagnostic(
14177        &mut self,
14178        _: &GoToPreviousDiagnostic,
14179        window: &mut Window,
14180        cx: &mut Context<Self>,
14181    ) {
14182        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14183        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14184    }
14185
14186    pub fn go_to_diagnostic_impl(
14187        &mut self,
14188        direction: Direction,
14189        window: &mut Window,
14190        cx: &mut Context<Self>,
14191    ) {
14192        let buffer = self.buffer.read(cx).snapshot(cx);
14193        let selection = self.selections.newest::<usize>(cx);
14194
14195        let mut active_group_id = None;
14196        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14197            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14198                active_group_id = Some(active_group.group_id);
14199            }
14200        }
14201
14202        fn filtered(
14203            snapshot: EditorSnapshot,
14204            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14205        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14206            diagnostics
14207                .filter(|entry| entry.range.start != entry.range.end)
14208                .filter(|entry| !entry.diagnostic.is_unnecessary)
14209                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14210        }
14211
14212        let snapshot = self.snapshot(window, cx);
14213        let before = filtered(
14214            snapshot.clone(),
14215            buffer
14216                .diagnostics_in_range(0..selection.start)
14217                .filter(|entry| entry.range.start <= selection.start),
14218        );
14219        let after = filtered(
14220            snapshot,
14221            buffer
14222                .diagnostics_in_range(selection.start..buffer.len())
14223                .filter(|entry| entry.range.start >= selection.start),
14224        );
14225
14226        let mut found: Option<DiagnosticEntry<usize>> = None;
14227        if direction == Direction::Prev {
14228            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14229            {
14230                for diagnostic in prev_diagnostics.into_iter().rev() {
14231                    if diagnostic.range.start != selection.start
14232                        || active_group_id
14233                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14234                    {
14235                        found = Some(diagnostic);
14236                        break 'outer;
14237                    }
14238                }
14239            }
14240        } else {
14241            for diagnostic in after.chain(before) {
14242                if diagnostic.range.start != selection.start
14243                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14244                {
14245                    found = Some(diagnostic);
14246                    break;
14247                }
14248            }
14249        }
14250        let Some(next_diagnostic) = found else {
14251            return;
14252        };
14253
14254        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14255            return;
14256        };
14257        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14258            s.select_ranges(vec![
14259                next_diagnostic.range.start..next_diagnostic.range.start,
14260            ])
14261        });
14262        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14263        self.refresh_inline_completion(false, true, window, cx);
14264    }
14265
14266    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14267        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14268        let snapshot = self.snapshot(window, cx);
14269        let selection = self.selections.newest::<Point>(cx);
14270        self.go_to_hunk_before_or_after_position(
14271            &snapshot,
14272            selection.head(),
14273            Direction::Next,
14274            window,
14275            cx,
14276        );
14277    }
14278
14279    pub fn go_to_hunk_before_or_after_position(
14280        &mut self,
14281        snapshot: &EditorSnapshot,
14282        position: Point,
14283        direction: Direction,
14284        window: &mut Window,
14285        cx: &mut Context<Editor>,
14286    ) {
14287        let row = if direction == Direction::Next {
14288            self.hunk_after_position(snapshot, position)
14289                .map(|hunk| hunk.row_range.start)
14290        } else {
14291            self.hunk_before_position(snapshot, position)
14292        };
14293
14294        if let Some(row) = row {
14295            let destination = Point::new(row.0, 0);
14296            let autoscroll = Autoscroll::center();
14297
14298            self.unfold_ranges(&[destination..destination], false, false, cx);
14299            self.change_selections(Some(autoscroll), window, cx, |s| {
14300                s.select_ranges([destination..destination]);
14301            });
14302        }
14303    }
14304
14305    fn hunk_after_position(
14306        &mut self,
14307        snapshot: &EditorSnapshot,
14308        position: Point,
14309    ) -> Option<MultiBufferDiffHunk> {
14310        snapshot
14311            .buffer_snapshot
14312            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14313            .find(|hunk| hunk.row_range.start.0 > position.row)
14314            .or_else(|| {
14315                snapshot
14316                    .buffer_snapshot
14317                    .diff_hunks_in_range(Point::zero()..position)
14318                    .find(|hunk| hunk.row_range.end.0 < position.row)
14319            })
14320    }
14321
14322    fn go_to_prev_hunk(
14323        &mut self,
14324        _: &GoToPreviousHunk,
14325        window: &mut Window,
14326        cx: &mut Context<Self>,
14327    ) {
14328        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14329        let snapshot = self.snapshot(window, cx);
14330        let selection = self.selections.newest::<Point>(cx);
14331        self.go_to_hunk_before_or_after_position(
14332            &snapshot,
14333            selection.head(),
14334            Direction::Prev,
14335            window,
14336            cx,
14337        );
14338    }
14339
14340    fn hunk_before_position(
14341        &mut self,
14342        snapshot: &EditorSnapshot,
14343        position: Point,
14344    ) -> Option<MultiBufferRow> {
14345        snapshot
14346            .buffer_snapshot
14347            .diff_hunk_before(position)
14348            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14349    }
14350
14351    fn go_to_next_change(
14352        &mut self,
14353        _: &GoToNextChange,
14354        window: &mut Window,
14355        cx: &mut Context<Self>,
14356    ) {
14357        if let Some(selections) = self
14358            .change_list
14359            .next_change(1, Direction::Next)
14360            .map(|s| s.to_vec())
14361        {
14362            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14363                let map = s.display_map();
14364                s.select_display_ranges(selections.iter().map(|a| {
14365                    let point = a.to_display_point(&map);
14366                    point..point
14367                }))
14368            })
14369        }
14370    }
14371
14372    fn go_to_previous_change(
14373        &mut self,
14374        _: &GoToPreviousChange,
14375        window: &mut Window,
14376        cx: &mut Context<Self>,
14377    ) {
14378        if let Some(selections) = self
14379            .change_list
14380            .next_change(1, Direction::Prev)
14381            .map(|s| s.to_vec())
14382        {
14383            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14384                let map = s.display_map();
14385                s.select_display_ranges(selections.iter().map(|a| {
14386                    let point = a.to_display_point(&map);
14387                    point..point
14388                }))
14389            })
14390        }
14391    }
14392
14393    fn go_to_line<T: 'static>(
14394        &mut self,
14395        position: Anchor,
14396        highlight_color: Option<Hsla>,
14397        window: &mut Window,
14398        cx: &mut Context<Self>,
14399    ) {
14400        let snapshot = self.snapshot(window, cx).display_snapshot;
14401        let position = position.to_point(&snapshot.buffer_snapshot);
14402        let start = snapshot
14403            .buffer_snapshot
14404            .clip_point(Point::new(position.row, 0), Bias::Left);
14405        let end = start + Point::new(1, 0);
14406        let start = snapshot.buffer_snapshot.anchor_before(start);
14407        let end = snapshot.buffer_snapshot.anchor_before(end);
14408
14409        self.highlight_rows::<T>(
14410            start..end,
14411            highlight_color
14412                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14413            Default::default(),
14414            cx,
14415        );
14416
14417        if self.buffer.read(cx).is_singleton() {
14418            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14419        }
14420    }
14421
14422    pub fn go_to_definition(
14423        &mut self,
14424        _: &GoToDefinition,
14425        window: &mut Window,
14426        cx: &mut Context<Self>,
14427    ) -> Task<Result<Navigated>> {
14428        let definition =
14429            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14430        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14431        cx.spawn_in(window, async move |editor, cx| {
14432            if definition.await? == Navigated::Yes {
14433                return Ok(Navigated::Yes);
14434            }
14435            match fallback_strategy {
14436                GoToDefinitionFallback::None => Ok(Navigated::No),
14437                GoToDefinitionFallback::FindAllReferences => {
14438                    match editor.update_in(cx, |editor, window, cx| {
14439                        editor.find_all_references(&FindAllReferences, window, cx)
14440                    })? {
14441                        Some(references) => references.await,
14442                        None => Ok(Navigated::No),
14443                    }
14444                }
14445            }
14446        })
14447    }
14448
14449    pub fn go_to_declaration(
14450        &mut self,
14451        _: &GoToDeclaration,
14452        window: &mut Window,
14453        cx: &mut Context<Self>,
14454    ) -> Task<Result<Navigated>> {
14455        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14456    }
14457
14458    pub fn go_to_declaration_split(
14459        &mut self,
14460        _: &GoToDeclaration,
14461        window: &mut Window,
14462        cx: &mut Context<Self>,
14463    ) -> Task<Result<Navigated>> {
14464        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14465    }
14466
14467    pub fn go_to_implementation(
14468        &mut self,
14469        _: &GoToImplementation,
14470        window: &mut Window,
14471        cx: &mut Context<Self>,
14472    ) -> Task<Result<Navigated>> {
14473        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14474    }
14475
14476    pub fn go_to_implementation_split(
14477        &mut self,
14478        _: &GoToImplementationSplit,
14479        window: &mut Window,
14480        cx: &mut Context<Self>,
14481    ) -> Task<Result<Navigated>> {
14482        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14483    }
14484
14485    pub fn go_to_type_definition(
14486        &mut self,
14487        _: &GoToTypeDefinition,
14488        window: &mut Window,
14489        cx: &mut Context<Self>,
14490    ) -> Task<Result<Navigated>> {
14491        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14492    }
14493
14494    pub fn go_to_definition_split(
14495        &mut self,
14496        _: &GoToDefinitionSplit,
14497        window: &mut Window,
14498        cx: &mut Context<Self>,
14499    ) -> Task<Result<Navigated>> {
14500        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14501    }
14502
14503    pub fn go_to_type_definition_split(
14504        &mut self,
14505        _: &GoToTypeDefinitionSplit,
14506        window: &mut Window,
14507        cx: &mut Context<Self>,
14508    ) -> Task<Result<Navigated>> {
14509        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14510    }
14511
14512    fn go_to_definition_of_kind(
14513        &mut self,
14514        kind: GotoDefinitionKind,
14515        split: bool,
14516        window: &mut Window,
14517        cx: &mut Context<Self>,
14518    ) -> Task<Result<Navigated>> {
14519        let Some(provider) = self.semantics_provider.clone() else {
14520            return Task::ready(Ok(Navigated::No));
14521        };
14522        let head = self.selections.newest::<usize>(cx).head();
14523        let buffer = self.buffer.read(cx);
14524        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14525            text_anchor
14526        } else {
14527            return Task::ready(Ok(Navigated::No));
14528        };
14529
14530        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14531            return Task::ready(Ok(Navigated::No));
14532        };
14533
14534        cx.spawn_in(window, async move |editor, cx| {
14535            let definitions = definitions.await?;
14536            let navigated = editor
14537                .update_in(cx, |editor, window, cx| {
14538                    editor.navigate_to_hover_links(
14539                        Some(kind),
14540                        definitions
14541                            .into_iter()
14542                            .filter(|location| {
14543                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14544                            })
14545                            .map(HoverLink::Text)
14546                            .collect::<Vec<_>>(),
14547                        split,
14548                        window,
14549                        cx,
14550                    )
14551                })?
14552                .await?;
14553            anyhow::Ok(navigated)
14554        })
14555    }
14556
14557    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14558        let selection = self.selections.newest_anchor();
14559        let head = selection.head();
14560        let tail = selection.tail();
14561
14562        let Some((buffer, start_position)) =
14563            self.buffer.read(cx).text_anchor_for_position(head, cx)
14564        else {
14565            return;
14566        };
14567
14568        let end_position = if head != tail {
14569            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14570                return;
14571            };
14572            Some(pos)
14573        } else {
14574            None
14575        };
14576
14577        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14578            let url = if let Some(end_pos) = end_position {
14579                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14580            } else {
14581                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14582            };
14583
14584            if let Some(url) = url {
14585                editor.update(cx, |_, cx| {
14586                    cx.open_url(&url);
14587                })
14588            } else {
14589                Ok(())
14590            }
14591        });
14592
14593        url_finder.detach();
14594    }
14595
14596    pub fn open_selected_filename(
14597        &mut self,
14598        _: &OpenSelectedFilename,
14599        window: &mut Window,
14600        cx: &mut Context<Self>,
14601    ) {
14602        let Some(workspace) = self.workspace() else {
14603            return;
14604        };
14605
14606        let position = self.selections.newest_anchor().head();
14607
14608        let Some((buffer, buffer_position)) =
14609            self.buffer.read(cx).text_anchor_for_position(position, cx)
14610        else {
14611            return;
14612        };
14613
14614        let project = self.project.clone();
14615
14616        cx.spawn_in(window, async move |_, cx| {
14617            let result = find_file(&buffer, project, buffer_position, cx).await;
14618
14619            if let Some((_, path)) = result {
14620                workspace
14621                    .update_in(cx, |workspace, window, cx| {
14622                        workspace.open_resolved_path(path, window, cx)
14623                    })?
14624                    .await?;
14625            }
14626            anyhow::Ok(())
14627        })
14628        .detach();
14629    }
14630
14631    pub(crate) fn navigate_to_hover_links(
14632        &mut self,
14633        kind: Option<GotoDefinitionKind>,
14634        mut definitions: Vec<HoverLink>,
14635        split: bool,
14636        window: &mut Window,
14637        cx: &mut Context<Editor>,
14638    ) -> Task<Result<Navigated>> {
14639        // If there is one definition, just open it directly
14640        if definitions.len() == 1 {
14641            let definition = definitions.pop().unwrap();
14642
14643            enum TargetTaskResult {
14644                Location(Option<Location>),
14645                AlreadyNavigated,
14646            }
14647
14648            let target_task = match definition {
14649                HoverLink::Text(link) => {
14650                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14651                }
14652                HoverLink::InlayHint(lsp_location, server_id) => {
14653                    let computation =
14654                        self.compute_target_location(lsp_location, server_id, window, cx);
14655                    cx.background_spawn(async move {
14656                        let location = computation.await?;
14657                        Ok(TargetTaskResult::Location(location))
14658                    })
14659                }
14660                HoverLink::Url(url) => {
14661                    cx.open_url(&url);
14662                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14663                }
14664                HoverLink::File(path) => {
14665                    if let Some(workspace) = self.workspace() {
14666                        cx.spawn_in(window, async move |_, cx| {
14667                            workspace
14668                                .update_in(cx, |workspace, window, cx| {
14669                                    workspace.open_resolved_path(path, window, cx)
14670                                })?
14671                                .await
14672                                .map(|_| TargetTaskResult::AlreadyNavigated)
14673                        })
14674                    } else {
14675                        Task::ready(Ok(TargetTaskResult::Location(None)))
14676                    }
14677                }
14678            };
14679            cx.spawn_in(window, async move |editor, cx| {
14680                let target = match target_task.await.context("target resolution task")? {
14681                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14682                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14683                    TargetTaskResult::Location(Some(target)) => target,
14684                };
14685
14686                editor.update_in(cx, |editor, window, cx| {
14687                    let Some(workspace) = editor.workspace() else {
14688                        return Navigated::No;
14689                    };
14690                    let pane = workspace.read(cx).active_pane().clone();
14691
14692                    let range = target.range.to_point(target.buffer.read(cx));
14693                    let range = editor.range_for_match(&range);
14694                    let range = collapse_multiline_range(range);
14695
14696                    if !split
14697                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14698                    {
14699                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14700                    } else {
14701                        window.defer(cx, move |window, cx| {
14702                            let target_editor: Entity<Self> =
14703                                workspace.update(cx, |workspace, cx| {
14704                                    let pane = if split {
14705                                        workspace.adjacent_pane(window, cx)
14706                                    } else {
14707                                        workspace.active_pane().clone()
14708                                    };
14709
14710                                    workspace.open_project_item(
14711                                        pane,
14712                                        target.buffer.clone(),
14713                                        true,
14714                                        true,
14715                                        window,
14716                                        cx,
14717                                    )
14718                                });
14719                            target_editor.update(cx, |target_editor, cx| {
14720                                // When selecting a definition in a different buffer, disable the nav history
14721                                // to avoid creating a history entry at the previous cursor location.
14722                                pane.update(cx, |pane, _| pane.disable_history());
14723                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14724                                pane.update(cx, |pane, _| pane.enable_history());
14725                            });
14726                        });
14727                    }
14728                    Navigated::Yes
14729                })
14730            })
14731        } else if !definitions.is_empty() {
14732            cx.spawn_in(window, async move |editor, cx| {
14733                let (title, location_tasks, workspace) = editor
14734                    .update_in(cx, |editor, window, cx| {
14735                        let tab_kind = match kind {
14736                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14737                            _ => "Definitions",
14738                        };
14739                        let title = definitions
14740                            .iter()
14741                            .find_map(|definition| match definition {
14742                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14743                                    let buffer = origin.buffer.read(cx);
14744                                    format!(
14745                                        "{} for {}",
14746                                        tab_kind,
14747                                        buffer
14748                                            .text_for_range(origin.range.clone())
14749                                            .collect::<String>()
14750                                    )
14751                                }),
14752                                HoverLink::InlayHint(_, _) => None,
14753                                HoverLink::Url(_) => None,
14754                                HoverLink::File(_) => None,
14755                            })
14756                            .unwrap_or(tab_kind.to_string());
14757                        let location_tasks = definitions
14758                            .into_iter()
14759                            .map(|definition| match definition {
14760                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14761                                HoverLink::InlayHint(lsp_location, server_id) => editor
14762                                    .compute_target_location(lsp_location, server_id, window, cx),
14763                                HoverLink::Url(_) => Task::ready(Ok(None)),
14764                                HoverLink::File(_) => Task::ready(Ok(None)),
14765                            })
14766                            .collect::<Vec<_>>();
14767                        (title, location_tasks, editor.workspace().clone())
14768                    })
14769                    .context("location tasks preparation")?;
14770
14771                let locations = future::join_all(location_tasks)
14772                    .await
14773                    .into_iter()
14774                    .filter_map(|location| location.transpose())
14775                    .collect::<Result<_>>()
14776                    .context("location tasks")?;
14777
14778                let Some(workspace) = workspace else {
14779                    return Ok(Navigated::No);
14780                };
14781                let opened = workspace
14782                    .update_in(cx, |workspace, window, cx| {
14783                        Self::open_locations_in_multibuffer(
14784                            workspace,
14785                            locations,
14786                            title,
14787                            split,
14788                            MultibufferSelectionMode::First,
14789                            window,
14790                            cx,
14791                        )
14792                    })
14793                    .ok();
14794
14795                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14796            })
14797        } else {
14798            Task::ready(Ok(Navigated::No))
14799        }
14800    }
14801
14802    fn compute_target_location(
14803        &self,
14804        lsp_location: lsp::Location,
14805        server_id: LanguageServerId,
14806        window: &mut Window,
14807        cx: &mut Context<Self>,
14808    ) -> Task<anyhow::Result<Option<Location>>> {
14809        let Some(project) = self.project.clone() else {
14810            return Task::ready(Ok(None));
14811        };
14812
14813        cx.spawn_in(window, async move |editor, cx| {
14814            let location_task = editor.update(cx, |_, cx| {
14815                project.update(cx, |project, cx| {
14816                    let language_server_name = project
14817                        .language_server_statuses(cx)
14818                        .find(|(id, _)| server_id == *id)
14819                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14820                    language_server_name.map(|language_server_name| {
14821                        project.open_local_buffer_via_lsp(
14822                            lsp_location.uri.clone(),
14823                            server_id,
14824                            language_server_name,
14825                            cx,
14826                        )
14827                    })
14828                })
14829            })?;
14830            let location = match location_task {
14831                Some(task) => Some({
14832                    let target_buffer_handle = task.await.context("open local buffer")?;
14833                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
14834                        let target_start = target_buffer
14835                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14836                        let target_end = target_buffer
14837                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14838                        target_buffer.anchor_after(target_start)
14839                            ..target_buffer.anchor_before(target_end)
14840                    })?;
14841                    Location {
14842                        buffer: target_buffer_handle,
14843                        range,
14844                    }
14845                }),
14846                None => None,
14847            };
14848            Ok(location)
14849        })
14850    }
14851
14852    pub fn find_all_references(
14853        &mut self,
14854        _: &FindAllReferences,
14855        window: &mut Window,
14856        cx: &mut Context<Self>,
14857    ) -> Option<Task<Result<Navigated>>> {
14858        let selection = self.selections.newest::<usize>(cx);
14859        let multi_buffer = self.buffer.read(cx);
14860        let head = selection.head();
14861
14862        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14863        let head_anchor = multi_buffer_snapshot.anchor_at(
14864            head,
14865            if head < selection.tail() {
14866                Bias::Right
14867            } else {
14868                Bias::Left
14869            },
14870        );
14871
14872        match self
14873            .find_all_references_task_sources
14874            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14875        {
14876            Ok(_) => {
14877                log::info!(
14878                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14879                );
14880                return None;
14881            }
14882            Err(i) => {
14883                self.find_all_references_task_sources.insert(i, head_anchor);
14884            }
14885        }
14886
14887        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14888        let workspace = self.workspace()?;
14889        let project = workspace.read(cx).project().clone();
14890        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14891        Some(cx.spawn_in(window, async move |editor, cx| {
14892            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14893                if let Ok(i) = editor
14894                    .find_all_references_task_sources
14895                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14896                {
14897                    editor.find_all_references_task_sources.remove(i);
14898                }
14899            });
14900
14901            let locations = references.await?;
14902            if locations.is_empty() {
14903                return anyhow::Ok(Navigated::No);
14904            }
14905
14906            workspace.update_in(cx, |workspace, window, cx| {
14907                let title = locations
14908                    .first()
14909                    .as_ref()
14910                    .map(|location| {
14911                        let buffer = location.buffer.read(cx);
14912                        format!(
14913                            "References to `{}`",
14914                            buffer
14915                                .text_for_range(location.range.clone())
14916                                .collect::<String>()
14917                        )
14918                    })
14919                    .unwrap();
14920                Self::open_locations_in_multibuffer(
14921                    workspace,
14922                    locations,
14923                    title,
14924                    false,
14925                    MultibufferSelectionMode::First,
14926                    window,
14927                    cx,
14928                );
14929                Navigated::Yes
14930            })
14931        }))
14932    }
14933
14934    /// Opens a multibuffer with the given project locations in it
14935    pub fn open_locations_in_multibuffer(
14936        workspace: &mut Workspace,
14937        mut locations: Vec<Location>,
14938        title: String,
14939        split: bool,
14940        multibuffer_selection_mode: MultibufferSelectionMode,
14941        window: &mut Window,
14942        cx: &mut Context<Workspace>,
14943    ) {
14944        // If there are multiple definitions, open them in a multibuffer
14945        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14946        let mut locations = locations.into_iter().peekable();
14947        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14948        let capability = workspace.project().read(cx).capability();
14949
14950        let excerpt_buffer = cx.new(|cx| {
14951            let mut multibuffer = MultiBuffer::new(capability);
14952            while let Some(location) = locations.next() {
14953                let buffer = location.buffer.read(cx);
14954                let mut ranges_for_buffer = Vec::new();
14955                let range = location.range.to_point(buffer);
14956                ranges_for_buffer.push(range.clone());
14957
14958                while let Some(next_location) = locations.peek() {
14959                    if next_location.buffer == location.buffer {
14960                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14961                        locations.next();
14962                    } else {
14963                        break;
14964                    }
14965                }
14966
14967                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14968                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14969                    PathKey::for_buffer(&location.buffer, cx),
14970                    location.buffer.clone(),
14971                    ranges_for_buffer,
14972                    DEFAULT_MULTIBUFFER_CONTEXT,
14973                    cx,
14974                );
14975                ranges.extend(new_ranges)
14976            }
14977
14978            multibuffer.with_title(title)
14979        });
14980
14981        let editor = cx.new(|cx| {
14982            Editor::for_multibuffer(
14983                excerpt_buffer,
14984                Some(workspace.project().clone()),
14985                window,
14986                cx,
14987            )
14988        });
14989        editor.update(cx, |editor, cx| {
14990            match multibuffer_selection_mode {
14991                MultibufferSelectionMode::First => {
14992                    if let Some(first_range) = ranges.first() {
14993                        editor.change_selections(None, window, cx, |selections| {
14994                            selections.clear_disjoint();
14995                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14996                        });
14997                    }
14998                    editor.highlight_background::<Self>(
14999                        &ranges,
15000                        |theme| theme.editor_highlighted_line_background,
15001                        cx,
15002                    );
15003                }
15004                MultibufferSelectionMode::All => {
15005                    editor.change_selections(None, window, cx, |selections| {
15006                        selections.clear_disjoint();
15007                        selections.select_anchor_ranges(ranges);
15008                    });
15009                }
15010            }
15011            editor.register_buffers_with_language_servers(cx);
15012        });
15013
15014        let item = Box::new(editor);
15015        let item_id = item.item_id();
15016
15017        if split {
15018            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15019        } else {
15020            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15021                let (preview_item_id, preview_item_idx) =
15022                    workspace.active_pane().read_with(cx, |pane, _| {
15023                        (pane.preview_item_id(), pane.preview_item_idx())
15024                    });
15025
15026                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15027
15028                if let Some(preview_item_id) = preview_item_id {
15029                    workspace.active_pane().update(cx, |pane, cx| {
15030                        pane.remove_item(preview_item_id, false, false, window, cx);
15031                    });
15032                }
15033            } else {
15034                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15035            }
15036        }
15037        workspace.active_pane().update(cx, |pane, cx| {
15038            pane.set_preview_item_id(Some(item_id), cx);
15039        });
15040    }
15041
15042    pub fn rename(
15043        &mut self,
15044        _: &Rename,
15045        window: &mut Window,
15046        cx: &mut Context<Self>,
15047    ) -> Option<Task<Result<()>>> {
15048        use language::ToOffset as _;
15049
15050        let provider = self.semantics_provider.clone()?;
15051        let selection = self.selections.newest_anchor().clone();
15052        let (cursor_buffer, cursor_buffer_position) = self
15053            .buffer
15054            .read(cx)
15055            .text_anchor_for_position(selection.head(), cx)?;
15056        let (tail_buffer, cursor_buffer_position_end) = self
15057            .buffer
15058            .read(cx)
15059            .text_anchor_for_position(selection.tail(), cx)?;
15060        if tail_buffer != cursor_buffer {
15061            return None;
15062        }
15063
15064        let snapshot = cursor_buffer.read(cx).snapshot();
15065        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15066        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15067        let prepare_rename = provider
15068            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15069            .unwrap_or_else(|| Task::ready(Ok(None)));
15070        drop(snapshot);
15071
15072        Some(cx.spawn_in(window, async move |this, cx| {
15073            let rename_range = if let Some(range) = prepare_rename.await? {
15074                Some(range)
15075            } else {
15076                this.update(cx, |this, cx| {
15077                    let buffer = this.buffer.read(cx).snapshot(cx);
15078                    let mut buffer_highlights = this
15079                        .document_highlights_for_position(selection.head(), &buffer)
15080                        .filter(|highlight| {
15081                            highlight.start.excerpt_id == selection.head().excerpt_id
15082                                && highlight.end.excerpt_id == selection.head().excerpt_id
15083                        });
15084                    buffer_highlights
15085                        .next()
15086                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15087                })?
15088            };
15089            if let Some(rename_range) = rename_range {
15090                this.update_in(cx, |this, window, cx| {
15091                    let snapshot = cursor_buffer.read(cx).snapshot();
15092                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15093                    let cursor_offset_in_rename_range =
15094                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15095                    let cursor_offset_in_rename_range_end =
15096                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15097
15098                    this.take_rename(false, window, cx);
15099                    let buffer = this.buffer.read(cx).read(cx);
15100                    let cursor_offset = selection.head().to_offset(&buffer);
15101                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15102                    let rename_end = rename_start + rename_buffer_range.len();
15103                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15104                    let mut old_highlight_id = None;
15105                    let old_name: Arc<str> = buffer
15106                        .chunks(rename_start..rename_end, true)
15107                        .map(|chunk| {
15108                            if old_highlight_id.is_none() {
15109                                old_highlight_id = chunk.syntax_highlight_id;
15110                            }
15111                            chunk.text
15112                        })
15113                        .collect::<String>()
15114                        .into();
15115
15116                    drop(buffer);
15117
15118                    // Position the selection in the rename editor so that it matches the current selection.
15119                    this.show_local_selections = false;
15120                    let rename_editor = cx.new(|cx| {
15121                        let mut editor = Editor::single_line(window, cx);
15122                        editor.buffer.update(cx, |buffer, cx| {
15123                            buffer.edit([(0..0, old_name.clone())], None, cx)
15124                        });
15125                        let rename_selection_range = match cursor_offset_in_rename_range
15126                            .cmp(&cursor_offset_in_rename_range_end)
15127                        {
15128                            Ordering::Equal => {
15129                                editor.select_all(&SelectAll, window, cx);
15130                                return editor;
15131                            }
15132                            Ordering::Less => {
15133                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15134                            }
15135                            Ordering::Greater => {
15136                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15137                            }
15138                        };
15139                        if rename_selection_range.end > old_name.len() {
15140                            editor.select_all(&SelectAll, window, cx);
15141                        } else {
15142                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15143                                s.select_ranges([rename_selection_range]);
15144                            });
15145                        }
15146                        editor
15147                    });
15148                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15149                        if e == &EditorEvent::Focused {
15150                            cx.emit(EditorEvent::FocusedIn)
15151                        }
15152                    })
15153                    .detach();
15154
15155                    let write_highlights =
15156                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15157                    let read_highlights =
15158                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15159                    let ranges = write_highlights
15160                        .iter()
15161                        .flat_map(|(_, ranges)| ranges.iter())
15162                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15163                        .cloned()
15164                        .collect();
15165
15166                    this.highlight_text::<Rename>(
15167                        ranges,
15168                        HighlightStyle {
15169                            fade_out: Some(0.6),
15170                            ..Default::default()
15171                        },
15172                        cx,
15173                    );
15174                    let rename_focus_handle = rename_editor.focus_handle(cx);
15175                    window.focus(&rename_focus_handle);
15176                    let block_id = this.insert_blocks(
15177                        [BlockProperties {
15178                            style: BlockStyle::Flex,
15179                            placement: BlockPlacement::Below(range.start),
15180                            height: Some(1),
15181                            render: Arc::new({
15182                                let rename_editor = rename_editor.clone();
15183                                move |cx: &mut BlockContext| {
15184                                    let mut text_style = cx.editor_style.text.clone();
15185                                    if let Some(highlight_style) = old_highlight_id
15186                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15187                                    {
15188                                        text_style = text_style.highlight(highlight_style);
15189                                    }
15190                                    div()
15191                                        .block_mouse_except_scroll()
15192                                        .pl(cx.anchor_x)
15193                                        .child(EditorElement::new(
15194                                            &rename_editor,
15195                                            EditorStyle {
15196                                                background: cx.theme().system().transparent,
15197                                                local_player: cx.editor_style.local_player,
15198                                                text: text_style,
15199                                                scrollbar_width: cx.editor_style.scrollbar_width,
15200                                                syntax: cx.editor_style.syntax.clone(),
15201                                                status: cx.editor_style.status.clone(),
15202                                                inlay_hints_style: HighlightStyle {
15203                                                    font_weight: Some(FontWeight::BOLD),
15204                                                    ..make_inlay_hints_style(cx.app)
15205                                                },
15206                                                inline_completion_styles: make_suggestion_styles(
15207                                                    cx.app,
15208                                                ),
15209                                                ..EditorStyle::default()
15210                                            },
15211                                        ))
15212                                        .into_any_element()
15213                                }
15214                            }),
15215                            priority: 0,
15216                            render_in_minimap: true,
15217                        }],
15218                        Some(Autoscroll::fit()),
15219                        cx,
15220                    )[0];
15221                    this.pending_rename = Some(RenameState {
15222                        range,
15223                        old_name,
15224                        editor: rename_editor,
15225                        block_id,
15226                    });
15227                })?;
15228            }
15229
15230            Ok(())
15231        }))
15232    }
15233
15234    pub fn confirm_rename(
15235        &mut self,
15236        _: &ConfirmRename,
15237        window: &mut Window,
15238        cx: &mut Context<Self>,
15239    ) -> Option<Task<Result<()>>> {
15240        let rename = self.take_rename(false, window, cx)?;
15241        let workspace = self.workspace()?.downgrade();
15242        let (buffer, start) = self
15243            .buffer
15244            .read(cx)
15245            .text_anchor_for_position(rename.range.start, cx)?;
15246        let (end_buffer, _) = self
15247            .buffer
15248            .read(cx)
15249            .text_anchor_for_position(rename.range.end, cx)?;
15250        if buffer != end_buffer {
15251            return None;
15252        }
15253
15254        let old_name = rename.old_name;
15255        let new_name = rename.editor.read(cx).text(cx);
15256
15257        let rename = self.semantics_provider.as_ref()?.perform_rename(
15258            &buffer,
15259            start,
15260            new_name.clone(),
15261            cx,
15262        )?;
15263
15264        Some(cx.spawn_in(window, async move |editor, cx| {
15265            let project_transaction = rename.await?;
15266            Self::open_project_transaction(
15267                &editor,
15268                workspace,
15269                project_transaction,
15270                format!("Rename: {}{}", old_name, new_name),
15271                cx,
15272            )
15273            .await?;
15274
15275            editor.update(cx, |editor, cx| {
15276                editor.refresh_document_highlights(cx);
15277            })?;
15278            Ok(())
15279        }))
15280    }
15281
15282    fn take_rename(
15283        &mut self,
15284        moving_cursor: bool,
15285        window: &mut Window,
15286        cx: &mut Context<Self>,
15287    ) -> Option<RenameState> {
15288        let rename = self.pending_rename.take()?;
15289        if rename.editor.focus_handle(cx).is_focused(window) {
15290            window.focus(&self.focus_handle);
15291        }
15292
15293        self.remove_blocks(
15294            [rename.block_id].into_iter().collect(),
15295            Some(Autoscroll::fit()),
15296            cx,
15297        );
15298        self.clear_highlights::<Rename>(cx);
15299        self.show_local_selections = true;
15300
15301        if moving_cursor {
15302            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15303                editor.selections.newest::<usize>(cx).head()
15304            });
15305
15306            // Update the selection to match the position of the selection inside
15307            // the rename editor.
15308            let snapshot = self.buffer.read(cx).read(cx);
15309            let rename_range = rename.range.to_offset(&snapshot);
15310            let cursor_in_editor = snapshot
15311                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15312                .min(rename_range.end);
15313            drop(snapshot);
15314
15315            self.change_selections(None, window, cx, |s| {
15316                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15317            });
15318        } else {
15319            self.refresh_document_highlights(cx);
15320        }
15321
15322        Some(rename)
15323    }
15324
15325    pub fn pending_rename(&self) -> Option<&RenameState> {
15326        self.pending_rename.as_ref()
15327    }
15328
15329    fn format(
15330        &mut self,
15331        _: &Format,
15332        window: &mut Window,
15333        cx: &mut Context<Self>,
15334    ) -> Option<Task<Result<()>>> {
15335        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15336
15337        let project = match &self.project {
15338            Some(project) => project.clone(),
15339            None => return None,
15340        };
15341
15342        Some(self.perform_format(
15343            project,
15344            FormatTrigger::Manual,
15345            FormatTarget::Buffers,
15346            window,
15347            cx,
15348        ))
15349    }
15350
15351    fn format_selections(
15352        &mut self,
15353        _: &FormatSelections,
15354        window: &mut Window,
15355        cx: &mut Context<Self>,
15356    ) -> Option<Task<Result<()>>> {
15357        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15358
15359        let project = match &self.project {
15360            Some(project) => project.clone(),
15361            None => return None,
15362        };
15363
15364        let ranges = self
15365            .selections
15366            .all_adjusted(cx)
15367            .into_iter()
15368            .map(|selection| selection.range())
15369            .collect_vec();
15370
15371        Some(self.perform_format(
15372            project,
15373            FormatTrigger::Manual,
15374            FormatTarget::Ranges(ranges),
15375            window,
15376            cx,
15377        ))
15378    }
15379
15380    fn perform_format(
15381        &mut self,
15382        project: Entity<Project>,
15383        trigger: FormatTrigger,
15384        target: FormatTarget,
15385        window: &mut Window,
15386        cx: &mut Context<Self>,
15387    ) -> Task<Result<()>> {
15388        let buffer = self.buffer.clone();
15389        let (buffers, target) = match target {
15390            FormatTarget::Buffers => {
15391                let mut buffers = buffer.read(cx).all_buffers();
15392                if trigger == FormatTrigger::Save {
15393                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15394                }
15395                (buffers, LspFormatTarget::Buffers)
15396            }
15397            FormatTarget::Ranges(selection_ranges) => {
15398                let multi_buffer = buffer.read(cx);
15399                let snapshot = multi_buffer.read(cx);
15400                let mut buffers = HashSet::default();
15401                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15402                    BTreeMap::new();
15403                for selection_range in selection_ranges {
15404                    for (buffer, buffer_range, _) in
15405                        snapshot.range_to_buffer_ranges(selection_range)
15406                    {
15407                        let buffer_id = buffer.remote_id();
15408                        let start = buffer.anchor_before(buffer_range.start);
15409                        let end = buffer.anchor_after(buffer_range.end);
15410                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15411                        buffer_id_to_ranges
15412                            .entry(buffer_id)
15413                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15414                            .or_insert_with(|| vec![start..end]);
15415                    }
15416                }
15417                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15418            }
15419        };
15420
15421        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15422        let selections_prev = transaction_id_prev
15423            .and_then(|transaction_id_prev| {
15424                // default to selections as they were after the last edit, if we have them,
15425                // instead of how they are now.
15426                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15427                // will take you back to where you made the last edit, instead of staying where you scrolled
15428                self.selection_history
15429                    .transaction(transaction_id_prev)
15430                    .map(|t| t.0.clone())
15431            })
15432            .unwrap_or_else(|| {
15433                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15434                self.selections.disjoint_anchors()
15435            });
15436
15437        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15438        let format = project.update(cx, |project, cx| {
15439            project.format(buffers, target, true, trigger, cx)
15440        });
15441
15442        cx.spawn_in(window, async move |editor, cx| {
15443            let transaction = futures::select_biased! {
15444                transaction = format.log_err().fuse() => transaction,
15445                () = timeout => {
15446                    log::warn!("timed out waiting for formatting");
15447                    None
15448                }
15449            };
15450
15451            buffer
15452                .update(cx, |buffer, cx| {
15453                    if let Some(transaction) = transaction {
15454                        if !buffer.is_singleton() {
15455                            buffer.push_transaction(&transaction.0, cx);
15456                        }
15457                    }
15458                    cx.notify();
15459                })
15460                .ok();
15461
15462            if let Some(transaction_id_now) =
15463                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15464            {
15465                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15466                if has_new_transaction {
15467                    _ = editor.update(cx, |editor, _| {
15468                        editor
15469                            .selection_history
15470                            .insert_transaction(transaction_id_now, selections_prev);
15471                    });
15472                }
15473            }
15474
15475            Ok(())
15476        })
15477    }
15478
15479    fn organize_imports(
15480        &mut self,
15481        _: &OrganizeImports,
15482        window: &mut Window,
15483        cx: &mut Context<Self>,
15484    ) -> Option<Task<Result<()>>> {
15485        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15486        let project = match &self.project {
15487            Some(project) => project.clone(),
15488            None => return None,
15489        };
15490        Some(self.perform_code_action_kind(
15491            project,
15492            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15493            window,
15494            cx,
15495        ))
15496    }
15497
15498    fn perform_code_action_kind(
15499        &mut self,
15500        project: Entity<Project>,
15501        kind: CodeActionKind,
15502        window: &mut Window,
15503        cx: &mut Context<Self>,
15504    ) -> Task<Result<()>> {
15505        let buffer = self.buffer.clone();
15506        let buffers = buffer.read(cx).all_buffers();
15507        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15508        let apply_action = project.update(cx, |project, cx| {
15509            project.apply_code_action_kind(buffers, kind, true, cx)
15510        });
15511        cx.spawn_in(window, async move |_, cx| {
15512            let transaction = futures::select_biased! {
15513                () = timeout => {
15514                    log::warn!("timed out waiting for executing code action");
15515                    None
15516                }
15517                transaction = apply_action.log_err().fuse() => transaction,
15518            };
15519            buffer
15520                .update(cx, |buffer, cx| {
15521                    // check if we need this
15522                    if let Some(transaction) = transaction {
15523                        if !buffer.is_singleton() {
15524                            buffer.push_transaction(&transaction.0, cx);
15525                        }
15526                    }
15527                    cx.notify();
15528                })
15529                .ok();
15530            Ok(())
15531        })
15532    }
15533
15534    fn restart_language_server(
15535        &mut self,
15536        _: &RestartLanguageServer,
15537        _: &mut Window,
15538        cx: &mut Context<Self>,
15539    ) {
15540        if let Some(project) = self.project.clone() {
15541            self.buffer.update(cx, |multi_buffer, cx| {
15542                project.update(cx, |project, cx| {
15543                    project.restart_language_servers_for_buffers(
15544                        multi_buffer.all_buffers().into_iter().collect(),
15545                        cx,
15546                    );
15547                });
15548            })
15549        }
15550    }
15551
15552    fn stop_language_server(
15553        &mut self,
15554        _: &StopLanguageServer,
15555        _: &mut Window,
15556        cx: &mut Context<Self>,
15557    ) {
15558        if let Some(project) = self.project.clone() {
15559            self.buffer.update(cx, |multi_buffer, cx| {
15560                project.update(cx, |project, cx| {
15561                    project.stop_language_servers_for_buffers(
15562                        multi_buffer.all_buffers().into_iter().collect(),
15563                        cx,
15564                    );
15565                    cx.emit(project::Event::RefreshInlayHints);
15566                });
15567            });
15568        }
15569    }
15570
15571    fn cancel_language_server_work(
15572        workspace: &mut Workspace,
15573        _: &actions::CancelLanguageServerWork,
15574        _: &mut Window,
15575        cx: &mut Context<Workspace>,
15576    ) {
15577        let project = workspace.project();
15578        let buffers = workspace
15579            .active_item(cx)
15580            .and_then(|item| item.act_as::<Editor>(cx))
15581            .map_or(HashSet::default(), |editor| {
15582                editor.read(cx).buffer.read(cx).all_buffers()
15583            });
15584        project.update(cx, |project, cx| {
15585            project.cancel_language_server_work_for_buffers(buffers, cx);
15586        });
15587    }
15588
15589    fn show_character_palette(
15590        &mut self,
15591        _: &ShowCharacterPalette,
15592        window: &mut Window,
15593        _: &mut Context<Self>,
15594    ) {
15595        window.show_character_palette();
15596    }
15597
15598    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15599        if self.mode.is_minimap() {
15600            return;
15601        }
15602
15603        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15604            let buffer = self.buffer.read(cx).snapshot(cx);
15605            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15606            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15607            let is_valid = buffer
15608                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15609                .any(|entry| {
15610                    entry.diagnostic.is_primary
15611                        && !entry.range.is_empty()
15612                        && entry.range.start == primary_range_start
15613                        && entry.diagnostic.message == active_diagnostics.active_message
15614                });
15615
15616            if !is_valid {
15617                self.dismiss_diagnostics(cx);
15618            }
15619        }
15620    }
15621
15622    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15623        match &self.active_diagnostics {
15624            ActiveDiagnostic::Group(group) => Some(group),
15625            _ => None,
15626        }
15627    }
15628
15629    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15630        self.dismiss_diagnostics(cx);
15631        self.active_diagnostics = ActiveDiagnostic::All;
15632    }
15633
15634    fn activate_diagnostics(
15635        &mut self,
15636        buffer_id: BufferId,
15637        diagnostic: DiagnosticEntry<usize>,
15638        window: &mut Window,
15639        cx: &mut Context<Self>,
15640    ) {
15641        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15642            return;
15643        }
15644        self.dismiss_diagnostics(cx);
15645        let snapshot = self.snapshot(window, cx);
15646        let buffer = self.buffer.read(cx).snapshot(cx);
15647        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15648            return;
15649        };
15650
15651        let diagnostic_group = buffer
15652            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15653            .collect::<Vec<_>>();
15654
15655        let blocks =
15656            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15657
15658        let blocks = self.display_map.update(cx, |display_map, cx| {
15659            display_map.insert_blocks(blocks, cx).into_iter().collect()
15660        });
15661        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15662            active_range: buffer.anchor_before(diagnostic.range.start)
15663                ..buffer.anchor_after(diagnostic.range.end),
15664            active_message: diagnostic.diagnostic.message.clone(),
15665            group_id: diagnostic.diagnostic.group_id,
15666            blocks,
15667        });
15668        cx.notify();
15669    }
15670
15671    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15672        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15673            return;
15674        };
15675
15676        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15677        if let ActiveDiagnostic::Group(group) = prev {
15678            self.display_map.update(cx, |display_map, cx| {
15679                display_map.remove_blocks(group.blocks, cx);
15680            });
15681            cx.notify();
15682        }
15683    }
15684
15685    /// Disable inline diagnostics rendering for this editor.
15686    pub fn disable_inline_diagnostics(&mut self) {
15687        self.inline_diagnostics_enabled = false;
15688        self.inline_diagnostics_update = Task::ready(());
15689        self.inline_diagnostics.clear();
15690    }
15691
15692    pub fn diagnostics_enabled(&self) -> bool {
15693        self.mode.is_full()
15694    }
15695
15696    pub fn inline_diagnostics_enabled(&self) -> bool {
15697        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15698    }
15699
15700    pub fn show_inline_diagnostics(&self) -> bool {
15701        self.show_inline_diagnostics
15702    }
15703
15704    pub fn toggle_inline_diagnostics(
15705        &mut self,
15706        _: &ToggleInlineDiagnostics,
15707        window: &mut Window,
15708        cx: &mut Context<Editor>,
15709    ) {
15710        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15711        self.refresh_inline_diagnostics(false, window, cx);
15712    }
15713
15714    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15715        self.diagnostics_max_severity = severity;
15716        self.display_map.update(cx, |display_map, _| {
15717            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15718        });
15719    }
15720
15721    pub fn toggle_diagnostics(
15722        &mut self,
15723        _: &ToggleDiagnostics,
15724        window: &mut Window,
15725        cx: &mut Context<Editor>,
15726    ) {
15727        if !self.diagnostics_enabled() {
15728            return;
15729        }
15730
15731        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15732            EditorSettings::get_global(cx)
15733                .diagnostics_max_severity
15734                .filter(|severity| severity != &DiagnosticSeverity::Off)
15735                .unwrap_or(DiagnosticSeverity::Hint)
15736        } else {
15737            DiagnosticSeverity::Off
15738        };
15739        self.set_max_diagnostics_severity(new_severity, cx);
15740        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15741            self.active_diagnostics = ActiveDiagnostic::None;
15742            self.inline_diagnostics_update = Task::ready(());
15743            self.inline_diagnostics.clear();
15744        } else {
15745            self.refresh_inline_diagnostics(false, window, cx);
15746        }
15747
15748        cx.notify();
15749    }
15750
15751    pub fn toggle_minimap(
15752        &mut self,
15753        _: &ToggleMinimap,
15754        window: &mut Window,
15755        cx: &mut Context<Editor>,
15756    ) {
15757        if self.supports_minimap(cx) {
15758            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15759        }
15760    }
15761
15762    fn refresh_inline_diagnostics(
15763        &mut self,
15764        debounce: bool,
15765        window: &mut Window,
15766        cx: &mut Context<Self>,
15767    ) {
15768        let max_severity = ProjectSettings::get_global(cx)
15769            .diagnostics
15770            .inline
15771            .max_severity
15772            .unwrap_or(self.diagnostics_max_severity);
15773
15774        if !self.inline_diagnostics_enabled()
15775            || !self.show_inline_diagnostics
15776            || max_severity == DiagnosticSeverity::Off
15777        {
15778            self.inline_diagnostics_update = Task::ready(());
15779            self.inline_diagnostics.clear();
15780            return;
15781        }
15782
15783        let debounce_ms = ProjectSettings::get_global(cx)
15784            .diagnostics
15785            .inline
15786            .update_debounce_ms;
15787        let debounce = if debounce && debounce_ms > 0 {
15788            Some(Duration::from_millis(debounce_ms))
15789        } else {
15790            None
15791        };
15792        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15793            if let Some(debounce) = debounce {
15794                cx.background_executor().timer(debounce).await;
15795            }
15796            let Some(snapshot) = editor.upgrade().and_then(|editor| {
15797                editor
15798                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15799                    .ok()
15800            }) else {
15801                return;
15802            };
15803
15804            let new_inline_diagnostics = cx
15805                .background_spawn(async move {
15806                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15807                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15808                        let message = diagnostic_entry
15809                            .diagnostic
15810                            .message
15811                            .split_once('\n')
15812                            .map(|(line, _)| line)
15813                            .map(SharedString::new)
15814                            .unwrap_or_else(|| {
15815                                SharedString::from(diagnostic_entry.diagnostic.message)
15816                            });
15817                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15818                        let (Ok(i) | Err(i)) = inline_diagnostics
15819                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15820                        inline_diagnostics.insert(
15821                            i,
15822                            (
15823                                start_anchor,
15824                                InlineDiagnostic {
15825                                    message,
15826                                    group_id: diagnostic_entry.diagnostic.group_id,
15827                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15828                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15829                                    severity: diagnostic_entry.diagnostic.severity,
15830                                },
15831                            ),
15832                        );
15833                    }
15834                    inline_diagnostics
15835                })
15836                .await;
15837
15838            editor
15839                .update(cx, |editor, cx| {
15840                    editor.inline_diagnostics = new_inline_diagnostics;
15841                    cx.notify();
15842                })
15843                .ok();
15844        });
15845    }
15846
15847    pub fn set_selections_from_remote(
15848        &mut self,
15849        selections: Vec<Selection<Anchor>>,
15850        pending_selection: Option<Selection<Anchor>>,
15851        window: &mut Window,
15852        cx: &mut Context<Self>,
15853    ) {
15854        let old_cursor_position = self.selections.newest_anchor().head();
15855        self.selections.change_with(cx, |s| {
15856            s.select_anchors(selections);
15857            if let Some(pending_selection) = pending_selection {
15858                s.set_pending(pending_selection, SelectMode::Character);
15859            } else {
15860                s.clear_pending();
15861            }
15862        });
15863        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15864    }
15865
15866    pub fn transact(
15867        &mut self,
15868        window: &mut Window,
15869        cx: &mut Context<Self>,
15870        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15871    ) -> Option<TransactionId> {
15872        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15873            this.start_transaction_at(Instant::now(), window, cx);
15874            update(this, window, cx);
15875            this.end_transaction_at(Instant::now(), cx)
15876        })
15877    }
15878
15879    pub fn start_transaction_at(
15880        &mut self,
15881        now: Instant,
15882        window: &mut Window,
15883        cx: &mut Context<Self>,
15884    ) {
15885        self.end_selection(window, cx);
15886        if let Some(tx_id) = self
15887            .buffer
15888            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15889        {
15890            self.selection_history
15891                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15892            cx.emit(EditorEvent::TransactionBegun {
15893                transaction_id: tx_id,
15894            })
15895        }
15896    }
15897
15898    pub fn end_transaction_at(
15899        &mut self,
15900        now: Instant,
15901        cx: &mut Context<Self>,
15902    ) -> Option<TransactionId> {
15903        if let Some(transaction_id) = self
15904            .buffer
15905            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15906        {
15907            if let Some((_, end_selections)) =
15908                self.selection_history.transaction_mut(transaction_id)
15909            {
15910                *end_selections = Some(self.selections.disjoint_anchors());
15911            } else {
15912                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15913            }
15914
15915            cx.emit(EditorEvent::Edited { transaction_id });
15916            Some(transaction_id)
15917        } else {
15918            None
15919        }
15920    }
15921
15922    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15923        if self.selection_mark_mode {
15924            self.change_selections(None, window, cx, |s| {
15925                s.move_with(|_, sel| {
15926                    sel.collapse_to(sel.head(), SelectionGoal::None);
15927                });
15928            })
15929        }
15930        self.selection_mark_mode = true;
15931        cx.notify();
15932    }
15933
15934    pub fn swap_selection_ends(
15935        &mut self,
15936        _: &actions::SwapSelectionEnds,
15937        window: &mut Window,
15938        cx: &mut Context<Self>,
15939    ) {
15940        self.change_selections(None, window, cx, |s| {
15941            s.move_with(|_, sel| {
15942                if sel.start != sel.end {
15943                    sel.reversed = !sel.reversed
15944                }
15945            });
15946        });
15947        self.request_autoscroll(Autoscroll::newest(), cx);
15948        cx.notify();
15949    }
15950
15951    pub fn toggle_fold(
15952        &mut self,
15953        _: &actions::ToggleFold,
15954        window: &mut Window,
15955        cx: &mut Context<Self>,
15956    ) {
15957        if self.is_singleton(cx) {
15958            let selection = self.selections.newest::<Point>(cx);
15959
15960            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15961            let range = if selection.is_empty() {
15962                let point = selection.head().to_display_point(&display_map);
15963                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15964                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15965                    .to_point(&display_map);
15966                start..end
15967            } else {
15968                selection.range()
15969            };
15970            if display_map.folds_in_range(range).next().is_some() {
15971                self.unfold_lines(&Default::default(), window, cx)
15972            } else {
15973                self.fold(&Default::default(), window, cx)
15974            }
15975        } else {
15976            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15977            let buffer_ids: HashSet<_> = self
15978                .selections
15979                .disjoint_anchor_ranges()
15980                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15981                .collect();
15982
15983            let should_unfold = buffer_ids
15984                .iter()
15985                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15986
15987            for buffer_id in buffer_ids {
15988                if should_unfold {
15989                    self.unfold_buffer(buffer_id, cx);
15990                } else {
15991                    self.fold_buffer(buffer_id, cx);
15992                }
15993            }
15994        }
15995    }
15996
15997    pub fn toggle_fold_recursive(
15998        &mut self,
15999        _: &actions::ToggleFoldRecursive,
16000        window: &mut Window,
16001        cx: &mut Context<Self>,
16002    ) {
16003        let selection = self.selections.newest::<Point>(cx);
16004
16005        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16006        let range = if selection.is_empty() {
16007            let point = selection.head().to_display_point(&display_map);
16008            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16009            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16010                .to_point(&display_map);
16011            start..end
16012        } else {
16013            selection.range()
16014        };
16015        if display_map.folds_in_range(range).next().is_some() {
16016            self.unfold_recursive(&Default::default(), window, cx)
16017        } else {
16018            self.fold_recursive(&Default::default(), window, cx)
16019        }
16020    }
16021
16022    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16023        if self.is_singleton(cx) {
16024            let mut to_fold = Vec::new();
16025            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16026            let selections = self.selections.all_adjusted(cx);
16027
16028            for selection in selections {
16029                let range = selection.range().sorted();
16030                let buffer_start_row = range.start.row;
16031
16032                if range.start.row != range.end.row {
16033                    let mut found = false;
16034                    let mut row = range.start.row;
16035                    while row <= range.end.row {
16036                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16037                        {
16038                            found = true;
16039                            row = crease.range().end.row + 1;
16040                            to_fold.push(crease);
16041                        } else {
16042                            row += 1
16043                        }
16044                    }
16045                    if found {
16046                        continue;
16047                    }
16048                }
16049
16050                for row in (0..=range.start.row).rev() {
16051                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16052                        if crease.range().end.row >= buffer_start_row {
16053                            to_fold.push(crease);
16054                            if row <= range.start.row {
16055                                break;
16056                            }
16057                        }
16058                    }
16059                }
16060            }
16061
16062            self.fold_creases(to_fold, true, window, cx);
16063        } else {
16064            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16065            let buffer_ids = self
16066                .selections
16067                .disjoint_anchor_ranges()
16068                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16069                .collect::<HashSet<_>>();
16070            for buffer_id in buffer_ids {
16071                self.fold_buffer(buffer_id, cx);
16072            }
16073        }
16074    }
16075
16076    fn fold_at_level(
16077        &mut self,
16078        fold_at: &FoldAtLevel,
16079        window: &mut Window,
16080        cx: &mut Context<Self>,
16081    ) {
16082        if !self.buffer.read(cx).is_singleton() {
16083            return;
16084        }
16085
16086        let fold_at_level = fold_at.0;
16087        let snapshot = self.buffer.read(cx).snapshot(cx);
16088        let mut to_fold = Vec::new();
16089        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16090
16091        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16092            while start_row < end_row {
16093                match self
16094                    .snapshot(window, cx)
16095                    .crease_for_buffer_row(MultiBufferRow(start_row))
16096                {
16097                    Some(crease) => {
16098                        let nested_start_row = crease.range().start.row + 1;
16099                        let nested_end_row = crease.range().end.row;
16100
16101                        if current_level < fold_at_level {
16102                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16103                        } else if current_level == fold_at_level {
16104                            to_fold.push(crease);
16105                        }
16106
16107                        start_row = nested_end_row + 1;
16108                    }
16109                    None => start_row += 1,
16110                }
16111            }
16112        }
16113
16114        self.fold_creases(to_fold, true, window, cx);
16115    }
16116
16117    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16118        if self.buffer.read(cx).is_singleton() {
16119            let mut fold_ranges = Vec::new();
16120            let snapshot = self.buffer.read(cx).snapshot(cx);
16121
16122            for row in 0..snapshot.max_row().0 {
16123                if let Some(foldable_range) = self
16124                    .snapshot(window, cx)
16125                    .crease_for_buffer_row(MultiBufferRow(row))
16126                {
16127                    fold_ranges.push(foldable_range);
16128                }
16129            }
16130
16131            self.fold_creases(fold_ranges, true, window, cx);
16132        } else {
16133            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16134                editor
16135                    .update_in(cx, |editor, _, cx| {
16136                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16137                            editor.fold_buffer(buffer_id, cx);
16138                        }
16139                    })
16140                    .ok();
16141            });
16142        }
16143    }
16144
16145    pub fn fold_function_bodies(
16146        &mut self,
16147        _: &actions::FoldFunctionBodies,
16148        window: &mut Window,
16149        cx: &mut Context<Self>,
16150    ) {
16151        let snapshot = self.buffer.read(cx).snapshot(cx);
16152
16153        let ranges = snapshot
16154            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16155            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16156            .collect::<Vec<_>>();
16157
16158        let creases = ranges
16159            .into_iter()
16160            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16161            .collect();
16162
16163        self.fold_creases(creases, true, window, cx);
16164    }
16165
16166    pub fn fold_recursive(
16167        &mut self,
16168        _: &actions::FoldRecursive,
16169        window: &mut Window,
16170        cx: &mut Context<Self>,
16171    ) {
16172        let mut to_fold = Vec::new();
16173        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16174        let selections = self.selections.all_adjusted(cx);
16175
16176        for selection in selections {
16177            let range = selection.range().sorted();
16178            let buffer_start_row = range.start.row;
16179
16180            if range.start.row != range.end.row {
16181                let mut found = false;
16182                for row in range.start.row..=range.end.row {
16183                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16184                        found = true;
16185                        to_fold.push(crease);
16186                    }
16187                }
16188                if found {
16189                    continue;
16190                }
16191            }
16192
16193            for row in (0..=range.start.row).rev() {
16194                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16195                    if crease.range().end.row >= buffer_start_row {
16196                        to_fold.push(crease);
16197                    } else {
16198                        break;
16199                    }
16200                }
16201            }
16202        }
16203
16204        self.fold_creases(to_fold, true, window, cx);
16205    }
16206
16207    pub fn fold_at(
16208        &mut self,
16209        buffer_row: MultiBufferRow,
16210        window: &mut Window,
16211        cx: &mut Context<Self>,
16212    ) {
16213        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16214
16215        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16216            let autoscroll = self
16217                .selections
16218                .all::<Point>(cx)
16219                .iter()
16220                .any(|selection| crease.range().overlaps(&selection.range()));
16221
16222            self.fold_creases(vec![crease], autoscroll, window, cx);
16223        }
16224    }
16225
16226    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16227        if self.is_singleton(cx) {
16228            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16229            let buffer = &display_map.buffer_snapshot;
16230            let selections = self.selections.all::<Point>(cx);
16231            let ranges = selections
16232                .iter()
16233                .map(|s| {
16234                    let range = s.display_range(&display_map).sorted();
16235                    let mut start = range.start.to_point(&display_map);
16236                    let mut end = range.end.to_point(&display_map);
16237                    start.column = 0;
16238                    end.column = buffer.line_len(MultiBufferRow(end.row));
16239                    start..end
16240                })
16241                .collect::<Vec<_>>();
16242
16243            self.unfold_ranges(&ranges, true, true, cx);
16244        } else {
16245            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16246            let buffer_ids = self
16247                .selections
16248                .disjoint_anchor_ranges()
16249                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16250                .collect::<HashSet<_>>();
16251            for buffer_id in buffer_ids {
16252                self.unfold_buffer(buffer_id, cx);
16253            }
16254        }
16255    }
16256
16257    pub fn unfold_recursive(
16258        &mut self,
16259        _: &UnfoldRecursive,
16260        _window: &mut Window,
16261        cx: &mut Context<Self>,
16262    ) {
16263        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16264        let selections = self.selections.all::<Point>(cx);
16265        let ranges = selections
16266            .iter()
16267            .map(|s| {
16268                let mut range = s.display_range(&display_map).sorted();
16269                *range.start.column_mut() = 0;
16270                *range.end.column_mut() = display_map.line_len(range.end.row());
16271                let start = range.start.to_point(&display_map);
16272                let end = range.end.to_point(&display_map);
16273                start..end
16274            })
16275            .collect::<Vec<_>>();
16276
16277        self.unfold_ranges(&ranges, true, true, cx);
16278    }
16279
16280    pub fn unfold_at(
16281        &mut self,
16282        buffer_row: MultiBufferRow,
16283        _window: &mut Window,
16284        cx: &mut Context<Self>,
16285    ) {
16286        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16287
16288        let intersection_range = Point::new(buffer_row.0, 0)
16289            ..Point::new(
16290                buffer_row.0,
16291                display_map.buffer_snapshot.line_len(buffer_row),
16292            );
16293
16294        let autoscroll = self
16295            .selections
16296            .all::<Point>(cx)
16297            .iter()
16298            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16299
16300        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16301    }
16302
16303    pub fn unfold_all(
16304        &mut self,
16305        _: &actions::UnfoldAll,
16306        _window: &mut Window,
16307        cx: &mut Context<Self>,
16308    ) {
16309        if self.buffer.read(cx).is_singleton() {
16310            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16311            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16312        } else {
16313            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16314                editor
16315                    .update(cx, |editor, cx| {
16316                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16317                            editor.unfold_buffer(buffer_id, cx);
16318                        }
16319                    })
16320                    .ok();
16321            });
16322        }
16323    }
16324
16325    pub fn fold_selected_ranges(
16326        &mut self,
16327        _: &FoldSelectedRanges,
16328        window: &mut Window,
16329        cx: &mut Context<Self>,
16330    ) {
16331        let selections = self.selections.all_adjusted(cx);
16332        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16333        let ranges = selections
16334            .into_iter()
16335            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16336            .collect::<Vec<_>>();
16337        self.fold_creases(ranges, true, window, cx);
16338    }
16339
16340    pub fn fold_ranges<T: ToOffset + Clone>(
16341        &mut self,
16342        ranges: Vec<Range<T>>,
16343        auto_scroll: bool,
16344        window: &mut Window,
16345        cx: &mut Context<Self>,
16346    ) {
16347        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16348        let ranges = ranges
16349            .into_iter()
16350            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16351            .collect::<Vec<_>>();
16352        self.fold_creases(ranges, auto_scroll, window, cx);
16353    }
16354
16355    pub fn fold_creases<T: ToOffset + Clone>(
16356        &mut self,
16357        creases: Vec<Crease<T>>,
16358        auto_scroll: bool,
16359        _window: &mut Window,
16360        cx: &mut Context<Self>,
16361    ) {
16362        if creases.is_empty() {
16363            return;
16364        }
16365
16366        let mut buffers_affected = HashSet::default();
16367        let multi_buffer = self.buffer().read(cx);
16368        for crease in &creases {
16369            if let Some((_, buffer, _)) =
16370                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16371            {
16372                buffers_affected.insert(buffer.read(cx).remote_id());
16373            };
16374        }
16375
16376        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16377
16378        if auto_scroll {
16379            self.request_autoscroll(Autoscroll::fit(), cx);
16380        }
16381
16382        cx.notify();
16383
16384        self.scrollbar_marker_state.dirty = true;
16385        self.folds_did_change(cx);
16386    }
16387
16388    /// Removes any folds whose ranges intersect any of the given ranges.
16389    pub fn unfold_ranges<T: ToOffset + Clone>(
16390        &mut self,
16391        ranges: &[Range<T>],
16392        inclusive: bool,
16393        auto_scroll: bool,
16394        cx: &mut Context<Self>,
16395    ) {
16396        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16397            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16398        });
16399        self.folds_did_change(cx);
16400    }
16401
16402    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16403        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16404            return;
16405        }
16406        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16407        self.display_map.update(cx, |display_map, cx| {
16408            display_map.fold_buffers([buffer_id], cx)
16409        });
16410        cx.emit(EditorEvent::BufferFoldToggled {
16411            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16412            folded: true,
16413        });
16414        cx.notify();
16415    }
16416
16417    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16418        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16419            return;
16420        }
16421        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16422        self.display_map.update(cx, |display_map, cx| {
16423            display_map.unfold_buffers([buffer_id], cx);
16424        });
16425        cx.emit(EditorEvent::BufferFoldToggled {
16426            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16427            folded: false,
16428        });
16429        cx.notify();
16430    }
16431
16432    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16433        self.display_map.read(cx).is_buffer_folded(buffer)
16434    }
16435
16436    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16437        self.display_map.read(cx).folded_buffers()
16438    }
16439
16440    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16441        self.display_map.update(cx, |display_map, cx| {
16442            display_map.disable_header_for_buffer(buffer_id, cx);
16443        });
16444        cx.notify();
16445    }
16446
16447    /// Removes any folds with the given ranges.
16448    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16449        &mut self,
16450        ranges: &[Range<T>],
16451        type_id: TypeId,
16452        auto_scroll: bool,
16453        cx: &mut Context<Self>,
16454    ) {
16455        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16456            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16457        });
16458        self.folds_did_change(cx);
16459    }
16460
16461    fn remove_folds_with<T: ToOffset + Clone>(
16462        &mut self,
16463        ranges: &[Range<T>],
16464        auto_scroll: bool,
16465        cx: &mut Context<Self>,
16466        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16467    ) {
16468        if ranges.is_empty() {
16469            return;
16470        }
16471
16472        let mut buffers_affected = HashSet::default();
16473        let multi_buffer = self.buffer().read(cx);
16474        for range in ranges {
16475            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16476                buffers_affected.insert(buffer.read(cx).remote_id());
16477            };
16478        }
16479
16480        self.display_map.update(cx, update);
16481
16482        if auto_scroll {
16483            self.request_autoscroll(Autoscroll::fit(), cx);
16484        }
16485
16486        cx.notify();
16487        self.scrollbar_marker_state.dirty = true;
16488        self.active_indent_guides_state.dirty = true;
16489    }
16490
16491    pub fn update_fold_widths(
16492        &mut self,
16493        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16494        cx: &mut Context<Self>,
16495    ) -> bool {
16496        self.display_map
16497            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16498    }
16499
16500    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16501        self.display_map.read(cx).fold_placeholder.clone()
16502    }
16503
16504    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16505        self.buffer.update(cx, |buffer, cx| {
16506            buffer.set_all_diff_hunks_expanded(cx);
16507        });
16508    }
16509
16510    pub fn expand_all_diff_hunks(
16511        &mut self,
16512        _: &ExpandAllDiffHunks,
16513        _window: &mut Window,
16514        cx: &mut Context<Self>,
16515    ) {
16516        self.buffer.update(cx, |buffer, cx| {
16517            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16518        });
16519    }
16520
16521    pub fn toggle_selected_diff_hunks(
16522        &mut self,
16523        _: &ToggleSelectedDiffHunks,
16524        _window: &mut Window,
16525        cx: &mut Context<Self>,
16526    ) {
16527        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16528        self.toggle_diff_hunks_in_ranges(ranges, cx);
16529    }
16530
16531    pub fn diff_hunks_in_ranges<'a>(
16532        &'a self,
16533        ranges: &'a [Range<Anchor>],
16534        buffer: &'a MultiBufferSnapshot,
16535    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16536        ranges.iter().flat_map(move |range| {
16537            let end_excerpt_id = range.end.excerpt_id;
16538            let range = range.to_point(buffer);
16539            let mut peek_end = range.end;
16540            if range.end.row < buffer.max_row().0 {
16541                peek_end = Point::new(range.end.row + 1, 0);
16542            }
16543            buffer
16544                .diff_hunks_in_range(range.start..peek_end)
16545                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16546        })
16547    }
16548
16549    pub fn has_stageable_diff_hunks_in_ranges(
16550        &self,
16551        ranges: &[Range<Anchor>],
16552        snapshot: &MultiBufferSnapshot,
16553    ) -> bool {
16554        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16555        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16556    }
16557
16558    pub fn toggle_staged_selected_diff_hunks(
16559        &mut self,
16560        _: &::git::ToggleStaged,
16561        _: &mut Window,
16562        cx: &mut Context<Self>,
16563    ) {
16564        let snapshot = self.buffer.read(cx).snapshot(cx);
16565        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16566        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16567        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16568    }
16569
16570    pub fn set_render_diff_hunk_controls(
16571        &mut self,
16572        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16573        cx: &mut Context<Self>,
16574    ) {
16575        self.render_diff_hunk_controls = render_diff_hunk_controls;
16576        cx.notify();
16577    }
16578
16579    pub fn stage_and_next(
16580        &mut self,
16581        _: &::git::StageAndNext,
16582        window: &mut Window,
16583        cx: &mut Context<Self>,
16584    ) {
16585        self.do_stage_or_unstage_and_next(true, window, cx);
16586    }
16587
16588    pub fn unstage_and_next(
16589        &mut self,
16590        _: &::git::UnstageAndNext,
16591        window: &mut Window,
16592        cx: &mut Context<Self>,
16593    ) {
16594        self.do_stage_or_unstage_and_next(false, window, cx);
16595    }
16596
16597    pub fn stage_or_unstage_diff_hunks(
16598        &mut self,
16599        stage: bool,
16600        ranges: Vec<Range<Anchor>>,
16601        cx: &mut Context<Self>,
16602    ) {
16603        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16604        cx.spawn(async move |this, cx| {
16605            task.await?;
16606            this.update(cx, |this, cx| {
16607                let snapshot = this.buffer.read(cx).snapshot(cx);
16608                let chunk_by = this
16609                    .diff_hunks_in_ranges(&ranges, &snapshot)
16610                    .chunk_by(|hunk| hunk.buffer_id);
16611                for (buffer_id, hunks) in &chunk_by {
16612                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16613                }
16614            })
16615        })
16616        .detach_and_log_err(cx);
16617    }
16618
16619    fn save_buffers_for_ranges_if_needed(
16620        &mut self,
16621        ranges: &[Range<Anchor>],
16622        cx: &mut Context<Editor>,
16623    ) -> Task<Result<()>> {
16624        let multibuffer = self.buffer.read(cx);
16625        let snapshot = multibuffer.read(cx);
16626        let buffer_ids: HashSet<_> = ranges
16627            .iter()
16628            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16629            .collect();
16630        drop(snapshot);
16631
16632        let mut buffers = HashSet::default();
16633        for buffer_id in buffer_ids {
16634            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16635                let buffer = buffer_entity.read(cx);
16636                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16637                {
16638                    buffers.insert(buffer_entity);
16639                }
16640            }
16641        }
16642
16643        if let Some(project) = &self.project {
16644            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16645        } else {
16646            Task::ready(Ok(()))
16647        }
16648    }
16649
16650    fn do_stage_or_unstage_and_next(
16651        &mut self,
16652        stage: bool,
16653        window: &mut Window,
16654        cx: &mut Context<Self>,
16655    ) {
16656        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16657
16658        if ranges.iter().any(|range| range.start != range.end) {
16659            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16660            return;
16661        }
16662
16663        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16664        let snapshot = self.snapshot(window, cx);
16665        let position = self.selections.newest::<Point>(cx).head();
16666        let mut row = snapshot
16667            .buffer_snapshot
16668            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16669            .find(|hunk| hunk.row_range.start.0 > position.row)
16670            .map(|hunk| hunk.row_range.start);
16671
16672        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16673        // Outside of the project diff editor, wrap around to the beginning.
16674        if !all_diff_hunks_expanded {
16675            row = row.or_else(|| {
16676                snapshot
16677                    .buffer_snapshot
16678                    .diff_hunks_in_range(Point::zero()..position)
16679                    .find(|hunk| hunk.row_range.end.0 < position.row)
16680                    .map(|hunk| hunk.row_range.start)
16681            });
16682        }
16683
16684        if let Some(row) = row {
16685            let destination = Point::new(row.0, 0);
16686            let autoscroll = Autoscroll::center();
16687
16688            self.unfold_ranges(&[destination..destination], false, false, cx);
16689            self.change_selections(Some(autoscroll), window, cx, |s| {
16690                s.select_ranges([destination..destination]);
16691            });
16692        }
16693    }
16694
16695    fn do_stage_or_unstage(
16696        &self,
16697        stage: bool,
16698        buffer_id: BufferId,
16699        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16700        cx: &mut App,
16701    ) -> Option<()> {
16702        let project = self.project.as_ref()?;
16703        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16704        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16705        let buffer_snapshot = buffer.read(cx).snapshot();
16706        let file_exists = buffer_snapshot
16707            .file()
16708            .is_some_and(|file| file.disk_state().exists());
16709        diff.update(cx, |diff, cx| {
16710            diff.stage_or_unstage_hunks(
16711                stage,
16712                &hunks
16713                    .map(|hunk| buffer_diff::DiffHunk {
16714                        buffer_range: hunk.buffer_range,
16715                        diff_base_byte_range: hunk.diff_base_byte_range,
16716                        secondary_status: hunk.secondary_status,
16717                        range: Point::zero()..Point::zero(), // unused
16718                    })
16719                    .collect::<Vec<_>>(),
16720                &buffer_snapshot,
16721                file_exists,
16722                cx,
16723            )
16724        });
16725        None
16726    }
16727
16728    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16729        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16730        self.buffer
16731            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16732    }
16733
16734    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16735        self.buffer.update(cx, |buffer, cx| {
16736            let ranges = vec![Anchor::min()..Anchor::max()];
16737            if !buffer.all_diff_hunks_expanded()
16738                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16739            {
16740                buffer.collapse_diff_hunks(ranges, cx);
16741                true
16742            } else {
16743                false
16744            }
16745        })
16746    }
16747
16748    fn toggle_diff_hunks_in_ranges(
16749        &mut self,
16750        ranges: Vec<Range<Anchor>>,
16751        cx: &mut Context<Editor>,
16752    ) {
16753        self.buffer.update(cx, |buffer, cx| {
16754            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16755            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16756        })
16757    }
16758
16759    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16760        self.buffer.update(cx, |buffer, cx| {
16761            let snapshot = buffer.snapshot(cx);
16762            let excerpt_id = range.end.excerpt_id;
16763            let point_range = range.to_point(&snapshot);
16764            let expand = !buffer.single_hunk_is_expanded(range, cx);
16765            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16766        })
16767    }
16768
16769    pub(crate) fn apply_all_diff_hunks(
16770        &mut self,
16771        _: &ApplyAllDiffHunks,
16772        window: &mut Window,
16773        cx: &mut Context<Self>,
16774    ) {
16775        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16776
16777        let buffers = self.buffer.read(cx).all_buffers();
16778        for branch_buffer in buffers {
16779            branch_buffer.update(cx, |branch_buffer, cx| {
16780                branch_buffer.merge_into_base(Vec::new(), cx);
16781            });
16782        }
16783
16784        if let Some(project) = self.project.clone() {
16785            self.save(true, project, window, cx).detach_and_log_err(cx);
16786        }
16787    }
16788
16789    pub(crate) fn apply_selected_diff_hunks(
16790        &mut self,
16791        _: &ApplyDiffHunk,
16792        window: &mut Window,
16793        cx: &mut Context<Self>,
16794    ) {
16795        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16796        let snapshot = self.snapshot(window, cx);
16797        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16798        let mut ranges_by_buffer = HashMap::default();
16799        self.transact(window, cx, |editor, _window, cx| {
16800            for hunk in hunks {
16801                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16802                    ranges_by_buffer
16803                        .entry(buffer.clone())
16804                        .or_insert_with(Vec::new)
16805                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16806                }
16807            }
16808
16809            for (buffer, ranges) in ranges_by_buffer {
16810                buffer.update(cx, |buffer, cx| {
16811                    buffer.merge_into_base(ranges, cx);
16812                });
16813            }
16814        });
16815
16816        if let Some(project) = self.project.clone() {
16817            self.save(true, project, window, cx).detach_and_log_err(cx);
16818        }
16819    }
16820
16821    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16822        if hovered != self.gutter_hovered {
16823            self.gutter_hovered = hovered;
16824            cx.notify();
16825        }
16826    }
16827
16828    pub fn insert_blocks(
16829        &mut self,
16830        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16831        autoscroll: Option<Autoscroll>,
16832        cx: &mut Context<Self>,
16833    ) -> Vec<CustomBlockId> {
16834        let blocks = self
16835            .display_map
16836            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16837        if let Some(autoscroll) = autoscroll {
16838            self.request_autoscroll(autoscroll, cx);
16839        }
16840        cx.notify();
16841        blocks
16842    }
16843
16844    pub fn resize_blocks(
16845        &mut self,
16846        heights: HashMap<CustomBlockId, u32>,
16847        autoscroll: Option<Autoscroll>,
16848        cx: &mut Context<Self>,
16849    ) {
16850        self.display_map
16851            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16852        if let Some(autoscroll) = autoscroll {
16853            self.request_autoscroll(autoscroll, cx);
16854        }
16855        cx.notify();
16856    }
16857
16858    pub fn replace_blocks(
16859        &mut self,
16860        renderers: HashMap<CustomBlockId, RenderBlock>,
16861        autoscroll: Option<Autoscroll>,
16862        cx: &mut Context<Self>,
16863    ) {
16864        self.display_map
16865            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16866        if let Some(autoscroll) = autoscroll {
16867            self.request_autoscroll(autoscroll, cx);
16868        }
16869        cx.notify();
16870    }
16871
16872    pub fn remove_blocks(
16873        &mut self,
16874        block_ids: HashSet<CustomBlockId>,
16875        autoscroll: Option<Autoscroll>,
16876        cx: &mut Context<Self>,
16877    ) {
16878        self.display_map.update(cx, |display_map, cx| {
16879            display_map.remove_blocks(block_ids, cx)
16880        });
16881        if let Some(autoscroll) = autoscroll {
16882            self.request_autoscroll(autoscroll, cx);
16883        }
16884        cx.notify();
16885    }
16886
16887    pub fn row_for_block(
16888        &self,
16889        block_id: CustomBlockId,
16890        cx: &mut Context<Self>,
16891    ) -> Option<DisplayRow> {
16892        self.display_map
16893            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16894    }
16895
16896    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16897        self.focused_block = Some(focused_block);
16898    }
16899
16900    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16901        self.focused_block.take()
16902    }
16903
16904    pub fn insert_creases(
16905        &mut self,
16906        creases: impl IntoIterator<Item = Crease<Anchor>>,
16907        cx: &mut Context<Self>,
16908    ) -> Vec<CreaseId> {
16909        self.display_map
16910            .update(cx, |map, cx| map.insert_creases(creases, cx))
16911    }
16912
16913    pub fn remove_creases(
16914        &mut self,
16915        ids: impl IntoIterator<Item = CreaseId>,
16916        cx: &mut Context<Self>,
16917    ) -> Vec<(CreaseId, Range<Anchor>)> {
16918        self.display_map
16919            .update(cx, |map, cx| map.remove_creases(ids, cx))
16920    }
16921
16922    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16923        self.display_map
16924            .update(cx, |map, cx| map.snapshot(cx))
16925            .longest_row()
16926    }
16927
16928    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16929        self.display_map
16930            .update(cx, |map, cx| map.snapshot(cx))
16931            .max_point()
16932    }
16933
16934    pub fn text(&self, cx: &App) -> String {
16935        self.buffer.read(cx).read(cx).text()
16936    }
16937
16938    pub fn is_empty(&self, cx: &App) -> bool {
16939        self.buffer.read(cx).read(cx).is_empty()
16940    }
16941
16942    pub fn text_option(&self, cx: &App) -> Option<String> {
16943        let text = self.text(cx);
16944        let text = text.trim();
16945
16946        if text.is_empty() {
16947            return None;
16948        }
16949
16950        Some(text.to_string())
16951    }
16952
16953    pub fn set_text(
16954        &mut self,
16955        text: impl Into<Arc<str>>,
16956        window: &mut Window,
16957        cx: &mut Context<Self>,
16958    ) {
16959        self.transact(window, cx, |this, _, cx| {
16960            this.buffer
16961                .read(cx)
16962                .as_singleton()
16963                .expect("you can only call set_text on editors for singleton buffers")
16964                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16965        });
16966    }
16967
16968    pub fn display_text(&self, cx: &mut App) -> String {
16969        self.display_map
16970            .update(cx, |map, cx| map.snapshot(cx))
16971            .text()
16972    }
16973
16974    fn create_minimap(
16975        &self,
16976        minimap_settings: MinimapSettings,
16977        window: &mut Window,
16978        cx: &mut Context<Self>,
16979    ) -> Option<Entity<Self>> {
16980        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16981            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16982    }
16983
16984    fn initialize_new_minimap(
16985        &self,
16986        minimap_settings: MinimapSettings,
16987        window: &mut Window,
16988        cx: &mut Context<Self>,
16989    ) -> Entity<Self> {
16990        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16991
16992        let mut minimap = Editor::new_internal(
16993            EditorMode::Minimap {
16994                parent: cx.weak_entity(),
16995            },
16996            self.buffer.clone(),
16997            self.project.clone(),
16998            Some(self.display_map.clone()),
16999            window,
17000            cx,
17001        );
17002        minimap.scroll_manager.clone_state(&self.scroll_manager);
17003        minimap.set_text_style_refinement(TextStyleRefinement {
17004            font_size: Some(MINIMAP_FONT_SIZE),
17005            font_weight: Some(MINIMAP_FONT_WEIGHT),
17006            ..Default::default()
17007        });
17008        minimap.update_minimap_configuration(minimap_settings, cx);
17009        cx.new(|_| minimap)
17010    }
17011
17012    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17013        let current_line_highlight = minimap_settings
17014            .current_line_highlight
17015            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17016        self.set_current_line_highlight(Some(current_line_highlight));
17017    }
17018
17019    pub fn minimap(&self) -> Option<&Entity<Self>> {
17020        self.minimap
17021            .as_ref()
17022            .filter(|_| self.minimap_visibility.visible())
17023    }
17024
17025    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17026        let mut wrap_guides = smallvec![];
17027
17028        if self.show_wrap_guides == Some(false) {
17029            return wrap_guides;
17030        }
17031
17032        let settings = self.buffer.read(cx).language_settings(cx);
17033        if settings.show_wrap_guides {
17034            match self.soft_wrap_mode(cx) {
17035                SoftWrap::Column(soft_wrap) => {
17036                    wrap_guides.push((soft_wrap as usize, true));
17037                }
17038                SoftWrap::Bounded(soft_wrap) => {
17039                    wrap_guides.push((soft_wrap as usize, true));
17040                }
17041                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17042            }
17043            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17044        }
17045
17046        wrap_guides
17047    }
17048
17049    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17050        let settings = self.buffer.read(cx).language_settings(cx);
17051        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17052        match mode {
17053            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17054                SoftWrap::None
17055            }
17056            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17057            language_settings::SoftWrap::PreferredLineLength => {
17058                SoftWrap::Column(settings.preferred_line_length)
17059            }
17060            language_settings::SoftWrap::Bounded => {
17061                SoftWrap::Bounded(settings.preferred_line_length)
17062            }
17063        }
17064    }
17065
17066    pub fn set_soft_wrap_mode(
17067        &mut self,
17068        mode: language_settings::SoftWrap,
17069
17070        cx: &mut Context<Self>,
17071    ) {
17072        self.soft_wrap_mode_override = Some(mode);
17073        cx.notify();
17074    }
17075
17076    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17077        self.hard_wrap = hard_wrap;
17078        cx.notify();
17079    }
17080
17081    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17082        self.text_style_refinement = Some(style);
17083    }
17084
17085    /// called by the Element so we know what style we were most recently rendered with.
17086    pub(crate) fn set_style(
17087        &mut self,
17088        style: EditorStyle,
17089        window: &mut Window,
17090        cx: &mut Context<Self>,
17091    ) {
17092        // We intentionally do not inform the display map about the minimap style
17093        // so that wrapping is not recalculated and stays consistent for the editor
17094        // and its linked minimap.
17095        if !self.mode.is_minimap() {
17096            let rem_size = window.rem_size();
17097            self.display_map.update(cx, |map, cx| {
17098                map.set_font(
17099                    style.text.font(),
17100                    style.text.font_size.to_pixels(rem_size),
17101                    cx,
17102                )
17103            });
17104        }
17105        self.style = Some(style);
17106    }
17107
17108    pub fn style(&self) -> Option<&EditorStyle> {
17109        self.style.as_ref()
17110    }
17111
17112    // Called by the element. This method is not designed to be called outside of the editor
17113    // element's layout code because it does not notify when rewrapping is computed synchronously.
17114    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17115        self.display_map
17116            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17117    }
17118
17119    pub fn set_soft_wrap(&mut self) {
17120        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17121    }
17122
17123    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17124        if self.soft_wrap_mode_override.is_some() {
17125            self.soft_wrap_mode_override.take();
17126        } else {
17127            let soft_wrap = match self.soft_wrap_mode(cx) {
17128                SoftWrap::GitDiff => return,
17129                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17130                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17131                    language_settings::SoftWrap::None
17132                }
17133            };
17134            self.soft_wrap_mode_override = Some(soft_wrap);
17135        }
17136        cx.notify();
17137    }
17138
17139    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17140        let Some(workspace) = self.workspace() else {
17141            return;
17142        };
17143        let fs = workspace.read(cx).app_state().fs.clone();
17144        let current_show = TabBarSettings::get_global(cx).show;
17145        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17146            setting.show = Some(!current_show);
17147        });
17148    }
17149
17150    pub fn toggle_indent_guides(
17151        &mut self,
17152        _: &ToggleIndentGuides,
17153        _: &mut Window,
17154        cx: &mut Context<Self>,
17155    ) {
17156        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17157            self.buffer
17158                .read(cx)
17159                .language_settings(cx)
17160                .indent_guides
17161                .enabled
17162        });
17163        self.show_indent_guides = Some(!currently_enabled);
17164        cx.notify();
17165    }
17166
17167    fn should_show_indent_guides(&self) -> Option<bool> {
17168        self.show_indent_guides
17169    }
17170
17171    pub fn toggle_line_numbers(
17172        &mut self,
17173        _: &ToggleLineNumbers,
17174        _: &mut Window,
17175        cx: &mut Context<Self>,
17176    ) {
17177        let mut editor_settings = EditorSettings::get_global(cx).clone();
17178        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17179        EditorSettings::override_global(editor_settings, cx);
17180    }
17181
17182    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17183        if let Some(show_line_numbers) = self.show_line_numbers {
17184            return show_line_numbers;
17185        }
17186        EditorSettings::get_global(cx).gutter.line_numbers
17187    }
17188
17189    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17190        self.use_relative_line_numbers
17191            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17192    }
17193
17194    pub fn toggle_relative_line_numbers(
17195        &mut self,
17196        _: &ToggleRelativeLineNumbers,
17197        _: &mut Window,
17198        cx: &mut Context<Self>,
17199    ) {
17200        let is_relative = self.should_use_relative_line_numbers(cx);
17201        self.set_relative_line_number(Some(!is_relative), cx)
17202    }
17203
17204    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17205        self.use_relative_line_numbers = is_relative;
17206        cx.notify();
17207    }
17208
17209    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17210        self.show_gutter = show_gutter;
17211        cx.notify();
17212    }
17213
17214    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17215        self.show_scrollbars = ScrollbarAxes {
17216            horizontal: show,
17217            vertical: show,
17218        };
17219        cx.notify();
17220    }
17221
17222    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17223        self.show_scrollbars.vertical = show;
17224        cx.notify();
17225    }
17226
17227    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17228        self.show_scrollbars.horizontal = show;
17229        cx.notify();
17230    }
17231
17232    pub fn set_minimap_visibility(
17233        &mut self,
17234        minimap_visibility: MinimapVisibility,
17235        window: &mut Window,
17236        cx: &mut Context<Self>,
17237    ) {
17238        if self.minimap_visibility != minimap_visibility {
17239            if minimap_visibility.visible() && self.minimap.is_none() {
17240                let minimap_settings = EditorSettings::get_global(cx).minimap;
17241                self.minimap =
17242                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17243            }
17244            self.minimap_visibility = minimap_visibility;
17245            cx.notify();
17246        }
17247    }
17248
17249    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17250        self.set_show_scrollbars(false, cx);
17251        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17252    }
17253
17254    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17255        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17256    }
17257
17258    /// Normally the text in full mode and auto height editors is padded on the
17259    /// left side by roughly half a character width for improved hit testing.
17260    ///
17261    /// Use this method to disable this for cases where this is not wanted (e.g.
17262    /// if you want to align the editor text with some other text above or below)
17263    /// or if you want to add this padding to single-line editors.
17264    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17265        self.offset_content = offset_content;
17266        cx.notify();
17267    }
17268
17269    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17270        self.show_line_numbers = Some(show_line_numbers);
17271        cx.notify();
17272    }
17273
17274    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17275        self.disable_expand_excerpt_buttons = true;
17276        cx.notify();
17277    }
17278
17279    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17280        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17281        cx.notify();
17282    }
17283
17284    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17285        self.show_code_actions = Some(show_code_actions);
17286        cx.notify();
17287    }
17288
17289    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17290        self.show_runnables = Some(show_runnables);
17291        cx.notify();
17292    }
17293
17294    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17295        self.show_breakpoints = Some(show_breakpoints);
17296        cx.notify();
17297    }
17298
17299    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17300        if self.display_map.read(cx).masked != masked {
17301            self.display_map.update(cx, |map, _| map.masked = masked);
17302        }
17303        cx.notify()
17304    }
17305
17306    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17307        self.show_wrap_guides = Some(show_wrap_guides);
17308        cx.notify();
17309    }
17310
17311    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17312        self.show_indent_guides = Some(show_indent_guides);
17313        cx.notify();
17314    }
17315
17316    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17317        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17318            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17319                if let Some(dir) = file.abs_path(cx).parent() {
17320                    return Some(dir.to_owned());
17321                }
17322            }
17323
17324            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17325                return Some(project_path.path.to_path_buf());
17326            }
17327        }
17328
17329        None
17330    }
17331
17332    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17333        self.active_excerpt(cx)?
17334            .1
17335            .read(cx)
17336            .file()
17337            .and_then(|f| f.as_local())
17338    }
17339
17340    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17341        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17342            let buffer = buffer.read(cx);
17343            if let Some(project_path) = buffer.project_path(cx) {
17344                let project = self.project.as_ref()?.read(cx);
17345                project.absolute_path(&project_path, cx)
17346            } else {
17347                buffer
17348                    .file()
17349                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17350            }
17351        })
17352    }
17353
17354    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17355        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17356            let project_path = buffer.read(cx).project_path(cx)?;
17357            let project = self.project.as_ref()?.read(cx);
17358            let entry = project.entry_for_path(&project_path, cx)?;
17359            let path = entry.path.to_path_buf();
17360            Some(path)
17361        })
17362    }
17363
17364    pub fn reveal_in_finder(
17365        &mut self,
17366        _: &RevealInFileManager,
17367        _window: &mut Window,
17368        cx: &mut Context<Self>,
17369    ) {
17370        if let Some(target) = self.target_file(cx) {
17371            cx.reveal_path(&target.abs_path(cx));
17372        }
17373    }
17374
17375    pub fn copy_path(
17376        &mut self,
17377        _: &zed_actions::workspace::CopyPath,
17378        _window: &mut Window,
17379        cx: &mut Context<Self>,
17380    ) {
17381        if let Some(path) = self.target_file_abs_path(cx) {
17382            if let Some(path) = path.to_str() {
17383                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17384            }
17385        }
17386    }
17387
17388    pub fn copy_relative_path(
17389        &mut self,
17390        _: &zed_actions::workspace::CopyRelativePath,
17391        _window: &mut Window,
17392        cx: &mut Context<Self>,
17393    ) {
17394        if let Some(path) = self.target_file_path(cx) {
17395            if let Some(path) = path.to_str() {
17396                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17397            }
17398        }
17399    }
17400
17401    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17402        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17403            buffer.read(cx).project_path(cx)
17404        } else {
17405            None
17406        }
17407    }
17408
17409    // Returns true if the editor handled a go-to-line request
17410    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17411        maybe!({
17412            let breakpoint_store = self.breakpoint_store.as_ref()?;
17413
17414            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17415            else {
17416                self.clear_row_highlights::<ActiveDebugLine>();
17417                return None;
17418            };
17419
17420            let position = active_stack_frame.position;
17421            let buffer_id = position.buffer_id?;
17422            let snapshot = self
17423                .project
17424                .as_ref()?
17425                .read(cx)
17426                .buffer_for_id(buffer_id, cx)?
17427                .read(cx)
17428                .snapshot();
17429
17430            let mut handled = false;
17431            for (id, ExcerptRange { context, .. }) in
17432                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17433            {
17434                if context.start.cmp(&position, &snapshot).is_ge()
17435                    || context.end.cmp(&position, &snapshot).is_lt()
17436                {
17437                    continue;
17438                }
17439                let snapshot = self.buffer.read(cx).snapshot(cx);
17440                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17441
17442                handled = true;
17443                self.clear_row_highlights::<ActiveDebugLine>();
17444
17445                self.go_to_line::<ActiveDebugLine>(
17446                    multibuffer_anchor,
17447                    Some(cx.theme().colors().editor_debugger_active_line_background),
17448                    window,
17449                    cx,
17450                );
17451
17452                cx.notify();
17453            }
17454
17455            handled.then_some(())
17456        })
17457        .is_some()
17458    }
17459
17460    pub fn copy_file_name_without_extension(
17461        &mut self,
17462        _: &CopyFileNameWithoutExtension,
17463        _: &mut Window,
17464        cx: &mut Context<Self>,
17465    ) {
17466        if let Some(file) = self.target_file(cx) {
17467            if let Some(file_stem) = file.path().file_stem() {
17468                if let Some(name) = file_stem.to_str() {
17469                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17470                }
17471            }
17472        }
17473    }
17474
17475    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17476        if let Some(file) = self.target_file(cx) {
17477            if let Some(file_name) = file.path().file_name() {
17478                if let Some(name) = file_name.to_str() {
17479                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17480                }
17481            }
17482        }
17483    }
17484
17485    pub fn toggle_git_blame(
17486        &mut self,
17487        _: &::git::Blame,
17488        window: &mut Window,
17489        cx: &mut Context<Self>,
17490    ) {
17491        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17492
17493        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17494            self.start_git_blame(true, window, cx);
17495        }
17496
17497        cx.notify();
17498    }
17499
17500    pub fn toggle_git_blame_inline(
17501        &mut self,
17502        _: &ToggleGitBlameInline,
17503        window: &mut Window,
17504        cx: &mut Context<Self>,
17505    ) {
17506        self.toggle_git_blame_inline_internal(true, window, cx);
17507        cx.notify();
17508    }
17509
17510    pub fn open_git_blame_commit(
17511        &mut self,
17512        _: &OpenGitBlameCommit,
17513        window: &mut Window,
17514        cx: &mut Context<Self>,
17515    ) {
17516        self.open_git_blame_commit_internal(window, cx);
17517    }
17518
17519    fn open_git_blame_commit_internal(
17520        &mut self,
17521        window: &mut Window,
17522        cx: &mut Context<Self>,
17523    ) -> Option<()> {
17524        let blame = self.blame.as_ref()?;
17525        let snapshot = self.snapshot(window, cx);
17526        let cursor = self.selections.newest::<Point>(cx).head();
17527        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17528        let blame_entry = blame
17529            .update(cx, |blame, cx| {
17530                blame
17531                    .blame_for_rows(
17532                        &[RowInfo {
17533                            buffer_id: Some(buffer.remote_id()),
17534                            buffer_row: Some(point.row),
17535                            ..Default::default()
17536                        }],
17537                        cx,
17538                    )
17539                    .next()
17540            })
17541            .flatten()?;
17542        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17543        let repo = blame.read(cx).repository(cx)?;
17544        let workspace = self.workspace()?.downgrade();
17545        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17546        None
17547    }
17548
17549    pub fn git_blame_inline_enabled(&self) -> bool {
17550        self.git_blame_inline_enabled
17551    }
17552
17553    pub fn toggle_selection_menu(
17554        &mut self,
17555        _: &ToggleSelectionMenu,
17556        _: &mut Window,
17557        cx: &mut Context<Self>,
17558    ) {
17559        self.show_selection_menu = self
17560            .show_selection_menu
17561            .map(|show_selections_menu| !show_selections_menu)
17562            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17563
17564        cx.notify();
17565    }
17566
17567    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17568        self.show_selection_menu
17569            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17570    }
17571
17572    fn start_git_blame(
17573        &mut self,
17574        user_triggered: bool,
17575        window: &mut Window,
17576        cx: &mut Context<Self>,
17577    ) {
17578        if let Some(project) = self.project.as_ref() {
17579            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17580                return;
17581            };
17582
17583            if buffer.read(cx).file().is_none() {
17584                return;
17585            }
17586
17587            let focused = self.focus_handle(cx).contains_focused(window, cx);
17588
17589            let project = project.clone();
17590            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17591            self.blame_subscription =
17592                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17593            self.blame = Some(blame);
17594        }
17595    }
17596
17597    fn toggle_git_blame_inline_internal(
17598        &mut self,
17599        user_triggered: bool,
17600        window: &mut Window,
17601        cx: &mut Context<Self>,
17602    ) {
17603        if self.git_blame_inline_enabled {
17604            self.git_blame_inline_enabled = false;
17605            self.show_git_blame_inline = false;
17606            self.show_git_blame_inline_delay_task.take();
17607        } else {
17608            self.git_blame_inline_enabled = true;
17609            self.start_git_blame_inline(user_triggered, window, cx);
17610        }
17611
17612        cx.notify();
17613    }
17614
17615    fn start_git_blame_inline(
17616        &mut self,
17617        user_triggered: bool,
17618        window: &mut Window,
17619        cx: &mut Context<Self>,
17620    ) {
17621        self.start_git_blame(user_triggered, window, cx);
17622
17623        if ProjectSettings::get_global(cx)
17624            .git
17625            .inline_blame_delay()
17626            .is_some()
17627        {
17628            self.start_inline_blame_timer(window, cx);
17629        } else {
17630            self.show_git_blame_inline = true
17631        }
17632    }
17633
17634    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17635        self.blame.as_ref()
17636    }
17637
17638    pub fn show_git_blame_gutter(&self) -> bool {
17639        self.show_git_blame_gutter
17640    }
17641
17642    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17643        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17644    }
17645
17646    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17647        self.show_git_blame_inline
17648            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17649            && !self.newest_selection_head_on_empty_line(cx)
17650            && self.has_blame_entries(cx)
17651    }
17652
17653    fn has_blame_entries(&self, cx: &App) -> bool {
17654        self.blame()
17655            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17656    }
17657
17658    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17659        let cursor_anchor = self.selections.newest_anchor().head();
17660
17661        let snapshot = self.buffer.read(cx).snapshot(cx);
17662        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17663
17664        snapshot.line_len(buffer_row) == 0
17665    }
17666
17667    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17668        let buffer_and_selection = maybe!({
17669            let selection = self.selections.newest::<Point>(cx);
17670            let selection_range = selection.range();
17671
17672            let multi_buffer = self.buffer().read(cx);
17673            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17674            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17675
17676            let (buffer, range, _) = if selection.reversed {
17677                buffer_ranges.first()
17678            } else {
17679                buffer_ranges.last()
17680            }?;
17681
17682            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17683                ..text::ToPoint::to_point(&range.end, &buffer).row;
17684            Some((
17685                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17686                selection,
17687            ))
17688        });
17689
17690        let Some((buffer, selection)) = buffer_and_selection else {
17691            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17692        };
17693
17694        let Some(project) = self.project.as_ref() else {
17695            return Task::ready(Err(anyhow!("editor does not have project")));
17696        };
17697
17698        project.update(cx, |project, cx| {
17699            project.get_permalink_to_line(&buffer, selection, cx)
17700        })
17701    }
17702
17703    pub fn copy_permalink_to_line(
17704        &mut self,
17705        _: &CopyPermalinkToLine,
17706        window: &mut Window,
17707        cx: &mut Context<Self>,
17708    ) {
17709        let permalink_task = self.get_permalink_to_line(cx);
17710        let workspace = self.workspace();
17711
17712        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17713            Ok(permalink) => {
17714                cx.update(|_, cx| {
17715                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17716                })
17717                .ok();
17718            }
17719            Err(err) => {
17720                let message = format!("Failed to copy permalink: {err}");
17721
17722                anyhow::Result::<()>::Err(err).log_err();
17723
17724                if let Some(workspace) = workspace {
17725                    workspace
17726                        .update_in(cx, |workspace, _, cx| {
17727                            struct CopyPermalinkToLine;
17728
17729                            workspace.show_toast(
17730                                Toast::new(
17731                                    NotificationId::unique::<CopyPermalinkToLine>(),
17732                                    message,
17733                                ),
17734                                cx,
17735                            )
17736                        })
17737                        .ok();
17738                }
17739            }
17740        })
17741        .detach();
17742    }
17743
17744    pub fn copy_file_location(
17745        &mut self,
17746        _: &CopyFileLocation,
17747        _: &mut Window,
17748        cx: &mut Context<Self>,
17749    ) {
17750        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17751        if let Some(file) = self.target_file(cx) {
17752            if let Some(path) = file.path().to_str() {
17753                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17754            }
17755        }
17756    }
17757
17758    pub fn open_permalink_to_line(
17759        &mut self,
17760        _: &OpenPermalinkToLine,
17761        window: &mut Window,
17762        cx: &mut Context<Self>,
17763    ) {
17764        let permalink_task = self.get_permalink_to_line(cx);
17765        let workspace = self.workspace();
17766
17767        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17768            Ok(permalink) => {
17769                cx.update(|_, cx| {
17770                    cx.open_url(permalink.as_ref());
17771                })
17772                .ok();
17773            }
17774            Err(err) => {
17775                let message = format!("Failed to open permalink: {err}");
17776
17777                anyhow::Result::<()>::Err(err).log_err();
17778
17779                if let Some(workspace) = workspace {
17780                    workspace
17781                        .update(cx, |workspace, cx| {
17782                            struct OpenPermalinkToLine;
17783
17784                            workspace.show_toast(
17785                                Toast::new(
17786                                    NotificationId::unique::<OpenPermalinkToLine>(),
17787                                    message,
17788                                ),
17789                                cx,
17790                            )
17791                        })
17792                        .ok();
17793                }
17794            }
17795        })
17796        .detach();
17797    }
17798
17799    pub fn insert_uuid_v4(
17800        &mut self,
17801        _: &InsertUuidV4,
17802        window: &mut Window,
17803        cx: &mut Context<Self>,
17804    ) {
17805        self.insert_uuid(UuidVersion::V4, window, cx);
17806    }
17807
17808    pub fn insert_uuid_v7(
17809        &mut self,
17810        _: &InsertUuidV7,
17811        window: &mut Window,
17812        cx: &mut Context<Self>,
17813    ) {
17814        self.insert_uuid(UuidVersion::V7, window, cx);
17815    }
17816
17817    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17818        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17819        self.transact(window, cx, |this, window, cx| {
17820            let edits = this
17821                .selections
17822                .all::<Point>(cx)
17823                .into_iter()
17824                .map(|selection| {
17825                    let uuid = match version {
17826                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17827                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17828                    };
17829
17830                    (selection.range(), uuid.to_string())
17831                });
17832            this.edit(edits, cx);
17833            this.refresh_inline_completion(true, false, window, cx);
17834        });
17835    }
17836
17837    pub fn open_selections_in_multibuffer(
17838        &mut self,
17839        _: &OpenSelectionsInMultibuffer,
17840        window: &mut Window,
17841        cx: &mut Context<Self>,
17842    ) {
17843        let multibuffer = self.buffer.read(cx);
17844
17845        let Some(buffer) = multibuffer.as_singleton() else {
17846            return;
17847        };
17848
17849        let Some(workspace) = self.workspace() else {
17850            return;
17851        };
17852
17853        let locations = self
17854            .selections
17855            .disjoint_anchors()
17856            .iter()
17857            .map(|selection| {
17858                let range = if selection.reversed {
17859                    selection.end.text_anchor..selection.start.text_anchor
17860                } else {
17861                    selection.start.text_anchor..selection.end.text_anchor
17862                };
17863                Location {
17864                    buffer: buffer.clone(),
17865                    range,
17866                }
17867            })
17868            .collect::<Vec<_>>();
17869
17870        let title = multibuffer.title(cx).to_string();
17871
17872        cx.spawn_in(window, async move |_, cx| {
17873            workspace.update_in(cx, |workspace, window, cx| {
17874                Self::open_locations_in_multibuffer(
17875                    workspace,
17876                    locations,
17877                    format!("Selections for '{title}'"),
17878                    false,
17879                    MultibufferSelectionMode::All,
17880                    window,
17881                    cx,
17882                );
17883            })
17884        })
17885        .detach();
17886    }
17887
17888    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17889    /// last highlight added will be used.
17890    ///
17891    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17892    pub fn highlight_rows<T: 'static>(
17893        &mut self,
17894        range: Range<Anchor>,
17895        color: Hsla,
17896        options: RowHighlightOptions,
17897        cx: &mut Context<Self>,
17898    ) {
17899        let snapshot = self.buffer().read(cx).snapshot(cx);
17900        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17901        let ix = row_highlights.binary_search_by(|highlight| {
17902            Ordering::Equal
17903                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17904                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17905        });
17906
17907        if let Err(mut ix) = ix {
17908            let index = post_inc(&mut self.highlight_order);
17909
17910            // If this range intersects with the preceding highlight, then merge it with
17911            // the preceding highlight. Otherwise insert a new highlight.
17912            let mut merged = false;
17913            if ix > 0 {
17914                let prev_highlight = &mut row_highlights[ix - 1];
17915                if prev_highlight
17916                    .range
17917                    .end
17918                    .cmp(&range.start, &snapshot)
17919                    .is_ge()
17920                {
17921                    ix -= 1;
17922                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17923                        prev_highlight.range.end = range.end;
17924                    }
17925                    merged = true;
17926                    prev_highlight.index = index;
17927                    prev_highlight.color = color;
17928                    prev_highlight.options = options;
17929                }
17930            }
17931
17932            if !merged {
17933                row_highlights.insert(
17934                    ix,
17935                    RowHighlight {
17936                        range: range.clone(),
17937                        index,
17938                        color,
17939                        options,
17940                        type_id: TypeId::of::<T>(),
17941                    },
17942                );
17943            }
17944
17945            // If any of the following highlights intersect with this one, merge them.
17946            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17947                let highlight = &row_highlights[ix];
17948                if next_highlight
17949                    .range
17950                    .start
17951                    .cmp(&highlight.range.end, &snapshot)
17952                    .is_le()
17953                {
17954                    if next_highlight
17955                        .range
17956                        .end
17957                        .cmp(&highlight.range.end, &snapshot)
17958                        .is_gt()
17959                    {
17960                        row_highlights[ix].range.end = next_highlight.range.end;
17961                    }
17962                    row_highlights.remove(ix + 1);
17963                } else {
17964                    break;
17965                }
17966            }
17967        }
17968    }
17969
17970    /// Remove any highlighted row ranges of the given type that intersect the
17971    /// given ranges.
17972    pub fn remove_highlighted_rows<T: 'static>(
17973        &mut self,
17974        ranges_to_remove: Vec<Range<Anchor>>,
17975        cx: &mut Context<Self>,
17976    ) {
17977        let snapshot = self.buffer().read(cx).snapshot(cx);
17978        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17979        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17980        row_highlights.retain(|highlight| {
17981            while let Some(range_to_remove) = ranges_to_remove.peek() {
17982                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17983                    Ordering::Less | Ordering::Equal => {
17984                        ranges_to_remove.next();
17985                    }
17986                    Ordering::Greater => {
17987                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17988                            Ordering::Less | Ordering::Equal => {
17989                                return false;
17990                            }
17991                            Ordering::Greater => break,
17992                        }
17993                    }
17994                }
17995            }
17996
17997            true
17998        })
17999    }
18000
18001    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18002    pub fn clear_row_highlights<T: 'static>(&mut self) {
18003        self.highlighted_rows.remove(&TypeId::of::<T>());
18004    }
18005
18006    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18007    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18008        self.highlighted_rows
18009            .get(&TypeId::of::<T>())
18010            .map_or(&[] as &[_], |vec| vec.as_slice())
18011            .iter()
18012            .map(|highlight| (highlight.range.clone(), highlight.color))
18013    }
18014
18015    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18016    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18017    /// Allows to ignore certain kinds of highlights.
18018    pub fn highlighted_display_rows(
18019        &self,
18020        window: &mut Window,
18021        cx: &mut App,
18022    ) -> BTreeMap<DisplayRow, LineHighlight> {
18023        let snapshot = self.snapshot(window, cx);
18024        let mut used_highlight_orders = HashMap::default();
18025        self.highlighted_rows
18026            .iter()
18027            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18028            .fold(
18029                BTreeMap::<DisplayRow, LineHighlight>::new(),
18030                |mut unique_rows, highlight| {
18031                    let start = highlight.range.start.to_display_point(&snapshot);
18032                    let end = highlight.range.end.to_display_point(&snapshot);
18033                    let start_row = start.row().0;
18034                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18035                        && end.column() == 0
18036                    {
18037                        end.row().0.saturating_sub(1)
18038                    } else {
18039                        end.row().0
18040                    };
18041                    for row in start_row..=end_row {
18042                        let used_index =
18043                            used_highlight_orders.entry(row).or_insert(highlight.index);
18044                        if highlight.index >= *used_index {
18045                            *used_index = highlight.index;
18046                            unique_rows.insert(
18047                                DisplayRow(row),
18048                                LineHighlight {
18049                                    include_gutter: highlight.options.include_gutter,
18050                                    border: None,
18051                                    background: highlight.color.into(),
18052                                    type_id: Some(highlight.type_id),
18053                                },
18054                            );
18055                        }
18056                    }
18057                    unique_rows
18058                },
18059            )
18060    }
18061
18062    pub fn highlighted_display_row_for_autoscroll(
18063        &self,
18064        snapshot: &DisplaySnapshot,
18065    ) -> Option<DisplayRow> {
18066        self.highlighted_rows
18067            .values()
18068            .flat_map(|highlighted_rows| highlighted_rows.iter())
18069            .filter_map(|highlight| {
18070                if highlight.options.autoscroll {
18071                    Some(highlight.range.start.to_display_point(snapshot).row())
18072                } else {
18073                    None
18074                }
18075            })
18076            .min()
18077    }
18078
18079    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18080        self.highlight_background::<SearchWithinRange>(
18081            ranges,
18082            |colors| colors.editor_document_highlight_read_background,
18083            cx,
18084        )
18085    }
18086
18087    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18088        self.breadcrumb_header = Some(new_header);
18089    }
18090
18091    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18092        self.clear_background_highlights::<SearchWithinRange>(cx);
18093    }
18094
18095    pub fn highlight_background<T: 'static>(
18096        &mut self,
18097        ranges: &[Range<Anchor>],
18098        color_fetcher: fn(&ThemeColors) -> Hsla,
18099        cx: &mut Context<Self>,
18100    ) {
18101        self.background_highlights
18102            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18103        self.scrollbar_marker_state.dirty = true;
18104        cx.notify();
18105    }
18106
18107    pub fn clear_background_highlights<T: 'static>(
18108        &mut self,
18109        cx: &mut Context<Self>,
18110    ) -> Option<BackgroundHighlight> {
18111        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18112        if !text_highlights.1.is_empty() {
18113            self.scrollbar_marker_state.dirty = true;
18114            cx.notify();
18115        }
18116        Some(text_highlights)
18117    }
18118
18119    pub fn highlight_gutter<T: 'static>(
18120        &mut self,
18121        ranges: &[Range<Anchor>],
18122        color_fetcher: fn(&App) -> Hsla,
18123        cx: &mut Context<Self>,
18124    ) {
18125        self.gutter_highlights
18126            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18127        cx.notify();
18128    }
18129
18130    pub fn clear_gutter_highlights<T: 'static>(
18131        &mut self,
18132        cx: &mut Context<Self>,
18133    ) -> Option<GutterHighlight> {
18134        cx.notify();
18135        self.gutter_highlights.remove(&TypeId::of::<T>())
18136    }
18137
18138    #[cfg(feature = "test-support")]
18139    pub fn all_text_background_highlights(
18140        &self,
18141        window: &mut Window,
18142        cx: &mut Context<Self>,
18143    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18144        let snapshot = self.snapshot(window, cx);
18145        let buffer = &snapshot.buffer_snapshot;
18146        let start = buffer.anchor_before(0);
18147        let end = buffer.anchor_after(buffer.len());
18148        let theme = cx.theme().colors();
18149        self.background_highlights_in_range(start..end, &snapshot, theme)
18150    }
18151
18152    #[cfg(feature = "test-support")]
18153    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18154        let snapshot = self.buffer().read(cx).snapshot(cx);
18155
18156        let highlights = self
18157            .background_highlights
18158            .get(&TypeId::of::<items::BufferSearchHighlights>());
18159
18160        if let Some((_color, ranges)) = highlights {
18161            ranges
18162                .iter()
18163                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18164                .collect_vec()
18165        } else {
18166            vec![]
18167        }
18168    }
18169
18170    fn document_highlights_for_position<'a>(
18171        &'a self,
18172        position: Anchor,
18173        buffer: &'a MultiBufferSnapshot,
18174    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18175        let read_highlights = self
18176            .background_highlights
18177            .get(&TypeId::of::<DocumentHighlightRead>())
18178            .map(|h| &h.1);
18179        let write_highlights = self
18180            .background_highlights
18181            .get(&TypeId::of::<DocumentHighlightWrite>())
18182            .map(|h| &h.1);
18183        let left_position = position.bias_left(buffer);
18184        let right_position = position.bias_right(buffer);
18185        read_highlights
18186            .into_iter()
18187            .chain(write_highlights)
18188            .flat_map(move |ranges| {
18189                let start_ix = match ranges.binary_search_by(|probe| {
18190                    let cmp = probe.end.cmp(&left_position, buffer);
18191                    if cmp.is_ge() {
18192                        Ordering::Greater
18193                    } else {
18194                        Ordering::Less
18195                    }
18196                }) {
18197                    Ok(i) | Err(i) => i,
18198                };
18199
18200                ranges[start_ix..]
18201                    .iter()
18202                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18203            })
18204    }
18205
18206    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18207        self.background_highlights
18208            .get(&TypeId::of::<T>())
18209            .map_or(false, |(_, highlights)| !highlights.is_empty())
18210    }
18211
18212    pub fn background_highlights_in_range(
18213        &self,
18214        search_range: Range<Anchor>,
18215        display_snapshot: &DisplaySnapshot,
18216        theme: &ThemeColors,
18217    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18218        let mut results = Vec::new();
18219        for (color_fetcher, ranges) in self.background_highlights.values() {
18220            let color = color_fetcher(theme);
18221            let start_ix = match ranges.binary_search_by(|probe| {
18222                let cmp = probe
18223                    .end
18224                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18225                if cmp.is_gt() {
18226                    Ordering::Greater
18227                } else {
18228                    Ordering::Less
18229                }
18230            }) {
18231                Ok(i) | Err(i) => i,
18232            };
18233            for range in &ranges[start_ix..] {
18234                if range
18235                    .start
18236                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18237                    .is_ge()
18238                {
18239                    break;
18240                }
18241
18242                let start = range.start.to_display_point(display_snapshot);
18243                let end = range.end.to_display_point(display_snapshot);
18244                results.push((start..end, color))
18245            }
18246        }
18247        results
18248    }
18249
18250    pub fn background_highlight_row_ranges<T: 'static>(
18251        &self,
18252        search_range: Range<Anchor>,
18253        display_snapshot: &DisplaySnapshot,
18254        count: usize,
18255    ) -> Vec<RangeInclusive<DisplayPoint>> {
18256        let mut results = Vec::new();
18257        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18258            return vec![];
18259        };
18260
18261        let start_ix = match ranges.binary_search_by(|probe| {
18262            let cmp = probe
18263                .end
18264                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18265            if cmp.is_gt() {
18266                Ordering::Greater
18267            } else {
18268                Ordering::Less
18269            }
18270        }) {
18271            Ok(i) | Err(i) => i,
18272        };
18273        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18274            if let (Some(start_display), Some(end_display)) = (start, end) {
18275                results.push(
18276                    start_display.to_display_point(display_snapshot)
18277                        ..=end_display.to_display_point(display_snapshot),
18278                );
18279            }
18280        };
18281        let mut start_row: Option<Point> = None;
18282        let mut end_row: Option<Point> = None;
18283        if ranges.len() > count {
18284            return Vec::new();
18285        }
18286        for range in &ranges[start_ix..] {
18287            if range
18288                .start
18289                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18290                .is_ge()
18291            {
18292                break;
18293            }
18294            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18295            if let Some(current_row) = &end_row {
18296                if end.row == current_row.row {
18297                    continue;
18298                }
18299            }
18300            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18301            if start_row.is_none() {
18302                assert_eq!(end_row, None);
18303                start_row = Some(start);
18304                end_row = Some(end);
18305                continue;
18306            }
18307            if let Some(current_end) = end_row.as_mut() {
18308                if start.row > current_end.row + 1 {
18309                    push_region(start_row, end_row);
18310                    start_row = Some(start);
18311                    end_row = Some(end);
18312                } else {
18313                    // Merge two hunks.
18314                    *current_end = end;
18315                }
18316            } else {
18317                unreachable!();
18318            }
18319        }
18320        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18321        push_region(start_row, end_row);
18322        results
18323    }
18324
18325    pub fn gutter_highlights_in_range(
18326        &self,
18327        search_range: Range<Anchor>,
18328        display_snapshot: &DisplaySnapshot,
18329        cx: &App,
18330    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18331        let mut results = Vec::new();
18332        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18333            let color = color_fetcher(cx);
18334            let start_ix = match ranges.binary_search_by(|probe| {
18335                let cmp = probe
18336                    .end
18337                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18338                if cmp.is_gt() {
18339                    Ordering::Greater
18340                } else {
18341                    Ordering::Less
18342                }
18343            }) {
18344                Ok(i) | Err(i) => i,
18345            };
18346            for range in &ranges[start_ix..] {
18347                if range
18348                    .start
18349                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18350                    .is_ge()
18351                {
18352                    break;
18353                }
18354
18355                let start = range.start.to_display_point(display_snapshot);
18356                let end = range.end.to_display_point(display_snapshot);
18357                results.push((start..end, color))
18358            }
18359        }
18360        results
18361    }
18362
18363    /// Get the text ranges corresponding to the redaction query
18364    pub fn redacted_ranges(
18365        &self,
18366        search_range: Range<Anchor>,
18367        display_snapshot: &DisplaySnapshot,
18368        cx: &App,
18369    ) -> Vec<Range<DisplayPoint>> {
18370        display_snapshot
18371            .buffer_snapshot
18372            .redacted_ranges(search_range, |file| {
18373                if let Some(file) = file {
18374                    file.is_private()
18375                        && EditorSettings::get(
18376                            Some(SettingsLocation {
18377                                worktree_id: file.worktree_id(cx),
18378                                path: file.path().as_ref(),
18379                            }),
18380                            cx,
18381                        )
18382                        .redact_private_values
18383                } else {
18384                    false
18385                }
18386            })
18387            .map(|range| {
18388                range.start.to_display_point(display_snapshot)
18389                    ..range.end.to_display_point(display_snapshot)
18390            })
18391            .collect()
18392    }
18393
18394    pub fn highlight_text<T: 'static>(
18395        &mut self,
18396        ranges: Vec<Range<Anchor>>,
18397        style: HighlightStyle,
18398        cx: &mut Context<Self>,
18399    ) {
18400        self.display_map.update(cx, |map, _| {
18401            map.highlight_text(TypeId::of::<T>(), ranges, style)
18402        });
18403        cx.notify();
18404    }
18405
18406    pub(crate) fn highlight_inlays<T: 'static>(
18407        &mut self,
18408        highlights: Vec<InlayHighlight>,
18409        style: HighlightStyle,
18410        cx: &mut Context<Self>,
18411    ) {
18412        self.display_map.update(cx, |map, _| {
18413            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18414        });
18415        cx.notify();
18416    }
18417
18418    pub fn text_highlights<'a, T: 'static>(
18419        &'a self,
18420        cx: &'a App,
18421    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18422        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18423    }
18424
18425    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18426        let cleared = self
18427            .display_map
18428            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18429        if cleared {
18430            cx.notify();
18431        }
18432    }
18433
18434    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18435        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18436            && self.focus_handle.is_focused(window)
18437    }
18438
18439    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18440        self.show_cursor_when_unfocused = is_enabled;
18441        cx.notify();
18442    }
18443
18444    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18445        cx.notify();
18446    }
18447
18448    fn on_debug_session_event(
18449        &mut self,
18450        _session: Entity<Session>,
18451        event: &SessionEvent,
18452        cx: &mut Context<Self>,
18453    ) {
18454        match event {
18455            SessionEvent::InvalidateInlineValue => {
18456                self.refresh_inline_values(cx);
18457            }
18458            _ => {}
18459        }
18460    }
18461
18462    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18463        let Some(project) = self.project.clone() else {
18464            return;
18465        };
18466
18467        if !self.inline_value_cache.enabled {
18468            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18469            self.splice_inlays(&inlays, Vec::new(), cx);
18470            return;
18471        }
18472
18473        let current_execution_position = self
18474            .highlighted_rows
18475            .get(&TypeId::of::<ActiveDebugLine>())
18476            .and_then(|lines| lines.last().map(|line| line.range.start));
18477
18478        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18479            let inline_values = editor
18480                .update(cx, |editor, cx| {
18481                    let Some(current_execution_position) = current_execution_position else {
18482                        return Some(Task::ready(Ok(Vec::new())));
18483                    };
18484
18485                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18486                        let snapshot = buffer.snapshot(cx);
18487
18488                        let excerpt = snapshot.excerpt_containing(
18489                            current_execution_position..current_execution_position,
18490                        )?;
18491
18492                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18493                    })?;
18494
18495                    let range =
18496                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18497
18498                    project.inline_values(buffer, range, cx)
18499                })
18500                .ok()
18501                .flatten()?
18502                .await
18503                .context("refreshing debugger inlays")
18504                .log_err()?;
18505
18506            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18507
18508            for (buffer_id, inline_value) in inline_values
18509                .into_iter()
18510                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18511            {
18512                buffer_inline_values
18513                    .entry(buffer_id)
18514                    .or_default()
18515                    .push(inline_value);
18516            }
18517
18518            editor
18519                .update(cx, |editor, cx| {
18520                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18521                    let mut new_inlays = Vec::default();
18522
18523                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18524                        let buffer_id = buffer_snapshot.remote_id();
18525                        buffer_inline_values
18526                            .get(&buffer_id)
18527                            .into_iter()
18528                            .flatten()
18529                            .for_each(|hint| {
18530                                let inlay = Inlay::debugger_hint(
18531                                    post_inc(&mut editor.next_inlay_id),
18532                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18533                                    hint.text(),
18534                                );
18535
18536                                new_inlays.push(inlay);
18537                            });
18538                    }
18539
18540                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18541                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18542
18543                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18544                })
18545                .ok()?;
18546            Some(())
18547        });
18548    }
18549
18550    fn on_buffer_event(
18551        &mut self,
18552        multibuffer: &Entity<MultiBuffer>,
18553        event: &multi_buffer::Event,
18554        window: &mut Window,
18555        cx: &mut Context<Self>,
18556    ) {
18557        match event {
18558            multi_buffer::Event::Edited {
18559                singleton_buffer_edited,
18560                edited_buffer: buffer_edited,
18561            } => {
18562                self.scrollbar_marker_state.dirty = true;
18563                self.active_indent_guides_state.dirty = true;
18564                self.refresh_active_diagnostics(cx);
18565                self.refresh_code_actions(window, cx);
18566                self.refresh_selected_text_highlights(true, window, cx);
18567                refresh_matching_bracket_highlights(self, window, cx);
18568                if self.has_active_inline_completion() {
18569                    self.update_visible_inline_completion(window, cx);
18570                }
18571                if let Some(buffer) = buffer_edited {
18572                    let buffer_id = buffer.read(cx).remote_id();
18573                    if !self.registered_buffers.contains_key(&buffer_id) {
18574                        if let Some(project) = self.project.as_ref() {
18575                            project.update(cx, |project, cx| {
18576                                self.registered_buffers.insert(
18577                                    buffer_id,
18578                                    project.register_buffer_with_language_servers(&buffer, cx),
18579                                );
18580                            })
18581                        }
18582                    }
18583                }
18584                cx.emit(EditorEvent::BufferEdited);
18585                cx.emit(SearchEvent::MatchesInvalidated);
18586                if *singleton_buffer_edited {
18587                    if let Some(project) = &self.project {
18588                        #[allow(clippy::mutable_key_type)]
18589                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18590                            multibuffer
18591                                .all_buffers()
18592                                .into_iter()
18593                                .filter_map(|buffer| {
18594                                    buffer.update(cx, |buffer, cx| {
18595                                        let language = buffer.language()?;
18596                                        let should_discard = project.update(cx, |project, cx| {
18597                                            project.is_local()
18598                                                && !project.has_language_servers_for(buffer, cx)
18599                                        });
18600                                        should_discard.not().then_some(language.clone())
18601                                    })
18602                                })
18603                                .collect::<HashSet<_>>()
18604                        });
18605                        if !languages_affected.is_empty() {
18606                            self.refresh_inlay_hints(
18607                                InlayHintRefreshReason::BufferEdited(languages_affected),
18608                                cx,
18609                            );
18610                        }
18611                    }
18612                }
18613
18614                let Some(project) = &self.project else { return };
18615                let (telemetry, is_via_ssh) = {
18616                    let project = project.read(cx);
18617                    let telemetry = project.client().telemetry().clone();
18618                    let is_via_ssh = project.is_via_ssh();
18619                    (telemetry, is_via_ssh)
18620                };
18621                refresh_linked_ranges(self, window, cx);
18622                telemetry.log_edit_event("editor", is_via_ssh);
18623            }
18624            multi_buffer::Event::ExcerptsAdded {
18625                buffer,
18626                predecessor,
18627                excerpts,
18628            } => {
18629                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18630                let buffer_id = buffer.read(cx).remote_id();
18631                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18632                    if let Some(project) = &self.project {
18633                        update_uncommitted_diff_for_buffer(
18634                            cx.entity(),
18635                            project,
18636                            [buffer.clone()],
18637                            self.buffer.clone(),
18638                            cx,
18639                        )
18640                        .detach();
18641                    }
18642                }
18643                cx.emit(EditorEvent::ExcerptsAdded {
18644                    buffer: buffer.clone(),
18645                    predecessor: *predecessor,
18646                    excerpts: excerpts.clone(),
18647                });
18648                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18649            }
18650            multi_buffer::Event::ExcerptsRemoved {
18651                ids,
18652                removed_buffer_ids,
18653            } => {
18654                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18655                let buffer = self.buffer.read(cx);
18656                self.registered_buffers
18657                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18658                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18659                cx.emit(EditorEvent::ExcerptsRemoved {
18660                    ids: ids.clone(),
18661                    removed_buffer_ids: removed_buffer_ids.clone(),
18662                })
18663            }
18664            multi_buffer::Event::ExcerptsEdited {
18665                excerpt_ids,
18666                buffer_ids,
18667            } => {
18668                self.display_map.update(cx, |map, cx| {
18669                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18670                });
18671                cx.emit(EditorEvent::ExcerptsEdited {
18672                    ids: excerpt_ids.clone(),
18673                })
18674            }
18675            multi_buffer::Event::ExcerptsExpanded { ids } => {
18676                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18677                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18678            }
18679            multi_buffer::Event::Reparsed(buffer_id) => {
18680                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18681                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18682
18683                cx.emit(EditorEvent::Reparsed(*buffer_id));
18684            }
18685            multi_buffer::Event::DiffHunksToggled => {
18686                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18687            }
18688            multi_buffer::Event::LanguageChanged(buffer_id) => {
18689                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18690                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18691                cx.emit(EditorEvent::Reparsed(*buffer_id));
18692                cx.notify();
18693            }
18694            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18695            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18696            multi_buffer::Event::FileHandleChanged
18697            | multi_buffer::Event::Reloaded
18698            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18699            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18700            multi_buffer::Event::DiagnosticsUpdated => {
18701                self.refresh_active_diagnostics(cx);
18702                self.refresh_inline_diagnostics(true, window, cx);
18703                self.scrollbar_marker_state.dirty = true;
18704                cx.notify();
18705            }
18706            _ => {}
18707        };
18708    }
18709
18710    pub fn start_temporary_diff_override(&mut self) {
18711        self.load_diff_task.take();
18712        self.temporary_diff_override = true;
18713    }
18714
18715    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18716        self.temporary_diff_override = false;
18717        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18718        self.buffer.update(cx, |buffer, cx| {
18719            buffer.set_all_diff_hunks_collapsed(cx);
18720        });
18721
18722        if let Some(project) = self.project.clone() {
18723            self.load_diff_task = Some(
18724                update_uncommitted_diff_for_buffer(
18725                    cx.entity(),
18726                    &project,
18727                    self.buffer.read(cx).all_buffers(),
18728                    self.buffer.clone(),
18729                    cx,
18730                )
18731                .shared(),
18732            );
18733        }
18734    }
18735
18736    fn on_display_map_changed(
18737        &mut self,
18738        _: Entity<DisplayMap>,
18739        _: &mut Window,
18740        cx: &mut Context<Self>,
18741    ) {
18742        cx.notify();
18743    }
18744
18745    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18746        let new_severity = if self.diagnostics_enabled() {
18747            EditorSettings::get_global(cx)
18748                .diagnostics_max_severity
18749                .unwrap_or(DiagnosticSeverity::Hint)
18750        } else {
18751            DiagnosticSeverity::Off
18752        };
18753        self.set_max_diagnostics_severity(new_severity, cx);
18754        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18755        self.update_edit_prediction_settings(cx);
18756        self.refresh_inline_completion(true, false, window, cx);
18757        self.refresh_inlay_hints(
18758            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18759                self.selections.newest_anchor().head(),
18760                &self.buffer.read(cx).snapshot(cx),
18761                cx,
18762            )),
18763            cx,
18764        );
18765
18766        let old_cursor_shape = self.cursor_shape;
18767
18768        {
18769            let editor_settings = EditorSettings::get_global(cx);
18770            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18771            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18772            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18773            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18774        }
18775
18776        if old_cursor_shape != self.cursor_shape {
18777            cx.emit(EditorEvent::CursorShapeChanged);
18778        }
18779
18780        let project_settings = ProjectSettings::get_global(cx);
18781        self.serialize_dirty_buffers =
18782            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18783
18784        if self.mode.is_full() {
18785            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18786            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18787            if self.show_inline_diagnostics != show_inline_diagnostics {
18788                self.show_inline_diagnostics = show_inline_diagnostics;
18789                self.refresh_inline_diagnostics(false, window, cx);
18790            }
18791
18792            if self.git_blame_inline_enabled != inline_blame_enabled {
18793                self.toggle_git_blame_inline_internal(false, window, cx);
18794            }
18795
18796            let minimap_settings = EditorSettings::get_global(cx).minimap;
18797            if self.minimap_visibility != MinimapVisibility::Disabled {
18798                if self.minimap_visibility.settings_visibility()
18799                    != minimap_settings.minimap_enabled()
18800                {
18801                    self.set_minimap_visibility(
18802                        MinimapVisibility::for_mode(self.mode(), cx),
18803                        window,
18804                        cx,
18805                    );
18806                } else if let Some(minimap_entity) = self.minimap.as_ref() {
18807                    minimap_entity.update(cx, |minimap_editor, cx| {
18808                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
18809                    })
18810                }
18811            }
18812        }
18813
18814        cx.notify();
18815    }
18816
18817    pub fn set_searchable(&mut self, searchable: bool) {
18818        self.searchable = searchable;
18819    }
18820
18821    pub fn searchable(&self) -> bool {
18822        self.searchable
18823    }
18824
18825    fn open_proposed_changes_editor(
18826        &mut self,
18827        _: &OpenProposedChangesEditor,
18828        window: &mut Window,
18829        cx: &mut Context<Self>,
18830    ) {
18831        let Some(workspace) = self.workspace() else {
18832            cx.propagate();
18833            return;
18834        };
18835
18836        let selections = self.selections.all::<usize>(cx);
18837        let multi_buffer = self.buffer.read(cx);
18838        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18839        let mut new_selections_by_buffer = HashMap::default();
18840        for selection in selections {
18841            for (buffer, range, _) in
18842                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18843            {
18844                let mut range = range.to_point(buffer);
18845                range.start.column = 0;
18846                range.end.column = buffer.line_len(range.end.row);
18847                new_selections_by_buffer
18848                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18849                    .or_insert(Vec::new())
18850                    .push(range)
18851            }
18852        }
18853
18854        let proposed_changes_buffers = new_selections_by_buffer
18855            .into_iter()
18856            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18857            .collect::<Vec<_>>();
18858        let proposed_changes_editor = cx.new(|cx| {
18859            ProposedChangesEditor::new(
18860                "Proposed changes",
18861                proposed_changes_buffers,
18862                self.project.clone(),
18863                window,
18864                cx,
18865            )
18866        });
18867
18868        window.defer(cx, move |window, cx| {
18869            workspace.update(cx, |workspace, cx| {
18870                workspace.active_pane().update(cx, |pane, cx| {
18871                    pane.add_item(
18872                        Box::new(proposed_changes_editor),
18873                        true,
18874                        true,
18875                        None,
18876                        window,
18877                        cx,
18878                    );
18879                });
18880            });
18881        });
18882    }
18883
18884    pub fn open_excerpts_in_split(
18885        &mut self,
18886        _: &OpenExcerptsSplit,
18887        window: &mut Window,
18888        cx: &mut Context<Self>,
18889    ) {
18890        self.open_excerpts_common(None, true, window, cx)
18891    }
18892
18893    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18894        self.open_excerpts_common(None, false, window, cx)
18895    }
18896
18897    fn open_excerpts_common(
18898        &mut self,
18899        jump_data: Option<JumpData>,
18900        split: bool,
18901        window: &mut Window,
18902        cx: &mut Context<Self>,
18903    ) {
18904        let Some(workspace) = self.workspace() else {
18905            cx.propagate();
18906            return;
18907        };
18908
18909        if self.buffer.read(cx).is_singleton() {
18910            cx.propagate();
18911            return;
18912        }
18913
18914        let mut new_selections_by_buffer = HashMap::default();
18915        match &jump_data {
18916            Some(JumpData::MultiBufferPoint {
18917                excerpt_id,
18918                position,
18919                anchor,
18920                line_offset_from_top,
18921            }) => {
18922                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18923                if let Some(buffer) = multi_buffer_snapshot
18924                    .buffer_id_for_excerpt(*excerpt_id)
18925                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18926                {
18927                    let buffer_snapshot = buffer.read(cx).snapshot();
18928                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18929                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18930                    } else {
18931                        buffer_snapshot.clip_point(*position, Bias::Left)
18932                    };
18933                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18934                    new_selections_by_buffer.insert(
18935                        buffer,
18936                        (
18937                            vec![jump_to_offset..jump_to_offset],
18938                            Some(*line_offset_from_top),
18939                        ),
18940                    );
18941                }
18942            }
18943            Some(JumpData::MultiBufferRow {
18944                row,
18945                line_offset_from_top,
18946            }) => {
18947                let point = MultiBufferPoint::new(row.0, 0);
18948                if let Some((buffer, buffer_point, _)) =
18949                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18950                {
18951                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18952                    new_selections_by_buffer
18953                        .entry(buffer)
18954                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18955                        .0
18956                        .push(buffer_offset..buffer_offset)
18957                }
18958            }
18959            None => {
18960                let selections = self.selections.all::<usize>(cx);
18961                let multi_buffer = self.buffer.read(cx);
18962                for selection in selections {
18963                    for (snapshot, range, _, anchor) in multi_buffer
18964                        .snapshot(cx)
18965                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18966                    {
18967                        if let Some(anchor) = anchor {
18968                            // selection is in a deleted hunk
18969                            let Some(buffer_id) = anchor.buffer_id else {
18970                                continue;
18971                            };
18972                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18973                                continue;
18974                            };
18975                            let offset = text::ToOffset::to_offset(
18976                                &anchor.text_anchor,
18977                                &buffer_handle.read(cx).snapshot(),
18978                            );
18979                            let range = offset..offset;
18980                            new_selections_by_buffer
18981                                .entry(buffer_handle)
18982                                .or_insert((Vec::new(), None))
18983                                .0
18984                                .push(range)
18985                        } else {
18986                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18987                            else {
18988                                continue;
18989                            };
18990                            new_selections_by_buffer
18991                                .entry(buffer_handle)
18992                                .or_insert((Vec::new(), None))
18993                                .0
18994                                .push(range)
18995                        }
18996                    }
18997                }
18998            }
18999        }
19000
19001        new_selections_by_buffer
19002            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19003
19004        if new_selections_by_buffer.is_empty() {
19005            return;
19006        }
19007
19008        // We defer the pane interaction because we ourselves are a workspace item
19009        // and activating a new item causes the pane to call a method on us reentrantly,
19010        // which panics if we're on the stack.
19011        window.defer(cx, move |window, cx| {
19012            workspace.update(cx, |workspace, cx| {
19013                let pane = if split {
19014                    workspace.adjacent_pane(window, cx)
19015                } else {
19016                    workspace.active_pane().clone()
19017                };
19018
19019                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19020                    let editor = buffer
19021                        .read(cx)
19022                        .file()
19023                        .is_none()
19024                        .then(|| {
19025                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19026                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19027                            // Instead, we try to activate the existing editor in the pane first.
19028                            let (editor, pane_item_index) =
19029                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19030                                    let editor = item.downcast::<Editor>()?;
19031                                    let singleton_buffer =
19032                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19033                                    if singleton_buffer == buffer {
19034                                        Some((editor, i))
19035                                    } else {
19036                                        None
19037                                    }
19038                                })?;
19039                            pane.update(cx, |pane, cx| {
19040                                pane.activate_item(pane_item_index, true, true, window, cx)
19041                            });
19042                            Some(editor)
19043                        })
19044                        .flatten()
19045                        .unwrap_or_else(|| {
19046                            workspace.open_project_item::<Self>(
19047                                pane.clone(),
19048                                buffer,
19049                                true,
19050                                true,
19051                                window,
19052                                cx,
19053                            )
19054                        });
19055
19056                    editor.update(cx, |editor, cx| {
19057                        let autoscroll = match scroll_offset {
19058                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19059                            None => Autoscroll::newest(),
19060                        };
19061                        let nav_history = editor.nav_history.take();
19062                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19063                            s.select_ranges(ranges);
19064                        });
19065                        editor.nav_history = nav_history;
19066                    });
19067                }
19068            })
19069        });
19070    }
19071
19072    // For now, don't allow opening excerpts in buffers that aren't backed by
19073    // regular project files.
19074    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19075        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19076    }
19077
19078    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19079        let snapshot = self.buffer.read(cx).read(cx);
19080        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19081        Some(
19082            ranges
19083                .iter()
19084                .map(move |range| {
19085                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19086                })
19087                .collect(),
19088        )
19089    }
19090
19091    fn selection_replacement_ranges(
19092        &self,
19093        range: Range<OffsetUtf16>,
19094        cx: &mut App,
19095    ) -> Vec<Range<OffsetUtf16>> {
19096        let selections = self.selections.all::<OffsetUtf16>(cx);
19097        let newest_selection = selections
19098            .iter()
19099            .max_by_key(|selection| selection.id)
19100            .unwrap();
19101        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19102        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19103        let snapshot = self.buffer.read(cx).read(cx);
19104        selections
19105            .into_iter()
19106            .map(|mut selection| {
19107                selection.start.0 =
19108                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19109                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19110                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19111                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19112            })
19113            .collect()
19114    }
19115
19116    fn report_editor_event(
19117        &self,
19118        event_type: &'static str,
19119        file_extension: Option<String>,
19120        cx: &App,
19121    ) {
19122        if cfg!(any(test, feature = "test-support")) {
19123            return;
19124        }
19125
19126        let Some(project) = &self.project else { return };
19127
19128        // If None, we are in a file without an extension
19129        let file = self
19130            .buffer
19131            .read(cx)
19132            .as_singleton()
19133            .and_then(|b| b.read(cx).file());
19134        let file_extension = file_extension.or(file
19135            .as_ref()
19136            .and_then(|file| Path::new(file.file_name(cx)).extension())
19137            .and_then(|e| e.to_str())
19138            .map(|a| a.to_string()));
19139
19140        let vim_mode = vim_enabled(cx);
19141
19142        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19143        let copilot_enabled = edit_predictions_provider
19144            == language::language_settings::EditPredictionProvider::Copilot;
19145        let copilot_enabled_for_language = self
19146            .buffer
19147            .read(cx)
19148            .language_settings(cx)
19149            .show_edit_predictions;
19150
19151        let project = project.read(cx);
19152        telemetry::event!(
19153            event_type,
19154            file_extension,
19155            vim_mode,
19156            copilot_enabled,
19157            copilot_enabled_for_language,
19158            edit_predictions_provider,
19159            is_via_ssh = project.is_via_ssh(),
19160        );
19161    }
19162
19163    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19164    /// with each line being an array of {text, highlight} objects.
19165    fn copy_highlight_json(
19166        &mut self,
19167        _: &CopyHighlightJson,
19168        window: &mut Window,
19169        cx: &mut Context<Self>,
19170    ) {
19171        #[derive(Serialize)]
19172        struct Chunk<'a> {
19173            text: String,
19174            highlight: Option<&'a str>,
19175        }
19176
19177        let snapshot = self.buffer.read(cx).snapshot(cx);
19178        let range = self
19179            .selected_text_range(false, window, cx)
19180            .and_then(|selection| {
19181                if selection.range.is_empty() {
19182                    None
19183                } else {
19184                    Some(selection.range)
19185                }
19186            })
19187            .unwrap_or_else(|| 0..snapshot.len());
19188
19189        let chunks = snapshot.chunks(range, true);
19190        let mut lines = Vec::new();
19191        let mut line: VecDeque<Chunk> = VecDeque::new();
19192
19193        let Some(style) = self.style.as_ref() else {
19194            return;
19195        };
19196
19197        for chunk in chunks {
19198            let highlight = chunk
19199                .syntax_highlight_id
19200                .and_then(|id| id.name(&style.syntax));
19201            let mut chunk_lines = chunk.text.split('\n').peekable();
19202            while let Some(text) = chunk_lines.next() {
19203                let mut merged_with_last_token = false;
19204                if let Some(last_token) = line.back_mut() {
19205                    if last_token.highlight == highlight {
19206                        last_token.text.push_str(text);
19207                        merged_with_last_token = true;
19208                    }
19209                }
19210
19211                if !merged_with_last_token {
19212                    line.push_back(Chunk {
19213                        text: text.into(),
19214                        highlight,
19215                    });
19216                }
19217
19218                if chunk_lines.peek().is_some() {
19219                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19220                        line.pop_front();
19221                    }
19222                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19223                        line.pop_back();
19224                    }
19225
19226                    lines.push(mem::take(&mut line));
19227                }
19228            }
19229        }
19230
19231        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19232            return;
19233        };
19234        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19235    }
19236
19237    pub fn open_context_menu(
19238        &mut self,
19239        _: &OpenContextMenu,
19240        window: &mut Window,
19241        cx: &mut Context<Self>,
19242    ) {
19243        self.request_autoscroll(Autoscroll::newest(), cx);
19244        let position = self.selections.newest_display(cx).start;
19245        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19246    }
19247
19248    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19249        &self.inlay_hint_cache
19250    }
19251
19252    pub fn replay_insert_event(
19253        &mut self,
19254        text: &str,
19255        relative_utf16_range: Option<Range<isize>>,
19256        window: &mut Window,
19257        cx: &mut Context<Self>,
19258    ) {
19259        if !self.input_enabled {
19260            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19261            return;
19262        }
19263        if let Some(relative_utf16_range) = relative_utf16_range {
19264            let selections = self.selections.all::<OffsetUtf16>(cx);
19265            self.change_selections(None, window, cx, |s| {
19266                let new_ranges = selections.into_iter().map(|range| {
19267                    let start = OffsetUtf16(
19268                        range
19269                            .head()
19270                            .0
19271                            .saturating_add_signed(relative_utf16_range.start),
19272                    );
19273                    let end = OffsetUtf16(
19274                        range
19275                            .head()
19276                            .0
19277                            .saturating_add_signed(relative_utf16_range.end),
19278                    );
19279                    start..end
19280                });
19281                s.select_ranges(new_ranges);
19282            });
19283        }
19284
19285        self.handle_input(text, window, cx);
19286    }
19287
19288    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19289        let Some(provider) = self.semantics_provider.as_ref() else {
19290            return false;
19291        };
19292
19293        let mut supports = false;
19294        self.buffer().update(cx, |this, cx| {
19295            this.for_each_buffer(|buffer| {
19296                supports |= provider.supports_inlay_hints(buffer, cx);
19297            });
19298        });
19299
19300        supports
19301    }
19302
19303    pub fn is_focused(&self, window: &Window) -> bool {
19304        self.focus_handle.is_focused(window)
19305    }
19306
19307    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19308        cx.emit(EditorEvent::Focused);
19309
19310        if let Some(descendant) = self
19311            .last_focused_descendant
19312            .take()
19313            .and_then(|descendant| descendant.upgrade())
19314        {
19315            window.focus(&descendant);
19316        } else {
19317            if let Some(blame) = self.blame.as_ref() {
19318                blame.update(cx, GitBlame::focus)
19319            }
19320
19321            self.blink_manager.update(cx, BlinkManager::enable);
19322            self.show_cursor_names(window, cx);
19323            self.buffer.update(cx, |buffer, cx| {
19324                buffer.finalize_last_transaction(cx);
19325                if self.leader_id.is_none() {
19326                    buffer.set_active_selections(
19327                        &self.selections.disjoint_anchors(),
19328                        self.selections.line_mode,
19329                        self.cursor_shape,
19330                        cx,
19331                    );
19332                }
19333            });
19334        }
19335    }
19336
19337    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19338        cx.emit(EditorEvent::FocusedIn)
19339    }
19340
19341    fn handle_focus_out(
19342        &mut self,
19343        event: FocusOutEvent,
19344        _window: &mut Window,
19345        cx: &mut Context<Self>,
19346    ) {
19347        if event.blurred != self.focus_handle {
19348            self.last_focused_descendant = Some(event.blurred);
19349        }
19350        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19351    }
19352
19353    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19354        self.blink_manager.update(cx, BlinkManager::disable);
19355        self.buffer
19356            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19357
19358        if let Some(blame) = self.blame.as_ref() {
19359            blame.update(cx, GitBlame::blur)
19360        }
19361        if !self.hover_state.focused(window, cx) {
19362            hide_hover(self, cx);
19363        }
19364        if !self
19365            .context_menu
19366            .borrow()
19367            .as_ref()
19368            .is_some_and(|context_menu| context_menu.focused(window, cx))
19369        {
19370            self.hide_context_menu(window, cx);
19371        }
19372        self.discard_inline_completion(false, cx);
19373        cx.emit(EditorEvent::Blurred);
19374        cx.notify();
19375    }
19376
19377    pub fn register_action<A: Action>(
19378        &mut self,
19379        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19380    ) -> Subscription {
19381        let id = self.next_editor_action_id.post_inc();
19382        let listener = Arc::new(listener);
19383        self.editor_actions.borrow_mut().insert(
19384            id,
19385            Box::new(move |window, _| {
19386                let listener = listener.clone();
19387                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19388                    let action = action.downcast_ref().unwrap();
19389                    if phase == DispatchPhase::Bubble {
19390                        listener(action, window, cx)
19391                    }
19392                })
19393            }),
19394        );
19395
19396        let editor_actions = self.editor_actions.clone();
19397        Subscription::new(move || {
19398            editor_actions.borrow_mut().remove(&id);
19399        })
19400    }
19401
19402    pub fn file_header_size(&self) -> u32 {
19403        FILE_HEADER_HEIGHT
19404    }
19405
19406    pub fn restore(
19407        &mut self,
19408        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19409        window: &mut Window,
19410        cx: &mut Context<Self>,
19411    ) {
19412        let workspace = self.workspace();
19413        let project = self.project.as_ref();
19414        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19415            let mut tasks = Vec::new();
19416            for (buffer_id, changes) in revert_changes {
19417                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19418                    buffer.update(cx, |buffer, cx| {
19419                        buffer.edit(
19420                            changes
19421                                .into_iter()
19422                                .map(|(range, text)| (range, text.to_string())),
19423                            None,
19424                            cx,
19425                        );
19426                    });
19427
19428                    if let Some(project) =
19429                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19430                    {
19431                        project.update(cx, |project, cx| {
19432                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19433                        })
19434                    }
19435                }
19436            }
19437            tasks
19438        });
19439        cx.spawn_in(window, async move |_, cx| {
19440            for (buffer, task) in save_tasks {
19441                let result = task.await;
19442                if result.is_err() {
19443                    let Some(path) = buffer
19444                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19445                        .ok()
19446                    else {
19447                        continue;
19448                    };
19449                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19450                        let Some(task) = cx
19451                            .update_window_entity(&workspace, |workspace, window, cx| {
19452                                workspace
19453                                    .open_path_preview(path, None, false, false, false, window, cx)
19454                            })
19455                            .ok()
19456                        else {
19457                            continue;
19458                        };
19459                        task.await.log_err();
19460                    }
19461                }
19462            }
19463        })
19464        .detach();
19465        self.change_selections(None, window, cx, |selections| selections.refresh());
19466    }
19467
19468    pub fn to_pixel_point(
19469        &self,
19470        source: multi_buffer::Anchor,
19471        editor_snapshot: &EditorSnapshot,
19472        window: &mut Window,
19473    ) -> Option<gpui::Point<Pixels>> {
19474        let source_point = source.to_display_point(editor_snapshot);
19475        self.display_to_pixel_point(source_point, editor_snapshot, window)
19476    }
19477
19478    pub fn display_to_pixel_point(
19479        &self,
19480        source: DisplayPoint,
19481        editor_snapshot: &EditorSnapshot,
19482        window: &mut Window,
19483    ) -> Option<gpui::Point<Pixels>> {
19484        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19485        let text_layout_details = self.text_layout_details(window);
19486        let scroll_top = text_layout_details
19487            .scroll_anchor
19488            .scroll_position(editor_snapshot)
19489            .y;
19490
19491        if source.row().as_f32() < scroll_top.floor() {
19492            return None;
19493        }
19494        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19495        let source_y = line_height * (source.row().as_f32() - scroll_top);
19496        Some(gpui::Point::new(source_x, source_y))
19497    }
19498
19499    pub fn has_visible_completions_menu(&self) -> bool {
19500        !self.edit_prediction_preview_is_active()
19501            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19502                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19503            })
19504    }
19505
19506    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19507        if self.mode.is_minimap() {
19508            return;
19509        }
19510        self.addons
19511            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19512    }
19513
19514    pub fn unregister_addon<T: Addon>(&mut self) {
19515        self.addons.remove(&std::any::TypeId::of::<T>());
19516    }
19517
19518    pub fn addon<T: Addon>(&self) -> Option<&T> {
19519        let type_id = std::any::TypeId::of::<T>();
19520        self.addons
19521            .get(&type_id)
19522            .and_then(|item| item.to_any().downcast_ref::<T>())
19523    }
19524
19525    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19526        let type_id = std::any::TypeId::of::<T>();
19527        self.addons
19528            .get_mut(&type_id)
19529            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19530    }
19531
19532    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19533        let text_layout_details = self.text_layout_details(window);
19534        let style = &text_layout_details.editor_style;
19535        let font_id = window.text_system().resolve_font(&style.text.font());
19536        let font_size = style.text.font_size.to_pixels(window.rem_size());
19537        let line_height = style.text.line_height_in_pixels(window.rem_size());
19538        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19539
19540        gpui::Size::new(em_width, line_height)
19541    }
19542
19543    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19544        self.load_diff_task.clone()
19545    }
19546
19547    fn read_metadata_from_db(
19548        &mut self,
19549        item_id: u64,
19550        workspace_id: WorkspaceId,
19551        window: &mut Window,
19552        cx: &mut Context<Editor>,
19553    ) {
19554        if self.is_singleton(cx)
19555            && !self.mode.is_minimap()
19556            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19557        {
19558            let buffer_snapshot = OnceCell::new();
19559
19560            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19561                if !folds.is_empty() {
19562                    let snapshot =
19563                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19564                    self.fold_ranges(
19565                        folds
19566                            .into_iter()
19567                            .map(|(start, end)| {
19568                                snapshot.clip_offset(start, Bias::Left)
19569                                    ..snapshot.clip_offset(end, Bias::Right)
19570                            })
19571                            .collect(),
19572                        false,
19573                        window,
19574                        cx,
19575                    );
19576                }
19577            }
19578
19579            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19580                if !selections.is_empty() {
19581                    let snapshot =
19582                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19583                    self.change_selections(None, window, cx, |s| {
19584                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19585                            snapshot.clip_offset(start, Bias::Left)
19586                                ..snapshot.clip_offset(end, Bias::Right)
19587                        }));
19588                    });
19589                }
19590            };
19591        }
19592
19593        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19594    }
19595}
19596
19597fn vim_enabled(cx: &App) -> bool {
19598    cx.global::<SettingsStore>()
19599        .raw_user_settings()
19600        .get("vim_mode")
19601        == Some(&serde_json::Value::Bool(true))
19602}
19603
19604fn process_completion_for_edit(
19605    completion: &Completion,
19606    intent: CompletionIntent,
19607    buffer: &Entity<Buffer>,
19608    cursor_position: &text::Anchor,
19609    cx: &mut Context<Editor>,
19610) -> CompletionEdit {
19611    let buffer = buffer.read(cx);
19612    let buffer_snapshot = buffer.snapshot();
19613    let (snippet, new_text) = if completion.is_snippet() {
19614        let mut snippet_source = completion.new_text.clone();
19615        if let Some(scope) = buffer_snapshot.language_scope_at(cursor_position) {
19616            if scope.prefers_label_for_snippet_in_completion() {
19617                if let Some(label) = completion.label() {
19618                    if matches!(
19619                        completion.kind(),
19620                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
19621                    ) {
19622                        snippet_source = label;
19623                    }
19624                }
19625            }
19626        }
19627        match Snippet::parse(&snippet_source).log_err() {
19628            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
19629            None => (None, completion.new_text.clone()),
19630        }
19631    } else {
19632        (None, completion.new_text.clone())
19633    };
19634
19635    let mut range_to_replace = {
19636        let replace_range = &completion.replace_range;
19637        if let CompletionSource::Lsp {
19638            insert_range: Some(insert_range),
19639            ..
19640        } = &completion.source
19641        {
19642            debug_assert_eq!(
19643                insert_range.start, replace_range.start,
19644                "insert_range and replace_range should start at the same position"
19645            );
19646            debug_assert!(
19647                insert_range
19648                    .start
19649                    .cmp(&cursor_position, &buffer_snapshot)
19650                    .is_le(),
19651                "insert_range should start before or at cursor position"
19652            );
19653            debug_assert!(
19654                replace_range
19655                    .start
19656                    .cmp(&cursor_position, &buffer_snapshot)
19657                    .is_le(),
19658                "replace_range should start before or at cursor position"
19659            );
19660            debug_assert!(
19661                insert_range
19662                    .end
19663                    .cmp(&cursor_position, &buffer_snapshot)
19664                    .is_le(),
19665                "insert_range should end before or at cursor position"
19666            );
19667
19668            let should_replace = match intent {
19669                CompletionIntent::CompleteWithInsert => false,
19670                CompletionIntent::CompleteWithReplace => true,
19671                CompletionIntent::Complete | CompletionIntent::Compose => {
19672                    let insert_mode =
19673                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19674                            .completions
19675                            .lsp_insert_mode;
19676                    match insert_mode {
19677                        LspInsertMode::Insert => false,
19678                        LspInsertMode::Replace => true,
19679                        LspInsertMode::ReplaceSubsequence => {
19680                            let mut text_to_replace = buffer.chars_for_range(
19681                                buffer.anchor_before(replace_range.start)
19682                                    ..buffer.anchor_after(replace_range.end),
19683                            );
19684                            let mut current_needle = text_to_replace.next();
19685                            for haystack_ch in completion.label.text.chars() {
19686                                if let Some(needle_ch) = current_needle {
19687                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
19688                                        current_needle = text_to_replace.next();
19689                                    }
19690                                }
19691                            }
19692                            current_needle.is_none()
19693                        }
19694                        LspInsertMode::ReplaceSuffix => {
19695                            if replace_range
19696                                .end
19697                                .cmp(&cursor_position, &buffer_snapshot)
19698                                .is_gt()
19699                            {
19700                                let range_after_cursor = *cursor_position..replace_range.end;
19701                                let text_after_cursor = buffer
19702                                    .text_for_range(
19703                                        buffer.anchor_before(range_after_cursor.start)
19704                                            ..buffer.anchor_after(range_after_cursor.end),
19705                                    )
19706                                    .collect::<String>()
19707                                    .to_ascii_lowercase();
19708                                completion
19709                                    .label
19710                                    .text
19711                                    .to_ascii_lowercase()
19712                                    .ends_with(&text_after_cursor)
19713                            } else {
19714                                true
19715                            }
19716                        }
19717                    }
19718                }
19719            };
19720
19721            if should_replace {
19722                replace_range.clone()
19723            } else {
19724                insert_range.clone()
19725            }
19726        } else {
19727            replace_range.clone()
19728        }
19729    };
19730
19731    if range_to_replace
19732        .end
19733        .cmp(&cursor_position, &buffer_snapshot)
19734        .is_lt()
19735    {
19736        range_to_replace.end = *cursor_position;
19737    }
19738
19739    CompletionEdit {
19740        new_text,
19741        replace_range: range_to_replace.to_offset(&buffer),
19742        snippet,
19743    }
19744}
19745
19746struct CompletionEdit {
19747    new_text: String,
19748    replace_range: Range<usize>,
19749    snippet: Option<Snippet>,
19750}
19751
19752fn insert_extra_newline_brackets(
19753    buffer: &MultiBufferSnapshot,
19754    range: Range<usize>,
19755    language: &language::LanguageScope,
19756) -> bool {
19757    let leading_whitespace_len = buffer
19758        .reversed_chars_at(range.start)
19759        .take_while(|c| c.is_whitespace() && *c != '\n')
19760        .map(|c| c.len_utf8())
19761        .sum::<usize>();
19762    let trailing_whitespace_len = buffer
19763        .chars_at(range.end)
19764        .take_while(|c| c.is_whitespace() && *c != '\n')
19765        .map(|c| c.len_utf8())
19766        .sum::<usize>();
19767    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19768
19769    language.brackets().any(|(pair, enabled)| {
19770        let pair_start = pair.start.trim_end();
19771        let pair_end = pair.end.trim_start();
19772
19773        enabled
19774            && pair.newline
19775            && buffer.contains_str_at(range.end, pair_end)
19776            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19777    })
19778}
19779
19780fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19781    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19782        [(buffer, range, _)] => (*buffer, range.clone()),
19783        _ => return false,
19784    };
19785    let pair = {
19786        let mut result: Option<BracketMatch> = None;
19787
19788        for pair in buffer
19789            .all_bracket_ranges(range.clone())
19790            .filter(move |pair| {
19791                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19792            })
19793        {
19794            let len = pair.close_range.end - pair.open_range.start;
19795
19796            if let Some(existing) = &result {
19797                let existing_len = existing.close_range.end - existing.open_range.start;
19798                if len > existing_len {
19799                    continue;
19800                }
19801            }
19802
19803            result = Some(pair);
19804        }
19805
19806        result
19807    };
19808    let Some(pair) = pair else {
19809        return false;
19810    };
19811    pair.newline_only
19812        && buffer
19813            .chars_for_range(pair.open_range.end..range.start)
19814            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19815            .all(|c| c.is_whitespace() && c != '\n')
19816}
19817
19818fn update_uncommitted_diff_for_buffer(
19819    editor: Entity<Editor>,
19820    project: &Entity<Project>,
19821    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19822    buffer: Entity<MultiBuffer>,
19823    cx: &mut App,
19824) -> Task<()> {
19825    let mut tasks = Vec::new();
19826    project.update(cx, |project, cx| {
19827        for buffer in buffers {
19828            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19829                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19830            }
19831        }
19832    });
19833    cx.spawn(async move |cx| {
19834        let diffs = future::join_all(tasks).await;
19835        if editor
19836            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19837            .unwrap_or(false)
19838        {
19839            return;
19840        }
19841
19842        buffer
19843            .update(cx, |buffer, cx| {
19844                for diff in diffs.into_iter().flatten() {
19845                    buffer.add_diff(diff, cx);
19846                }
19847            })
19848            .ok();
19849    })
19850}
19851
19852fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19853    let tab_size = tab_size.get() as usize;
19854    let mut width = offset;
19855
19856    for ch in text.chars() {
19857        width += if ch == '\t' {
19858            tab_size - (width % tab_size)
19859        } else {
19860            1
19861        };
19862    }
19863
19864    width - offset
19865}
19866
19867#[cfg(test)]
19868mod tests {
19869    use super::*;
19870
19871    #[test]
19872    fn test_string_size_with_expanded_tabs() {
19873        let nz = |val| NonZeroU32::new(val).unwrap();
19874        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19875        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19876        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19877        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19878        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19879        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19880        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19881        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19882    }
19883}
19884
19885/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19886struct WordBreakingTokenizer<'a> {
19887    input: &'a str,
19888}
19889
19890impl<'a> WordBreakingTokenizer<'a> {
19891    fn new(input: &'a str) -> Self {
19892        Self { input }
19893    }
19894}
19895
19896fn is_char_ideographic(ch: char) -> bool {
19897    use unicode_script::Script::*;
19898    use unicode_script::UnicodeScript;
19899    matches!(ch.script(), Han | Tangut | Yi)
19900}
19901
19902fn is_grapheme_ideographic(text: &str) -> bool {
19903    text.chars().any(is_char_ideographic)
19904}
19905
19906fn is_grapheme_whitespace(text: &str) -> bool {
19907    text.chars().any(|x| x.is_whitespace())
19908}
19909
19910fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19911    text.chars().next().map_or(false, |ch| {
19912        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19913    })
19914}
19915
19916#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19917enum WordBreakToken<'a> {
19918    Word { token: &'a str, grapheme_len: usize },
19919    InlineWhitespace { token: &'a str, grapheme_len: usize },
19920    Newline,
19921}
19922
19923impl<'a> Iterator for WordBreakingTokenizer<'a> {
19924    /// Yields a span, the count of graphemes in the token, and whether it was
19925    /// whitespace. Note that it also breaks at word boundaries.
19926    type Item = WordBreakToken<'a>;
19927
19928    fn next(&mut self) -> Option<Self::Item> {
19929        use unicode_segmentation::UnicodeSegmentation;
19930        if self.input.is_empty() {
19931            return None;
19932        }
19933
19934        let mut iter = self.input.graphemes(true).peekable();
19935        let mut offset = 0;
19936        let mut grapheme_len = 0;
19937        if let Some(first_grapheme) = iter.next() {
19938            let is_newline = first_grapheme == "\n";
19939            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19940            offset += first_grapheme.len();
19941            grapheme_len += 1;
19942            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19943                if let Some(grapheme) = iter.peek().copied() {
19944                    if should_stay_with_preceding_ideograph(grapheme) {
19945                        offset += grapheme.len();
19946                        grapheme_len += 1;
19947                    }
19948                }
19949            } else {
19950                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19951                let mut next_word_bound = words.peek().copied();
19952                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19953                    next_word_bound = words.next();
19954                }
19955                while let Some(grapheme) = iter.peek().copied() {
19956                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19957                        break;
19958                    };
19959                    if is_grapheme_whitespace(grapheme) != is_whitespace
19960                        || (grapheme == "\n") != is_newline
19961                    {
19962                        break;
19963                    };
19964                    offset += grapheme.len();
19965                    grapheme_len += 1;
19966                    iter.next();
19967                }
19968            }
19969            let token = &self.input[..offset];
19970            self.input = &self.input[offset..];
19971            if token == "\n" {
19972                Some(WordBreakToken::Newline)
19973            } else if is_whitespace {
19974                Some(WordBreakToken::InlineWhitespace {
19975                    token,
19976                    grapheme_len,
19977                })
19978            } else {
19979                Some(WordBreakToken::Word {
19980                    token,
19981                    grapheme_len,
19982                })
19983            }
19984        } else {
19985            None
19986        }
19987    }
19988}
19989
19990#[test]
19991fn test_word_breaking_tokenizer() {
19992    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19993        ("", &[]),
19994        ("  ", &[whitespace("  ", 2)]),
19995        ("Ʒ", &[word("Ʒ", 1)]),
19996        ("Ǽ", &[word("Ǽ", 1)]),
19997        ("", &[word("", 1)]),
19998        ("⋑⋑", &[word("⋑⋑", 2)]),
19999        (
20000            "原理,进而",
20001            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20002        ),
20003        (
20004            "hello world",
20005            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20006        ),
20007        (
20008            "hello, world",
20009            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20010        ),
20011        (
20012            "  hello world",
20013            &[
20014                whitespace("  ", 2),
20015                word("hello", 5),
20016                whitespace(" ", 1),
20017                word("world", 5),
20018            ],
20019        ),
20020        (
20021            "这是什么 \n 钢笔",
20022            &[
20023                word("", 1),
20024                word("", 1),
20025                word("", 1),
20026                word("", 1),
20027                whitespace(" ", 1),
20028                newline(),
20029                whitespace(" ", 1),
20030                word("", 1),
20031                word("", 1),
20032            ],
20033        ),
20034        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20035    ];
20036
20037    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20038        WordBreakToken::Word {
20039            token,
20040            grapheme_len,
20041        }
20042    }
20043
20044    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20045        WordBreakToken::InlineWhitespace {
20046            token,
20047            grapheme_len,
20048        }
20049    }
20050
20051    fn newline() -> WordBreakToken<'static> {
20052        WordBreakToken::Newline
20053    }
20054
20055    for (input, result) in tests {
20056        assert_eq!(
20057            WordBreakingTokenizer::new(input)
20058                .collect::<Vec<_>>()
20059                .as_slice(),
20060            *result,
20061        );
20062    }
20063}
20064
20065fn wrap_with_prefix(
20066    line_prefix: String,
20067    unwrapped_text: String,
20068    wrap_column: usize,
20069    tab_size: NonZeroU32,
20070    preserve_existing_whitespace: bool,
20071) -> String {
20072    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20073    let mut wrapped_text = String::new();
20074    let mut current_line = line_prefix.clone();
20075
20076    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20077    let mut current_line_len = line_prefix_len;
20078    let mut in_whitespace = false;
20079    for token in tokenizer {
20080        let have_preceding_whitespace = in_whitespace;
20081        match token {
20082            WordBreakToken::Word {
20083                token,
20084                grapheme_len,
20085            } => {
20086                in_whitespace = false;
20087                if current_line_len + grapheme_len > wrap_column
20088                    && current_line_len != line_prefix_len
20089                {
20090                    wrapped_text.push_str(current_line.trim_end());
20091                    wrapped_text.push('\n');
20092                    current_line.truncate(line_prefix.len());
20093                    current_line_len = line_prefix_len;
20094                }
20095                current_line.push_str(token);
20096                current_line_len += grapheme_len;
20097            }
20098            WordBreakToken::InlineWhitespace {
20099                mut token,
20100                mut grapheme_len,
20101            } => {
20102                in_whitespace = true;
20103                if have_preceding_whitespace && !preserve_existing_whitespace {
20104                    continue;
20105                }
20106                if !preserve_existing_whitespace {
20107                    token = " ";
20108                    grapheme_len = 1;
20109                }
20110                if current_line_len + grapheme_len > wrap_column {
20111                    wrapped_text.push_str(current_line.trim_end());
20112                    wrapped_text.push('\n');
20113                    current_line.truncate(line_prefix.len());
20114                    current_line_len = line_prefix_len;
20115                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20116                    current_line.push_str(token);
20117                    current_line_len += grapheme_len;
20118                }
20119            }
20120            WordBreakToken::Newline => {
20121                in_whitespace = true;
20122                if preserve_existing_whitespace {
20123                    wrapped_text.push_str(current_line.trim_end());
20124                    wrapped_text.push('\n');
20125                    current_line.truncate(line_prefix.len());
20126                    current_line_len = line_prefix_len;
20127                } else if have_preceding_whitespace {
20128                    continue;
20129                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20130                {
20131                    wrapped_text.push_str(current_line.trim_end());
20132                    wrapped_text.push('\n');
20133                    current_line.truncate(line_prefix.len());
20134                    current_line_len = line_prefix_len;
20135                } else if current_line_len != line_prefix_len {
20136                    current_line.push(' ');
20137                    current_line_len += 1;
20138                }
20139            }
20140        }
20141    }
20142
20143    if !current_line.is_empty() {
20144        wrapped_text.push_str(&current_line);
20145    }
20146    wrapped_text
20147}
20148
20149#[test]
20150fn test_wrap_with_prefix() {
20151    assert_eq!(
20152        wrap_with_prefix(
20153            "# ".to_string(),
20154            "abcdefg".to_string(),
20155            4,
20156            NonZeroU32::new(4).unwrap(),
20157            false,
20158        ),
20159        "# abcdefg"
20160    );
20161    assert_eq!(
20162        wrap_with_prefix(
20163            "".to_string(),
20164            "\thello world".to_string(),
20165            8,
20166            NonZeroU32::new(4).unwrap(),
20167            false,
20168        ),
20169        "hello\nworld"
20170    );
20171    assert_eq!(
20172        wrap_with_prefix(
20173            "// ".to_string(),
20174            "xx \nyy zz aa bb cc".to_string(),
20175            12,
20176            NonZeroU32::new(4).unwrap(),
20177            false,
20178        ),
20179        "// xx yy zz\n// aa bb cc"
20180    );
20181    assert_eq!(
20182        wrap_with_prefix(
20183            String::new(),
20184            "这是什么 \n 钢笔".to_string(),
20185            3,
20186            NonZeroU32::new(4).unwrap(),
20187            false,
20188        ),
20189        "这是什\n么 钢\n"
20190    );
20191}
20192
20193pub trait CollaborationHub {
20194    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20195    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20196    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20197}
20198
20199impl CollaborationHub for Entity<Project> {
20200    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20201        self.read(cx).collaborators()
20202    }
20203
20204    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20205        self.read(cx).user_store().read(cx).participant_indices()
20206    }
20207
20208    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20209        let this = self.read(cx);
20210        let user_ids = this.collaborators().values().map(|c| c.user_id);
20211        this.user_store().read(cx).participant_names(user_ids, cx)
20212    }
20213}
20214
20215pub trait SemanticsProvider {
20216    fn hover(
20217        &self,
20218        buffer: &Entity<Buffer>,
20219        position: text::Anchor,
20220        cx: &mut App,
20221    ) -> Option<Task<Vec<project::Hover>>>;
20222
20223    fn inline_values(
20224        &self,
20225        buffer_handle: Entity<Buffer>,
20226        range: Range<text::Anchor>,
20227        cx: &mut App,
20228    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20229
20230    fn inlay_hints(
20231        &self,
20232        buffer_handle: Entity<Buffer>,
20233        range: Range<text::Anchor>,
20234        cx: &mut App,
20235    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20236
20237    fn resolve_inlay_hint(
20238        &self,
20239        hint: InlayHint,
20240        buffer_handle: Entity<Buffer>,
20241        server_id: LanguageServerId,
20242        cx: &mut App,
20243    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20244
20245    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20246
20247    fn document_highlights(
20248        &self,
20249        buffer: &Entity<Buffer>,
20250        position: text::Anchor,
20251        cx: &mut App,
20252    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20253
20254    fn definitions(
20255        &self,
20256        buffer: &Entity<Buffer>,
20257        position: text::Anchor,
20258        kind: GotoDefinitionKind,
20259        cx: &mut App,
20260    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20261
20262    fn range_for_rename(
20263        &self,
20264        buffer: &Entity<Buffer>,
20265        position: text::Anchor,
20266        cx: &mut App,
20267    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20268
20269    fn perform_rename(
20270        &self,
20271        buffer: &Entity<Buffer>,
20272        position: text::Anchor,
20273        new_name: String,
20274        cx: &mut App,
20275    ) -> Option<Task<Result<ProjectTransaction>>>;
20276}
20277
20278pub trait CompletionProvider {
20279    fn completions(
20280        &self,
20281        excerpt_id: ExcerptId,
20282        buffer: &Entity<Buffer>,
20283        buffer_position: text::Anchor,
20284        trigger: CompletionContext,
20285        window: &mut Window,
20286        cx: &mut Context<Editor>,
20287    ) -> Task<Result<Vec<CompletionResponse>>>;
20288
20289    fn resolve_completions(
20290        &self,
20291        buffer: Entity<Buffer>,
20292        completion_indices: Vec<usize>,
20293        completions: Rc<RefCell<Box<[Completion]>>>,
20294        cx: &mut Context<Editor>,
20295    ) -> Task<Result<bool>>;
20296
20297    fn apply_additional_edits_for_completion(
20298        &self,
20299        _buffer: Entity<Buffer>,
20300        _completions: Rc<RefCell<Box<[Completion]>>>,
20301        _completion_index: usize,
20302        _push_to_history: bool,
20303        _cx: &mut Context<Editor>,
20304    ) -> Task<Result<Option<language::Transaction>>> {
20305        Task::ready(Ok(None))
20306    }
20307
20308    fn is_completion_trigger(
20309        &self,
20310        buffer: &Entity<Buffer>,
20311        position: language::Anchor,
20312        text: &str,
20313        trigger_in_words: bool,
20314        menu_is_open: bool,
20315        cx: &mut Context<Editor>,
20316    ) -> bool;
20317
20318    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20319
20320    fn sort_completions(&self) -> bool {
20321        true
20322    }
20323
20324    fn filter_completions(&self) -> bool {
20325        true
20326    }
20327}
20328
20329pub trait CodeActionProvider {
20330    fn id(&self) -> Arc<str>;
20331
20332    fn code_actions(
20333        &self,
20334        buffer: &Entity<Buffer>,
20335        range: Range<text::Anchor>,
20336        window: &mut Window,
20337        cx: &mut App,
20338    ) -> Task<Result<Vec<CodeAction>>>;
20339
20340    fn apply_code_action(
20341        &self,
20342        buffer_handle: Entity<Buffer>,
20343        action: CodeAction,
20344        excerpt_id: ExcerptId,
20345        push_to_history: bool,
20346        window: &mut Window,
20347        cx: &mut App,
20348    ) -> Task<Result<ProjectTransaction>>;
20349}
20350
20351impl CodeActionProvider for Entity<Project> {
20352    fn id(&self) -> Arc<str> {
20353        "project".into()
20354    }
20355
20356    fn code_actions(
20357        &self,
20358        buffer: &Entity<Buffer>,
20359        range: Range<text::Anchor>,
20360        _window: &mut Window,
20361        cx: &mut App,
20362    ) -> Task<Result<Vec<CodeAction>>> {
20363        self.update(cx, |project, cx| {
20364            let code_lens = project.code_lens(buffer, range.clone(), cx);
20365            let code_actions = project.code_actions(buffer, range, None, cx);
20366            cx.background_spawn(async move {
20367                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20368                Ok(code_lens
20369                    .context("code lens fetch")?
20370                    .into_iter()
20371                    .chain(code_actions.context("code action fetch")?)
20372                    .collect())
20373            })
20374        })
20375    }
20376
20377    fn apply_code_action(
20378        &self,
20379        buffer_handle: Entity<Buffer>,
20380        action: CodeAction,
20381        _excerpt_id: ExcerptId,
20382        push_to_history: bool,
20383        _window: &mut Window,
20384        cx: &mut App,
20385    ) -> Task<Result<ProjectTransaction>> {
20386        self.update(cx, |project, cx| {
20387            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20388        })
20389    }
20390}
20391
20392fn snippet_completions(
20393    project: &Project,
20394    buffer: &Entity<Buffer>,
20395    buffer_position: text::Anchor,
20396    cx: &mut App,
20397) -> Task<Result<CompletionResponse>> {
20398    let languages = buffer.read(cx).languages_at(buffer_position);
20399    let snippet_store = project.snippets().read(cx);
20400
20401    let scopes: Vec<_> = languages
20402        .iter()
20403        .filter_map(|language| {
20404            let language_name = language.lsp_id();
20405            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20406
20407            if snippets.is_empty() {
20408                None
20409            } else {
20410                Some((language.default_scope(), snippets))
20411            }
20412        })
20413        .collect();
20414
20415    if scopes.is_empty() {
20416        return Task::ready(Ok(CompletionResponse {
20417            completions: vec![],
20418            is_incomplete: false,
20419        }));
20420    }
20421
20422    let snapshot = buffer.read(cx).text_snapshot();
20423    let chars: String = snapshot
20424        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20425        .collect();
20426    let executor = cx.background_executor().clone();
20427
20428    cx.background_spawn(async move {
20429        let mut is_incomplete = false;
20430        let mut completions: Vec<Completion> = Vec::new();
20431        for (scope, snippets) in scopes.into_iter() {
20432            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20433            let mut last_word = chars
20434                .chars()
20435                .take_while(|c| classifier.is_word(*c))
20436                .collect::<String>();
20437            last_word = last_word.chars().rev().collect();
20438
20439            if last_word.is_empty() {
20440                return Ok(CompletionResponse {
20441                    completions: vec![],
20442                    is_incomplete: true,
20443                });
20444            }
20445
20446            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20447            let to_lsp = |point: &text::Anchor| {
20448                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20449                point_to_lsp(end)
20450            };
20451            let lsp_end = to_lsp(&buffer_position);
20452
20453            let candidates = snippets
20454                .iter()
20455                .enumerate()
20456                .flat_map(|(ix, snippet)| {
20457                    snippet
20458                        .prefix
20459                        .iter()
20460                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20461                })
20462                .collect::<Vec<StringMatchCandidate>>();
20463
20464            const MAX_RESULTS: usize = 100;
20465            let mut matches = fuzzy::match_strings(
20466                &candidates,
20467                &last_word,
20468                last_word.chars().any(|c| c.is_uppercase()),
20469                MAX_RESULTS,
20470                &Default::default(),
20471                executor.clone(),
20472            )
20473            .await;
20474
20475            if matches.len() >= MAX_RESULTS {
20476                is_incomplete = true;
20477            }
20478
20479            // Remove all candidates where the query's start does not match the start of any word in the candidate
20480            if let Some(query_start) = last_word.chars().next() {
20481                matches.retain(|string_match| {
20482                    split_words(&string_match.string).any(|word| {
20483                        // Check that the first codepoint of the word as lowercase matches the first
20484                        // codepoint of the query as lowercase
20485                        word.chars()
20486                            .flat_map(|codepoint| codepoint.to_lowercase())
20487                            .zip(query_start.to_lowercase())
20488                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20489                    })
20490                });
20491            }
20492
20493            let matched_strings = matches
20494                .into_iter()
20495                .map(|m| m.string)
20496                .collect::<HashSet<_>>();
20497
20498            completions.extend(snippets.iter().filter_map(|snippet| {
20499                let matching_prefix = snippet
20500                    .prefix
20501                    .iter()
20502                    .find(|prefix| matched_strings.contains(*prefix))?;
20503                let start = as_offset - last_word.len();
20504                let start = snapshot.anchor_before(start);
20505                let range = start..buffer_position;
20506                let lsp_start = to_lsp(&start);
20507                let lsp_range = lsp::Range {
20508                    start: lsp_start,
20509                    end: lsp_end,
20510                };
20511                Some(Completion {
20512                    replace_range: range,
20513                    new_text: snippet.body.clone(),
20514                    source: CompletionSource::Lsp {
20515                        insert_range: None,
20516                        server_id: LanguageServerId(usize::MAX),
20517                        resolved: true,
20518                        lsp_completion: Box::new(lsp::CompletionItem {
20519                            label: snippet.prefix.first().unwrap().clone(),
20520                            kind: Some(CompletionItemKind::SNIPPET),
20521                            label_details: snippet.description.as_ref().map(|description| {
20522                                lsp::CompletionItemLabelDetails {
20523                                    detail: Some(description.clone()),
20524                                    description: None,
20525                                }
20526                            }),
20527                            insert_text_format: Some(InsertTextFormat::SNIPPET),
20528                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20529                                lsp::InsertReplaceEdit {
20530                                    new_text: snippet.body.clone(),
20531                                    insert: lsp_range,
20532                                    replace: lsp_range,
20533                                },
20534                            )),
20535                            filter_text: Some(snippet.body.clone()),
20536                            sort_text: Some(char::MAX.to_string()),
20537                            ..lsp::CompletionItem::default()
20538                        }),
20539                        lsp_defaults: None,
20540                    },
20541                    label: CodeLabel {
20542                        text: matching_prefix.clone(),
20543                        runs: Vec::new(),
20544                        filter_range: 0..matching_prefix.len(),
20545                    },
20546                    icon_path: None,
20547                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
20548                        single_line: snippet.name.clone().into(),
20549                        plain_text: snippet
20550                            .description
20551                            .clone()
20552                            .map(|description| description.into()),
20553                    }),
20554                    insert_text_mode: None,
20555                    confirm: None,
20556                })
20557            }))
20558        }
20559
20560        Ok(CompletionResponse {
20561            completions,
20562            is_incomplete,
20563        })
20564    })
20565}
20566
20567impl CompletionProvider for Entity<Project> {
20568    fn completions(
20569        &self,
20570        _excerpt_id: ExcerptId,
20571        buffer: &Entity<Buffer>,
20572        buffer_position: text::Anchor,
20573        options: CompletionContext,
20574        _window: &mut Window,
20575        cx: &mut Context<Editor>,
20576    ) -> Task<Result<Vec<CompletionResponse>>> {
20577        self.update(cx, |project, cx| {
20578            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20579            let project_completions = project.completions(buffer, buffer_position, options, cx);
20580            cx.background_spawn(async move {
20581                let mut responses = project_completions.await?;
20582                let snippets = snippets.await?;
20583                if !snippets.completions.is_empty() {
20584                    responses.push(snippets);
20585                }
20586                Ok(responses)
20587            })
20588        })
20589    }
20590
20591    fn resolve_completions(
20592        &self,
20593        buffer: Entity<Buffer>,
20594        completion_indices: Vec<usize>,
20595        completions: Rc<RefCell<Box<[Completion]>>>,
20596        cx: &mut Context<Editor>,
20597    ) -> Task<Result<bool>> {
20598        self.update(cx, |project, cx| {
20599            project.lsp_store().update(cx, |lsp_store, cx| {
20600                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20601            })
20602        })
20603    }
20604
20605    fn apply_additional_edits_for_completion(
20606        &self,
20607        buffer: Entity<Buffer>,
20608        completions: Rc<RefCell<Box<[Completion]>>>,
20609        completion_index: usize,
20610        push_to_history: bool,
20611        cx: &mut Context<Editor>,
20612    ) -> Task<Result<Option<language::Transaction>>> {
20613        self.update(cx, |project, cx| {
20614            project.lsp_store().update(cx, |lsp_store, cx| {
20615                lsp_store.apply_additional_edits_for_completion(
20616                    buffer,
20617                    completions,
20618                    completion_index,
20619                    push_to_history,
20620                    cx,
20621                )
20622            })
20623        })
20624    }
20625
20626    fn is_completion_trigger(
20627        &self,
20628        buffer: &Entity<Buffer>,
20629        position: language::Anchor,
20630        text: &str,
20631        trigger_in_words: bool,
20632        menu_is_open: bool,
20633        cx: &mut Context<Editor>,
20634    ) -> bool {
20635        let mut chars = text.chars();
20636        let char = if let Some(char) = chars.next() {
20637            char
20638        } else {
20639            return false;
20640        };
20641        if chars.next().is_some() {
20642            return false;
20643        }
20644
20645        let buffer = buffer.read(cx);
20646        let snapshot = buffer.snapshot();
20647        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
20648            return false;
20649        }
20650        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20651        if trigger_in_words && classifier.is_word(char) {
20652            return true;
20653        }
20654
20655        buffer.completion_triggers().contains(text)
20656    }
20657}
20658
20659impl SemanticsProvider for Entity<Project> {
20660    fn hover(
20661        &self,
20662        buffer: &Entity<Buffer>,
20663        position: text::Anchor,
20664        cx: &mut App,
20665    ) -> Option<Task<Vec<project::Hover>>> {
20666        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20667    }
20668
20669    fn document_highlights(
20670        &self,
20671        buffer: &Entity<Buffer>,
20672        position: text::Anchor,
20673        cx: &mut App,
20674    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20675        Some(self.update(cx, |project, cx| {
20676            project.document_highlights(buffer, position, cx)
20677        }))
20678    }
20679
20680    fn definitions(
20681        &self,
20682        buffer: &Entity<Buffer>,
20683        position: text::Anchor,
20684        kind: GotoDefinitionKind,
20685        cx: &mut App,
20686    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20687        Some(self.update(cx, |project, cx| match kind {
20688            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20689            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20690            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20691            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20692        }))
20693    }
20694
20695    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20696        // TODO: make this work for remote projects
20697        self.update(cx, |project, cx| {
20698            if project
20699                .active_debug_session(cx)
20700                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20701            {
20702                return true;
20703            }
20704
20705            buffer.update(cx, |buffer, cx| {
20706                project.any_language_server_supports_inlay_hints(buffer, cx)
20707            })
20708        })
20709    }
20710
20711    fn inline_values(
20712        &self,
20713        buffer_handle: Entity<Buffer>,
20714
20715        range: Range<text::Anchor>,
20716        cx: &mut App,
20717    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20718        self.update(cx, |project, cx| {
20719            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20720
20721            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20722        })
20723    }
20724
20725    fn inlay_hints(
20726        &self,
20727        buffer_handle: Entity<Buffer>,
20728        range: Range<text::Anchor>,
20729        cx: &mut App,
20730    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20731        Some(self.update(cx, |project, cx| {
20732            project.inlay_hints(buffer_handle, range, cx)
20733        }))
20734    }
20735
20736    fn resolve_inlay_hint(
20737        &self,
20738        hint: InlayHint,
20739        buffer_handle: Entity<Buffer>,
20740        server_id: LanguageServerId,
20741        cx: &mut App,
20742    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20743        Some(self.update(cx, |project, cx| {
20744            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20745        }))
20746    }
20747
20748    fn range_for_rename(
20749        &self,
20750        buffer: &Entity<Buffer>,
20751        position: text::Anchor,
20752        cx: &mut App,
20753    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20754        Some(self.update(cx, |project, cx| {
20755            let buffer = buffer.clone();
20756            let task = project.prepare_rename(buffer.clone(), position, cx);
20757            cx.spawn(async move |_, cx| {
20758                Ok(match task.await? {
20759                    PrepareRenameResponse::Success(range) => Some(range),
20760                    PrepareRenameResponse::InvalidPosition => None,
20761                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20762                        // Fallback on using TreeSitter info to determine identifier range
20763                        buffer.read_with(cx, |buffer, _| {
20764                            let snapshot = buffer.snapshot();
20765                            let (range, kind) = snapshot.surrounding_word(position);
20766                            if kind != Some(CharKind::Word) {
20767                                return None;
20768                            }
20769                            Some(
20770                                snapshot.anchor_before(range.start)
20771                                    ..snapshot.anchor_after(range.end),
20772                            )
20773                        })?
20774                    }
20775                })
20776            })
20777        }))
20778    }
20779
20780    fn perform_rename(
20781        &self,
20782        buffer: &Entity<Buffer>,
20783        position: text::Anchor,
20784        new_name: String,
20785        cx: &mut App,
20786    ) -> Option<Task<Result<ProjectTransaction>>> {
20787        Some(self.update(cx, |project, cx| {
20788            project.perform_rename(buffer.clone(), position, new_name, cx)
20789        }))
20790    }
20791}
20792
20793fn inlay_hint_settings(
20794    location: Anchor,
20795    snapshot: &MultiBufferSnapshot,
20796    cx: &mut Context<Editor>,
20797) -> InlayHintSettings {
20798    let file = snapshot.file_at(location);
20799    let language = snapshot.language_at(location).map(|l| l.name());
20800    language_settings(language, file, cx).inlay_hints
20801}
20802
20803fn consume_contiguous_rows(
20804    contiguous_row_selections: &mut Vec<Selection<Point>>,
20805    selection: &Selection<Point>,
20806    display_map: &DisplaySnapshot,
20807    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20808) -> (MultiBufferRow, MultiBufferRow) {
20809    contiguous_row_selections.push(selection.clone());
20810    let start_row = MultiBufferRow(selection.start.row);
20811    let mut end_row = ending_row(selection, display_map);
20812
20813    while let Some(next_selection) = selections.peek() {
20814        if next_selection.start.row <= end_row.0 {
20815            end_row = ending_row(next_selection, display_map);
20816            contiguous_row_selections.push(selections.next().unwrap().clone());
20817        } else {
20818            break;
20819        }
20820    }
20821    (start_row, end_row)
20822}
20823
20824fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20825    if next_selection.end.column > 0 || next_selection.is_empty() {
20826        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20827    } else {
20828        MultiBufferRow(next_selection.end.row)
20829    }
20830}
20831
20832impl EditorSnapshot {
20833    pub fn remote_selections_in_range<'a>(
20834        &'a self,
20835        range: &'a Range<Anchor>,
20836        collaboration_hub: &dyn CollaborationHub,
20837        cx: &'a App,
20838    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20839        let participant_names = collaboration_hub.user_names(cx);
20840        let participant_indices = collaboration_hub.user_participant_indices(cx);
20841        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20842        let collaborators_by_replica_id = collaborators_by_peer_id
20843            .values()
20844            .map(|collaborator| (collaborator.replica_id, collaborator))
20845            .collect::<HashMap<_, _>>();
20846        self.buffer_snapshot
20847            .selections_in_range(range, false)
20848            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20849                if replica_id == AGENT_REPLICA_ID {
20850                    Some(RemoteSelection {
20851                        replica_id,
20852                        selection,
20853                        cursor_shape,
20854                        line_mode,
20855                        collaborator_id: CollaboratorId::Agent,
20856                        user_name: Some("Agent".into()),
20857                        color: cx.theme().players().agent(),
20858                    })
20859                } else {
20860                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20861                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20862                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20863                    Some(RemoteSelection {
20864                        replica_id,
20865                        selection,
20866                        cursor_shape,
20867                        line_mode,
20868                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20869                        user_name,
20870                        color: if let Some(index) = participant_index {
20871                            cx.theme().players().color_for_participant(index.0)
20872                        } else {
20873                            cx.theme().players().absent()
20874                        },
20875                    })
20876                }
20877            })
20878    }
20879
20880    pub fn hunks_for_ranges(
20881        &self,
20882        ranges: impl IntoIterator<Item = Range<Point>>,
20883    ) -> Vec<MultiBufferDiffHunk> {
20884        let mut hunks = Vec::new();
20885        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20886            HashMap::default();
20887        for query_range in ranges {
20888            let query_rows =
20889                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20890            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20891                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20892            ) {
20893                // Include deleted hunks that are adjacent to the query range, because
20894                // otherwise they would be missed.
20895                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20896                if hunk.status().is_deleted() {
20897                    intersects_range |= hunk.row_range.start == query_rows.end;
20898                    intersects_range |= hunk.row_range.end == query_rows.start;
20899                }
20900                if intersects_range {
20901                    if !processed_buffer_rows
20902                        .entry(hunk.buffer_id)
20903                        .or_default()
20904                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20905                    {
20906                        continue;
20907                    }
20908                    hunks.push(hunk);
20909                }
20910            }
20911        }
20912
20913        hunks
20914    }
20915
20916    fn display_diff_hunks_for_rows<'a>(
20917        &'a self,
20918        display_rows: Range<DisplayRow>,
20919        folded_buffers: &'a HashSet<BufferId>,
20920    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20921        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20922        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20923
20924        self.buffer_snapshot
20925            .diff_hunks_in_range(buffer_start..buffer_end)
20926            .filter_map(|hunk| {
20927                if folded_buffers.contains(&hunk.buffer_id) {
20928                    return None;
20929                }
20930
20931                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20932                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20933
20934                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20935                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20936
20937                let display_hunk = if hunk_display_start.column() != 0 {
20938                    DisplayDiffHunk::Folded {
20939                        display_row: hunk_display_start.row(),
20940                    }
20941                } else {
20942                    let mut end_row = hunk_display_end.row();
20943                    if hunk_display_end.column() > 0 {
20944                        end_row.0 += 1;
20945                    }
20946                    let is_created_file = hunk.is_created_file();
20947                    DisplayDiffHunk::Unfolded {
20948                        status: hunk.status(),
20949                        diff_base_byte_range: hunk.diff_base_byte_range,
20950                        display_row_range: hunk_display_start.row()..end_row,
20951                        multi_buffer_range: Anchor::range_in_buffer(
20952                            hunk.excerpt_id,
20953                            hunk.buffer_id,
20954                            hunk.buffer_range,
20955                        ),
20956                        is_created_file,
20957                    }
20958                };
20959
20960                Some(display_hunk)
20961            })
20962    }
20963
20964    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20965        self.display_snapshot.buffer_snapshot.language_at(position)
20966    }
20967
20968    pub fn is_focused(&self) -> bool {
20969        self.is_focused
20970    }
20971
20972    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20973        self.placeholder_text.as_ref()
20974    }
20975
20976    pub fn scroll_position(&self) -> gpui::Point<f32> {
20977        self.scroll_anchor.scroll_position(&self.display_snapshot)
20978    }
20979
20980    fn gutter_dimensions(
20981        &self,
20982        font_id: FontId,
20983        font_size: Pixels,
20984        max_line_number_width: Pixels,
20985        cx: &App,
20986    ) -> Option<GutterDimensions> {
20987        if !self.show_gutter {
20988            return None;
20989        }
20990
20991        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20992        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20993
20994        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20995            matches!(
20996                ProjectSettings::get_global(cx).git.git_gutter,
20997                Some(GitGutterSetting::TrackedFiles)
20998            )
20999        });
21000        let gutter_settings = EditorSettings::get_global(cx).gutter;
21001        let show_line_numbers = self
21002            .show_line_numbers
21003            .unwrap_or(gutter_settings.line_numbers);
21004        let line_gutter_width = if show_line_numbers {
21005            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
21006            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
21007            max_line_number_width.max(min_width_for_number_on_gutter)
21008        } else {
21009            0.0.into()
21010        };
21011
21012        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21013        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21014
21015        let git_blame_entries_width =
21016            self.git_blame_gutter_max_author_length
21017                .map(|max_author_length| {
21018                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21019                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21020
21021                    /// The number of characters to dedicate to gaps and margins.
21022                    const SPACING_WIDTH: usize = 4;
21023
21024                    let max_char_count = max_author_length.min(renderer.max_author_length())
21025                        + ::git::SHORT_SHA_LENGTH
21026                        + MAX_RELATIVE_TIMESTAMP.len()
21027                        + SPACING_WIDTH;
21028
21029                    em_advance * max_char_count
21030                });
21031
21032        let is_singleton = self.buffer_snapshot.is_singleton();
21033
21034        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21035        left_padding += if !is_singleton {
21036            em_width * 4.0
21037        } else if show_runnables || show_breakpoints {
21038            em_width * 3.0
21039        } else if show_git_gutter && show_line_numbers {
21040            em_width * 2.0
21041        } else if show_git_gutter || show_line_numbers {
21042            em_width
21043        } else {
21044            px(0.)
21045        };
21046
21047        let shows_folds = is_singleton && gutter_settings.folds;
21048
21049        let right_padding = if shows_folds && show_line_numbers {
21050            em_width * 4.0
21051        } else if shows_folds || (!is_singleton && show_line_numbers) {
21052            em_width * 3.0
21053        } else if show_line_numbers {
21054            em_width
21055        } else {
21056            px(0.)
21057        };
21058
21059        Some(GutterDimensions {
21060            left_padding,
21061            right_padding,
21062            width: line_gutter_width + left_padding + right_padding,
21063            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21064            git_blame_entries_width,
21065        })
21066    }
21067
21068    pub fn render_crease_toggle(
21069        &self,
21070        buffer_row: MultiBufferRow,
21071        row_contains_cursor: bool,
21072        editor: Entity<Editor>,
21073        window: &mut Window,
21074        cx: &mut App,
21075    ) -> Option<AnyElement> {
21076        let folded = self.is_line_folded(buffer_row);
21077        let mut is_foldable = false;
21078
21079        if let Some(crease) = self
21080            .crease_snapshot
21081            .query_row(buffer_row, &self.buffer_snapshot)
21082        {
21083            is_foldable = true;
21084            match crease {
21085                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21086                    if let Some(render_toggle) = render_toggle {
21087                        let toggle_callback =
21088                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21089                                if folded {
21090                                    editor.update(cx, |editor, cx| {
21091                                        editor.fold_at(buffer_row, window, cx)
21092                                    });
21093                                } else {
21094                                    editor.update(cx, |editor, cx| {
21095                                        editor.unfold_at(buffer_row, window, cx)
21096                                    });
21097                                }
21098                            });
21099                        return Some((render_toggle)(
21100                            buffer_row,
21101                            folded,
21102                            toggle_callback,
21103                            window,
21104                            cx,
21105                        ));
21106                    }
21107                }
21108            }
21109        }
21110
21111        is_foldable |= self.starts_indent(buffer_row);
21112
21113        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21114            Some(
21115                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21116                    .toggle_state(folded)
21117                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21118                        if folded {
21119                            this.unfold_at(buffer_row, window, cx);
21120                        } else {
21121                            this.fold_at(buffer_row, window, cx);
21122                        }
21123                    }))
21124                    .into_any_element(),
21125            )
21126        } else {
21127            None
21128        }
21129    }
21130
21131    pub fn render_crease_trailer(
21132        &self,
21133        buffer_row: MultiBufferRow,
21134        window: &mut Window,
21135        cx: &mut App,
21136    ) -> Option<AnyElement> {
21137        let folded = self.is_line_folded(buffer_row);
21138        if let Crease::Inline { render_trailer, .. } = self
21139            .crease_snapshot
21140            .query_row(buffer_row, &self.buffer_snapshot)?
21141        {
21142            let render_trailer = render_trailer.as_ref()?;
21143            Some(render_trailer(buffer_row, folded, window, cx))
21144        } else {
21145            None
21146        }
21147    }
21148}
21149
21150impl Deref for EditorSnapshot {
21151    type Target = DisplaySnapshot;
21152
21153    fn deref(&self) -> &Self::Target {
21154        &self.display_snapshot
21155    }
21156}
21157
21158#[derive(Clone, Debug, PartialEq, Eq)]
21159pub enum EditorEvent {
21160    InputIgnored {
21161        text: Arc<str>,
21162    },
21163    InputHandled {
21164        utf16_range_to_replace: Option<Range<isize>>,
21165        text: Arc<str>,
21166    },
21167    ExcerptsAdded {
21168        buffer: Entity<Buffer>,
21169        predecessor: ExcerptId,
21170        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21171    },
21172    ExcerptsRemoved {
21173        ids: Vec<ExcerptId>,
21174        removed_buffer_ids: Vec<BufferId>,
21175    },
21176    BufferFoldToggled {
21177        ids: Vec<ExcerptId>,
21178        folded: bool,
21179    },
21180    ExcerptsEdited {
21181        ids: Vec<ExcerptId>,
21182    },
21183    ExcerptsExpanded {
21184        ids: Vec<ExcerptId>,
21185    },
21186    BufferEdited,
21187    Edited {
21188        transaction_id: clock::Lamport,
21189    },
21190    Reparsed(BufferId),
21191    Focused,
21192    FocusedIn,
21193    Blurred,
21194    DirtyChanged,
21195    Saved,
21196    TitleChanged,
21197    DiffBaseChanged,
21198    SelectionsChanged {
21199        local: bool,
21200    },
21201    ScrollPositionChanged {
21202        local: bool,
21203        autoscroll: bool,
21204    },
21205    Closed,
21206    TransactionUndone {
21207        transaction_id: clock::Lamport,
21208    },
21209    TransactionBegun {
21210        transaction_id: clock::Lamport,
21211    },
21212    Reloaded,
21213    CursorShapeChanged,
21214    PushedToNavHistory {
21215        anchor: Anchor,
21216        is_deactivate: bool,
21217    },
21218}
21219
21220impl EventEmitter<EditorEvent> for Editor {}
21221
21222impl Focusable for Editor {
21223    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21224        self.focus_handle.clone()
21225    }
21226}
21227
21228impl Render for Editor {
21229    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21230        let settings = ThemeSettings::get_global(cx);
21231
21232        let mut text_style = match self.mode {
21233            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21234                color: cx.theme().colors().editor_foreground,
21235                font_family: settings.ui_font.family.clone(),
21236                font_features: settings.ui_font.features.clone(),
21237                font_fallbacks: settings.ui_font.fallbacks.clone(),
21238                font_size: rems(0.875).into(),
21239                font_weight: settings.ui_font.weight,
21240                line_height: relative(settings.buffer_line_height.value()),
21241                ..Default::default()
21242            },
21243            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21244                color: cx.theme().colors().editor_foreground,
21245                font_family: settings.buffer_font.family.clone(),
21246                font_features: settings.buffer_font.features.clone(),
21247                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21248                font_size: settings.buffer_font_size(cx).into(),
21249                font_weight: settings.buffer_font.weight,
21250                line_height: relative(settings.buffer_line_height.value()),
21251                ..Default::default()
21252            },
21253        };
21254        if let Some(text_style_refinement) = &self.text_style_refinement {
21255            text_style.refine(text_style_refinement)
21256        }
21257
21258        let background = match self.mode {
21259            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21260            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21261            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21262            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21263        };
21264
21265        EditorElement::new(
21266            &cx.entity(),
21267            EditorStyle {
21268                background,
21269                local_player: cx.theme().players().local(),
21270                text: text_style,
21271                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21272                syntax: cx.theme().syntax().clone(),
21273                status: cx.theme().status().clone(),
21274                inlay_hints_style: make_inlay_hints_style(cx),
21275                inline_completion_styles: make_suggestion_styles(cx),
21276                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21277                show_underlines: !self.mode.is_minimap(),
21278            },
21279        )
21280    }
21281}
21282
21283impl EntityInputHandler for Editor {
21284    fn text_for_range(
21285        &mut self,
21286        range_utf16: Range<usize>,
21287        adjusted_range: &mut Option<Range<usize>>,
21288        _: &mut Window,
21289        cx: &mut Context<Self>,
21290    ) -> Option<String> {
21291        let snapshot = self.buffer.read(cx).read(cx);
21292        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21293        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21294        if (start.0..end.0) != range_utf16 {
21295            adjusted_range.replace(start.0..end.0);
21296        }
21297        Some(snapshot.text_for_range(start..end).collect())
21298    }
21299
21300    fn selected_text_range(
21301        &mut self,
21302        ignore_disabled_input: bool,
21303        _: &mut Window,
21304        cx: &mut Context<Self>,
21305    ) -> Option<UTF16Selection> {
21306        // Prevent the IME menu from appearing when holding down an alphabetic key
21307        // while input is disabled.
21308        if !ignore_disabled_input && !self.input_enabled {
21309            return None;
21310        }
21311
21312        let selection = self.selections.newest::<OffsetUtf16>(cx);
21313        let range = selection.range();
21314
21315        Some(UTF16Selection {
21316            range: range.start.0..range.end.0,
21317            reversed: selection.reversed,
21318        })
21319    }
21320
21321    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21322        let snapshot = self.buffer.read(cx).read(cx);
21323        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21324        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21325    }
21326
21327    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21328        self.clear_highlights::<InputComposition>(cx);
21329        self.ime_transaction.take();
21330    }
21331
21332    fn replace_text_in_range(
21333        &mut self,
21334        range_utf16: Option<Range<usize>>,
21335        text: &str,
21336        window: &mut Window,
21337        cx: &mut Context<Self>,
21338    ) {
21339        if !self.input_enabled {
21340            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21341            return;
21342        }
21343
21344        self.transact(window, cx, |this, window, cx| {
21345            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21346                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21347                Some(this.selection_replacement_ranges(range_utf16, cx))
21348            } else {
21349                this.marked_text_ranges(cx)
21350            };
21351
21352            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21353                let newest_selection_id = this.selections.newest_anchor().id;
21354                this.selections
21355                    .all::<OffsetUtf16>(cx)
21356                    .iter()
21357                    .zip(ranges_to_replace.iter())
21358                    .find_map(|(selection, range)| {
21359                        if selection.id == newest_selection_id {
21360                            Some(
21361                                (range.start.0 as isize - selection.head().0 as isize)
21362                                    ..(range.end.0 as isize - selection.head().0 as isize),
21363                            )
21364                        } else {
21365                            None
21366                        }
21367                    })
21368            });
21369
21370            cx.emit(EditorEvent::InputHandled {
21371                utf16_range_to_replace: range_to_replace,
21372                text: text.into(),
21373            });
21374
21375            if let Some(new_selected_ranges) = new_selected_ranges {
21376                this.change_selections(None, window, cx, |selections| {
21377                    selections.select_ranges(new_selected_ranges)
21378                });
21379                this.backspace(&Default::default(), window, cx);
21380            }
21381
21382            this.handle_input(text, window, cx);
21383        });
21384
21385        if let Some(transaction) = self.ime_transaction {
21386            self.buffer.update(cx, |buffer, cx| {
21387                buffer.group_until_transaction(transaction, cx);
21388            });
21389        }
21390
21391        self.unmark_text(window, cx);
21392    }
21393
21394    fn replace_and_mark_text_in_range(
21395        &mut self,
21396        range_utf16: Option<Range<usize>>,
21397        text: &str,
21398        new_selected_range_utf16: Option<Range<usize>>,
21399        window: &mut Window,
21400        cx: &mut Context<Self>,
21401    ) {
21402        if !self.input_enabled {
21403            return;
21404        }
21405
21406        let transaction = self.transact(window, cx, |this, window, cx| {
21407            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21408                let snapshot = this.buffer.read(cx).read(cx);
21409                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21410                    for marked_range in &mut marked_ranges {
21411                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21412                        marked_range.start.0 += relative_range_utf16.start;
21413                        marked_range.start =
21414                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21415                        marked_range.end =
21416                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21417                    }
21418                }
21419                Some(marked_ranges)
21420            } else if let Some(range_utf16) = range_utf16 {
21421                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21422                Some(this.selection_replacement_ranges(range_utf16, cx))
21423            } else {
21424                None
21425            };
21426
21427            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21428                let newest_selection_id = this.selections.newest_anchor().id;
21429                this.selections
21430                    .all::<OffsetUtf16>(cx)
21431                    .iter()
21432                    .zip(ranges_to_replace.iter())
21433                    .find_map(|(selection, range)| {
21434                        if selection.id == newest_selection_id {
21435                            Some(
21436                                (range.start.0 as isize - selection.head().0 as isize)
21437                                    ..(range.end.0 as isize - selection.head().0 as isize),
21438                            )
21439                        } else {
21440                            None
21441                        }
21442                    })
21443            });
21444
21445            cx.emit(EditorEvent::InputHandled {
21446                utf16_range_to_replace: range_to_replace,
21447                text: text.into(),
21448            });
21449
21450            if let Some(ranges) = ranges_to_replace {
21451                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21452            }
21453
21454            let marked_ranges = {
21455                let snapshot = this.buffer.read(cx).read(cx);
21456                this.selections
21457                    .disjoint_anchors()
21458                    .iter()
21459                    .map(|selection| {
21460                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21461                    })
21462                    .collect::<Vec<_>>()
21463            };
21464
21465            if text.is_empty() {
21466                this.unmark_text(window, cx);
21467            } else {
21468                this.highlight_text::<InputComposition>(
21469                    marked_ranges.clone(),
21470                    HighlightStyle {
21471                        underline: Some(UnderlineStyle {
21472                            thickness: px(1.),
21473                            color: None,
21474                            wavy: false,
21475                        }),
21476                        ..Default::default()
21477                    },
21478                    cx,
21479                );
21480            }
21481
21482            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21483            let use_autoclose = this.use_autoclose;
21484            let use_auto_surround = this.use_auto_surround;
21485            this.set_use_autoclose(false);
21486            this.set_use_auto_surround(false);
21487            this.handle_input(text, window, cx);
21488            this.set_use_autoclose(use_autoclose);
21489            this.set_use_auto_surround(use_auto_surround);
21490
21491            if let Some(new_selected_range) = new_selected_range_utf16 {
21492                let snapshot = this.buffer.read(cx).read(cx);
21493                let new_selected_ranges = marked_ranges
21494                    .into_iter()
21495                    .map(|marked_range| {
21496                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21497                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21498                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21499                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21500                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21501                    })
21502                    .collect::<Vec<_>>();
21503
21504                drop(snapshot);
21505                this.change_selections(None, window, cx, |selections| {
21506                    selections.select_ranges(new_selected_ranges)
21507                });
21508            }
21509        });
21510
21511        self.ime_transaction = self.ime_transaction.or(transaction);
21512        if let Some(transaction) = self.ime_transaction {
21513            self.buffer.update(cx, |buffer, cx| {
21514                buffer.group_until_transaction(transaction, cx);
21515            });
21516        }
21517
21518        if self.text_highlights::<InputComposition>(cx).is_none() {
21519            self.ime_transaction.take();
21520        }
21521    }
21522
21523    fn bounds_for_range(
21524        &mut self,
21525        range_utf16: Range<usize>,
21526        element_bounds: gpui::Bounds<Pixels>,
21527        window: &mut Window,
21528        cx: &mut Context<Self>,
21529    ) -> Option<gpui::Bounds<Pixels>> {
21530        let text_layout_details = self.text_layout_details(window);
21531        let gpui::Size {
21532            width: em_width,
21533            height: line_height,
21534        } = self.character_size(window);
21535
21536        let snapshot = self.snapshot(window, cx);
21537        let scroll_position = snapshot.scroll_position();
21538        let scroll_left = scroll_position.x * em_width;
21539
21540        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21541        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21542            + self.gutter_dimensions.width
21543            + self.gutter_dimensions.margin;
21544        let y = line_height * (start.row().as_f32() - scroll_position.y);
21545
21546        Some(Bounds {
21547            origin: element_bounds.origin + point(x, y),
21548            size: size(em_width, line_height),
21549        })
21550    }
21551
21552    fn character_index_for_point(
21553        &mut self,
21554        point: gpui::Point<Pixels>,
21555        _window: &mut Window,
21556        _cx: &mut Context<Self>,
21557    ) -> Option<usize> {
21558        let position_map = self.last_position_map.as_ref()?;
21559        if !position_map.text_hitbox.contains(&point) {
21560            return None;
21561        }
21562        let display_point = position_map.point_for_position(point).previous_valid;
21563        let anchor = position_map
21564            .snapshot
21565            .display_point_to_anchor(display_point, Bias::Left);
21566        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21567        Some(utf16_offset.0)
21568    }
21569}
21570
21571trait SelectionExt {
21572    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21573    fn spanned_rows(
21574        &self,
21575        include_end_if_at_line_start: bool,
21576        map: &DisplaySnapshot,
21577    ) -> Range<MultiBufferRow>;
21578}
21579
21580impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21581    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21582        let start = self
21583            .start
21584            .to_point(&map.buffer_snapshot)
21585            .to_display_point(map);
21586        let end = self
21587            .end
21588            .to_point(&map.buffer_snapshot)
21589            .to_display_point(map);
21590        if self.reversed {
21591            end..start
21592        } else {
21593            start..end
21594        }
21595    }
21596
21597    fn spanned_rows(
21598        &self,
21599        include_end_if_at_line_start: bool,
21600        map: &DisplaySnapshot,
21601    ) -> Range<MultiBufferRow> {
21602        let start = self.start.to_point(&map.buffer_snapshot);
21603        let mut end = self.end.to_point(&map.buffer_snapshot);
21604        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21605            end.row -= 1;
21606        }
21607
21608        let buffer_start = map.prev_line_boundary(start).0;
21609        let buffer_end = map.next_line_boundary(end).0;
21610        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21611    }
21612}
21613
21614impl<T: InvalidationRegion> InvalidationStack<T> {
21615    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21616    where
21617        S: Clone + ToOffset,
21618    {
21619        while let Some(region) = self.last() {
21620            let all_selections_inside_invalidation_ranges =
21621                if selections.len() == region.ranges().len() {
21622                    selections
21623                        .iter()
21624                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21625                        .all(|(selection, invalidation_range)| {
21626                            let head = selection.head().to_offset(buffer);
21627                            invalidation_range.start <= head && invalidation_range.end >= head
21628                        })
21629                } else {
21630                    false
21631                };
21632
21633            if all_selections_inside_invalidation_ranges {
21634                break;
21635            } else {
21636                self.pop();
21637            }
21638        }
21639    }
21640}
21641
21642impl<T> Default for InvalidationStack<T> {
21643    fn default() -> Self {
21644        Self(Default::default())
21645    }
21646}
21647
21648impl<T> Deref for InvalidationStack<T> {
21649    type Target = Vec<T>;
21650
21651    fn deref(&self) -> &Self::Target {
21652        &self.0
21653    }
21654}
21655
21656impl<T> DerefMut for InvalidationStack<T> {
21657    fn deref_mut(&mut self) -> &mut Self::Target {
21658        &mut self.0
21659    }
21660}
21661
21662impl InvalidationRegion for SnippetState {
21663    fn ranges(&self) -> &[Range<Anchor>] {
21664        &self.ranges[self.active_index]
21665    }
21666}
21667
21668fn inline_completion_edit_text(
21669    current_snapshot: &BufferSnapshot,
21670    edits: &[(Range<Anchor>, String)],
21671    edit_preview: &EditPreview,
21672    include_deletions: bool,
21673    cx: &App,
21674) -> HighlightedText {
21675    let edits = edits
21676        .iter()
21677        .map(|(anchor, text)| {
21678            (
21679                anchor.start.text_anchor..anchor.end.text_anchor,
21680                text.clone(),
21681            )
21682        })
21683        .collect::<Vec<_>>();
21684
21685    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21686}
21687
21688pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21689    match severity {
21690        lsp::DiagnosticSeverity::ERROR => colors.error,
21691        lsp::DiagnosticSeverity::WARNING => colors.warning,
21692        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21693        lsp::DiagnosticSeverity::HINT => colors.info,
21694        _ => colors.ignored,
21695    }
21696}
21697
21698pub fn styled_runs_for_code_label<'a>(
21699    label: &'a CodeLabel,
21700    syntax_theme: &'a theme::SyntaxTheme,
21701) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21702    let fade_out = HighlightStyle {
21703        fade_out: Some(0.35),
21704        ..Default::default()
21705    };
21706
21707    let mut prev_end = label.filter_range.end;
21708    label
21709        .runs
21710        .iter()
21711        .enumerate()
21712        .flat_map(move |(ix, (range, highlight_id))| {
21713            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21714                style
21715            } else {
21716                return Default::default();
21717            };
21718            let mut muted_style = style;
21719            muted_style.highlight(fade_out);
21720
21721            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21722            if range.start >= label.filter_range.end {
21723                if range.start > prev_end {
21724                    runs.push((prev_end..range.start, fade_out));
21725                }
21726                runs.push((range.clone(), muted_style));
21727            } else if range.end <= label.filter_range.end {
21728                runs.push((range.clone(), style));
21729            } else {
21730                runs.push((range.start..label.filter_range.end, style));
21731                runs.push((label.filter_range.end..range.end, muted_style));
21732            }
21733            prev_end = cmp::max(prev_end, range.end);
21734
21735            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21736                runs.push((prev_end..label.text.len(), fade_out));
21737            }
21738
21739            runs
21740        })
21741}
21742
21743pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21744    let mut prev_index = 0;
21745    let mut prev_codepoint: Option<char> = None;
21746    text.char_indices()
21747        .chain([(text.len(), '\0')])
21748        .filter_map(move |(index, codepoint)| {
21749            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21750            let is_boundary = index == text.len()
21751                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21752                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21753            if is_boundary {
21754                let chunk = &text[prev_index..index];
21755                prev_index = index;
21756                Some(chunk)
21757            } else {
21758                None
21759            }
21760        })
21761}
21762
21763pub trait RangeToAnchorExt: Sized {
21764    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21765
21766    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21767        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21768        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21769    }
21770}
21771
21772impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21773    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21774        let start_offset = self.start.to_offset(snapshot);
21775        let end_offset = self.end.to_offset(snapshot);
21776        if start_offset == end_offset {
21777            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21778        } else {
21779            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21780        }
21781    }
21782}
21783
21784pub trait RowExt {
21785    fn as_f32(&self) -> f32;
21786
21787    fn next_row(&self) -> Self;
21788
21789    fn previous_row(&self) -> Self;
21790
21791    fn minus(&self, other: Self) -> u32;
21792}
21793
21794impl RowExt for DisplayRow {
21795    fn as_f32(&self) -> f32 {
21796        self.0 as f32
21797    }
21798
21799    fn next_row(&self) -> Self {
21800        Self(self.0 + 1)
21801    }
21802
21803    fn previous_row(&self) -> Self {
21804        Self(self.0.saturating_sub(1))
21805    }
21806
21807    fn minus(&self, other: Self) -> u32 {
21808        self.0 - other.0
21809    }
21810}
21811
21812impl RowExt for MultiBufferRow {
21813    fn as_f32(&self) -> f32 {
21814        self.0 as f32
21815    }
21816
21817    fn next_row(&self) -> Self {
21818        Self(self.0 + 1)
21819    }
21820
21821    fn previous_row(&self) -> Self {
21822        Self(self.0.saturating_sub(1))
21823    }
21824
21825    fn minus(&self, other: Self) -> u32 {
21826        self.0 - other.0
21827    }
21828}
21829
21830trait RowRangeExt {
21831    type Row;
21832
21833    fn len(&self) -> usize;
21834
21835    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21836}
21837
21838impl RowRangeExt for Range<MultiBufferRow> {
21839    type Row = MultiBufferRow;
21840
21841    fn len(&self) -> usize {
21842        (self.end.0 - self.start.0) as usize
21843    }
21844
21845    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21846        (self.start.0..self.end.0).map(MultiBufferRow)
21847    }
21848}
21849
21850impl RowRangeExt for Range<DisplayRow> {
21851    type Row = DisplayRow;
21852
21853    fn len(&self) -> usize {
21854        (self.end.0 - self.start.0) as usize
21855    }
21856
21857    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21858        (self.start.0..self.end.0).map(DisplayRow)
21859    }
21860}
21861
21862/// If select range has more than one line, we
21863/// just point the cursor to range.start.
21864fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21865    if range.start.row == range.end.row {
21866        range
21867    } else {
21868        range.start..range.start
21869    }
21870}
21871pub struct KillRing(ClipboardItem);
21872impl Global for KillRing {}
21873
21874const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21875
21876enum BreakpointPromptEditAction {
21877    Log,
21878    Condition,
21879    HitCondition,
21880}
21881
21882struct BreakpointPromptEditor {
21883    pub(crate) prompt: Entity<Editor>,
21884    editor: WeakEntity<Editor>,
21885    breakpoint_anchor: Anchor,
21886    breakpoint: Breakpoint,
21887    edit_action: BreakpointPromptEditAction,
21888    block_ids: HashSet<CustomBlockId>,
21889    editor_margins: Arc<Mutex<EditorMargins>>,
21890    _subscriptions: Vec<Subscription>,
21891}
21892
21893impl BreakpointPromptEditor {
21894    const MAX_LINES: u8 = 4;
21895
21896    fn new(
21897        editor: WeakEntity<Editor>,
21898        breakpoint_anchor: Anchor,
21899        breakpoint: Breakpoint,
21900        edit_action: BreakpointPromptEditAction,
21901        window: &mut Window,
21902        cx: &mut Context<Self>,
21903    ) -> Self {
21904        let base_text = match edit_action {
21905            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21906            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21907            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21908        }
21909        .map(|msg| msg.to_string())
21910        .unwrap_or_default();
21911
21912        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21913        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21914
21915        let prompt = cx.new(|cx| {
21916            let mut prompt = Editor::new(
21917                EditorMode::AutoHeight {
21918                    max_lines: Self::MAX_LINES as usize,
21919                },
21920                buffer,
21921                None,
21922                window,
21923                cx,
21924            );
21925            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21926            prompt.set_show_cursor_when_unfocused(false, cx);
21927            prompt.set_placeholder_text(
21928                match edit_action {
21929                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21930                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21931                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21932                },
21933                cx,
21934            );
21935
21936            prompt
21937        });
21938
21939        Self {
21940            prompt,
21941            editor,
21942            breakpoint_anchor,
21943            breakpoint,
21944            edit_action,
21945            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21946            block_ids: Default::default(),
21947            _subscriptions: vec![],
21948        }
21949    }
21950
21951    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21952        self.block_ids.extend(block_ids)
21953    }
21954
21955    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21956        if let Some(editor) = self.editor.upgrade() {
21957            let message = self
21958                .prompt
21959                .read(cx)
21960                .buffer
21961                .read(cx)
21962                .as_singleton()
21963                .expect("A multi buffer in breakpoint prompt isn't possible")
21964                .read(cx)
21965                .as_rope()
21966                .to_string();
21967
21968            editor.update(cx, |editor, cx| {
21969                editor.edit_breakpoint_at_anchor(
21970                    self.breakpoint_anchor,
21971                    self.breakpoint.clone(),
21972                    match self.edit_action {
21973                        BreakpointPromptEditAction::Log => {
21974                            BreakpointEditAction::EditLogMessage(message.into())
21975                        }
21976                        BreakpointPromptEditAction::Condition => {
21977                            BreakpointEditAction::EditCondition(message.into())
21978                        }
21979                        BreakpointPromptEditAction::HitCondition => {
21980                            BreakpointEditAction::EditHitCondition(message.into())
21981                        }
21982                    },
21983                    cx,
21984                );
21985
21986                editor.remove_blocks(self.block_ids.clone(), None, cx);
21987                cx.focus_self(window);
21988            });
21989        }
21990    }
21991
21992    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21993        self.editor
21994            .update(cx, |editor, cx| {
21995                editor.remove_blocks(self.block_ids.clone(), None, cx);
21996                window.focus(&editor.focus_handle);
21997            })
21998            .log_err();
21999    }
22000
22001    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22002        let settings = ThemeSettings::get_global(cx);
22003        let text_style = TextStyle {
22004            color: if self.prompt.read(cx).read_only(cx) {
22005                cx.theme().colors().text_disabled
22006            } else {
22007                cx.theme().colors().text
22008            },
22009            font_family: settings.buffer_font.family.clone(),
22010            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22011            font_size: settings.buffer_font_size(cx).into(),
22012            font_weight: settings.buffer_font.weight,
22013            line_height: relative(settings.buffer_line_height.value()),
22014            ..Default::default()
22015        };
22016        EditorElement::new(
22017            &self.prompt,
22018            EditorStyle {
22019                background: cx.theme().colors().editor_background,
22020                local_player: cx.theme().players().local(),
22021                text: text_style,
22022                ..Default::default()
22023            },
22024        )
22025    }
22026}
22027
22028impl Render for BreakpointPromptEditor {
22029    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22030        let editor_margins = *self.editor_margins.lock();
22031        let gutter_dimensions = editor_margins.gutter;
22032        h_flex()
22033            .key_context("Editor")
22034            .bg(cx.theme().colors().editor_background)
22035            .border_y_1()
22036            .border_color(cx.theme().status().info_border)
22037            .size_full()
22038            .py(window.line_height() / 2.5)
22039            .on_action(cx.listener(Self::confirm))
22040            .on_action(cx.listener(Self::cancel))
22041            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22042            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22043    }
22044}
22045
22046impl Focusable for BreakpointPromptEditor {
22047    fn focus_handle(&self, cx: &App) -> FocusHandle {
22048        self.prompt.focus_handle(cx)
22049    }
22050}
22051
22052fn all_edits_insertions_or_deletions(
22053    edits: &Vec<(Range<Anchor>, String)>,
22054    snapshot: &MultiBufferSnapshot,
22055) -> bool {
22056    let mut all_insertions = true;
22057    let mut all_deletions = true;
22058
22059    for (range, new_text) in edits.iter() {
22060        let range_is_empty = range.to_offset(&snapshot).is_empty();
22061        let text_is_empty = new_text.is_empty();
22062
22063        if range_is_empty != text_is_empty {
22064            if range_is_empty {
22065                all_deletions = false;
22066            } else {
22067                all_insertions = false;
22068            }
22069        } else {
22070            return false;
22071        }
22072
22073        if !all_insertions && !all_deletions {
22074            return false;
22075        }
22076    }
22077    all_insertions || all_deletions
22078}
22079
22080struct MissingEditPredictionKeybindingTooltip;
22081
22082impl Render for MissingEditPredictionKeybindingTooltip {
22083    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22084        ui::tooltip_container(window, cx, |container, _, cx| {
22085            container
22086                .flex_shrink_0()
22087                .max_w_80()
22088                .min_h(rems_from_px(124.))
22089                .justify_between()
22090                .child(
22091                    v_flex()
22092                        .flex_1()
22093                        .text_ui_sm(cx)
22094                        .child(Label::new("Conflict with Accept Keybinding"))
22095                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22096                )
22097                .child(
22098                    h_flex()
22099                        .pb_1()
22100                        .gap_1()
22101                        .items_end()
22102                        .w_full()
22103                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22104                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22105                        }))
22106                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22107                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22108                        })),
22109                )
22110        })
22111    }
22112}
22113
22114#[derive(Debug, Clone, Copy, PartialEq)]
22115pub struct LineHighlight {
22116    pub background: Background,
22117    pub border: Option<gpui::Hsla>,
22118    pub include_gutter: bool,
22119    pub type_id: Option<TypeId>,
22120}
22121
22122fn render_diff_hunk_controls(
22123    row: u32,
22124    status: &DiffHunkStatus,
22125    hunk_range: Range<Anchor>,
22126    is_created_file: bool,
22127    line_height: Pixels,
22128    editor: &Entity<Editor>,
22129    _window: &mut Window,
22130    cx: &mut App,
22131) -> AnyElement {
22132    h_flex()
22133        .h(line_height)
22134        .mr_1()
22135        .gap_1()
22136        .px_0p5()
22137        .pb_1()
22138        .border_x_1()
22139        .border_b_1()
22140        .border_color(cx.theme().colors().border_variant)
22141        .rounded_b_lg()
22142        .bg(cx.theme().colors().editor_background)
22143        .gap_1()
22144        .block_mouse_except_scroll()
22145        .shadow_md()
22146        .child(if status.has_secondary_hunk() {
22147            Button::new(("stage", row as u64), "Stage")
22148                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22149                .tooltip({
22150                    let focus_handle = editor.focus_handle(cx);
22151                    move |window, cx| {
22152                        Tooltip::for_action_in(
22153                            "Stage Hunk",
22154                            &::git::ToggleStaged,
22155                            &focus_handle,
22156                            window,
22157                            cx,
22158                        )
22159                    }
22160                })
22161                .on_click({
22162                    let editor = editor.clone();
22163                    move |_event, _window, cx| {
22164                        editor.update(cx, |editor, cx| {
22165                            editor.stage_or_unstage_diff_hunks(
22166                                true,
22167                                vec![hunk_range.start..hunk_range.start],
22168                                cx,
22169                            );
22170                        });
22171                    }
22172                })
22173        } else {
22174            Button::new(("unstage", row as u64), "Unstage")
22175                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22176                .tooltip({
22177                    let focus_handle = editor.focus_handle(cx);
22178                    move |window, cx| {
22179                        Tooltip::for_action_in(
22180                            "Unstage Hunk",
22181                            &::git::ToggleStaged,
22182                            &focus_handle,
22183                            window,
22184                            cx,
22185                        )
22186                    }
22187                })
22188                .on_click({
22189                    let editor = editor.clone();
22190                    move |_event, _window, cx| {
22191                        editor.update(cx, |editor, cx| {
22192                            editor.stage_or_unstage_diff_hunks(
22193                                false,
22194                                vec![hunk_range.start..hunk_range.start],
22195                                cx,
22196                            );
22197                        });
22198                    }
22199                })
22200        })
22201        .child(
22202            Button::new(("restore", row as u64), "Restore")
22203                .tooltip({
22204                    let focus_handle = editor.focus_handle(cx);
22205                    move |window, cx| {
22206                        Tooltip::for_action_in(
22207                            "Restore Hunk",
22208                            &::git::Restore,
22209                            &focus_handle,
22210                            window,
22211                            cx,
22212                        )
22213                    }
22214                })
22215                .on_click({
22216                    let editor = editor.clone();
22217                    move |_event, window, cx| {
22218                        editor.update(cx, |editor, cx| {
22219                            let snapshot = editor.snapshot(window, cx);
22220                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22221                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22222                        });
22223                    }
22224                })
22225                .disabled(is_created_file),
22226        )
22227        .when(
22228            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22229            |el| {
22230                el.child(
22231                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22232                        .shape(IconButtonShape::Square)
22233                        .icon_size(IconSize::Small)
22234                        // .disabled(!has_multiple_hunks)
22235                        .tooltip({
22236                            let focus_handle = editor.focus_handle(cx);
22237                            move |window, cx| {
22238                                Tooltip::for_action_in(
22239                                    "Next Hunk",
22240                                    &GoToHunk,
22241                                    &focus_handle,
22242                                    window,
22243                                    cx,
22244                                )
22245                            }
22246                        })
22247                        .on_click({
22248                            let editor = editor.clone();
22249                            move |_event, window, cx| {
22250                                editor.update(cx, |editor, cx| {
22251                                    let snapshot = editor.snapshot(window, cx);
22252                                    let position =
22253                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22254                                    editor.go_to_hunk_before_or_after_position(
22255                                        &snapshot,
22256                                        position,
22257                                        Direction::Next,
22258                                        window,
22259                                        cx,
22260                                    );
22261                                    editor.expand_selected_diff_hunks(cx);
22262                                });
22263                            }
22264                        }),
22265                )
22266                .child(
22267                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22268                        .shape(IconButtonShape::Square)
22269                        .icon_size(IconSize::Small)
22270                        // .disabled(!has_multiple_hunks)
22271                        .tooltip({
22272                            let focus_handle = editor.focus_handle(cx);
22273                            move |window, cx| {
22274                                Tooltip::for_action_in(
22275                                    "Previous Hunk",
22276                                    &GoToPreviousHunk,
22277                                    &focus_handle,
22278                                    window,
22279                                    cx,
22280                                )
22281                            }
22282                        })
22283                        .on_click({
22284                            let editor = editor.clone();
22285                            move |_event, window, cx| {
22286                                editor.update(cx, |editor, cx| {
22287                                    let snapshot = editor.snapshot(window, cx);
22288                                    let point =
22289                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22290                                    editor.go_to_hunk_before_or_after_position(
22291                                        &snapshot,
22292                                        point,
22293                                        Direction::Prev,
22294                                        window,
22295                                        cx,
22296                                    );
22297                                    editor.expand_selected_diff_hunks(cx);
22298                                });
22299                            }
22300                        }),
22301                )
22302            },
22303        )
22304        .into_any_element()
22305}