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
10877        // Shrink and split selections to respect paragraph boundaries.
10878        let ranges = selections.into_iter().flat_map(|selection| {
10879            let language_settings = buffer.language_settings_at(selection.head(), cx);
10880            let language_scope = buffer.language_scope_at(selection.head());
10881
10882            let Some(start_row) = (selection.start.row..=selection.end.row)
10883                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
10884            else {
10885                return vec![];
10886            };
10887            let Some(end_row) = (selection.start.row..=selection.end.row)
10888                .rev()
10889                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
10890            else {
10891                return vec![];
10892            };
10893
10894            let mut row = start_row;
10895            let mut ranges = Vec::new();
10896            while let Some(blank_row) =
10897                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
10898            {
10899                let next_paragraph_start = (blank_row + 1..=end_row)
10900                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
10901                    .unwrap();
10902                ranges.push((
10903                    language_settings.clone(),
10904                    language_scope.clone(),
10905                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
10906                ));
10907                row = next_paragraph_start;
10908            }
10909            ranges.push((
10910                language_settings.clone(),
10911                language_scope.clone(),
10912                Point::new(row, 0)..Point::new(end_row, 0),
10913            ));
10914
10915            ranges
10916        });
10917
10918        let mut edits = Vec::new();
10919        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10920
10921        for (language_settings, language_scope, range) in ranges {
10922            let mut start_row = range.start.row;
10923            let mut end_row = range.end.row;
10924
10925            // Skip selections that overlap with a range that has already been rewrapped.
10926            let selection_range = start_row..end_row;
10927            if rewrapped_row_ranges
10928                .iter()
10929                .any(|range| range.overlaps(&selection_range))
10930            {
10931                continue;
10932            }
10933
10934            let tab_size = language_settings.tab_size;
10935
10936            // Since not all lines in the selection may be at the same indent
10937            // level, choose the indent size that is the most common between all
10938            // of the lines.
10939            //
10940            // If there is a tie, we use the deepest indent.
10941            let (indent_size, indent_end) = {
10942                let mut indent_size_occurrences = HashMap::default();
10943                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10944
10945                for row in start_row..=end_row {
10946                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10947                    rows_by_indent_size.entry(indent).or_default().push(row);
10948                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10949                }
10950
10951                let indent_size = indent_size_occurrences
10952                    .into_iter()
10953                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10954                    .map(|(indent, _)| indent)
10955                    .unwrap_or_default();
10956                let row = rows_by_indent_size[&indent_size][0];
10957                let indent_end = Point::new(row, indent_size.len);
10958
10959                (indent_size, indent_end)
10960            };
10961
10962            let mut line_prefix = indent_size.chars().collect::<String>();
10963
10964            let mut inside_comment = false;
10965            if let Some(comment_prefix) = language_scope.and_then(|language| {
10966                language
10967                    .line_comment_prefixes()
10968                    .iter()
10969                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10970                    .cloned()
10971            }) {
10972                line_prefix.push_str(&comment_prefix);
10973                inside_comment = true;
10974            }
10975
10976            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10977                RewrapBehavior::InComments => inside_comment,
10978                RewrapBehavior::InSelections => !range.is_empty(),
10979                RewrapBehavior::Anywhere => true,
10980            };
10981
10982            let should_rewrap = options.override_language_settings
10983                || allow_rewrap_based_on_language
10984                || self.hard_wrap.is_some();
10985            if !should_rewrap {
10986                continue;
10987            }
10988
10989            if range.is_empty() {
10990                'expand_upwards: while start_row > 0 {
10991                    let prev_row = start_row - 1;
10992                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10993                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10994                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
10995                    {
10996                        start_row = prev_row;
10997                    } else {
10998                        break 'expand_upwards;
10999                    }
11000                }
11001
11002                'expand_downwards: while end_row < buffer.max_point().row {
11003                    let next_row = end_row + 1;
11004                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11005                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11006                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11007                    {
11008                        end_row = next_row;
11009                    } else {
11010                        break 'expand_downwards;
11011                    }
11012                }
11013            }
11014
11015            let start = Point::new(start_row, 0);
11016            let start_offset = start.to_offset(&buffer);
11017            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11018            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11019            let Some(lines_without_prefixes) = selection_text
11020                .lines()
11021                .map(|line| {
11022                    line.strip_prefix(&line_prefix)
11023                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11024                        .with_context(|| {
11025                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11026                        })
11027                })
11028                .collect::<Result<Vec<_>, _>>()
11029                .log_err()
11030            else {
11031                continue;
11032            };
11033
11034            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11035                buffer
11036                    .language_settings_at(Point::new(start_row, 0), cx)
11037                    .preferred_line_length as usize
11038            });
11039            let wrapped_text = wrap_with_prefix(
11040                line_prefix,
11041                lines_without_prefixes.join("\n"),
11042                wrap_column,
11043                tab_size,
11044                options.preserve_existing_whitespace,
11045            );
11046
11047            // TODO: should always use char-based diff while still supporting cursor behavior that
11048            // matches vim.
11049            let mut diff_options = DiffOptions::default();
11050            if options.override_language_settings {
11051                diff_options.max_word_diff_len = 0;
11052                diff_options.max_word_diff_line_count = 0;
11053            } else {
11054                diff_options.max_word_diff_len = usize::MAX;
11055                diff_options.max_word_diff_line_count = usize::MAX;
11056            }
11057
11058            for (old_range, new_text) in
11059                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11060            {
11061                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11062                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11063                edits.push((edit_start..edit_end, new_text));
11064            }
11065
11066            rewrapped_row_ranges.push(start_row..=end_row);
11067        }
11068
11069        self.buffer
11070            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11071    }
11072
11073    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11074        let mut text = String::new();
11075        let buffer = self.buffer.read(cx).snapshot(cx);
11076        let mut selections = self.selections.all::<Point>(cx);
11077        let mut clipboard_selections = Vec::with_capacity(selections.len());
11078        {
11079            let max_point = buffer.max_point();
11080            let mut is_first = true;
11081            for selection in &mut selections {
11082                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11083                if is_entire_line {
11084                    selection.start = Point::new(selection.start.row, 0);
11085                    if !selection.is_empty() && selection.end.column == 0 {
11086                        selection.end = cmp::min(max_point, selection.end);
11087                    } else {
11088                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11089                    }
11090                    selection.goal = SelectionGoal::None;
11091                }
11092                if is_first {
11093                    is_first = false;
11094                } else {
11095                    text += "\n";
11096                }
11097                let mut len = 0;
11098                for chunk in buffer.text_for_range(selection.start..selection.end) {
11099                    text.push_str(chunk);
11100                    len += chunk.len();
11101                }
11102                clipboard_selections.push(ClipboardSelection {
11103                    len,
11104                    is_entire_line,
11105                    first_line_indent: buffer
11106                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11107                        .len,
11108                });
11109            }
11110        }
11111
11112        self.transact(window, cx, |this, window, cx| {
11113            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11114                s.select(selections);
11115            });
11116            this.insert("", window, cx);
11117        });
11118        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11119    }
11120
11121    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11122        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11123        let item = self.cut_common(window, cx);
11124        cx.write_to_clipboard(item);
11125    }
11126
11127    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11128        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11129        self.change_selections(None, window, cx, |s| {
11130            s.move_with(|snapshot, sel| {
11131                if sel.is_empty() {
11132                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11133                }
11134            });
11135        });
11136        let item = self.cut_common(window, cx);
11137        cx.set_global(KillRing(item))
11138    }
11139
11140    pub fn kill_ring_yank(
11141        &mut self,
11142        _: &KillRingYank,
11143        window: &mut Window,
11144        cx: &mut Context<Self>,
11145    ) {
11146        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11147        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11148            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11149                (kill_ring.text().to_string(), kill_ring.metadata_json())
11150            } else {
11151                return;
11152            }
11153        } else {
11154            return;
11155        };
11156        self.do_paste(&text, metadata, false, window, cx);
11157    }
11158
11159    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11160        self.do_copy(true, cx);
11161    }
11162
11163    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11164        self.do_copy(false, cx);
11165    }
11166
11167    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11168        let selections = self.selections.all::<Point>(cx);
11169        let buffer = self.buffer.read(cx).read(cx);
11170        let mut text = String::new();
11171
11172        let mut clipboard_selections = Vec::with_capacity(selections.len());
11173        {
11174            let max_point = buffer.max_point();
11175            let mut is_first = true;
11176            for selection in &selections {
11177                let mut start = selection.start;
11178                let mut end = selection.end;
11179                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11180                if is_entire_line {
11181                    start = Point::new(start.row, 0);
11182                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11183                }
11184
11185                let mut trimmed_selections = Vec::new();
11186                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11187                    let row = MultiBufferRow(start.row);
11188                    let first_indent = buffer.indent_size_for_line(row);
11189                    if first_indent.len == 0 || start.column > first_indent.len {
11190                        trimmed_selections.push(start..end);
11191                    } else {
11192                        trimmed_selections.push(
11193                            Point::new(row.0, first_indent.len)
11194                                ..Point::new(row.0, buffer.line_len(row)),
11195                        );
11196                        for row in start.row + 1..=end.row {
11197                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11198                            if row == end.row {
11199                                line_len = end.column;
11200                            }
11201                            if line_len == 0 {
11202                                trimmed_selections
11203                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11204                                continue;
11205                            }
11206                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11207                            if row_indent_size.len >= first_indent.len {
11208                                trimmed_selections.push(
11209                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11210                                );
11211                            } else {
11212                                trimmed_selections.clear();
11213                                trimmed_selections.push(start..end);
11214                                break;
11215                            }
11216                        }
11217                    }
11218                } else {
11219                    trimmed_selections.push(start..end);
11220                }
11221
11222                for trimmed_range in trimmed_selections {
11223                    if is_first {
11224                        is_first = false;
11225                    } else {
11226                        text += "\n";
11227                    }
11228                    let mut len = 0;
11229                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11230                        text.push_str(chunk);
11231                        len += chunk.len();
11232                    }
11233                    clipboard_selections.push(ClipboardSelection {
11234                        len,
11235                        is_entire_line,
11236                        first_line_indent: buffer
11237                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11238                            .len,
11239                    });
11240                }
11241            }
11242        }
11243
11244        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11245            text,
11246            clipboard_selections,
11247        ));
11248    }
11249
11250    pub fn do_paste(
11251        &mut self,
11252        text: &String,
11253        clipboard_selections: Option<Vec<ClipboardSelection>>,
11254        handle_entire_lines: bool,
11255        window: &mut Window,
11256        cx: &mut Context<Self>,
11257    ) {
11258        if self.read_only(cx) {
11259            return;
11260        }
11261
11262        let clipboard_text = Cow::Borrowed(text);
11263
11264        self.transact(window, cx, |this, window, cx| {
11265            if let Some(mut clipboard_selections) = clipboard_selections {
11266                let old_selections = this.selections.all::<usize>(cx);
11267                let all_selections_were_entire_line =
11268                    clipboard_selections.iter().all(|s| s.is_entire_line);
11269                let first_selection_indent_column =
11270                    clipboard_selections.first().map(|s| s.first_line_indent);
11271                if clipboard_selections.len() != old_selections.len() {
11272                    clipboard_selections.drain(..);
11273                }
11274                let cursor_offset = this.selections.last::<usize>(cx).head();
11275                let mut auto_indent_on_paste = true;
11276
11277                this.buffer.update(cx, |buffer, cx| {
11278                    let snapshot = buffer.read(cx);
11279                    auto_indent_on_paste = snapshot
11280                        .language_settings_at(cursor_offset, cx)
11281                        .auto_indent_on_paste;
11282
11283                    let mut start_offset = 0;
11284                    let mut edits = Vec::new();
11285                    let mut original_indent_columns = Vec::new();
11286                    for (ix, selection) in old_selections.iter().enumerate() {
11287                        let to_insert;
11288                        let entire_line;
11289                        let original_indent_column;
11290                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11291                            let end_offset = start_offset + clipboard_selection.len;
11292                            to_insert = &clipboard_text[start_offset..end_offset];
11293                            entire_line = clipboard_selection.is_entire_line;
11294                            start_offset = end_offset + 1;
11295                            original_indent_column = Some(clipboard_selection.first_line_indent);
11296                        } else {
11297                            to_insert = clipboard_text.as_str();
11298                            entire_line = all_selections_were_entire_line;
11299                            original_indent_column = first_selection_indent_column
11300                        }
11301
11302                        // If the corresponding selection was empty when this slice of the
11303                        // clipboard text was written, then the entire line containing the
11304                        // selection was copied. If this selection is also currently empty,
11305                        // then paste the line before the current line of the buffer.
11306                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11307                            let column = selection.start.to_point(&snapshot).column as usize;
11308                            let line_start = selection.start - column;
11309                            line_start..line_start
11310                        } else {
11311                            selection.range()
11312                        };
11313
11314                        edits.push((range, to_insert));
11315                        original_indent_columns.push(original_indent_column);
11316                    }
11317                    drop(snapshot);
11318
11319                    buffer.edit(
11320                        edits,
11321                        if auto_indent_on_paste {
11322                            Some(AutoindentMode::Block {
11323                                original_indent_columns,
11324                            })
11325                        } else {
11326                            None
11327                        },
11328                        cx,
11329                    );
11330                });
11331
11332                let selections = this.selections.all::<usize>(cx);
11333                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11334                    s.select(selections)
11335                });
11336            } else {
11337                this.insert(&clipboard_text, window, cx);
11338            }
11339        });
11340    }
11341
11342    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11343        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11344        if let Some(item) = cx.read_from_clipboard() {
11345            let entries = item.entries();
11346
11347            match entries.first() {
11348                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11349                // of all the pasted entries.
11350                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11351                    .do_paste(
11352                        clipboard_string.text(),
11353                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11354                        true,
11355                        window,
11356                        cx,
11357                    ),
11358                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11359            }
11360        }
11361    }
11362
11363    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11364        if self.read_only(cx) {
11365            return;
11366        }
11367
11368        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11369
11370        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11371            if let Some((selections, _)) =
11372                self.selection_history.transaction(transaction_id).cloned()
11373            {
11374                self.change_selections(None, window, cx, |s| {
11375                    s.select_anchors(selections.to_vec());
11376                });
11377            } else {
11378                log::error!(
11379                    "No entry in selection_history found for undo. \
11380                     This may correspond to a bug where undo does not update the selection. \
11381                     If this is occurring, please add details to \
11382                     https://github.com/zed-industries/zed/issues/22692"
11383                );
11384            }
11385            self.request_autoscroll(Autoscroll::fit(), cx);
11386            self.unmark_text(window, cx);
11387            self.refresh_inline_completion(true, false, window, cx);
11388            cx.emit(EditorEvent::Edited { transaction_id });
11389            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11390        }
11391    }
11392
11393    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11394        if self.read_only(cx) {
11395            return;
11396        }
11397
11398        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11399
11400        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11401            if let Some((_, Some(selections))) =
11402                self.selection_history.transaction(transaction_id).cloned()
11403            {
11404                self.change_selections(None, window, cx, |s| {
11405                    s.select_anchors(selections.to_vec());
11406                });
11407            } else {
11408                log::error!(
11409                    "No entry in selection_history found for redo. \
11410                     This may correspond to a bug where undo does not update the selection. \
11411                     If this is occurring, please add details to \
11412                     https://github.com/zed-industries/zed/issues/22692"
11413                );
11414            }
11415            self.request_autoscroll(Autoscroll::fit(), cx);
11416            self.unmark_text(window, cx);
11417            self.refresh_inline_completion(true, false, window, cx);
11418            cx.emit(EditorEvent::Edited { transaction_id });
11419        }
11420    }
11421
11422    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11423        self.buffer
11424            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11425    }
11426
11427    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11428        self.buffer
11429            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11430    }
11431
11432    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11433        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11434        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11435            s.move_with(|map, selection| {
11436                let cursor = if selection.is_empty() {
11437                    movement::left(map, selection.start)
11438                } else {
11439                    selection.start
11440                };
11441                selection.collapse_to(cursor, SelectionGoal::None);
11442            });
11443        })
11444    }
11445
11446    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11447        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11448        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11449            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11450        })
11451    }
11452
11453    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11454        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11455        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11456            s.move_with(|map, selection| {
11457                let cursor = if selection.is_empty() {
11458                    movement::right(map, selection.end)
11459                } else {
11460                    selection.end
11461                };
11462                selection.collapse_to(cursor, SelectionGoal::None)
11463            });
11464        })
11465    }
11466
11467    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11468        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11469        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11470            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11471        })
11472    }
11473
11474    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11475        if self.take_rename(true, window, cx).is_some() {
11476            return;
11477        }
11478
11479        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11480            cx.propagate();
11481            return;
11482        }
11483
11484        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11485
11486        let text_layout_details = &self.text_layout_details(window);
11487        let selection_count = self.selections.count();
11488        let first_selection = self.selections.first_anchor();
11489
11490        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11491            s.move_with(|map, selection| {
11492                if !selection.is_empty() {
11493                    selection.goal = SelectionGoal::None;
11494                }
11495                let (cursor, goal) = movement::up(
11496                    map,
11497                    selection.start,
11498                    selection.goal,
11499                    false,
11500                    text_layout_details,
11501                );
11502                selection.collapse_to(cursor, goal);
11503            });
11504        });
11505
11506        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11507        {
11508            cx.propagate();
11509        }
11510    }
11511
11512    pub fn move_up_by_lines(
11513        &mut self,
11514        action: &MoveUpByLines,
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::up_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 move_down_by_lines(
11550        &mut self,
11551        action: &MoveDownByLines,
11552        window: &mut Window,
11553        cx: &mut Context<Self>,
11554    ) {
11555        if self.take_rename(true, window, cx).is_some() {
11556            return;
11557        }
11558
11559        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11560            cx.propagate();
11561            return;
11562        }
11563
11564        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11565
11566        let text_layout_details = &self.text_layout_details(window);
11567
11568        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11569            s.move_with(|map, selection| {
11570                if !selection.is_empty() {
11571                    selection.goal = SelectionGoal::None;
11572                }
11573                let (cursor, goal) = movement::down_by_rows(
11574                    map,
11575                    selection.start,
11576                    action.lines,
11577                    selection.goal,
11578                    false,
11579                    text_layout_details,
11580                );
11581                selection.collapse_to(cursor, goal);
11582            });
11583        })
11584    }
11585
11586    pub fn select_down_by_lines(
11587        &mut self,
11588        action: &SelectDownByLines,
11589        window: &mut Window,
11590        cx: &mut Context<Self>,
11591    ) {
11592        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11593        let text_layout_details = &self.text_layout_details(window);
11594        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11595            s.move_heads_with(|map, head, goal| {
11596                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11597            })
11598        })
11599    }
11600
11601    pub fn select_up_by_lines(
11602        &mut self,
11603        action: &SelectUpByLines,
11604        window: &mut Window,
11605        cx: &mut Context<Self>,
11606    ) {
11607        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11608        let text_layout_details = &self.text_layout_details(window);
11609        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11610            s.move_heads_with(|map, head, goal| {
11611                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11612            })
11613        })
11614    }
11615
11616    pub fn select_page_up(
11617        &mut self,
11618        _: &SelectPageUp,
11619        window: &mut Window,
11620        cx: &mut Context<Self>,
11621    ) {
11622        let Some(row_count) = self.visible_row_count() else {
11623            return;
11624        };
11625
11626        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11627
11628        let text_layout_details = &self.text_layout_details(window);
11629
11630        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11631            s.move_heads_with(|map, head, goal| {
11632                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11633            })
11634        })
11635    }
11636
11637    pub fn move_page_up(
11638        &mut self,
11639        action: &MovePageUp,
11640        window: &mut Window,
11641        cx: &mut Context<Self>,
11642    ) {
11643        if self.take_rename(true, window, cx).is_some() {
11644            return;
11645        }
11646
11647        if self
11648            .context_menu
11649            .borrow_mut()
11650            .as_mut()
11651            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11652            .unwrap_or(false)
11653        {
11654            return;
11655        }
11656
11657        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11658            cx.propagate();
11659            return;
11660        }
11661
11662        let Some(row_count) = self.visible_row_count() else {
11663            return;
11664        };
11665
11666        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11667
11668        let autoscroll = if action.center_cursor {
11669            Autoscroll::center()
11670        } else {
11671            Autoscroll::fit()
11672        };
11673
11674        let text_layout_details = &self.text_layout_details(window);
11675
11676        self.change_selections(Some(autoscroll), window, cx, |s| {
11677            s.move_with(|map, selection| {
11678                if !selection.is_empty() {
11679                    selection.goal = SelectionGoal::None;
11680                }
11681                let (cursor, goal) = movement::up_by_rows(
11682                    map,
11683                    selection.end,
11684                    row_count,
11685                    selection.goal,
11686                    false,
11687                    text_layout_details,
11688                );
11689                selection.collapse_to(cursor, goal);
11690            });
11691        });
11692    }
11693
11694    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11695        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11696        let text_layout_details = &self.text_layout_details(window);
11697        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11698            s.move_heads_with(|map, head, goal| {
11699                movement::up(map, head, goal, false, text_layout_details)
11700            })
11701        })
11702    }
11703
11704    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11705        self.take_rename(true, window, cx);
11706
11707        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11708            cx.propagate();
11709            return;
11710        }
11711
11712        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11713
11714        let text_layout_details = &self.text_layout_details(window);
11715        let selection_count = self.selections.count();
11716        let first_selection = self.selections.first_anchor();
11717
11718        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11719            s.move_with(|map, selection| {
11720                if !selection.is_empty() {
11721                    selection.goal = SelectionGoal::None;
11722                }
11723                let (cursor, goal) = movement::down(
11724                    map,
11725                    selection.end,
11726                    selection.goal,
11727                    false,
11728                    text_layout_details,
11729                );
11730                selection.collapse_to(cursor, goal);
11731            });
11732        });
11733
11734        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11735        {
11736            cx.propagate();
11737        }
11738    }
11739
11740    pub fn select_page_down(
11741        &mut self,
11742        _: &SelectPageDown,
11743        window: &mut Window,
11744        cx: &mut Context<Self>,
11745    ) {
11746        let Some(row_count) = self.visible_row_count() else {
11747            return;
11748        };
11749
11750        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11751
11752        let text_layout_details = &self.text_layout_details(window);
11753
11754        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11755            s.move_heads_with(|map, head, goal| {
11756                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11757            })
11758        })
11759    }
11760
11761    pub fn move_page_down(
11762        &mut self,
11763        action: &MovePageDown,
11764        window: &mut Window,
11765        cx: &mut Context<Self>,
11766    ) {
11767        if self.take_rename(true, window, cx).is_some() {
11768            return;
11769        }
11770
11771        if self
11772            .context_menu
11773            .borrow_mut()
11774            .as_mut()
11775            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11776            .unwrap_or(false)
11777        {
11778            return;
11779        }
11780
11781        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11782            cx.propagate();
11783            return;
11784        }
11785
11786        let Some(row_count) = self.visible_row_count() else {
11787            return;
11788        };
11789
11790        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11791
11792        let autoscroll = if action.center_cursor {
11793            Autoscroll::center()
11794        } else {
11795            Autoscroll::fit()
11796        };
11797
11798        let text_layout_details = &self.text_layout_details(window);
11799        self.change_selections(Some(autoscroll), window, cx, |s| {
11800            s.move_with(|map, selection| {
11801                if !selection.is_empty() {
11802                    selection.goal = SelectionGoal::None;
11803                }
11804                let (cursor, goal) = movement::down_by_rows(
11805                    map,
11806                    selection.end,
11807                    row_count,
11808                    selection.goal,
11809                    false,
11810                    text_layout_details,
11811                );
11812                selection.collapse_to(cursor, goal);
11813            });
11814        });
11815    }
11816
11817    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11818        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11819        let text_layout_details = &self.text_layout_details(window);
11820        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11821            s.move_heads_with(|map, head, goal| {
11822                movement::down(map, head, goal, false, text_layout_details)
11823            })
11824        });
11825    }
11826
11827    pub fn context_menu_first(
11828        &mut self,
11829        _: &ContextMenuFirst,
11830        window: &mut Window,
11831        cx: &mut Context<Self>,
11832    ) {
11833        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11834            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11835        }
11836    }
11837
11838    pub fn context_menu_prev(
11839        &mut self,
11840        _: &ContextMenuPrevious,
11841        window: &mut Window,
11842        cx: &mut Context<Self>,
11843    ) {
11844        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11845            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11846        }
11847    }
11848
11849    pub fn context_menu_next(
11850        &mut self,
11851        _: &ContextMenuNext,
11852        window: &mut Window,
11853        cx: &mut Context<Self>,
11854    ) {
11855        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11856            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11857        }
11858    }
11859
11860    pub fn context_menu_last(
11861        &mut self,
11862        _: &ContextMenuLast,
11863        window: &mut Window,
11864        cx: &mut Context<Self>,
11865    ) {
11866        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11867            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11868        }
11869    }
11870
11871    pub fn move_to_previous_word_start(
11872        &mut self,
11873        _: &MoveToPreviousWordStart,
11874        window: &mut Window,
11875        cx: &mut Context<Self>,
11876    ) {
11877        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11878        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11879            s.move_cursors_with(|map, head, _| {
11880                (
11881                    movement::previous_word_start(map, head),
11882                    SelectionGoal::None,
11883                )
11884            });
11885        })
11886    }
11887
11888    pub fn move_to_previous_subword_start(
11889        &mut self,
11890        _: &MoveToPreviousSubwordStart,
11891        window: &mut Window,
11892        cx: &mut Context<Self>,
11893    ) {
11894        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11895        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11896            s.move_cursors_with(|map, head, _| {
11897                (
11898                    movement::previous_subword_start(map, head),
11899                    SelectionGoal::None,
11900                )
11901            });
11902        })
11903    }
11904
11905    pub fn select_to_previous_word_start(
11906        &mut self,
11907        _: &SelectToPreviousWordStart,
11908        window: &mut Window,
11909        cx: &mut Context<Self>,
11910    ) {
11911        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11912        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11913            s.move_heads_with(|map, head, _| {
11914                (
11915                    movement::previous_word_start(map, head),
11916                    SelectionGoal::None,
11917                )
11918            });
11919        })
11920    }
11921
11922    pub fn select_to_previous_subword_start(
11923        &mut self,
11924        _: &SelectToPreviousSubwordStart,
11925        window: &mut Window,
11926        cx: &mut Context<Self>,
11927    ) {
11928        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11929        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11930            s.move_heads_with(|map, head, _| {
11931                (
11932                    movement::previous_subword_start(map, head),
11933                    SelectionGoal::None,
11934                )
11935            });
11936        })
11937    }
11938
11939    pub fn delete_to_previous_word_start(
11940        &mut self,
11941        action: &DeleteToPreviousWordStart,
11942        window: &mut Window,
11943        cx: &mut Context<Self>,
11944    ) {
11945        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11946        self.transact(window, cx, |this, window, cx| {
11947            this.select_autoclose_pair(window, cx);
11948            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11949                s.move_with(|map, selection| {
11950                    if selection.is_empty() {
11951                        let cursor = if action.ignore_newlines {
11952                            movement::previous_word_start(map, selection.head())
11953                        } else {
11954                            movement::previous_word_start_or_newline(map, selection.head())
11955                        };
11956                        selection.set_head(cursor, SelectionGoal::None);
11957                    }
11958                });
11959            });
11960            this.insert("", window, cx);
11961        });
11962    }
11963
11964    pub fn delete_to_previous_subword_start(
11965        &mut self,
11966        _: &DeleteToPreviousSubwordStart,
11967        window: &mut Window,
11968        cx: &mut Context<Self>,
11969    ) {
11970        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11971        self.transact(window, cx, |this, window, cx| {
11972            this.select_autoclose_pair(window, cx);
11973            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11974                s.move_with(|map, selection| {
11975                    if selection.is_empty() {
11976                        let cursor = movement::previous_subword_start(map, selection.head());
11977                        selection.set_head(cursor, SelectionGoal::None);
11978                    }
11979                });
11980            });
11981            this.insert("", window, cx);
11982        });
11983    }
11984
11985    pub fn move_to_next_word_end(
11986        &mut self,
11987        _: &MoveToNextWordEnd,
11988        window: &mut Window,
11989        cx: &mut Context<Self>,
11990    ) {
11991        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11992        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11993            s.move_cursors_with(|map, head, _| {
11994                (movement::next_word_end(map, head), SelectionGoal::None)
11995            });
11996        })
11997    }
11998
11999    pub fn move_to_next_subword_end(
12000        &mut self,
12001        _: &MoveToNextSubwordEnd,
12002        window: &mut Window,
12003        cx: &mut Context<Self>,
12004    ) {
12005        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12006        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12007            s.move_cursors_with(|map, head, _| {
12008                (movement::next_subword_end(map, head), SelectionGoal::None)
12009            });
12010        })
12011    }
12012
12013    pub fn select_to_next_word_end(
12014        &mut self,
12015        _: &SelectToNextWordEnd,
12016        window: &mut Window,
12017        cx: &mut Context<Self>,
12018    ) {
12019        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12020        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12021            s.move_heads_with(|map, head, _| {
12022                (movement::next_word_end(map, head), SelectionGoal::None)
12023            });
12024        })
12025    }
12026
12027    pub fn select_to_next_subword_end(
12028        &mut self,
12029        _: &SelectToNextSubwordEnd,
12030        window: &mut Window,
12031        cx: &mut Context<Self>,
12032    ) {
12033        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12034        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12035            s.move_heads_with(|map, head, _| {
12036                (movement::next_subword_end(map, head), SelectionGoal::None)
12037            });
12038        })
12039    }
12040
12041    pub fn delete_to_next_word_end(
12042        &mut self,
12043        action: &DeleteToNextWordEnd,
12044        window: &mut Window,
12045        cx: &mut Context<Self>,
12046    ) {
12047        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12048        self.transact(window, cx, |this, window, cx| {
12049            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12050                s.move_with(|map, selection| {
12051                    if selection.is_empty() {
12052                        let cursor = if action.ignore_newlines {
12053                            movement::next_word_end(map, selection.head())
12054                        } else {
12055                            movement::next_word_end_or_newline(map, selection.head())
12056                        };
12057                        selection.set_head(cursor, SelectionGoal::None);
12058                    }
12059                });
12060            });
12061            this.insert("", window, cx);
12062        });
12063    }
12064
12065    pub fn delete_to_next_subword_end(
12066        &mut self,
12067        _: &DeleteToNextSubwordEnd,
12068        window: &mut Window,
12069        cx: &mut Context<Self>,
12070    ) {
12071        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12072        self.transact(window, cx, |this, window, cx| {
12073            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12074                s.move_with(|map, selection| {
12075                    if selection.is_empty() {
12076                        let cursor = movement::next_subword_end(map, selection.head());
12077                        selection.set_head(cursor, SelectionGoal::None);
12078                    }
12079                });
12080            });
12081            this.insert("", window, cx);
12082        });
12083    }
12084
12085    pub fn move_to_beginning_of_line(
12086        &mut self,
12087        action: &MoveToBeginningOfLine,
12088        window: &mut Window,
12089        cx: &mut Context<Self>,
12090    ) {
12091        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12092        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12093            s.move_cursors_with(|map, head, _| {
12094                (
12095                    movement::indented_line_beginning(
12096                        map,
12097                        head,
12098                        action.stop_at_soft_wraps,
12099                        action.stop_at_indent,
12100                    ),
12101                    SelectionGoal::None,
12102                )
12103            });
12104        })
12105    }
12106
12107    pub fn select_to_beginning_of_line(
12108        &mut self,
12109        action: &SelectToBeginningOfLine,
12110        window: &mut Window,
12111        cx: &mut Context<Self>,
12112    ) {
12113        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12114        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12115            s.move_heads_with(|map, head, _| {
12116                (
12117                    movement::indented_line_beginning(
12118                        map,
12119                        head,
12120                        action.stop_at_soft_wraps,
12121                        action.stop_at_indent,
12122                    ),
12123                    SelectionGoal::None,
12124                )
12125            });
12126        });
12127    }
12128
12129    pub fn delete_to_beginning_of_line(
12130        &mut self,
12131        action: &DeleteToBeginningOfLine,
12132        window: &mut Window,
12133        cx: &mut Context<Self>,
12134    ) {
12135        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12136        self.transact(window, cx, |this, window, cx| {
12137            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12138                s.move_with(|_, selection| {
12139                    selection.reversed = true;
12140                });
12141            });
12142
12143            this.select_to_beginning_of_line(
12144                &SelectToBeginningOfLine {
12145                    stop_at_soft_wraps: false,
12146                    stop_at_indent: action.stop_at_indent,
12147                },
12148                window,
12149                cx,
12150            );
12151            this.backspace(&Backspace, window, cx);
12152        });
12153    }
12154
12155    pub fn move_to_end_of_line(
12156        &mut self,
12157        action: &MoveToEndOfLine,
12158        window: &mut Window,
12159        cx: &mut Context<Self>,
12160    ) {
12161        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12162        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12163            s.move_cursors_with(|map, head, _| {
12164                (
12165                    movement::line_end(map, head, action.stop_at_soft_wraps),
12166                    SelectionGoal::None,
12167                )
12168            });
12169        })
12170    }
12171
12172    pub fn select_to_end_of_line(
12173        &mut self,
12174        action: &SelectToEndOfLine,
12175        window: &mut Window,
12176        cx: &mut Context<Self>,
12177    ) {
12178        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12179        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12180            s.move_heads_with(|map, head, _| {
12181                (
12182                    movement::line_end(map, head, action.stop_at_soft_wraps),
12183                    SelectionGoal::None,
12184                )
12185            });
12186        })
12187    }
12188
12189    pub fn delete_to_end_of_line(
12190        &mut self,
12191        _: &DeleteToEndOfLine,
12192        window: &mut Window,
12193        cx: &mut Context<Self>,
12194    ) {
12195        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12196        self.transact(window, cx, |this, window, cx| {
12197            this.select_to_end_of_line(
12198                &SelectToEndOfLine {
12199                    stop_at_soft_wraps: false,
12200                },
12201                window,
12202                cx,
12203            );
12204            this.delete(&Delete, window, cx);
12205        });
12206    }
12207
12208    pub fn cut_to_end_of_line(
12209        &mut self,
12210        _: &CutToEndOfLine,
12211        window: &mut Window,
12212        cx: &mut Context<Self>,
12213    ) {
12214        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12215        self.transact(window, cx, |this, window, cx| {
12216            this.select_to_end_of_line(
12217                &SelectToEndOfLine {
12218                    stop_at_soft_wraps: false,
12219                },
12220                window,
12221                cx,
12222            );
12223            this.cut(&Cut, window, cx);
12224        });
12225    }
12226
12227    pub fn move_to_start_of_paragraph(
12228        &mut self,
12229        _: &MoveToStartOfParagraph,
12230        window: &mut Window,
12231        cx: &mut Context<Self>,
12232    ) {
12233        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12234            cx.propagate();
12235            return;
12236        }
12237        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12238        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12239            s.move_with(|map, selection| {
12240                selection.collapse_to(
12241                    movement::start_of_paragraph(map, selection.head(), 1),
12242                    SelectionGoal::None,
12243                )
12244            });
12245        })
12246    }
12247
12248    pub fn move_to_end_of_paragraph(
12249        &mut self,
12250        _: &MoveToEndOfParagraph,
12251        window: &mut Window,
12252        cx: &mut Context<Self>,
12253    ) {
12254        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12255            cx.propagate();
12256            return;
12257        }
12258        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12259        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12260            s.move_with(|map, selection| {
12261                selection.collapse_to(
12262                    movement::end_of_paragraph(map, selection.head(), 1),
12263                    SelectionGoal::None,
12264                )
12265            });
12266        })
12267    }
12268
12269    pub fn select_to_start_of_paragraph(
12270        &mut self,
12271        _: &SelectToStartOfParagraph,
12272        window: &mut Window,
12273        cx: &mut Context<Self>,
12274    ) {
12275        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12276            cx.propagate();
12277            return;
12278        }
12279        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12280        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12281            s.move_heads_with(|map, head, _| {
12282                (
12283                    movement::start_of_paragraph(map, head, 1),
12284                    SelectionGoal::None,
12285                )
12286            });
12287        })
12288    }
12289
12290    pub fn select_to_end_of_paragraph(
12291        &mut self,
12292        _: &SelectToEndOfParagraph,
12293        window: &mut Window,
12294        cx: &mut Context<Self>,
12295    ) {
12296        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12297            cx.propagate();
12298            return;
12299        }
12300        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12301        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12302            s.move_heads_with(|map, head, _| {
12303                (
12304                    movement::end_of_paragraph(map, head, 1),
12305                    SelectionGoal::None,
12306                )
12307            });
12308        })
12309    }
12310
12311    pub fn move_to_start_of_excerpt(
12312        &mut self,
12313        _: &MoveToStartOfExcerpt,
12314        window: &mut Window,
12315        cx: &mut Context<Self>,
12316    ) {
12317        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12318            cx.propagate();
12319            return;
12320        }
12321        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12322        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12323            s.move_with(|map, selection| {
12324                selection.collapse_to(
12325                    movement::start_of_excerpt(
12326                        map,
12327                        selection.head(),
12328                        workspace::searchable::Direction::Prev,
12329                    ),
12330                    SelectionGoal::None,
12331                )
12332            });
12333        })
12334    }
12335
12336    pub fn move_to_start_of_next_excerpt(
12337        &mut self,
12338        _: &MoveToStartOfNextExcerpt,
12339        window: &mut Window,
12340        cx: &mut Context<Self>,
12341    ) {
12342        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12343            cx.propagate();
12344            return;
12345        }
12346
12347        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12348            s.move_with(|map, selection| {
12349                selection.collapse_to(
12350                    movement::start_of_excerpt(
12351                        map,
12352                        selection.head(),
12353                        workspace::searchable::Direction::Next,
12354                    ),
12355                    SelectionGoal::None,
12356                )
12357            });
12358        })
12359    }
12360
12361    pub fn move_to_end_of_excerpt(
12362        &mut self,
12363        _: &MoveToEndOfExcerpt,
12364        window: &mut Window,
12365        cx: &mut Context<Self>,
12366    ) {
12367        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12368            cx.propagate();
12369            return;
12370        }
12371        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12372        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12373            s.move_with(|map, selection| {
12374                selection.collapse_to(
12375                    movement::end_of_excerpt(
12376                        map,
12377                        selection.head(),
12378                        workspace::searchable::Direction::Next,
12379                    ),
12380                    SelectionGoal::None,
12381                )
12382            });
12383        })
12384    }
12385
12386    pub fn move_to_end_of_previous_excerpt(
12387        &mut self,
12388        _: &MoveToEndOfPreviousExcerpt,
12389        window: &mut Window,
12390        cx: &mut Context<Self>,
12391    ) {
12392        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12393            cx.propagate();
12394            return;
12395        }
12396        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12397        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12398            s.move_with(|map, selection| {
12399                selection.collapse_to(
12400                    movement::end_of_excerpt(
12401                        map,
12402                        selection.head(),
12403                        workspace::searchable::Direction::Prev,
12404                    ),
12405                    SelectionGoal::None,
12406                )
12407            });
12408        })
12409    }
12410
12411    pub fn select_to_start_of_excerpt(
12412        &mut self,
12413        _: &SelectToStartOfExcerpt,
12414        window: &mut Window,
12415        cx: &mut Context<Self>,
12416    ) {
12417        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12418            cx.propagate();
12419            return;
12420        }
12421        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12422        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12423            s.move_heads_with(|map, head, _| {
12424                (
12425                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12426                    SelectionGoal::None,
12427                )
12428            });
12429        })
12430    }
12431
12432    pub fn select_to_start_of_next_excerpt(
12433        &mut self,
12434        _: &SelectToStartOfNextExcerpt,
12435        window: &mut Window,
12436        cx: &mut Context<Self>,
12437    ) {
12438        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12439            cx.propagate();
12440            return;
12441        }
12442        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12443        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12444            s.move_heads_with(|map, head, _| {
12445                (
12446                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12447                    SelectionGoal::None,
12448                )
12449            });
12450        })
12451    }
12452
12453    pub fn select_to_end_of_excerpt(
12454        &mut self,
12455        _: &SelectToEndOfExcerpt,
12456        window: &mut Window,
12457        cx: &mut Context<Self>,
12458    ) {
12459        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12460            cx.propagate();
12461            return;
12462        }
12463        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12464        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12465            s.move_heads_with(|map, head, _| {
12466                (
12467                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12468                    SelectionGoal::None,
12469                )
12470            });
12471        })
12472    }
12473
12474    pub fn select_to_end_of_previous_excerpt(
12475        &mut self,
12476        _: &SelectToEndOfPreviousExcerpt,
12477        window: &mut Window,
12478        cx: &mut Context<Self>,
12479    ) {
12480        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12481            cx.propagate();
12482            return;
12483        }
12484        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12485        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12486            s.move_heads_with(|map, head, _| {
12487                (
12488                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12489                    SelectionGoal::None,
12490                )
12491            });
12492        })
12493    }
12494
12495    pub fn move_to_beginning(
12496        &mut self,
12497        _: &MoveToBeginning,
12498        window: &mut Window,
12499        cx: &mut Context<Self>,
12500    ) {
12501        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12502            cx.propagate();
12503            return;
12504        }
12505        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12506        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12507            s.select_ranges(vec![0..0]);
12508        });
12509    }
12510
12511    pub fn select_to_beginning(
12512        &mut self,
12513        _: &SelectToBeginning,
12514        window: &mut Window,
12515        cx: &mut Context<Self>,
12516    ) {
12517        let mut selection = self.selections.last::<Point>(cx);
12518        selection.set_head(Point::zero(), SelectionGoal::None);
12519        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12520        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12521            s.select(vec![selection]);
12522        });
12523    }
12524
12525    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12526        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12527            cx.propagate();
12528            return;
12529        }
12530        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12531        let cursor = self.buffer.read(cx).read(cx).len();
12532        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12533            s.select_ranges(vec![cursor..cursor])
12534        });
12535    }
12536
12537    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12538        self.nav_history = nav_history;
12539    }
12540
12541    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12542        self.nav_history.as_ref()
12543    }
12544
12545    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12546        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12547    }
12548
12549    fn push_to_nav_history(
12550        &mut self,
12551        cursor_anchor: Anchor,
12552        new_position: Option<Point>,
12553        is_deactivate: bool,
12554        cx: &mut Context<Self>,
12555    ) {
12556        if let Some(nav_history) = self.nav_history.as_mut() {
12557            let buffer = self.buffer.read(cx).read(cx);
12558            let cursor_position = cursor_anchor.to_point(&buffer);
12559            let scroll_state = self.scroll_manager.anchor();
12560            let scroll_top_row = scroll_state.top_row(&buffer);
12561            drop(buffer);
12562
12563            if let Some(new_position) = new_position {
12564                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12565                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12566                    return;
12567                }
12568            }
12569
12570            nav_history.push(
12571                Some(NavigationData {
12572                    cursor_anchor,
12573                    cursor_position,
12574                    scroll_anchor: scroll_state,
12575                    scroll_top_row,
12576                }),
12577                cx,
12578            );
12579            cx.emit(EditorEvent::PushedToNavHistory {
12580                anchor: cursor_anchor,
12581                is_deactivate,
12582            })
12583        }
12584    }
12585
12586    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12587        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12588        let buffer = self.buffer.read(cx).snapshot(cx);
12589        let mut selection = self.selections.first::<usize>(cx);
12590        selection.set_head(buffer.len(), SelectionGoal::None);
12591        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12592            s.select(vec![selection]);
12593        });
12594    }
12595
12596    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12597        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12598        let end = self.buffer.read(cx).read(cx).len();
12599        self.change_selections(None, window, cx, |s| {
12600            s.select_ranges(vec![0..end]);
12601        });
12602    }
12603
12604    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12605        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12606        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12607        let mut selections = self.selections.all::<Point>(cx);
12608        let max_point = display_map.buffer_snapshot.max_point();
12609        for selection in &mut selections {
12610            let rows = selection.spanned_rows(true, &display_map);
12611            selection.start = Point::new(rows.start.0, 0);
12612            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12613            selection.reversed = false;
12614        }
12615        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12616            s.select(selections);
12617        });
12618    }
12619
12620    pub fn split_selection_into_lines(
12621        &mut self,
12622        _: &SplitSelectionIntoLines,
12623        window: &mut Window,
12624        cx: &mut Context<Self>,
12625    ) {
12626        let selections = self
12627            .selections
12628            .all::<Point>(cx)
12629            .into_iter()
12630            .map(|selection| selection.start..selection.end)
12631            .collect::<Vec<_>>();
12632        self.unfold_ranges(&selections, true, true, cx);
12633
12634        let mut new_selection_ranges = Vec::new();
12635        {
12636            let buffer = self.buffer.read(cx).read(cx);
12637            for selection in selections {
12638                for row in selection.start.row..selection.end.row {
12639                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12640                    new_selection_ranges.push(cursor..cursor);
12641                }
12642
12643                let is_multiline_selection = selection.start.row != selection.end.row;
12644                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12645                // so this action feels more ergonomic when paired with other selection operations
12646                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12647                if !should_skip_last {
12648                    new_selection_ranges.push(selection.end..selection.end);
12649                }
12650            }
12651        }
12652        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12653            s.select_ranges(new_selection_ranges);
12654        });
12655    }
12656
12657    pub fn add_selection_above(
12658        &mut self,
12659        _: &AddSelectionAbove,
12660        window: &mut Window,
12661        cx: &mut Context<Self>,
12662    ) {
12663        self.add_selection(true, window, cx);
12664    }
12665
12666    pub fn add_selection_below(
12667        &mut self,
12668        _: &AddSelectionBelow,
12669        window: &mut Window,
12670        cx: &mut Context<Self>,
12671    ) {
12672        self.add_selection(false, window, cx);
12673    }
12674
12675    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12676        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12677
12678        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12679        let mut selections = self.selections.all::<Point>(cx);
12680        let text_layout_details = self.text_layout_details(window);
12681        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12682            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12683            let range = oldest_selection.display_range(&display_map).sorted();
12684
12685            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12686            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12687            let positions = start_x.min(end_x)..start_x.max(end_x);
12688
12689            selections.clear();
12690            let mut stack = Vec::new();
12691            for row in range.start.row().0..=range.end.row().0 {
12692                if let Some(selection) = self.selections.build_columnar_selection(
12693                    &display_map,
12694                    DisplayRow(row),
12695                    &positions,
12696                    oldest_selection.reversed,
12697                    &text_layout_details,
12698                ) {
12699                    stack.push(selection.id);
12700                    selections.push(selection);
12701                }
12702            }
12703
12704            if above {
12705                stack.reverse();
12706            }
12707
12708            AddSelectionsState { above, stack }
12709        });
12710
12711        let last_added_selection = *state.stack.last().unwrap();
12712        let mut new_selections = Vec::new();
12713        if above == state.above {
12714            let end_row = if above {
12715                DisplayRow(0)
12716            } else {
12717                display_map.max_point().row()
12718            };
12719
12720            'outer: for selection in selections {
12721                if selection.id == last_added_selection {
12722                    let range = selection.display_range(&display_map).sorted();
12723                    debug_assert_eq!(range.start.row(), range.end.row());
12724                    let mut row = range.start.row();
12725                    let positions =
12726                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12727                            px(start)..px(end)
12728                        } else {
12729                            let start_x =
12730                                display_map.x_for_display_point(range.start, &text_layout_details);
12731                            let end_x =
12732                                display_map.x_for_display_point(range.end, &text_layout_details);
12733                            start_x.min(end_x)..start_x.max(end_x)
12734                        };
12735
12736                    while row != end_row {
12737                        if above {
12738                            row.0 -= 1;
12739                        } else {
12740                            row.0 += 1;
12741                        }
12742
12743                        if let Some(new_selection) = self.selections.build_columnar_selection(
12744                            &display_map,
12745                            row,
12746                            &positions,
12747                            selection.reversed,
12748                            &text_layout_details,
12749                        ) {
12750                            state.stack.push(new_selection.id);
12751                            if above {
12752                                new_selections.push(new_selection);
12753                                new_selections.push(selection);
12754                            } else {
12755                                new_selections.push(selection);
12756                                new_selections.push(new_selection);
12757                            }
12758
12759                            continue 'outer;
12760                        }
12761                    }
12762                }
12763
12764                new_selections.push(selection);
12765            }
12766        } else {
12767            new_selections = selections;
12768            new_selections.retain(|s| s.id != last_added_selection);
12769            state.stack.pop();
12770        }
12771
12772        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12773            s.select(new_selections);
12774        });
12775        if state.stack.len() > 1 {
12776            self.add_selections_state = Some(state);
12777        }
12778    }
12779
12780    fn select_match_ranges(
12781        &mut self,
12782        range: Range<usize>,
12783        reversed: bool,
12784        replace_newest: bool,
12785        auto_scroll: Option<Autoscroll>,
12786        window: &mut Window,
12787        cx: &mut Context<Editor>,
12788    ) {
12789        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12790        self.change_selections(auto_scroll, window, cx, |s| {
12791            if replace_newest {
12792                s.delete(s.newest_anchor().id);
12793            }
12794            if reversed {
12795                s.insert_range(range.end..range.start);
12796            } else {
12797                s.insert_range(range);
12798            }
12799        });
12800    }
12801
12802    pub fn select_next_match_internal(
12803        &mut self,
12804        display_map: &DisplaySnapshot,
12805        replace_newest: bool,
12806        autoscroll: Option<Autoscroll>,
12807        window: &mut Window,
12808        cx: &mut Context<Self>,
12809    ) -> Result<()> {
12810        let buffer = &display_map.buffer_snapshot;
12811        let mut selections = self.selections.all::<usize>(cx);
12812        if let Some(mut select_next_state) = self.select_next_state.take() {
12813            let query = &select_next_state.query;
12814            if !select_next_state.done {
12815                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12816                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12817                let mut next_selected_range = None;
12818
12819                let bytes_after_last_selection =
12820                    buffer.bytes_in_range(last_selection.end..buffer.len());
12821                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12822                let query_matches = query
12823                    .stream_find_iter(bytes_after_last_selection)
12824                    .map(|result| (last_selection.end, result))
12825                    .chain(
12826                        query
12827                            .stream_find_iter(bytes_before_first_selection)
12828                            .map(|result| (0, result)),
12829                    );
12830
12831                for (start_offset, query_match) in query_matches {
12832                    let query_match = query_match.unwrap(); // can only fail due to I/O
12833                    let offset_range =
12834                        start_offset + query_match.start()..start_offset + query_match.end();
12835                    let display_range = offset_range.start.to_display_point(display_map)
12836                        ..offset_range.end.to_display_point(display_map);
12837
12838                    if !select_next_state.wordwise
12839                        || (!movement::is_inside_word(display_map, display_range.start)
12840                            && !movement::is_inside_word(display_map, display_range.end))
12841                    {
12842                        // TODO: This is n^2, because we might check all the selections
12843                        if !selections
12844                            .iter()
12845                            .any(|selection| selection.range().overlaps(&offset_range))
12846                        {
12847                            next_selected_range = Some(offset_range);
12848                            break;
12849                        }
12850                    }
12851                }
12852
12853                if let Some(next_selected_range) = next_selected_range {
12854                    self.select_match_ranges(
12855                        next_selected_range,
12856                        last_selection.reversed,
12857                        replace_newest,
12858                        autoscroll,
12859                        window,
12860                        cx,
12861                    );
12862                } else {
12863                    select_next_state.done = true;
12864                }
12865            }
12866
12867            self.select_next_state = Some(select_next_state);
12868        } else {
12869            let mut only_carets = true;
12870            let mut same_text_selected = true;
12871            let mut selected_text = None;
12872
12873            let mut selections_iter = selections.iter().peekable();
12874            while let Some(selection) = selections_iter.next() {
12875                if selection.start != selection.end {
12876                    only_carets = false;
12877                }
12878
12879                if same_text_selected {
12880                    if selected_text.is_none() {
12881                        selected_text =
12882                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12883                    }
12884
12885                    if let Some(next_selection) = selections_iter.peek() {
12886                        if next_selection.range().len() == selection.range().len() {
12887                            let next_selected_text = buffer
12888                                .text_for_range(next_selection.range())
12889                                .collect::<String>();
12890                            if Some(next_selected_text) != selected_text {
12891                                same_text_selected = false;
12892                                selected_text = None;
12893                            }
12894                        } else {
12895                            same_text_selected = false;
12896                            selected_text = None;
12897                        }
12898                    }
12899                }
12900            }
12901
12902            if only_carets {
12903                for selection in &mut selections {
12904                    let word_range = movement::surrounding_word(
12905                        display_map,
12906                        selection.start.to_display_point(display_map),
12907                    );
12908                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12909                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12910                    selection.goal = SelectionGoal::None;
12911                    selection.reversed = false;
12912                    self.select_match_ranges(
12913                        selection.start..selection.end,
12914                        selection.reversed,
12915                        replace_newest,
12916                        autoscroll,
12917                        window,
12918                        cx,
12919                    );
12920                }
12921
12922                if selections.len() == 1 {
12923                    let selection = selections
12924                        .last()
12925                        .expect("ensured that there's only one selection");
12926                    let query = buffer
12927                        .text_for_range(selection.start..selection.end)
12928                        .collect::<String>();
12929                    let is_empty = query.is_empty();
12930                    let select_state = SelectNextState {
12931                        query: AhoCorasick::new(&[query])?,
12932                        wordwise: true,
12933                        done: is_empty,
12934                    };
12935                    self.select_next_state = Some(select_state);
12936                } else {
12937                    self.select_next_state = None;
12938                }
12939            } else if let Some(selected_text) = selected_text {
12940                self.select_next_state = Some(SelectNextState {
12941                    query: AhoCorasick::new(&[selected_text])?,
12942                    wordwise: false,
12943                    done: false,
12944                });
12945                self.select_next_match_internal(
12946                    display_map,
12947                    replace_newest,
12948                    autoscroll,
12949                    window,
12950                    cx,
12951                )?;
12952            }
12953        }
12954        Ok(())
12955    }
12956
12957    pub fn select_all_matches(
12958        &mut self,
12959        _action: &SelectAllMatches,
12960        window: &mut Window,
12961        cx: &mut Context<Self>,
12962    ) -> Result<()> {
12963        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12964
12965        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12966
12967        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12968        let Some(select_next_state) = self.select_next_state.as_mut() else {
12969            return Ok(());
12970        };
12971        if select_next_state.done {
12972            return Ok(());
12973        }
12974
12975        let mut new_selections = Vec::new();
12976
12977        let reversed = self.selections.oldest::<usize>(cx).reversed;
12978        let buffer = &display_map.buffer_snapshot;
12979        let query_matches = select_next_state
12980            .query
12981            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12982
12983        for query_match in query_matches.into_iter() {
12984            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12985            let offset_range = if reversed {
12986                query_match.end()..query_match.start()
12987            } else {
12988                query_match.start()..query_match.end()
12989            };
12990            let display_range = offset_range.start.to_display_point(&display_map)
12991                ..offset_range.end.to_display_point(&display_map);
12992
12993            if !select_next_state.wordwise
12994                || (!movement::is_inside_word(&display_map, display_range.start)
12995                    && !movement::is_inside_word(&display_map, display_range.end))
12996            {
12997                new_selections.push(offset_range.start..offset_range.end);
12998            }
12999        }
13000
13001        select_next_state.done = true;
13002        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13003        self.change_selections(None, window, cx, |selections| {
13004            selections.select_ranges(new_selections)
13005        });
13006
13007        Ok(())
13008    }
13009
13010    pub fn select_next(
13011        &mut self,
13012        action: &SelectNext,
13013        window: &mut Window,
13014        cx: &mut Context<Self>,
13015    ) -> Result<()> {
13016        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13017        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13018        self.select_next_match_internal(
13019            &display_map,
13020            action.replace_newest,
13021            Some(Autoscroll::newest()),
13022            window,
13023            cx,
13024        )?;
13025        Ok(())
13026    }
13027
13028    pub fn select_previous(
13029        &mut self,
13030        action: &SelectPrevious,
13031        window: &mut Window,
13032        cx: &mut Context<Self>,
13033    ) -> Result<()> {
13034        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13035        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13036        let buffer = &display_map.buffer_snapshot;
13037        let mut selections = self.selections.all::<usize>(cx);
13038        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13039            let query = &select_prev_state.query;
13040            if !select_prev_state.done {
13041                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13042                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13043                let mut next_selected_range = None;
13044                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13045                let bytes_before_last_selection =
13046                    buffer.reversed_bytes_in_range(0..last_selection.start);
13047                let bytes_after_first_selection =
13048                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13049                let query_matches = query
13050                    .stream_find_iter(bytes_before_last_selection)
13051                    .map(|result| (last_selection.start, result))
13052                    .chain(
13053                        query
13054                            .stream_find_iter(bytes_after_first_selection)
13055                            .map(|result| (buffer.len(), result)),
13056                    );
13057                for (end_offset, query_match) in query_matches {
13058                    let query_match = query_match.unwrap(); // can only fail due to I/O
13059                    let offset_range =
13060                        end_offset - query_match.end()..end_offset - query_match.start();
13061                    let display_range = offset_range.start.to_display_point(&display_map)
13062                        ..offset_range.end.to_display_point(&display_map);
13063
13064                    if !select_prev_state.wordwise
13065                        || (!movement::is_inside_word(&display_map, display_range.start)
13066                            && !movement::is_inside_word(&display_map, display_range.end))
13067                    {
13068                        next_selected_range = Some(offset_range);
13069                        break;
13070                    }
13071                }
13072
13073                if let Some(next_selected_range) = next_selected_range {
13074                    self.select_match_ranges(
13075                        next_selected_range,
13076                        last_selection.reversed,
13077                        action.replace_newest,
13078                        Some(Autoscroll::newest()),
13079                        window,
13080                        cx,
13081                    );
13082                } else {
13083                    select_prev_state.done = true;
13084                }
13085            }
13086
13087            self.select_prev_state = Some(select_prev_state);
13088        } else {
13089            let mut only_carets = true;
13090            let mut same_text_selected = true;
13091            let mut selected_text = None;
13092
13093            let mut selections_iter = selections.iter().peekable();
13094            while let Some(selection) = selections_iter.next() {
13095                if selection.start != selection.end {
13096                    only_carets = false;
13097                }
13098
13099                if same_text_selected {
13100                    if selected_text.is_none() {
13101                        selected_text =
13102                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13103                    }
13104
13105                    if let Some(next_selection) = selections_iter.peek() {
13106                        if next_selection.range().len() == selection.range().len() {
13107                            let next_selected_text = buffer
13108                                .text_for_range(next_selection.range())
13109                                .collect::<String>();
13110                            if Some(next_selected_text) != selected_text {
13111                                same_text_selected = false;
13112                                selected_text = None;
13113                            }
13114                        } else {
13115                            same_text_selected = false;
13116                            selected_text = None;
13117                        }
13118                    }
13119                }
13120            }
13121
13122            if only_carets {
13123                for selection in &mut selections {
13124                    let word_range = movement::surrounding_word(
13125                        &display_map,
13126                        selection.start.to_display_point(&display_map),
13127                    );
13128                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13129                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13130                    selection.goal = SelectionGoal::None;
13131                    selection.reversed = false;
13132                    self.select_match_ranges(
13133                        selection.start..selection.end,
13134                        selection.reversed,
13135                        action.replace_newest,
13136                        Some(Autoscroll::newest()),
13137                        window,
13138                        cx,
13139                    );
13140                }
13141                if selections.len() == 1 {
13142                    let selection = selections
13143                        .last()
13144                        .expect("ensured that there's only one selection");
13145                    let query = buffer
13146                        .text_for_range(selection.start..selection.end)
13147                        .collect::<String>();
13148                    let is_empty = query.is_empty();
13149                    let select_state = SelectNextState {
13150                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13151                        wordwise: true,
13152                        done: is_empty,
13153                    };
13154                    self.select_prev_state = Some(select_state);
13155                } else {
13156                    self.select_prev_state = None;
13157                }
13158            } else if let Some(selected_text) = selected_text {
13159                self.select_prev_state = Some(SelectNextState {
13160                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13161                    wordwise: false,
13162                    done: false,
13163                });
13164                self.select_previous(action, window, cx)?;
13165            }
13166        }
13167        Ok(())
13168    }
13169
13170    pub fn find_next_match(
13171        &mut self,
13172        _: &FindNextMatch,
13173        window: &mut Window,
13174        cx: &mut Context<Self>,
13175    ) -> Result<()> {
13176        let selections = self.selections.disjoint_anchors();
13177        match selections.first() {
13178            Some(first) if selections.len() >= 2 => {
13179                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13180                    s.select_ranges([first.range()]);
13181                });
13182            }
13183            _ => self.select_next(
13184                &SelectNext {
13185                    replace_newest: true,
13186                },
13187                window,
13188                cx,
13189            )?,
13190        }
13191        Ok(())
13192    }
13193
13194    pub fn find_previous_match(
13195        &mut self,
13196        _: &FindPreviousMatch,
13197        window: &mut Window,
13198        cx: &mut Context<Self>,
13199    ) -> Result<()> {
13200        let selections = self.selections.disjoint_anchors();
13201        match selections.last() {
13202            Some(last) if selections.len() >= 2 => {
13203                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13204                    s.select_ranges([last.range()]);
13205                });
13206            }
13207            _ => self.select_previous(
13208                &SelectPrevious {
13209                    replace_newest: true,
13210                },
13211                window,
13212                cx,
13213            )?,
13214        }
13215        Ok(())
13216    }
13217
13218    pub fn toggle_comments(
13219        &mut self,
13220        action: &ToggleComments,
13221        window: &mut Window,
13222        cx: &mut Context<Self>,
13223    ) {
13224        if self.read_only(cx) {
13225            return;
13226        }
13227        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13228        let text_layout_details = &self.text_layout_details(window);
13229        self.transact(window, cx, |this, window, cx| {
13230            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13231            let mut edits = Vec::new();
13232            let mut selection_edit_ranges = Vec::new();
13233            let mut last_toggled_row = None;
13234            let snapshot = this.buffer.read(cx).read(cx);
13235            let empty_str: Arc<str> = Arc::default();
13236            let mut suffixes_inserted = Vec::new();
13237            let ignore_indent = action.ignore_indent;
13238
13239            fn comment_prefix_range(
13240                snapshot: &MultiBufferSnapshot,
13241                row: MultiBufferRow,
13242                comment_prefix: &str,
13243                comment_prefix_whitespace: &str,
13244                ignore_indent: bool,
13245            ) -> Range<Point> {
13246                let indent_size = if ignore_indent {
13247                    0
13248                } else {
13249                    snapshot.indent_size_for_line(row).len
13250                };
13251
13252                let start = Point::new(row.0, indent_size);
13253
13254                let mut line_bytes = snapshot
13255                    .bytes_in_range(start..snapshot.max_point())
13256                    .flatten()
13257                    .copied();
13258
13259                // If this line currently begins with the line comment prefix, then record
13260                // the range containing the prefix.
13261                if line_bytes
13262                    .by_ref()
13263                    .take(comment_prefix.len())
13264                    .eq(comment_prefix.bytes())
13265                {
13266                    // Include any whitespace that matches the comment prefix.
13267                    let matching_whitespace_len = line_bytes
13268                        .zip(comment_prefix_whitespace.bytes())
13269                        .take_while(|(a, b)| a == b)
13270                        .count() as u32;
13271                    let end = Point::new(
13272                        start.row,
13273                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13274                    );
13275                    start..end
13276                } else {
13277                    start..start
13278                }
13279            }
13280
13281            fn comment_suffix_range(
13282                snapshot: &MultiBufferSnapshot,
13283                row: MultiBufferRow,
13284                comment_suffix: &str,
13285                comment_suffix_has_leading_space: bool,
13286            ) -> Range<Point> {
13287                let end = Point::new(row.0, snapshot.line_len(row));
13288                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13289
13290                let mut line_end_bytes = snapshot
13291                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13292                    .flatten()
13293                    .copied();
13294
13295                let leading_space_len = if suffix_start_column > 0
13296                    && line_end_bytes.next() == Some(b' ')
13297                    && comment_suffix_has_leading_space
13298                {
13299                    1
13300                } else {
13301                    0
13302                };
13303
13304                // If this line currently begins with the line comment prefix, then record
13305                // the range containing the prefix.
13306                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13307                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13308                    start..end
13309                } else {
13310                    end..end
13311                }
13312            }
13313
13314            // TODO: Handle selections that cross excerpts
13315            for selection in &mut selections {
13316                let start_column = snapshot
13317                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13318                    .len;
13319                let language = if let Some(language) =
13320                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13321                {
13322                    language
13323                } else {
13324                    continue;
13325                };
13326
13327                selection_edit_ranges.clear();
13328
13329                // If multiple selections contain a given row, avoid processing that
13330                // row more than once.
13331                let mut start_row = MultiBufferRow(selection.start.row);
13332                if last_toggled_row == Some(start_row) {
13333                    start_row = start_row.next_row();
13334                }
13335                let end_row =
13336                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13337                        MultiBufferRow(selection.end.row - 1)
13338                    } else {
13339                        MultiBufferRow(selection.end.row)
13340                    };
13341                last_toggled_row = Some(end_row);
13342
13343                if start_row > end_row {
13344                    continue;
13345                }
13346
13347                // If the language has line comments, toggle those.
13348                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13349
13350                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13351                if ignore_indent {
13352                    full_comment_prefixes = full_comment_prefixes
13353                        .into_iter()
13354                        .map(|s| Arc::from(s.trim_end()))
13355                        .collect();
13356                }
13357
13358                if !full_comment_prefixes.is_empty() {
13359                    let first_prefix = full_comment_prefixes
13360                        .first()
13361                        .expect("prefixes is non-empty");
13362                    let prefix_trimmed_lengths = full_comment_prefixes
13363                        .iter()
13364                        .map(|p| p.trim_end_matches(' ').len())
13365                        .collect::<SmallVec<[usize; 4]>>();
13366
13367                    let mut all_selection_lines_are_comments = true;
13368
13369                    for row in start_row.0..=end_row.0 {
13370                        let row = MultiBufferRow(row);
13371                        if start_row < end_row && snapshot.is_line_blank(row) {
13372                            continue;
13373                        }
13374
13375                        let prefix_range = full_comment_prefixes
13376                            .iter()
13377                            .zip(prefix_trimmed_lengths.iter().copied())
13378                            .map(|(prefix, trimmed_prefix_len)| {
13379                                comment_prefix_range(
13380                                    snapshot.deref(),
13381                                    row,
13382                                    &prefix[..trimmed_prefix_len],
13383                                    &prefix[trimmed_prefix_len..],
13384                                    ignore_indent,
13385                                )
13386                            })
13387                            .max_by_key(|range| range.end.column - range.start.column)
13388                            .expect("prefixes is non-empty");
13389
13390                        if prefix_range.is_empty() {
13391                            all_selection_lines_are_comments = false;
13392                        }
13393
13394                        selection_edit_ranges.push(prefix_range);
13395                    }
13396
13397                    if all_selection_lines_are_comments {
13398                        edits.extend(
13399                            selection_edit_ranges
13400                                .iter()
13401                                .cloned()
13402                                .map(|range| (range, empty_str.clone())),
13403                        );
13404                    } else {
13405                        let min_column = selection_edit_ranges
13406                            .iter()
13407                            .map(|range| range.start.column)
13408                            .min()
13409                            .unwrap_or(0);
13410                        edits.extend(selection_edit_ranges.iter().map(|range| {
13411                            let position = Point::new(range.start.row, min_column);
13412                            (position..position, first_prefix.clone())
13413                        }));
13414                    }
13415                } else if let Some((full_comment_prefix, comment_suffix)) =
13416                    language.block_comment_delimiters()
13417                {
13418                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13419                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13420                    let prefix_range = comment_prefix_range(
13421                        snapshot.deref(),
13422                        start_row,
13423                        comment_prefix,
13424                        comment_prefix_whitespace,
13425                        ignore_indent,
13426                    );
13427                    let suffix_range = comment_suffix_range(
13428                        snapshot.deref(),
13429                        end_row,
13430                        comment_suffix.trim_start_matches(' '),
13431                        comment_suffix.starts_with(' '),
13432                    );
13433
13434                    if prefix_range.is_empty() || suffix_range.is_empty() {
13435                        edits.push((
13436                            prefix_range.start..prefix_range.start,
13437                            full_comment_prefix.clone(),
13438                        ));
13439                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13440                        suffixes_inserted.push((end_row, comment_suffix.len()));
13441                    } else {
13442                        edits.push((prefix_range, empty_str.clone()));
13443                        edits.push((suffix_range, empty_str.clone()));
13444                    }
13445                } else {
13446                    continue;
13447                }
13448            }
13449
13450            drop(snapshot);
13451            this.buffer.update(cx, |buffer, cx| {
13452                buffer.edit(edits, None, cx);
13453            });
13454
13455            // Adjust selections so that they end before any comment suffixes that
13456            // were inserted.
13457            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13458            let mut selections = this.selections.all::<Point>(cx);
13459            let snapshot = this.buffer.read(cx).read(cx);
13460            for selection in &mut selections {
13461                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13462                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13463                        Ordering::Less => {
13464                            suffixes_inserted.next();
13465                            continue;
13466                        }
13467                        Ordering::Greater => break,
13468                        Ordering::Equal => {
13469                            if selection.end.column == snapshot.line_len(row) {
13470                                if selection.is_empty() {
13471                                    selection.start.column -= suffix_len as u32;
13472                                }
13473                                selection.end.column -= suffix_len as u32;
13474                            }
13475                            break;
13476                        }
13477                    }
13478                }
13479            }
13480
13481            drop(snapshot);
13482            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13483                s.select(selections)
13484            });
13485
13486            let selections = this.selections.all::<Point>(cx);
13487            let selections_on_single_row = selections.windows(2).all(|selections| {
13488                selections[0].start.row == selections[1].start.row
13489                    && selections[0].end.row == selections[1].end.row
13490                    && selections[0].start.row == selections[0].end.row
13491            });
13492            let selections_selecting = selections
13493                .iter()
13494                .any(|selection| selection.start != selection.end);
13495            let advance_downwards = action.advance_downwards
13496                && selections_on_single_row
13497                && !selections_selecting
13498                && !matches!(this.mode, EditorMode::SingleLine { .. });
13499
13500            if advance_downwards {
13501                let snapshot = this.buffer.read(cx).snapshot(cx);
13502
13503                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13504                    s.move_cursors_with(|display_snapshot, display_point, _| {
13505                        let mut point = display_point.to_point(display_snapshot);
13506                        point.row += 1;
13507                        point = snapshot.clip_point(point, Bias::Left);
13508                        let display_point = point.to_display_point(display_snapshot);
13509                        let goal = SelectionGoal::HorizontalPosition(
13510                            display_snapshot
13511                                .x_for_display_point(display_point, text_layout_details)
13512                                .into(),
13513                        );
13514                        (display_point, goal)
13515                    })
13516                });
13517            }
13518        });
13519    }
13520
13521    pub fn select_enclosing_symbol(
13522        &mut self,
13523        _: &SelectEnclosingSymbol,
13524        window: &mut Window,
13525        cx: &mut Context<Self>,
13526    ) {
13527        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13528
13529        let buffer = self.buffer.read(cx).snapshot(cx);
13530        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13531
13532        fn update_selection(
13533            selection: &Selection<usize>,
13534            buffer_snap: &MultiBufferSnapshot,
13535        ) -> Option<Selection<usize>> {
13536            let cursor = selection.head();
13537            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13538            for symbol in symbols.iter().rev() {
13539                let start = symbol.range.start.to_offset(buffer_snap);
13540                let end = symbol.range.end.to_offset(buffer_snap);
13541                let new_range = start..end;
13542                if start < selection.start || end > selection.end {
13543                    return Some(Selection {
13544                        id: selection.id,
13545                        start: new_range.start,
13546                        end: new_range.end,
13547                        goal: SelectionGoal::None,
13548                        reversed: selection.reversed,
13549                    });
13550                }
13551            }
13552            None
13553        }
13554
13555        let mut selected_larger_symbol = false;
13556        let new_selections = old_selections
13557            .iter()
13558            .map(|selection| match update_selection(selection, &buffer) {
13559                Some(new_selection) => {
13560                    if new_selection.range() != selection.range() {
13561                        selected_larger_symbol = true;
13562                    }
13563                    new_selection
13564                }
13565                None => selection.clone(),
13566            })
13567            .collect::<Vec<_>>();
13568
13569        if selected_larger_symbol {
13570            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13571                s.select(new_selections);
13572            });
13573        }
13574    }
13575
13576    pub fn select_larger_syntax_node(
13577        &mut self,
13578        _: &SelectLargerSyntaxNode,
13579        window: &mut Window,
13580        cx: &mut Context<Self>,
13581    ) {
13582        let Some(visible_row_count) = self.visible_row_count() else {
13583            return;
13584        };
13585        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13586        if old_selections.is_empty() {
13587            return;
13588        }
13589
13590        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13591
13592        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13593        let buffer = self.buffer.read(cx).snapshot(cx);
13594
13595        let mut selected_larger_node = false;
13596        let mut new_selections = old_selections
13597            .iter()
13598            .map(|selection| {
13599                let old_range = selection.start..selection.end;
13600
13601                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13602                    // manually select word at selection
13603                    if ["string_content", "inline"].contains(&node.kind()) {
13604                        let word_range = {
13605                            let display_point = buffer
13606                                .offset_to_point(old_range.start)
13607                                .to_display_point(&display_map);
13608                            let Range { start, end } =
13609                                movement::surrounding_word(&display_map, display_point);
13610                            start.to_point(&display_map).to_offset(&buffer)
13611                                ..end.to_point(&display_map).to_offset(&buffer)
13612                        };
13613                        // ignore if word is already selected
13614                        if !word_range.is_empty() && old_range != word_range {
13615                            let last_word_range = {
13616                                let display_point = buffer
13617                                    .offset_to_point(old_range.end)
13618                                    .to_display_point(&display_map);
13619                                let Range { start, end } =
13620                                    movement::surrounding_word(&display_map, display_point);
13621                                start.to_point(&display_map).to_offset(&buffer)
13622                                    ..end.to_point(&display_map).to_offset(&buffer)
13623                            };
13624                            // only select word if start and end point belongs to same word
13625                            if word_range == last_word_range {
13626                                selected_larger_node = true;
13627                                return Selection {
13628                                    id: selection.id,
13629                                    start: word_range.start,
13630                                    end: word_range.end,
13631                                    goal: SelectionGoal::None,
13632                                    reversed: selection.reversed,
13633                                };
13634                            }
13635                        }
13636                    }
13637                }
13638
13639                let mut new_range = old_range.clone();
13640                while let Some((_node, containing_range)) =
13641                    buffer.syntax_ancestor(new_range.clone())
13642                {
13643                    new_range = match containing_range {
13644                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13645                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13646                    };
13647                    if !display_map.intersects_fold(new_range.start)
13648                        && !display_map.intersects_fold(new_range.end)
13649                    {
13650                        break;
13651                    }
13652                }
13653
13654                selected_larger_node |= new_range != old_range;
13655                Selection {
13656                    id: selection.id,
13657                    start: new_range.start,
13658                    end: new_range.end,
13659                    goal: SelectionGoal::None,
13660                    reversed: selection.reversed,
13661                }
13662            })
13663            .collect::<Vec<_>>();
13664
13665        if !selected_larger_node {
13666            return; // don't put this call in the history
13667        }
13668
13669        // scroll based on transformation done to the last selection created by the user
13670        let (last_old, last_new) = old_selections
13671            .last()
13672            .zip(new_selections.last().cloned())
13673            .expect("old_selections isn't empty");
13674
13675        // revert selection
13676        let is_selection_reversed = {
13677            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13678            new_selections.last_mut().expect("checked above").reversed =
13679                should_newest_selection_be_reversed;
13680            should_newest_selection_be_reversed
13681        };
13682
13683        if selected_larger_node {
13684            self.select_syntax_node_history.disable_clearing = true;
13685            self.change_selections(None, window, cx, |s| {
13686                s.select(new_selections.clone());
13687            });
13688            self.select_syntax_node_history.disable_clearing = false;
13689        }
13690
13691        let start_row = last_new.start.to_display_point(&display_map).row().0;
13692        let end_row = last_new.end.to_display_point(&display_map).row().0;
13693        let selection_height = end_row - start_row + 1;
13694        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13695
13696        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13697        let scroll_behavior = if fits_on_the_screen {
13698            self.request_autoscroll(Autoscroll::fit(), cx);
13699            SelectSyntaxNodeScrollBehavior::FitSelection
13700        } else if is_selection_reversed {
13701            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13702            SelectSyntaxNodeScrollBehavior::CursorTop
13703        } else {
13704            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13705            SelectSyntaxNodeScrollBehavior::CursorBottom
13706        };
13707
13708        self.select_syntax_node_history.push((
13709            old_selections,
13710            scroll_behavior,
13711            is_selection_reversed,
13712        ));
13713    }
13714
13715    pub fn select_smaller_syntax_node(
13716        &mut self,
13717        _: &SelectSmallerSyntaxNode,
13718        window: &mut Window,
13719        cx: &mut Context<Self>,
13720    ) {
13721        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13722
13723        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13724            self.select_syntax_node_history.pop()
13725        {
13726            if let Some(selection) = selections.last_mut() {
13727                selection.reversed = is_selection_reversed;
13728            }
13729
13730            self.select_syntax_node_history.disable_clearing = true;
13731            self.change_selections(None, window, cx, |s| {
13732                s.select(selections.to_vec());
13733            });
13734            self.select_syntax_node_history.disable_clearing = false;
13735
13736            match scroll_behavior {
13737                SelectSyntaxNodeScrollBehavior::CursorTop => {
13738                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13739                }
13740                SelectSyntaxNodeScrollBehavior::FitSelection => {
13741                    self.request_autoscroll(Autoscroll::fit(), cx);
13742                }
13743                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13744                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13745                }
13746            }
13747        }
13748    }
13749
13750    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13751        if !EditorSettings::get_global(cx).gutter.runnables {
13752            self.clear_tasks();
13753            return Task::ready(());
13754        }
13755        let project = self.project.as_ref().map(Entity::downgrade);
13756        let task_sources = self.lsp_task_sources(cx);
13757        let multi_buffer = self.buffer.downgrade();
13758        cx.spawn_in(window, async move |editor, cx| {
13759            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13760            let Some(project) = project.and_then(|p| p.upgrade()) else {
13761                return;
13762            };
13763            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13764                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13765            }) else {
13766                return;
13767            };
13768
13769            let hide_runnables = project
13770                .update(cx, |project, cx| {
13771                    // Do not display any test indicators in non-dev server remote projects.
13772                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13773                })
13774                .unwrap_or(true);
13775            if hide_runnables {
13776                return;
13777            }
13778            let new_rows =
13779                cx.background_spawn({
13780                    let snapshot = display_snapshot.clone();
13781                    async move {
13782                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13783                    }
13784                })
13785                    .await;
13786            let Ok(lsp_tasks) =
13787                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13788            else {
13789                return;
13790            };
13791            let lsp_tasks = lsp_tasks.await;
13792
13793            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13794                lsp_tasks
13795                    .into_iter()
13796                    .flat_map(|(kind, tasks)| {
13797                        tasks.into_iter().filter_map(move |(location, task)| {
13798                            Some((kind.clone(), location?, task))
13799                        })
13800                    })
13801                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13802                        let buffer = location.target.buffer;
13803                        let buffer_snapshot = buffer.read(cx).snapshot();
13804                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13805                            |(excerpt_id, snapshot, _)| {
13806                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13807                                    display_snapshot
13808                                        .buffer_snapshot
13809                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13810                                } else {
13811                                    None
13812                                }
13813                            },
13814                        );
13815                        if let Some(offset) = offset {
13816                            let task_buffer_range =
13817                                location.target.range.to_point(&buffer_snapshot);
13818                            let context_buffer_range =
13819                                task_buffer_range.to_offset(&buffer_snapshot);
13820                            let context_range = BufferOffset(context_buffer_range.start)
13821                                ..BufferOffset(context_buffer_range.end);
13822
13823                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13824                                .or_insert_with(|| RunnableTasks {
13825                                    templates: Vec::new(),
13826                                    offset,
13827                                    column: task_buffer_range.start.column,
13828                                    extra_variables: HashMap::default(),
13829                                    context_range,
13830                                })
13831                                .templates
13832                                .push((kind, task.original_task().clone()));
13833                        }
13834
13835                        acc
13836                    })
13837            }) else {
13838                return;
13839            };
13840
13841            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
13842                buffer.language_settings(cx).tasks.prefer_lsp
13843            }) else {
13844                return;
13845            };
13846
13847            let rows = Self::runnable_rows(
13848                project,
13849                display_snapshot,
13850                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
13851                new_rows,
13852                cx.clone(),
13853            );
13854            editor
13855                .update(cx, |editor, _| {
13856                    editor.clear_tasks();
13857                    for (key, mut value) in rows {
13858                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13859                            value.templates.extend(lsp_tasks.templates);
13860                        }
13861
13862                        editor.insert_tasks(key, value);
13863                    }
13864                    for (key, value) in lsp_tasks_by_rows {
13865                        editor.insert_tasks(key, value);
13866                    }
13867                })
13868                .ok();
13869        })
13870    }
13871    fn fetch_runnable_ranges(
13872        snapshot: &DisplaySnapshot,
13873        range: Range<Anchor>,
13874    ) -> Vec<language::RunnableRange> {
13875        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13876    }
13877
13878    fn runnable_rows(
13879        project: Entity<Project>,
13880        snapshot: DisplaySnapshot,
13881        prefer_lsp: bool,
13882        runnable_ranges: Vec<RunnableRange>,
13883        mut cx: AsyncWindowContext,
13884    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13885        runnable_ranges
13886            .into_iter()
13887            .filter_map(|mut runnable| {
13888                let mut tasks = cx
13889                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13890                    .ok()?;
13891                if prefer_lsp {
13892                    tasks.retain(|(task_kind, _)| {
13893                        !matches!(task_kind, TaskSourceKind::Language { .. })
13894                    });
13895                }
13896                if tasks.is_empty() {
13897                    return None;
13898                }
13899
13900                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13901
13902                let row = snapshot
13903                    .buffer_snapshot
13904                    .buffer_line_for_row(MultiBufferRow(point.row))?
13905                    .1
13906                    .start
13907                    .row;
13908
13909                let context_range =
13910                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13911                Some((
13912                    (runnable.buffer_id, row),
13913                    RunnableTasks {
13914                        templates: tasks,
13915                        offset: snapshot
13916                            .buffer_snapshot
13917                            .anchor_before(runnable.run_range.start),
13918                        context_range,
13919                        column: point.column,
13920                        extra_variables: runnable.extra_captures,
13921                    },
13922                ))
13923            })
13924            .collect()
13925    }
13926
13927    fn templates_with_tags(
13928        project: &Entity<Project>,
13929        runnable: &mut Runnable,
13930        cx: &mut App,
13931    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13932        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13933            let (worktree_id, file) = project
13934                .buffer_for_id(runnable.buffer, cx)
13935                .and_then(|buffer| buffer.read(cx).file())
13936                .map(|file| (file.worktree_id(cx), file.clone()))
13937                .unzip();
13938
13939            (
13940                project.task_store().read(cx).task_inventory().cloned(),
13941                worktree_id,
13942                file,
13943            )
13944        });
13945
13946        let mut templates_with_tags = mem::take(&mut runnable.tags)
13947            .into_iter()
13948            .flat_map(|RunnableTag(tag)| {
13949                inventory
13950                    .as_ref()
13951                    .into_iter()
13952                    .flat_map(|inventory| {
13953                        inventory.read(cx).list_tasks(
13954                            file.clone(),
13955                            Some(runnable.language.clone()),
13956                            worktree_id,
13957                            cx,
13958                        )
13959                    })
13960                    .filter(move |(_, template)| {
13961                        template.tags.iter().any(|source_tag| source_tag == &tag)
13962                    })
13963            })
13964            .sorted_by_key(|(kind, _)| kind.to_owned())
13965            .collect::<Vec<_>>();
13966        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13967            // Strongest source wins; if we have worktree tag binding, prefer that to
13968            // global and language bindings;
13969            // if we have a global binding, prefer that to language binding.
13970            let first_mismatch = templates_with_tags
13971                .iter()
13972                .position(|(tag_source, _)| tag_source != leading_tag_source);
13973            if let Some(index) = first_mismatch {
13974                templates_with_tags.truncate(index);
13975            }
13976        }
13977
13978        templates_with_tags
13979    }
13980
13981    pub fn move_to_enclosing_bracket(
13982        &mut self,
13983        _: &MoveToEnclosingBracket,
13984        window: &mut Window,
13985        cx: &mut Context<Self>,
13986    ) {
13987        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13988        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13989            s.move_offsets_with(|snapshot, selection| {
13990                let Some(enclosing_bracket_ranges) =
13991                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13992                else {
13993                    return;
13994                };
13995
13996                let mut best_length = usize::MAX;
13997                let mut best_inside = false;
13998                let mut best_in_bracket_range = false;
13999                let mut best_destination = None;
14000                for (open, close) in enclosing_bracket_ranges {
14001                    let close = close.to_inclusive();
14002                    let length = close.end() - open.start;
14003                    let inside = selection.start >= open.end && selection.end <= *close.start();
14004                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14005                        || close.contains(&selection.head());
14006
14007                    // If best is next to a bracket and current isn't, skip
14008                    if !in_bracket_range && best_in_bracket_range {
14009                        continue;
14010                    }
14011
14012                    // Prefer smaller lengths unless best is inside and current isn't
14013                    if length > best_length && (best_inside || !inside) {
14014                        continue;
14015                    }
14016
14017                    best_length = length;
14018                    best_inside = inside;
14019                    best_in_bracket_range = in_bracket_range;
14020                    best_destination = Some(
14021                        if close.contains(&selection.start) && close.contains(&selection.end) {
14022                            if inside { open.end } else { open.start }
14023                        } else if inside {
14024                            *close.start()
14025                        } else {
14026                            *close.end()
14027                        },
14028                    );
14029                }
14030
14031                if let Some(destination) = best_destination {
14032                    selection.collapse_to(destination, SelectionGoal::None);
14033                }
14034            })
14035        });
14036    }
14037
14038    pub fn undo_selection(
14039        &mut self,
14040        _: &UndoSelection,
14041        window: &mut Window,
14042        cx: &mut Context<Self>,
14043    ) {
14044        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14045        self.end_selection(window, cx);
14046        self.selection_history.mode = SelectionHistoryMode::Undoing;
14047        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14048            self.change_selections(None, window, cx, |s| {
14049                s.select_anchors(entry.selections.to_vec())
14050            });
14051            self.select_next_state = entry.select_next_state;
14052            self.select_prev_state = entry.select_prev_state;
14053            self.add_selections_state = entry.add_selections_state;
14054            self.request_autoscroll(Autoscroll::newest(), cx);
14055        }
14056        self.selection_history.mode = SelectionHistoryMode::Normal;
14057    }
14058
14059    pub fn redo_selection(
14060        &mut self,
14061        _: &RedoSelection,
14062        window: &mut Window,
14063        cx: &mut Context<Self>,
14064    ) {
14065        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14066        self.end_selection(window, cx);
14067        self.selection_history.mode = SelectionHistoryMode::Redoing;
14068        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14069            self.change_selections(None, window, cx, |s| {
14070                s.select_anchors(entry.selections.to_vec())
14071            });
14072            self.select_next_state = entry.select_next_state;
14073            self.select_prev_state = entry.select_prev_state;
14074            self.add_selections_state = entry.add_selections_state;
14075            self.request_autoscroll(Autoscroll::newest(), cx);
14076        }
14077        self.selection_history.mode = SelectionHistoryMode::Normal;
14078    }
14079
14080    pub fn expand_excerpts(
14081        &mut self,
14082        action: &ExpandExcerpts,
14083        _: &mut Window,
14084        cx: &mut Context<Self>,
14085    ) {
14086        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14087    }
14088
14089    pub fn expand_excerpts_down(
14090        &mut self,
14091        action: &ExpandExcerptsDown,
14092        _: &mut Window,
14093        cx: &mut Context<Self>,
14094    ) {
14095        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14096    }
14097
14098    pub fn expand_excerpts_up(
14099        &mut self,
14100        action: &ExpandExcerptsUp,
14101        _: &mut Window,
14102        cx: &mut Context<Self>,
14103    ) {
14104        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14105    }
14106
14107    pub fn expand_excerpts_for_direction(
14108        &mut self,
14109        lines: u32,
14110        direction: ExpandExcerptDirection,
14111
14112        cx: &mut Context<Self>,
14113    ) {
14114        let selections = self.selections.disjoint_anchors();
14115
14116        let lines = if lines == 0 {
14117            EditorSettings::get_global(cx).expand_excerpt_lines
14118        } else {
14119            lines
14120        };
14121
14122        self.buffer.update(cx, |buffer, cx| {
14123            let snapshot = buffer.snapshot(cx);
14124            let mut excerpt_ids = selections
14125                .iter()
14126                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14127                .collect::<Vec<_>>();
14128            excerpt_ids.sort();
14129            excerpt_ids.dedup();
14130            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14131        })
14132    }
14133
14134    pub fn expand_excerpt(
14135        &mut self,
14136        excerpt: ExcerptId,
14137        direction: ExpandExcerptDirection,
14138        window: &mut Window,
14139        cx: &mut Context<Self>,
14140    ) {
14141        let current_scroll_position = self.scroll_position(cx);
14142        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14143        let mut should_scroll_up = false;
14144
14145        if direction == ExpandExcerptDirection::Down {
14146            let multi_buffer = self.buffer.read(cx);
14147            let snapshot = multi_buffer.snapshot(cx);
14148            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14149                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14150                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14151                        let buffer_snapshot = buffer.read(cx).snapshot();
14152                        let excerpt_end_row =
14153                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14154                        let last_row = buffer_snapshot.max_point().row;
14155                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14156                        should_scroll_up = lines_below >= lines_to_expand;
14157                    }
14158                }
14159            }
14160        }
14161
14162        self.buffer.update(cx, |buffer, cx| {
14163            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14164        });
14165
14166        if should_scroll_up {
14167            let new_scroll_position =
14168                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14169            self.set_scroll_position(new_scroll_position, window, cx);
14170        }
14171    }
14172
14173    pub fn go_to_singleton_buffer_point(
14174        &mut self,
14175        point: Point,
14176        window: &mut Window,
14177        cx: &mut Context<Self>,
14178    ) {
14179        self.go_to_singleton_buffer_range(point..point, window, cx);
14180    }
14181
14182    pub fn go_to_singleton_buffer_range(
14183        &mut self,
14184        range: Range<Point>,
14185        window: &mut Window,
14186        cx: &mut Context<Self>,
14187    ) {
14188        let multibuffer = self.buffer().read(cx);
14189        let Some(buffer) = multibuffer.as_singleton() else {
14190            return;
14191        };
14192        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14193            return;
14194        };
14195        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14196            return;
14197        };
14198        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14199            s.select_anchor_ranges([start..end])
14200        });
14201    }
14202
14203    pub fn go_to_diagnostic(
14204        &mut self,
14205        _: &GoToDiagnostic,
14206        window: &mut Window,
14207        cx: &mut Context<Self>,
14208    ) {
14209        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14210        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14211    }
14212
14213    pub fn go_to_prev_diagnostic(
14214        &mut self,
14215        _: &GoToPreviousDiagnostic,
14216        window: &mut Window,
14217        cx: &mut Context<Self>,
14218    ) {
14219        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14220        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14221    }
14222
14223    pub fn go_to_diagnostic_impl(
14224        &mut self,
14225        direction: Direction,
14226        window: &mut Window,
14227        cx: &mut Context<Self>,
14228    ) {
14229        let buffer = self.buffer.read(cx).snapshot(cx);
14230        let selection = self.selections.newest::<usize>(cx);
14231
14232        let mut active_group_id = None;
14233        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14234            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14235                active_group_id = Some(active_group.group_id);
14236            }
14237        }
14238
14239        fn filtered(
14240            snapshot: EditorSnapshot,
14241            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14242        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14243            diagnostics
14244                .filter(|entry| entry.range.start != entry.range.end)
14245                .filter(|entry| !entry.diagnostic.is_unnecessary)
14246                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14247        }
14248
14249        let snapshot = self.snapshot(window, cx);
14250        let before = filtered(
14251            snapshot.clone(),
14252            buffer
14253                .diagnostics_in_range(0..selection.start)
14254                .filter(|entry| entry.range.start <= selection.start),
14255        );
14256        let after = filtered(
14257            snapshot,
14258            buffer
14259                .diagnostics_in_range(selection.start..buffer.len())
14260                .filter(|entry| entry.range.start >= selection.start),
14261        );
14262
14263        let mut found: Option<DiagnosticEntry<usize>> = None;
14264        if direction == Direction::Prev {
14265            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14266            {
14267                for diagnostic in prev_diagnostics.into_iter().rev() {
14268                    if diagnostic.range.start != selection.start
14269                        || active_group_id
14270                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14271                    {
14272                        found = Some(diagnostic);
14273                        break 'outer;
14274                    }
14275                }
14276            }
14277        } else {
14278            for diagnostic in after.chain(before) {
14279                if diagnostic.range.start != selection.start
14280                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14281                {
14282                    found = Some(diagnostic);
14283                    break;
14284                }
14285            }
14286        }
14287        let Some(next_diagnostic) = found else {
14288            return;
14289        };
14290
14291        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14292            return;
14293        };
14294        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14295            s.select_ranges(vec![
14296                next_diagnostic.range.start..next_diagnostic.range.start,
14297            ])
14298        });
14299        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14300        self.refresh_inline_completion(false, true, window, cx);
14301    }
14302
14303    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14304        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14305        let snapshot = self.snapshot(window, cx);
14306        let selection = self.selections.newest::<Point>(cx);
14307        self.go_to_hunk_before_or_after_position(
14308            &snapshot,
14309            selection.head(),
14310            Direction::Next,
14311            window,
14312            cx,
14313        );
14314    }
14315
14316    pub fn go_to_hunk_before_or_after_position(
14317        &mut self,
14318        snapshot: &EditorSnapshot,
14319        position: Point,
14320        direction: Direction,
14321        window: &mut Window,
14322        cx: &mut Context<Editor>,
14323    ) {
14324        let row = if direction == Direction::Next {
14325            self.hunk_after_position(snapshot, position)
14326                .map(|hunk| hunk.row_range.start)
14327        } else {
14328            self.hunk_before_position(snapshot, position)
14329        };
14330
14331        if let Some(row) = row {
14332            let destination = Point::new(row.0, 0);
14333            let autoscroll = Autoscroll::center();
14334
14335            self.unfold_ranges(&[destination..destination], false, false, cx);
14336            self.change_selections(Some(autoscroll), window, cx, |s| {
14337                s.select_ranges([destination..destination]);
14338            });
14339        }
14340    }
14341
14342    fn hunk_after_position(
14343        &mut self,
14344        snapshot: &EditorSnapshot,
14345        position: Point,
14346    ) -> Option<MultiBufferDiffHunk> {
14347        snapshot
14348            .buffer_snapshot
14349            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14350            .find(|hunk| hunk.row_range.start.0 > position.row)
14351            .or_else(|| {
14352                snapshot
14353                    .buffer_snapshot
14354                    .diff_hunks_in_range(Point::zero()..position)
14355                    .find(|hunk| hunk.row_range.end.0 < position.row)
14356            })
14357    }
14358
14359    fn go_to_prev_hunk(
14360        &mut self,
14361        _: &GoToPreviousHunk,
14362        window: &mut Window,
14363        cx: &mut Context<Self>,
14364    ) {
14365        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14366        let snapshot = self.snapshot(window, cx);
14367        let selection = self.selections.newest::<Point>(cx);
14368        self.go_to_hunk_before_or_after_position(
14369            &snapshot,
14370            selection.head(),
14371            Direction::Prev,
14372            window,
14373            cx,
14374        );
14375    }
14376
14377    fn hunk_before_position(
14378        &mut self,
14379        snapshot: &EditorSnapshot,
14380        position: Point,
14381    ) -> Option<MultiBufferRow> {
14382        snapshot
14383            .buffer_snapshot
14384            .diff_hunk_before(position)
14385            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14386    }
14387
14388    fn go_to_next_change(
14389        &mut self,
14390        _: &GoToNextChange,
14391        window: &mut Window,
14392        cx: &mut Context<Self>,
14393    ) {
14394        if let Some(selections) = self
14395            .change_list
14396            .next_change(1, Direction::Next)
14397            .map(|s| s.to_vec())
14398        {
14399            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14400                let map = s.display_map();
14401                s.select_display_ranges(selections.iter().map(|a| {
14402                    let point = a.to_display_point(&map);
14403                    point..point
14404                }))
14405            })
14406        }
14407    }
14408
14409    fn go_to_previous_change(
14410        &mut self,
14411        _: &GoToPreviousChange,
14412        window: &mut Window,
14413        cx: &mut Context<Self>,
14414    ) {
14415        if let Some(selections) = self
14416            .change_list
14417            .next_change(1, Direction::Prev)
14418            .map(|s| s.to_vec())
14419        {
14420            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14421                let map = s.display_map();
14422                s.select_display_ranges(selections.iter().map(|a| {
14423                    let point = a.to_display_point(&map);
14424                    point..point
14425                }))
14426            })
14427        }
14428    }
14429
14430    fn go_to_line<T: 'static>(
14431        &mut self,
14432        position: Anchor,
14433        highlight_color: Option<Hsla>,
14434        window: &mut Window,
14435        cx: &mut Context<Self>,
14436    ) {
14437        let snapshot = self.snapshot(window, cx).display_snapshot;
14438        let position = position.to_point(&snapshot.buffer_snapshot);
14439        let start = snapshot
14440            .buffer_snapshot
14441            .clip_point(Point::new(position.row, 0), Bias::Left);
14442        let end = start + Point::new(1, 0);
14443        let start = snapshot.buffer_snapshot.anchor_before(start);
14444        let end = snapshot.buffer_snapshot.anchor_before(end);
14445
14446        self.highlight_rows::<T>(
14447            start..end,
14448            highlight_color
14449                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14450            Default::default(),
14451            cx,
14452        );
14453
14454        if self.buffer.read(cx).is_singleton() {
14455            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14456        }
14457    }
14458
14459    pub fn go_to_definition(
14460        &mut self,
14461        _: &GoToDefinition,
14462        window: &mut Window,
14463        cx: &mut Context<Self>,
14464    ) -> Task<Result<Navigated>> {
14465        let definition =
14466            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14467        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14468        cx.spawn_in(window, async move |editor, cx| {
14469            if definition.await? == Navigated::Yes {
14470                return Ok(Navigated::Yes);
14471            }
14472            match fallback_strategy {
14473                GoToDefinitionFallback::None => Ok(Navigated::No),
14474                GoToDefinitionFallback::FindAllReferences => {
14475                    match editor.update_in(cx, |editor, window, cx| {
14476                        editor.find_all_references(&FindAllReferences, window, cx)
14477                    })? {
14478                        Some(references) => references.await,
14479                        None => Ok(Navigated::No),
14480                    }
14481                }
14482            }
14483        })
14484    }
14485
14486    pub fn go_to_declaration(
14487        &mut self,
14488        _: &GoToDeclaration,
14489        window: &mut Window,
14490        cx: &mut Context<Self>,
14491    ) -> Task<Result<Navigated>> {
14492        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14493    }
14494
14495    pub fn go_to_declaration_split(
14496        &mut self,
14497        _: &GoToDeclaration,
14498        window: &mut Window,
14499        cx: &mut Context<Self>,
14500    ) -> Task<Result<Navigated>> {
14501        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14502    }
14503
14504    pub fn go_to_implementation(
14505        &mut self,
14506        _: &GoToImplementation,
14507        window: &mut Window,
14508        cx: &mut Context<Self>,
14509    ) -> Task<Result<Navigated>> {
14510        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14511    }
14512
14513    pub fn go_to_implementation_split(
14514        &mut self,
14515        _: &GoToImplementationSplit,
14516        window: &mut Window,
14517        cx: &mut Context<Self>,
14518    ) -> Task<Result<Navigated>> {
14519        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14520    }
14521
14522    pub fn go_to_type_definition(
14523        &mut self,
14524        _: &GoToTypeDefinition,
14525        window: &mut Window,
14526        cx: &mut Context<Self>,
14527    ) -> Task<Result<Navigated>> {
14528        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14529    }
14530
14531    pub fn go_to_definition_split(
14532        &mut self,
14533        _: &GoToDefinitionSplit,
14534        window: &mut Window,
14535        cx: &mut Context<Self>,
14536    ) -> Task<Result<Navigated>> {
14537        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14538    }
14539
14540    pub fn go_to_type_definition_split(
14541        &mut self,
14542        _: &GoToTypeDefinitionSplit,
14543        window: &mut Window,
14544        cx: &mut Context<Self>,
14545    ) -> Task<Result<Navigated>> {
14546        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14547    }
14548
14549    fn go_to_definition_of_kind(
14550        &mut self,
14551        kind: GotoDefinitionKind,
14552        split: bool,
14553        window: &mut Window,
14554        cx: &mut Context<Self>,
14555    ) -> Task<Result<Navigated>> {
14556        let Some(provider) = self.semantics_provider.clone() else {
14557            return Task::ready(Ok(Navigated::No));
14558        };
14559        let head = self.selections.newest::<usize>(cx).head();
14560        let buffer = self.buffer.read(cx);
14561        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14562            text_anchor
14563        } else {
14564            return Task::ready(Ok(Navigated::No));
14565        };
14566
14567        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14568            return Task::ready(Ok(Navigated::No));
14569        };
14570
14571        cx.spawn_in(window, async move |editor, cx| {
14572            let definitions = definitions.await?;
14573            let navigated = editor
14574                .update_in(cx, |editor, window, cx| {
14575                    editor.navigate_to_hover_links(
14576                        Some(kind),
14577                        definitions
14578                            .into_iter()
14579                            .filter(|location| {
14580                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14581                            })
14582                            .map(HoverLink::Text)
14583                            .collect::<Vec<_>>(),
14584                        split,
14585                        window,
14586                        cx,
14587                    )
14588                })?
14589                .await?;
14590            anyhow::Ok(navigated)
14591        })
14592    }
14593
14594    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14595        let selection = self.selections.newest_anchor();
14596        let head = selection.head();
14597        let tail = selection.tail();
14598
14599        let Some((buffer, start_position)) =
14600            self.buffer.read(cx).text_anchor_for_position(head, cx)
14601        else {
14602            return;
14603        };
14604
14605        let end_position = if head != tail {
14606            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14607                return;
14608            };
14609            Some(pos)
14610        } else {
14611            None
14612        };
14613
14614        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14615            let url = if let Some(end_pos) = end_position {
14616                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14617            } else {
14618                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14619            };
14620
14621            if let Some(url) = url {
14622                editor.update(cx, |_, cx| {
14623                    cx.open_url(&url);
14624                })
14625            } else {
14626                Ok(())
14627            }
14628        });
14629
14630        url_finder.detach();
14631    }
14632
14633    pub fn open_selected_filename(
14634        &mut self,
14635        _: &OpenSelectedFilename,
14636        window: &mut Window,
14637        cx: &mut Context<Self>,
14638    ) {
14639        let Some(workspace) = self.workspace() else {
14640            return;
14641        };
14642
14643        let position = self.selections.newest_anchor().head();
14644
14645        let Some((buffer, buffer_position)) =
14646            self.buffer.read(cx).text_anchor_for_position(position, cx)
14647        else {
14648            return;
14649        };
14650
14651        let project = self.project.clone();
14652
14653        cx.spawn_in(window, async move |_, cx| {
14654            let result = find_file(&buffer, project, buffer_position, cx).await;
14655
14656            if let Some((_, path)) = result {
14657                workspace
14658                    .update_in(cx, |workspace, window, cx| {
14659                        workspace.open_resolved_path(path, window, cx)
14660                    })?
14661                    .await?;
14662            }
14663            anyhow::Ok(())
14664        })
14665        .detach();
14666    }
14667
14668    pub(crate) fn navigate_to_hover_links(
14669        &mut self,
14670        kind: Option<GotoDefinitionKind>,
14671        mut definitions: Vec<HoverLink>,
14672        split: bool,
14673        window: &mut Window,
14674        cx: &mut Context<Editor>,
14675    ) -> Task<Result<Navigated>> {
14676        // If there is one definition, just open it directly
14677        if definitions.len() == 1 {
14678            let definition = definitions.pop().unwrap();
14679
14680            enum TargetTaskResult {
14681                Location(Option<Location>),
14682                AlreadyNavigated,
14683            }
14684
14685            let target_task = match definition {
14686                HoverLink::Text(link) => {
14687                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14688                }
14689                HoverLink::InlayHint(lsp_location, server_id) => {
14690                    let computation =
14691                        self.compute_target_location(lsp_location, server_id, window, cx);
14692                    cx.background_spawn(async move {
14693                        let location = computation.await?;
14694                        Ok(TargetTaskResult::Location(location))
14695                    })
14696                }
14697                HoverLink::Url(url) => {
14698                    cx.open_url(&url);
14699                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14700                }
14701                HoverLink::File(path) => {
14702                    if let Some(workspace) = self.workspace() {
14703                        cx.spawn_in(window, async move |_, cx| {
14704                            workspace
14705                                .update_in(cx, |workspace, window, cx| {
14706                                    workspace.open_resolved_path(path, window, cx)
14707                                })?
14708                                .await
14709                                .map(|_| TargetTaskResult::AlreadyNavigated)
14710                        })
14711                    } else {
14712                        Task::ready(Ok(TargetTaskResult::Location(None)))
14713                    }
14714                }
14715            };
14716            cx.spawn_in(window, async move |editor, cx| {
14717                let target = match target_task.await.context("target resolution task")? {
14718                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14719                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14720                    TargetTaskResult::Location(Some(target)) => target,
14721                };
14722
14723                editor.update_in(cx, |editor, window, cx| {
14724                    let Some(workspace) = editor.workspace() else {
14725                        return Navigated::No;
14726                    };
14727                    let pane = workspace.read(cx).active_pane().clone();
14728
14729                    let range = target.range.to_point(target.buffer.read(cx));
14730                    let range = editor.range_for_match(&range);
14731                    let range = collapse_multiline_range(range);
14732
14733                    if !split
14734                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14735                    {
14736                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14737                    } else {
14738                        window.defer(cx, move |window, cx| {
14739                            let target_editor: Entity<Self> =
14740                                workspace.update(cx, |workspace, cx| {
14741                                    let pane = if split {
14742                                        workspace.adjacent_pane(window, cx)
14743                                    } else {
14744                                        workspace.active_pane().clone()
14745                                    };
14746
14747                                    workspace.open_project_item(
14748                                        pane,
14749                                        target.buffer.clone(),
14750                                        true,
14751                                        true,
14752                                        window,
14753                                        cx,
14754                                    )
14755                                });
14756                            target_editor.update(cx, |target_editor, cx| {
14757                                // When selecting a definition in a different buffer, disable the nav history
14758                                // to avoid creating a history entry at the previous cursor location.
14759                                pane.update(cx, |pane, _| pane.disable_history());
14760                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14761                                pane.update(cx, |pane, _| pane.enable_history());
14762                            });
14763                        });
14764                    }
14765                    Navigated::Yes
14766                })
14767            })
14768        } else if !definitions.is_empty() {
14769            cx.spawn_in(window, async move |editor, cx| {
14770                let (title, location_tasks, workspace) = editor
14771                    .update_in(cx, |editor, window, cx| {
14772                        let tab_kind = match kind {
14773                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14774                            _ => "Definitions",
14775                        };
14776                        let title = definitions
14777                            .iter()
14778                            .find_map(|definition| match definition {
14779                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14780                                    let buffer = origin.buffer.read(cx);
14781                                    format!(
14782                                        "{} for {}",
14783                                        tab_kind,
14784                                        buffer
14785                                            .text_for_range(origin.range.clone())
14786                                            .collect::<String>()
14787                                    )
14788                                }),
14789                                HoverLink::InlayHint(_, _) => None,
14790                                HoverLink::Url(_) => None,
14791                                HoverLink::File(_) => None,
14792                            })
14793                            .unwrap_or(tab_kind.to_string());
14794                        let location_tasks = definitions
14795                            .into_iter()
14796                            .map(|definition| match definition {
14797                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14798                                HoverLink::InlayHint(lsp_location, server_id) => editor
14799                                    .compute_target_location(lsp_location, server_id, window, cx),
14800                                HoverLink::Url(_) => Task::ready(Ok(None)),
14801                                HoverLink::File(_) => Task::ready(Ok(None)),
14802                            })
14803                            .collect::<Vec<_>>();
14804                        (title, location_tasks, editor.workspace().clone())
14805                    })
14806                    .context("location tasks preparation")?;
14807
14808                let locations = future::join_all(location_tasks)
14809                    .await
14810                    .into_iter()
14811                    .filter_map(|location| location.transpose())
14812                    .collect::<Result<_>>()
14813                    .context("location tasks")?;
14814
14815                let Some(workspace) = workspace else {
14816                    return Ok(Navigated::No);
14817                };
14818                let opened = workspace
14819                    .update_in(cx, |workspace, window, cx| {
14820                        Self::open_locations_in_multibuffer(
14821                            workspace,
14822                            locations,
14823                            title,
14824                            split,
14825                            MultibufferSelectionMode::First,
14826                            window,
14827                            cx,
14828                        )
14829                    })
14830                    .ok();
14831
14832                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14833            })
14834        } else {
14835            Task::ready(Ok(Navigated::No))
14836        }
14837    }
14838
14839    fn compute_target_location(
14840        &self,
14841        lsp_location: lsp::Location,
14842        server_id: LanguageServerId,
14843        window: &mut Window,
14844        cx: &mut Context<Self>,
14845    ) -> Task<anyhow::Result<Option<Location>>> {
14846        let Some(project) = self.project.clone() else {
14847            return Task::ready(Ok(None));
14848        };
14849
14850        cx.spawn_in(window, async move |editor, cx| {
14851            let location_task = editor.update(cx, |_, cx| {
14852                project.update(cx, |project, cx| {
14853                    let language_server_name = project
14854                        .language_server_statuses(cx)
14855                        .find(|(id, _)| server_id == *id)
14856                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14857                    language_server_name.map(|language_server_name| {
14858                        project.open_local_buffer_via_lsp(
14859                            lsp_location.uri.clone(),
14860                            server_id,
14861                            language_server_name,
14862                            cx,
14863                        )
14864                    })
14865                })
14866            })?;
14867            let location = match location_task {
14868                Some(task) => Some({
14869                    let target_buffer_handle = task.await.context("open local buffer")?;
14870                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
14871                        let target_start = target_buffer
14872                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14873                        let target_end = target_buffer
14874                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14875                        target_buffer.anchor_after(target_start)
14876                            ..target_buffer.anchor_before(target_end)
14877                    })?;
14878                    Location {
14879                        buffer: target_buffer_handle,
14880                        range,
14881                    }
14882                }),
14883                None => None,
14884            };
14885            Ok(location)
14886        })
14887    }
14888
14889    pub fn find_all_references(
14890        &mut self,
14891        _: &FindAllReferences,
14892        window: &mut Window,
14893        cx: &mut Context<Self>,
14894    ) -> Option<Task<Result<Navigated>>> {
14895        let selection = self.selections.newest::<usize>(cx);
14896        let multi_buffer = self.buffer.read(cx);
14897        let head = selection.head();
14898
14899        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14900        let head_anchor = multi_buffer_snapshot.anchor_at(
14901            head,
14902            if head < selection.tail() {
14903                Bias::Right
14904            } else {
14905                Bias::Left
14906            },
14907        );
14908
14909        match self
14910            .find_all_references_task_sources
14911            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14912        {
14913            Ok(_) => {
14914                log::info!(
14915                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14916                );
14917                return None;
14918            }
14919            Err(i) => {
14920                self.find_all_references_task_sources.insert(i, head_anchor);
14921            }
14922        }
14923
14924        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14925        let workspace = self.workspace()?;
14926        let project = workspace.read(cx).project().clone();
14927        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14928        Some(cx.spawn_in(window, async move |editor, cx| {
14929            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14930                if let Ok(i) = editor
14931                    .find_all_references_task_sources
14932                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14933                {
14934                    editor.find_all_references_task_sources.remove(i);
14935                }
14936            });
14937
14938            let locations = references.await?;
14939            if locations.is_empty() {
14940                return anyhow::Ok(Navigated::No);
14941            }
14942
14943            workspace.update_in(cx, |workspace, window, cx| {
14944                let title = locations
14945                    .first()
14946                    .as_ref()
14947                    .map(|location| {
14948                        let buffer = location.buffer.read(cx);
14949                        format!(
14950                            "References to `{}`",
14951                            buffer
14952                                .text_for_range(location.range.clone())
14953                                .collect::<String>()
14954                        )
14955                    })
14956                    .unwrap();
14957                Self::open_locations_in_multibuffer(
14958                    workspace,
14959                    locations,
14960                    title,
14961                    false,
14962                    MultibufferSelectionMode::First,
14963                    window,
14964                    cx,
14965                );
14966                Navigated::Yes
14967            })
14968        }))
14969    }
14970
14971    /// Opens a multibuffer with the given project locations in it
14972    pub fn open_locations_in_multibuffer(
14973        workspace: &mut Workspace,
14974        mut locations: Vec<Location>,
14975        title: String,
14976        split: bool,
14977        multibuffer_selection_mode: MultibufferSelectionMode,
14978        window: &mut Window,
14979        cx: &mut Context<Workspace>,
14980    ) {
14981        // If there are multiple definitions, open them in a multibuffer
14982        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14983        let mut locations = locations.into_iter().peekable();
14984        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14985        let capability = workspace.project().read(cx).capability();
14986
14987        let excerpt_buffer = cx.new(|cx| {
14988            let mut multibuffer = MultiBuffer::new(capability);
14989            while let Some(location) = locations.next() {
14990                let buffer = location.buffer.read(cx);
14991                let mut ranges_for_buffer = Vec::new();
14992                let range = location.range.to_point(buffer);
14993                ranges_for_buffer.push(range.clone());
14994
14995                while let Some(next_location) = locations.peek() {
14996                    if next_location.buffer == location.buffer {
14997                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14998                        locations.next();
14999                    } else {
15000                        break;
15001                    }
15002                }
15003
15004                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15005                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15006                    PathKey::for_buffer(&location.buffer, cx),
15007                    location.buffer.clone(),
15008                    ranges_for_buffer,
15009                    DEFAULT_MULTIBUFFER_CONTEXT,
15010                    cx,
15011                );
15012                ranges.extend(new_ranges)
15013            }
15014
15015            multibuffer.with_title(title)
15016        });
15017
15018        let editor = cx.new(|cx| {
15019            Editor::for_multibuffer(
15020                excerpt_buffer,
15021                Some(workspace.project().clone()),
15022                window,
15023                cx,
15024            )
15025        });
15026        editor.update(cx, |editor, cx| {
15027            match multibuffer_selection_mode {
15028                MultibufferSelectionMode::First => {
15029                    if let Some(first_range) = ranges.first() {
15030                        editor.change_selections(None, window, cx, |selections| {
15031                            selections.clear_disjoint();
15032                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15033                        });
15034                    }
15035                    editor.highlight_background::<Self>(
15036                        &ranges,
15037                        |theme| theme.editor_highlighted_line_background,
15038                        cx,
15039                    );
15040                }
15041                MultibufferSelectionMode::All => {
15042                    editor.change_selections(None, window, cx, |selections| {
15043                        selections.clear_disjoint();
15044                        selections.select_anchor_ranges(ranges);
15045                    });
15046                }
15047            }
15048            editor.register_buffers_with_language_servers(cx);
15049        });
15050
15051        let item = Box::new(editor);
15052        let item_id = item.item_id();
15053
15054        if split {
15055            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15056        } else {
15057            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15058                let (preview_item_id, preview_item_idx) =
15059                    workspace.active_pane().read_with(cx, |pane, _| {
15060                        (pane.preview_item_id(), pane.preview_item_idx())
15061                    });
15062
15063                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15064
15065                if let Some(preview_item_id) = preview_item_id {
15066                    workspace.active_pane().update(cx, |pane, cx| {
15067                        pane.remove_item(preview_item_id, false, false, window, cx);
15068                    });
15069                }
15070            } else {
15071                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15072            }
15073        }
15074        workspace.active_pane().update(cx, |pane, cx| {
15075            pane.set_preview_item_id(Some(item_id), cx);
15076        });
15077    }
15078
15079    pub fn rename(
15080        &mut self,
15081        _: &Rename,
15082        window: &mut Window,
15083        cx: &mut Context<Self>,
15084    ) -> Option<Task<Result<()>>> {
15085        use language::ToOffset as _;
15086
15087        let provider = self.semantics_provider.clone()?;
15088        let selection = self.selections.newest_anchor().clone();
15089        let (cursor_buffer, cursor_buffer_position) = self
15090            .buffer
15091            .read(cx)
15092            .text_anchor_for_position(selection.head(), cx)?;
15093        let (tail_buffer, cursor_buffer_position_end) = self
15094            .buffer
15095            .read(cx)
15096            .text_anchor_for_position(selection.tail(), cx)?;
15097        if tail_buffer != cursor_buffer {
15098            return None;
15099        }
15100
15101        let snapshot = cursor_buffer.read(cx).snapshot();
15102        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15103        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15104        let prepare_rename = provider
15105            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15106            .unwrap_or_else(|| Task::ready(Ok(None)));
15107        drop(snapshot);
15108
15109        Some(cx.spawn_in(window, async move |this, cx| {
15110            let rename_range = if let Some(range) = prepare_rename.await? {
15111                Some(range)
15112            } else {
15113                this.update(cx, |this, cx| {
15114                    let buffer = this.buffer.read(cx).snapshot(cx);
15115                    let mut buffer_highlights = this
15116                        .document_highlights_for_position(selection.head(), &buffer)
15117                        .filter(|highlight| {
15118                            highlight.start.excerpt_id == selection.head().excerpt_id
15119                                && highlight.end.excerpt_id == selection.head().excerpt_id
15120                        });
15121                    buffer_highlights
15122                        .next()
15123                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15124                })?
15125            };
15126            if let Some(rename_range) = rename_range {
15127                this.update_in(cx, |this, window, cx| {
15128                    let snapshot = cursor_buffer.read(cx).snapshot();
15129                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15130                    let cursor_offset_in_rename_range =
15131                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15132                    let cursor_offset_in_rename_range_end =
15133                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15134
15135                    this.take_rename(false, window, cx);
15136                    let buffer = this.buffer.read(cx).read(cx);
15137                    let cursor_offset = selection.head().to_offset(&buffer);
15138                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15139                    let rename_end = rename_start + rename_buffer_range.len();
15140                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15141                    let mut old_highlight_id = None;
15142                    let old_name: Arc<str> = buffer
15143                        .chunks(rename_start..rename_end, true)
15144                        .map(|chunk| {
15145                            if old_highlight_id.is_none() {
15146                                old_highlight_id = chunk.syntax_highlight_id;
15147                            }
15148                            chunk.text
15149                        })
15150                        .collect::<String>()
15151                        .into();
15152
15153                    drop(buffer);
15154
15155                    // Position the selection in the rename editor so that it matches the current selection.
15156                    this.show_local_selections = false;
15157                    let rename_editor = cx.new(|cx| {
15158                        let mut editor = Editor::single_line(window, cx);
15159                        editor.buffer.update(cx, |buffer, cx| {
15160                            buffer.edit([(0..0, old_name.clone())], None, cx)
15161                        });
15162                        let rename_selection_range = match cursor_offset_in_rename_range
15163                            .cmp(&cursor_offset_in_rename_range_end)
15164                        {
15165                            Ordering::Equal => {
15166                                editor.select_all(&SelectAll, window, cx);
15167                                return editor;
15168                            }
15169                            Ordering::Less => {
15170                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15171                            }
15172                            Ordering::Greater => {
15173                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15174                            }
15175                        };
15176                        if rename_selection_range.end > old_name.len() {
15177                            editor.select_all(&SelectAll, window, cx);
15178                        } else {
15179                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15180                                s.select_ranges([rename_selection_range]);
15181                            });
15182                        }
15183                        editor
15184                    });
15185                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15186                        if e == &EditorEvent::Focused {
15187                            cx.emit(EditorEvent::FocusedIn)
15188                        }
15189                    })
15190                    .detach();
15191
15192                    let write_highlights =
15193                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15194                    let read_highlights =
15195                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15196                    let ranges = write_highlights
15197                        .iter()
15198                        .flat_map(|(_, ranges)| ranges.iter())
15199                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15200                        .cloned()
15201                        .collect();
15202
15203                    this.highlight_text::<Rename>(
15204                        ranges,
15205                        HighlightStyle {
15206                            fade_out: Some(0.6),
15207                            ..Default::default()
15208                        },
15209                        cx,
15210                    );
15211                    let rename_focus_handle = rename_editor.focus_handle(cx);
15212                    window.focus(&rename_focus_handle);
15213                    let block_id = this.insert_blocks(
15214                        [BlockProperties {
15215                            style: BlockStyle::Flex,
15216                            placement: BlockPlacement::Below(range.start),
15217                            height: Some(1),
15218                            render: Arc::new({
15219                                let rename_editor = rename_editor.clone();
15220                                move |cx: &mut BlockContext| {
15221                                    let mut text_style = cx.editor_style.text.clone();
15222                                    if let Some(highlight_style) = old_highlight_id
15223                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15224                                    {
15225                                        text_style = text_style.highlight(highlight_style);
15226                                    }
15227                                    div()
15228                                        .block_mouse_except_scroll()
15229                                        .pl(cx.anchor_x)
15230                                        .child(EditorElement::new(
15231                                            &rename_editor,
15232                                            EditorStyle {
15233                                                background: cx.theme().system().transparent,
15234                                                local_player: cx.editor_style.local_player,
15235                                                text: text_style,
15236                                                scrollbar_width: cx.editor_style.scrollbar_width,
15237                                                syntax: cx.editor_style.syntax.clone(),
15238                                                status: cx.editor_style.status.clone(),
15239                                                inlay_hints_style: HighlightStyle {
15240                                                    font_weight: Some(FontWeight::BOLD),
15241                                                    ..make_inlay_hints_style(cx.app)
15242                                                },
15243                                                inline_completion_styles: make_suggestion_styles(
15244                                                    cx.app,
15245                                                ),
15246                                                ..EditorStyle::default()
15247                                            },
15248                                        ))
15249                                        .into_any_element()
15250                                }
15251                            }),
15252                            priority: 0,
15253                            render_in_minimap: true,
15254                        }],
15255                        Some(Autoscroll::fit()),
15256                        cx,
15257                    )[0];
15258                    this.pending_rename = Some(RenameState {
15259                        range,
15260                        old_name,
15261                        editor: rename_editor,
15262                        block_id,
15263                    });
15264                })?;
15265            }
15266
15267            Ok(())
15268        }))
15269    }
15270
15271    pub fn confirm_rename(
15272        &mut self,
15273        _: &ConfirmRename,
15274        window: &mut Window,
15275        cx: &mut Context<Self>,
15276    ) -> Option<Task<Result<()>>> {
15277        let rename = self.take_rename(false, window, cx)?;
15278        let workspace = self.workspace()?.downgrade();
15279        let (buffer, start) = self
15280            .buffer
15281            .read(cx)
15282            .text_anchor_for_position(rename.range.start, cx)?;
15283        let (end_buffer, _) = self
15284            .buffer
15285            .read(cx)
15286            .text_anchor_for_position(rename.range.end, cx)?;
15287        if buffer != end_buffer {
15288            return None;
15289        }
15290
15291        let old_name = rename.old_name;
15292        let new_name = rename.editor.read(cx).text(cx);
15293
15294        let rename = self.semantics_provider.as_ref()?.perform_rename(
15295            &buffer,
15296            start,
15297            new_name.clone(),
15298            cx,
15299        )?;
15300
15301        Some(cx.spawn_in(window, async move |editor, cx| {
15302            let project_transaction = rename.await?;
15303            Self::open_project_transaction(
15304                &editor,
15305                workspace,
15306                project_transaction,
15307                format!("Rename: {}{}", old_name, new_name),
15308                cx,
15309            )
15310            .await?;
15311
15312            editor.update(cx, |editor, cx| {
15313                editor.refresh_document_highlights(cx);
15314            })?;
15315            Ok(())
15316        }))
15317    }
15318
15319    fn take_rename(
15320        &mut self,
15321        moving_cursor: bool,
15322        window: &mut Window,
15323        cx: &mut Context<Self>,
15324    ) -> Option<RenameState> {
15325        let rename = self.pending_rename.take()?;
15326        if rename.editor.focus_handle(cx).is_focused(window) {
15327            window.focus(&self.focus_handle);
15328        }
15329
15330        self.remove_blocks(
15331            [rename.block_id].into_iter().collect(),
15332            Some(Autoscroll::fit()),
15333            cx,
15334        );
15335        self.clear_highlights::<Rename>(cx);
15336        self.show_local_selections = true;
15337
15338        if moving_cursor {
15339            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15340                editor.selections.newest::<usize>(cx).head()
15341            });
15342
15343            // Update the selection to match the position of the selection inside
15344            // the rename editor.
15345            let snapshot = self.buffer.read(cx).read(cx);
15346            let rename_range = rename.range.to_offset(&snapshot);
15347            let cursor_in_editor = snapshot
15348                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15349                .min(rename_range.end);
15350            drop(snapshot);
15351
15352            self.change_selections(None, window, cx, |s| {
15353                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15354            });
15355        } else {
15356            self.refresh_document_highlights(cx);
15357        }
15358
15359        Some(rename)
15360    }
15361
15362    pub fn pending_rename(&self) -> Option<&RenameState> {
15363        self.pending_rename.as_ref()
15364    }
15365
15366    fn format(
15367        &mut self,
15368        _: &Format,
15369        window: &mut Window,
15370        cx: &mut Context<Self>,
15371    ) -> Option<Task<Result<()>>> {
15372        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15373
15374        let project = match &self.project {
15375            Some(project) => project.clone(),
15376            None => return None,
15377        };
15378
15379        Some(self.perform_format(
15380            project,
15381            FormatTrigger::Manual,
15382            FormatTarget::Buffers,
15383            window,
15384            cx,
15385        ))
15386    }
15387
15388    fn format_selections(
15389        &mut self,
15390        _: &FormatSelections,
15391        window: &mut Window,
15392        cx: &mut Context<Self>,
15393    ) -> Option<Task<Result<()>>> {
15394        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15395
15396        let project = match &self.project {
15397            Some(project) => project.clone(),
15398            None => return None,
15399        };
15400
15401        let ranges = self
15402            .selections
15403            .all_adjusted(cx)
15404            .into_iter()
15405            .map(|selection| selection.range())
15406            .collect_vec();
15407
15408        Some(self.perform_format(
15409            project,
15410            FormatTrigger::Manual,
15411            FormatTarget::Ranges(ranges),
15412            window,
15413            cx,
15414        ))
15415    }
15416
15417    fn perform_format(
15418        &mut self,
15419        project: Entity<Project>,
15420        trigger: FormatTrigger,
15421        target: FormatTarget,
15422        window: &mut Window,
15423        cx: &mut Context<Self>,
15424    ) -> Task<Result<()>> {
15425        let buffer = self.buffer.clone();
15426        let (buffers, target) = match target {
15427            FormatTarget::Buffers => {
15428                let mut buffers = buffer.read(cx).all_buffers();
15429                if trigger == FormatTrigger::Save {
15430                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15431                }
15432                (buffers, LspFormatTarget::Buffers)
15433            }
15434            FormatTarget::Ranges(selection_ranges) => {
15435                let multi_buffer = buffer.read(cx);
15436                let snapshot = multi_buffer.read(cx);
15437                let mut buffers = HashSet::default();
15438                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15439                    BTreeMap::new();
15440                for selection_range in selection_ranges {
15441                    for (buffer, buffer_range, _) in
15442                        snapshot.range_to_buffer_ranges(selection_range)
15443                    {
15444                        let buffer_id = buffer.remote_id();
15445                        let start = buffer.anchor_before(buffer_range.start);
15446                        let end = buffer.anchor_after(buffer_range.end);
15447                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15448                        buffer_id_to_ranges
15449                            .entry(buffer_id)
15450                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15451                            .or_insert_with(|| vec![start..end]);
15452                    }
15453                }
15454                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15455            }
15456        };
15457
15458        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15459        let selections_prev = transaction_id_prev
15460            .and_then(|transaction_id_prev| {
15461                // default to selections as they were after the last edit, if we have them,
15462                // instead of how they are now.
15463                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15464                // will take you back to where you made the last edit, instead of staying where you scrolled
15465                self.selection_history
15466                    .transaction(transaction_id_prev)
15467                    .map(|t| t.0.clone())
15468            })
15469            .unwrap_or_else(|| {
15470                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15471                self.selections.disjoint_anchors()
15472            });
15473
15474        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15475        let format = project.update(cx, |project, cx| {
15476            project.format(buffers, target, true, trigger, cx)
15477        });
15478
15479        cx.spawn_in(window, async move |editor, cx| {
15480            let transaction = futures::select_biased! {
15481                transaction = format.log_err().fuse() => transaction,
15482                () = timeout => {
15483                    log::warn!("timed out waiting for formatting");
15484                    None
15485                }
15486            };
15487
15488            buffer
15489                .update(cx, |buffer, cx| {
15490                    if let Some(transaction) = transaction {
15491                        if !buffer.is_singleton() {
15492                            buffer.push_transaction(&transaction.0, cx);
15493                        }
15494                    }
15495                    cx.notify();
15496                })
15497                .ok();
15498
15499            if let Some(transaction_id_now) =
15500                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15501            {
15502                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15503                if has_new_transaction {
15504                    _ = editor.update(cx, |editor, _| {
15505                        editor
15506                            .selection_history
15507                            .insert_transaction(transaction_id_now, selections_prev);
15508                    });
15509                }
15510            }
15511
15512            Ok(())
15513        })
15514    }
15515
15516    fn organize_imports(
15517        &mut self,
15518        _: &OrganizeImports,
15519        window: &mut Window,
15520        cx: &mut Context<Self>,
15521    ) -> Option<Task<Result<()>>> {
15522        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15523        let project = match &self.project {
15524            Some(project) => project.clone(),
15525            None => return None,
15526        };
15527        Some(self.perform_code_action_kind(
15528            project,
15529            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15530            window,
15531            cx,
15532        ))
15533    }
15534
15535    fn perform_code_action_kind(
15536        &mut self,
15537        project: Entity<Project>,
15538        kind: CodeActionKind,
15539        window: &mut Window,
15540        cx: &mut Context<Self>,
15541    ) -> Task<Result<()>> {
15542        let buffer = self.buffer.clone();
15543        let buffers = buffer.read(cx).all_buffers();
15544        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15545        let apply_action = project.update(cx, |project, cx| {
15546            project.apply_code_action_kind(buffers, kind, true, cx)
15547        });
15548        cx.spawn_in(window, async move |_, cx| {
15549            let transaction = futures::select_biased! {
15550                () = timeout => {
15551                    log::warn!("timed out waiting for executing code action");
15552                    None
15553                }
15554                transaction = apply_action.log_err().fuse() => transaction,
15555            };
15556            buffer
15557                .update(cx, |buffer, cx| {
15558                    // check if we need this
15559                    if let Some(transaction) = transaction {
15560                        if !buffer.is_singleton() {
15561                            buffer.push_transaction(&transaction.0, cx);
15562                        }
15563                    }
15564                    cx.notify();
15565                })
15566                .ok();
15567            Ok(())
15568        })
15569    }
15570
15571    fn restart_language_server(
15572        &mut self,
15573        _: &RestartLanguageServer,
15574        _: &mut Window,
15575        cx: &mut Context<Self>,
15576    ) {
15577        if let Some(project) = self.project.clone() {
15578            self.buffer.update(cx, |multi_buffer, cx| {
15579                project.update(cx, |project, cx| {
15580                    project.restart_language_servers_for_buffers(
15581                        multi_buffer.all_buffers().into_iter().collect(),
15582                        cx,
15583                    );
15584                });
15585            })
15586        }
15587    }
15588
15589    fn stop_language_server(
15590        &mut self,
15591        _: &StopLanguageServer,
15592        _: &mut Window,
15593        cx: &mut Context<Self>,
15594    ) {
15595        if let Some(project) = self.project.clone() {
15596            self.buffer.update(cx, |multi_buffer, cx| {
15597                project.update(cx, |project, cx| {
15598                    project.stop_language_servers_for_buffers(
15599                        multi_buffer.all_buffers().into_iter().collect(),
15600                        cx,
15601                    );
15602                    cx.emit(project::Event::RefreshInlayHints);
15603                });
15604            });
15605        }
15606    }
15607
15608    fn cancel_language_server_work(
15609        workspace: &mut Workspace,
15610        _: &actions::CancelLanguageServerWork,
15611        _: &mut Window,
15612        cx: &mut Context<Workspace>,
15613    ) {
15614        let project = workspace.project();
15615        let buffers = workspace
15616            .active_item(cx)
15617            .and_then(|item| item.act_as::<Editor>(cx))
15618            .map_or(HashSet::default(), |editor| {
15619                editor.read(cx).buffer.read(cx).all_buffers()
15620            });
15621        project.update(cx, |project, cx| {
15622            project.cancel_language_server_work_for_buffers(buffers, cx);
15623        });
15624    }
15625
15626    fn show_character_palette(
15627        &mut self,
15628        _: &ShowCharacterPalette,
15629        window: &mut Window,
15630        _: &mut Context<Self>,
15631    ) {
15632        window.show_character_palette();
15633    }
15634
15635    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15636        if self.mode.is_minimap() {
15637            return;
15638        }
15639
15640        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15641            let buffer = self.buffer.read(cx).snapshot(cx);
15642            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15643            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15644            let is_valid = buffer
15645                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15646                .any(|entry| {
15647                    entry.diagnostic.is_primary
15648                        && !entry.range.is_empty()
15649                        && entry.range.start == primary_range_start
15650                        && entry.diagnostic.message == active_diagnostics.active_message
15651                });
15652
15653            if !is_valid {
15654                self.dismiss_diagnostics(cx);
15655            }
15656        }
15657    }
15658
15659    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15660        match &self.active_diagnostics {
15661            ActiveDiagnostic::Group(group) => Some(group),
15662            _ => None,
15663        }
15664    }
15665
15666    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15667        self.dismiss_diagnostics(cx);
15668        self.active_diagnostics = ActiveDiagnostic::All;
15669    }
15670
15671    fn activate_diagnostics(
15672        &mut self,
15673        buffer_id: BufferId,
15674        diagnostic: DiagnosticEntry<usize>,
15675        window: &mut Window,
15676        cx: &mut Context<Self>,
15677    ) {
15678        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15679            return;
15680        }
15681        self.dismiss_diagnostics(cx);
15682        let snapshot = self.snapshot(window, cx);
15683        let buffer = self.buffer.read(cx).snapshot(cx);
15684        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15685            return;
15686        };
15687
15688        let diagnostic_group = buffer
15689            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15690            .collect::<Vec<_>>();
15691
15692        let blocks =
15693            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15694
15695        let blocks = self.display_map.update(cx, |display_map, cx| {
15696            display_map.insert_blocks(blocks, cx).into_iter().collect()
15697        });
15698        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15699            active_range: buffer.anchor_before(diagnostic.range.start)
15700                ..buffer.anchor_after(diagnostic.range.end),
15701            active_message: diagnostic.diagnostic.message.clone(),
15702            group_id: diagnostic.diagnostic.group_id,
15703            blocks,
15704        });
15705        cx.notify();
15706    }
15707
15708    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15709        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15710            return;
15711        };
15712
15713        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15714        if let ActiveDiagnostic::Group(group) = prev {
15715            self.display_map.update(cx, |display_map, cx| {
15716                display_map.remove_blocks(group.blocks, cx);
15717            });
15718            cx.notify();
15719        }
15720    }
15721
15722    /// Disable inline diagnostics rendering for this editor.
15723    pub fn disable_inline_diagnostics(&mut self) {
15724        self.inline_diagnostics_enabled = false;
15725        self.inline_diagnostics_update = Task::ready(());
15726        self.inline_diagnostics.clear();
15727    }
15728
15729    pub fn diagnostics_enabled(&self) -> bool {
15730        self.mode.is_full()
15731    }
15732
15733    pub fn inline_diagnostics_enabled(&self) -> bool {
15734        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15735    }
15736
15737    pub fn show_inline_diagnostics(&self) -> bool {
15738        self.show_inline_diagnostics
15739    }
15740
15741    pub fn toggle_inline_diagnostics(
15742        &mut self,
15743        _: &ToggleInlineDiagnostics,
15744        window: &mut Window,
15745        cx: &mut Context<Editor>,
15746    ) {
15747        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15748        self.refresh_inline_diagnostics(false, window, cx);
15749    }
15750
15751    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15752        self.diagnostics_max_severity = severity;
15753        self.display_map.update(cx, |display_map, _| {
15754            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15755        });
15756    }
15757
15758    pub fn toggle_diagnostics(
15759        &mut self,
15760        _: &ToggleDiagnostics,
15761        window: &mut Window,
15762        cx: &mut Context<Editor>,
15763    ) {
15764        if !self.diagnostics_enabled() {
15765            return;
15766        }
15767
15768        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15769            EditorSettings::get_global(cx)
15770                .diagnostics_max_severity
15771                .filter(|severity| severity != &DiagnosticSeverity::Off)
15772                .unwrap_or(DiagnosticSeverity::Hint)
15773        } else {
15774            DiagnosticSeverity::Off
15775        };
15776        self.set_max_diagnostics_severity(new_severity, cx);
15777        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15778            self.active_diagnostics = ActiveDiagnostic::None;
15779            self.inline_diagnostics_update = Task::ready(());
15780            self.inline_diagnostics.clear();
15781        } else {
15782            self.refresh_inline_diagnostics(false, window, cx);
15783        }
15784
15785        cx.notify();
15786    }
15787
15788    pub fn toggle_minimap(
15789        &mut self,
15790        _: &ToggleMinimap,
15791        window: &mut Window,
15792        cx: &mut Context<Editor>,
15793    ) {
15794        if self.supports_minimap(cx) {
15795            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15796        }
15797    }
15798
15799    fn refresh_inline_diagnostics(
15800        &mut self,
15801        debounce: bool,
15802        window: &mut Window,
15803        cx: &mut Context<Self>,
15804    ) {
15805        let max_severity = ProjectSettings::get_global(cx)
15806            .diagnostics
15807            .inline
15808            .max_severity
15809            .unwrap_or(self.diagnostics_max_severity);
15810
15811        if !self.inline_diagnostics_enabled()
15812            || !self.show_inline_diagnostics
15813            || max_severity == DiagnosticSeverity::Off
15814        {
15815            self.inline_diagnostics_update = Task::ready(());
15816            self.inline_diagnostics.clear();
15817            return;
15818        }
15819
15820        let debounce_ms = ProjectSettings::get_global(cx)
15821            .diagnostics
15822            .inline
15823            .update_debounce_ms;
15824        let debounce = if debounce && debounce_ms > 0 {
15825            Some(Duration::from_millis(debounce_ms))
15826        } else {
15827            None
15828        };
15829        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15830            if let Some(debounce) = debounce {
15831                cx.background_executor().timer(debounce).await;
15832            }
15833            let Some(snapshot) = editor.upgrade().and_then(|editor| {
15834                editor
15835                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15836                    .ok()
15837            }) else {
15838                return;
15839            };
15840
15841            let new_inline_diagnostics = cx
15842                .background_spawn(async move {
15843                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15844                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15845                        let message = diagnostic_entry
15846                            .diagnostic
15847                            .message
15848                            .split_once('\n')
15849                            .map(|(line, _)| line)
15850                            .map(SharedString::new)
15851                            .unwrap_or_else(|| {
15852                                SharedString::from(diagnostic_entry.diagnostic.message)
15853                            });
15854                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15855                        let (Ok(i) | Err(i)) = inline_diagnostics
15856                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15857                        inline_diagnostics.insert(
15858                            i,
15859                            (
15860                                start_anchor,
15861                                InlineDiagnostic {
15862                                    message,
15863                                    group_id: diagnostic_entry.diagnostic.group_id,
15864                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15865                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15866                                    severity: diagnostic_entry.diagnostic.severity,
15867                                },
15868                            ),
15869                        );
15870                    }
15871                    inline_diagnostics
15872                })
15873                .await;
15874
15875            editor
15876                .update(cx, |editor, cx| {
15877                    editor.inline_diagnostics = new_inline_diagnostics;
15878                    cx.notify();
15879                })
15880                .ok();
15881        });
15882    }
15883
15884    pub fn set_selections_from_remote(
15885        &mut self,
15886        selections: Vec<Selection<Anchor>>,
15887        pending_selection: Option<Selection<Anchor>>,
15888        window: &mut Window,
15889        cx: &mut Context<Self>,
15890    ) {
15891        let old_cursor_position = self.selections.newest_anchor().head();
15892        self.selections.change_with(cx, |s| {
15893            s.select_anchors(selections);
15894            if let Some(pending_selection) = pending_selection {
15895                s.set_pending(pending_selection, SelectMode::Character);
15896            } else {
15897                s.clear_pending();
15898            }
15899        });
15900        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15901    }
15902
15903    pub fn transact(
15904        &mut self,
15905        window: &mut Window,
15906        cx: &mut Context<Self>,
15907        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15908    ) -> Option<TransactionId> {
15909        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15910            this.start_transaction_at(Instant::now(), window, cx);
15911            update(this, window, cx);
15912            this.end_transaction_at(Instant::now(), cx)
15913        })
15914    }
15915
15916    pub fn start_transaction_at(
15917        &mut self,
15918        now: Instant,
15919        window: &mut Window,
15920        cx: &mut Context<Self>,
15921    ) {
15922        self.end_selection(window, cx);
15923        if let Some(tx_id) = self
15924            .buffer
15925            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15926        {
15927            self.selection_history
15928                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15929            cx.emit(EditorEvent::TransactionBegun {
15930                transaction_id: tx_id,
15931            })
15932        }
15933    }
15934
15935    pub fn end_transaction_at(
15936        &mut self,
15937        now: Instant,
15938        cx: &mut Context<Self>,
15939    ) -> Option<TransactionId> {
15940        if let Some(transaction_id) = self
15941            .buffer
15942            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15943        {
15944            if let Some((_, end_selections)) =
15945                self.selection_history.transaction_mut(transaction_id)
15946            {
15947                *end_selections = Some(self.selections.disjoint_anchors());
15948            } else {
15949                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15950            }
15951
15952            cx.emit(EditorEvent::Edited { transaction_id });
15953            Some(transaction_id)
15954        } else {
15955            None
15956        }
15957    }
15958
15959    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15960        if self.selection_mark_mode {
15961            self.change_selections(None, window, cx, |s| {
15962                s.move_with(|_, sel| {
15963                    sel.collapse_to(sel.head(), SelectionGoal::None);
15964                });
15965            })
15966        }
15967        self.selection_mark_mode = true;
15968        cx.notify();
15969    }
15970
15971    pub fn swap_selection_ends(
15972        &mut self,
15973        _: &actions::SwapSelectionEnds,
15974        window: &mut Window,
15975        cx: &mut Context<Self>,
15976    ) {
15977        self.change_selections(None, window, cx, |s| {
15978            s.move_with(|_, sel| {
15979                if sel.start != sel.end {
15980                    sel.reversed = !sel.reversed
15981                }
15982            });
15983        });
15984        self.request_autoscroll(Autoscroll::newest(), cx);
15985        cx.notify();
15986    }
15987
15988    pub fn toggle_fold(
15989        &mut self,
15990        _: &actions::ToggleFold,
15991        window: &mut Window,
15992        cx: &mut Context<Self>,
15993    ) {
15994        if self.is_singleton(cx) {
15995            let selection = self.selections.newest::<Point>(cx);
15996
15997            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15998            let range = if selection.is_empty() {
15999                let point = selection.head().to_display_point(&display_map);
16000                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16001                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16002                    .to_point(&display_map);
16003                start..end
16004            } else {
16005                selection.range()
16006            };
16007            if display_map.folds_in_range(range).next().is_some() {
16008                self.unfold_lines(&Default::default(), window, cx)
16009            } else {
16010                self.fold(&Default::default(), window, cx)
16011            }
16012        } else {
16013            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16014            let buffer_ids: HashSet<_> = self
16015                .selections
16016                .disjoint_anchor_ranges()
16017                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16018                .collect();
16019
16020            let should_unfold = buffer_ids
16021                .iter()
16022                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16023
16024            for buffer_id in buffer_ids {
16025                if should_unfold {
16026                    self.unfold_buffer(buffer_id, cx);
16027                } else {
16028                    self.fold_buffer(buffer_id, cx);
16029                }
16030            }
16031        }
16032    }
16033
16034    pub fn toggle_fold_recursive(
16035        &mut self,
16036        _: &actions::ToggleFoldRecursive,
16037        window: &mut Window,
16038        cx: &mut Context<Self>,
16039    ) {
16040        let selection = self.selections.newest::<Point>(cx);
16041
16042        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16043        let range = if selection.is_empty() {
16044            let point = selection.head().to_display_point(&display_map);
16045            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16046            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16047                .to_point(&display_map);
16048            start..end
16049        } else {
16050            selection.range()
16051        };
16052        if display_map.folds_in_range(range).next().is_some() {
16053            self.unfold_recursive(&Default::default(), window, cx)
16054        } else {
16055            self.fold_recursive(&Default::default(), window, cx)
16056        }
16057    }
16058
16059    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16060        if self.is_singleton(cx) {
16061            let mut to_fold = Vec::new();
16062            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16063            let selections = self.selections.all_adjusted(cx);
16064
16065            for selection in selections {
16066                let range = selection.range().sorted();
16067                let buffer_start_row = range.start.row;
16068
16069                if range.start.row != range.end.row {
16070                    let mut found = false;
16071                    let mut row = range.start.row;
16072                    while row <= range.end.row {
16073                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16074                        {
16075                            found = true;
16076                            row = crease.range().end.row + 1;
16077                            to_fold.push(crease);
16078                        } else {
16079                            row += 1
16080                        }
16081                    }
16082                    if found {
16083                        continue;
16084                    }
16085                }
16086
16087                for row in (0..=range.start.row).rev() {
16088                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16089                        if crease.range().end.row >= buffer_start_row {
16090                            to_fold.push(crease);
16091                            if row <= range.start.row {
16092                                break;
16093                            }
16094                        }
16095                    }
16096                }
16097            }
16098
16099            self.fold_creases(to_fold, true, window, cx);
16100        } else {
16101            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16102            let buffer_ids = self
16103                .selections
16104                .disjoint_anchor_ranges()
16105                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16106                .collect::<HashSet<_>>();
16107            for buffer_id in buffer_ids {
16108                self.fold_buffer(buffer_id, cx);
16109            }
16110        }
16111    }
16112
16113    fn fold_at_level(
16114        &mut self,
16115        fold_at: &FoldAtLevel,
16116        window: &mut Window,
16117        cx: &mut Context<Self>,
16118    ) {
16119        if !self.buffer.read(cx).is_singleton() {
16120            return;
16121        }
16122
16123        let fold_at_level = fold_at.0;
16124        let snapshot = self.buffer.read(cx).snapshot(cx);
16125        let mut to_fold = Vec::new();
16126        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16127
16128        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16129            while start_row < end_row {
16130                match self
16131                    .snapshot(window, cx)
16132                    .crease_for_buffer_row(MultiBufferRow(start_row))
16133                {
16134                    Some(crease) => {
16135                        let nested_start_row = crease.range().start.row + 1;
16136                        let nested_end_row = crease.range().end.row;
16137
16138                        if current_level < fold_at_level {
16139                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16140                        } else if current_level == fold_at_level {
16141                            to_fold.push(crease);
16142                        }
16143
16144                        start_row = nested_end_row + 1;
16145                    }
16146                    None => start_row += 1,
16147                }
16148            }
16149        }
16150
16151        self.fold_creases(to_fold, true, window, cx);
16152    }
16153
16154    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16155        if self.buffer.read(cx).is_singleton() {
16156            let mut fold_ranges = Vec::new();
16157            let snapshot = self.buffer.read(cx).snapshot(cx);
16158
16159            for row in 0..snapshot.max_row().0 {
16160                if let Some(foldable_range) = self
16161                    .snapshot(window, cx)
16162                    .crease_for_buffer_row(MultiBufferRow(row))
16163                {
16164                    fold_ranges.push(foldable_range);
16165                }
16166            }
16167
16168            self.fold_creases(fold_ranges, true, window, cx);
16169        } else {
16170            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16171                editor
16172                    .update_in(cx, |editor, _, cx| {
16173                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16174                            editor.fold_buffer(buffer_id, cx);
16175                        }
16176                    })
16177                    .ok();
16178            });
16179        }
16180    }
16181
16182    pub fn fold_function_bodies(
16183        &mut self,
16184        _: &actions::FoldFunctionBodies,
16185        window: &mut Window,
16186        cx: &mut Context<Self>,
16187    ) {
16188        let snapshot = self.buffer.read(cx).snapshot(cx);
16189
16190        let ranges = snapshot
16191            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16192            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16193            .collect::<Vec<_>>();
16194
16195        let creases = ranges
16196            .into_iter()
16197            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16198            .collect();
16199
16200        self.fold_creases(creases, true, window, cx);
16201    }
16202
16203    pub fn fold_recursive(
16204        &mut self,
16205        _: &actions::FoldRecursive,
16206        window: &mut Window,
16207        cx: &mut Context<Self>,
16208    ) {
16209        let mut to_fold = Vec::new();
16210        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16211        let selections = self.selections.all_adjusted(cx);
16212
16213        for selection in selections {
16214            let range = selection.range().sorted();
16215            let buffer_start_row = range.start.row;
16216
16217            if range.start.row != range.end.row {
16218                let mut found = false;
16219                for row in range.start.row..=range.end.row {
16220                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16221                        found = true;
16222                        to_fold.push(crease);
16223                    }
16224                }
16225                if found {
16226                    continue;
16227                }
16228            }
16229
16230            for row in (0..=range.start.row).rev() {
16231                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16232                    if crease.range().end.row >= buffer_start_row {
16233                        to_fold.push(crease);
16234                    } else {
16235                        break;
16236                    }
16237                }
16238            }
16239        }
16240
16241        self.fold_creases(to_fold, true, window, cx);
16242    }
16243
16244    pub fn fold_at(
16245        &mut self,
16246        buffer_row: MultiBufferRow,
16247        window: &mut Window,
16248        cx: &mut Context<Self>,
16249    ) {
16250        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16251
16252        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16253            let autoscroll = self
16254                .selections
16255                .all::<Point>(cx)
16256                .iter()
16257                .any(|selection| crease.range().overlaps(&selection.range()));
16258
16259            self.fold_creases(vec![crease], autoscroll, window, cx);
16260        }
16261    }
16262
16263    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16264        if self.is_singleton(cx) {
16265            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16266            let buffer = &display_map.buffer_snapshot;
16267            let selections = self.selections.all::<Point>(cx);
16268            let ranges = selections
16269                .iter()
16270                .map(|s| {
16271                    let range = s.display_range(&display_map).sorted();
16272                    let mut start = range.start.to_point(&display_map);
16273                    let mut end = range.end.to_point(&display_map);
16274                    start.column = 0;
16275                    end.column = buffer.line_len(MultiBufferRow(end.row));
16276                    start..end
16277                })
16278                .collect::<Vec<_>>();
16279
16280            self.unfold_ranges(&ranges, true, true, cx);
16281        } else {
16282            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16283            let buffer_ids = self
16284                .selections
16285                .disjoint_anchor_ranges()
16286                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16287                .collect::<HashSet<_>>();
16288            for buffer_id in buffer_ids {
16289                self.unfold_buffer(buffer_id, cx);
16290            }
16291        }
16292    }
16293
16294    pub fn unfold_recursive(
16295        &mut self,
16296        _: &UnfoldRecursive,
16297        _window: &mut Window,
16298        cx: &mut Context<Self>,
16299    ) {
16300        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16301        let selections = self.selections.all::<Point>(cx);
16302        let ranges = selections
16303            .iter()
16304            .map(|s| {
16305                let mut range = s.display_range(&display_map).sorted();
16306                *range.start.column_mut() = 0;
16307                *range.end.column_mut() = display_map.line_len(range.end.row());
16308                let start = range.start.to_point(&display_map);
16309                let end = range.end.to_point(&display_map);
16310                start..end
16311            })
16312            .collect::<Vec<_>>();
16313
16314        self.unfold_ranges(&ranges, true, true, cx);
16315    }
16316
16317    pub fn unfold_at(
16318        &mut self,
16319        buffer_row: MultiBufferRow,
16320        _window: &mut Window,
16321        cx: &mut Context<Self>,
16322    ) {
16323        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16324
16325        let intersection_range = Point::new(buffer_row.0, 0)
16326            ..Point::new(
16327                buffer_row.0,
16328                display_map.buffer_snapshot.line_len(buffer_row),
16329            );
16330
16331        let autoscroll = self
16332            .selections
16333            .all::<Point>(cx)
16334            .iter()
16335            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16336
16337        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16338    }
16339
16340    pub fn unfold_all(
16341        &mut self,
16342        _: &actions::UnfoldAll,
16343        _window: &mut Window,
16344        cx: &mut Context<Self>,
16345    ) {
16346        if self.buffer.read(cx).is_singleton() {
16347            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16348            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16349        } else {
16350            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16351                editor
16352                    .update(cx, |editor, cx| {
16353                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16354                            editor.unfold_buffer(buffer_id, cx);
16355                        }
16356                    })
16357                    .ok();
16358            });
16359        }
16360    }
16361
16362    pub fn fold_selected_ranges(
16363        &mut self,
16364        _: &FoldSelectedRanges,
16365        window: &mut Window,
16366        cx: &mut Context<Self>,
16367    ) {
16368        let selections = self.selections.all_adjusted(cx);
16369        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16370        let ranges = selections
16371            .into_iter()
16372            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16373            .collect::<Vec<_>>();
16374        self.fold_creases(ranges, true, window, cx);
16375    }
16376
16377    pub fn fold_ranges<T: ToOffset + Clone>(
16378        &mut self,
16379        ranges: Vec<Range<T>>,
16380        auto_scroll: bool,
16381        window: &mut Window,
16382        cx: &mut Context<Self>,
16383    ) {
16384        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16385        let ranges = ranges
16386            .into_iter()
16387            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16388            .collect::<Vec<_>>();
16389        self.fold_creases(ranges, auto_scroll, window, cx);
16390    }
16391
16392    pub fn fold_creases<T: ToOffset + Clone>(
16393        &mut self,
16394        creases: Vec<Crease<T>>,
16395        auto_scroll: bool,
16396        _window: &mut Window,
16397        cx: &mut Context<Self>,
16398    ) {
16399        if creases.is_empty() {
16400            return;
16401        }
16402
16403        let mut buffers_affected = HashSet::default();
16404        let multi_buffer = self.buffer().read(cx);
16405        for crease in &creases {
16406            if let Some((_, buffer, _)) =
16407                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16408            {
16409                buffers_affected.insert(buffer.read(cx).remote_id());
16410            };
16411        }
16412
16413        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16414
16415        if auto_scroll {
16416            self.request_autoscroll(Autoscroll::fit(), cx);
16417        }
16418
16419        cx.notify();
16420
16421        self.scrollbar_marker_state.dirty = true;
16422        self.folds_did_change(cx);
16423    }
16424
16425    /// Removes any folds whose ranges intersect any of the given ranges.
16426    pub fn unfold_ranges<T: ToOffset + Clone>(
16427        &mut self,
16428        ranges: &[Range<T>],
16429        inclusive: bool,
16430        auto_scroll: bool,
16431        cx: &mut Context<Self>,
16432    ) {
16433        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16434            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16435        });
16436        self.folds_did_change(cx);
16437    }
16438
16439    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16440        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16441            return;
16442        }
16443        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16444        self.display_map.update(cx, |display_map, cx| {
16445            display_map.fold_buffers([buffer_id], cx)
16446        });
16447        cx.emit(EditorEvent::BufferFoldToggled {
16448            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16449            folded: true,
16450        });
16451        cx.notify();
16452    }
16453
16454    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16455        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16456            return;
16457        }
16458        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16459        self.display_map.update(cx, |display_map, cx| {
16460            display_map.unfold_buffers([buffer_id], cx);
16461        });
16462        cx.emit(EditorEvent::BufferFoldToggled {
16463            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16464            folded: false,
16465        });
16466        cx.notify();
16467    }
16468
16469    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16470        self.display_map.read(cx).is_buffer_folded(buffer)
16471    }
16472
16473    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16474        self.display_map.read(cx).folded_buffers()
16475    }
16476
16477    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16478        self.display_map.update(cx, |display_map, cx| {
16479            display_map.disable_header_for_buffer(buffer_id, cx);
16480        });
16481        cx.notify();
16482    }
16483
16484    /// Removes any folds with the given ranges.
16485    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16486        &mut self,
16487        ranges: &[Range<T>],
16488        type_id: TypeId,
16489        auto_scroll: bool,
16490        cx: &mut Context<Self>,
16491    ) {
16492        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16493            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16494        });
16495        self.folds_did_change(cx);
16496    }
16497
16498    fn remove_folds_with<T: ToOffset + Clone>(
16499        &mut self,
16500        ranges: &[Range<T>],
16501        auto_scroll: bool,
16502        cx: &mut Context<Self>,
16503        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16504    ) {
16505        if ranges.is_empty() {
16506            return;
16507        }
16508
16509        let mut buffers_affected = HashSet::default();
16510        let multi_buffer = self.buffer().read(cx);
16511        for range in ranges {
16512            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16513                buffers_affected.insert(buffer.read(cx).remote_id());
16514            };
16515        }
16516
16517        self.display_map.update(cx, update);
16518
16519        if auto_scroll {
16520            self.request_autoscroll(Autoscroll::fit(), cx);
16521        }
16522
16523        cx.notify();
16524        self.scrollbar_marker_state.dirty = true;
16525        self.active_indent_guides_state.dirty = true;
16526    }
16527
16528    pub fn update_fold_widths(
16529        &mut self,
16530        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16531        cx: &mut Context<Self>,
16532    ) -> bool {
16533        self.display_map
16534            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16535    }
16536
16537    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16538        self.display_map.read(cx).fold_placeholder.clone()
16539    }
16540
16541    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16542        self.buffer.update(cx, |buffer, cx| {
16543            buffer.set_all_diff_hunks_expanded(cx);
16544        });
16545    }
16546
16547    pub fn expand_all_diff_hunks(
16548        &mut self,
16549        _: &ExpandAllDiffHunks,
16550        _window: &mut Window,
16551        cx: &mut Context<Self>,
16552    ) {
16553        self.buffer.update(cx, |buffer, cx| {
16554            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16555        });
16556    }
16557
16558    pub fn toggle_selected_diff_hunks(
16559        &mut self,
16560        _: &ToggleSelectedDiffHunks,
16561        _window: &mut Window,
16562        cx: &mut Context<Self>,
16563    ) {
16564        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16565        self.toggle_diff_hunks_in_ranges(ranges, cx);
16566    }
16567
16568    pub fn diff_hunks_in_ranges<'a>(
16569        &'a self,
16570        ranges: &'a [Range<Anchor>],
16571        buffer: &'a MultiBufferSnapshot,
16572    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16573        ranges.iter().flat_map(move |range| {
16574            let end_excerpt_id = range.end.excerpt_id;
16575            let range = range.to_point(buffer);
16576            let mut peek_end = range.end;
16577            if range.end.row < buffer.max_row().0 {
16578                peek_end = Point::new(range.end.row + 1, 0);
16579            }
16580            buffer
16581                .diff_hunks_in_range(range.start..peek_end)
16582                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16583        })
16584    }
16585
16586    pub fn has_stageable_diff_hunks_in_ranges(
16587        &self,
16588        ranges: &[Range<Anchor>],
16589        snapshot: &MultiBufferSnapshot,
16590    ) -> bool {
16591        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16592        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16593    }
16594
16595    pub fn toggle_staged_selected_diff_hunks(
16596        &mut self,
16597        _: &::git::ToggleStaged,
16598        _: &mut Window,
16599        cx: &mut Context<Self>,
16600    ) {
16601        let snapshot = self.buffer.read(cx).snapshot(cx);
16602        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16603        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16604        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16605    }
16606
16607    pub fn set_render_diff_hunk_controls(
16608        &mut self,
16609        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16610        cx: &mut Context<Self>,
16611    ) {
16612        self.render_diff_hunk_controls = render_diff_hunk_controls;
16613        cx.notify();
16614    }
16615
16616    pub fn stage_and_next(
16617        &mut self,
16618        _: &::git::StageAndNext,
16619        window: &mut Window,
16620        cx: &mut Context<Self>,
16621    ) {
16622        self.do_stage_or_unstage_and_next(true, window, cx);
16623    }
16624
16625    pub fn unstage_and_next(
16626        &mut self,
16627        _: &::git::UnstageAndNext,
16628        window: &mut Window,
16629        cx: &mut Context<Self>,
16630    ) {
16631        self.do_stage_or_unstage_and_next(false, window, cx);
16632    }
16633
16634    pub fn stage_or_unstage_diff_hunks(
16635        &mut self,
16636        stage: bool,
16637        ranges: Vec<Range<Anchor>>,
16638        cx: &mut Context<Self>,
16639    ) {
16640        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16641        cx.spawn(async move |this, cx| {
16642            task.await?;
16643            this.update(cx, |this, cx| {
16644                let snapshot = this.buffer.read(cx).snapshot(cx);
16645                let chunk_by = this
16646                    .diff_hunks_in_ranges(&ranges, &snapshot)
16647                    .chunk_by(|hunk| hunk.buffer_id);
16648                for (buffer_id, hunks) in &chunk_by {
16649                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16650                }
16651            })
16652        })
16653        .detach_and_log_err(cx);
16654    }
16655
16656    fn save_buffers_for_ranges_if_needed(
16657        &mut self,
16658        ranges: &[Range<Anchor>],
16659        cx: &mut Context<Editor>,
16660    ) -> Task<Result<()>> {
16661        let multibuffer = self.buffer.read(cx);
16662        let snapshot = multibuffer.read(cx);
16663        let buffer_ids: HashSet<_> = ranges
16664            .iter()
16665            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16666            .collect();
16667        drop(snapshot);
16668
16669        let mut buffers = HashSet::default();
16670        for buffer_id in buffer_ids {
16671            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16672                let buffer = buffer_entity.read(cx);
16673                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16674                {
16675                    buffers.insert(buffer_entity);
16676                }
16677            }
16678        }
16679
16680        if let Some(project) = &self.project {
16681            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16682        } else {
16683            Task::ready(Ok(()))
16684        }
16685    }
16686
16687    fn do_stage_or_unstage_and_next(
16688        &mut self,
16689        stage: bool,
16690        window: &mut Window,
16691        cx: &mut Context<Self>,
16692    ) {
16693        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16694
16695        if ranges.iter().any(|range| range.start != range.end) {
16696            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16697            return;
16698        }
16699
16700        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16701        let snapshot = self.snapshot(window, cx);
16702        let position = self.selections.newest::<Point>(cx).head();
16703        let mut row = snapshot
16704            .buffer_snapshot
16705            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16706            .find(|hunk| hunk.row_range.start.0 > position.row)
16707            .map(|hunk| hunk.row_range.start);
16708
16709        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16710        // Outside of the project diff editor, wrap around to the beginning.
16711        if !all_diff_hunks_expanded {
16712            row = row.or_else(|| {
16713                snapshot
16714                    .buffer_snapshot
16715                    .diff_hunks_in_range(Point::zero()..position)
16716                    .find(|hunk| hunk.row_range.end.0 < position.row)
16717                    .map(|hunk| hunk.row_range.start)
16718            });
16719        }
16720
16721        if let Some(row) = row {
16722            let destination = Point::new(row.0, 0);
16723            let autoscroll = Autoscroll::center();
16724
16725            self.unfold_ranges(&[destination..destination], false, false, cx);
16726            self.change_selections(Some(autoscroll), window, cx, |s| {
16727                s.select_ranges([destination..destination]);
16728            });
16729        }
16730    }
16731
16732    fn do_stage_or_unstage(
16733        &self,
16734        stage: bool,
16735        buffer_id: BufferId,
16736        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16737        cx: &mut App,
16738    ) -> Option<()> {
16739        let project = self.project.as_ref()?;
16740        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16741        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16742        let buffer_snapshot = buffer.read(cx).snapshot();
16743        let file_exists = buffer_snapshot
16744            .file()
16745            .is_some_and(|file| file.disk_state().exists());
16746        diff.update(cx, |diff, cx| {
16747            diff.stage_or_unstage_hunks(
16748                stage,
16749                &hunks
16750                    .map(|hunk| buffer_diff::DiffHunk {
16751                        buffer_range: hunk.buffer_range,
16752                        diff_base_byte_range: hunk.diff_base_byte_range,
16753                        secondary_status: hunk.secondary_status,
16754                        range: Point::zero()..Point::zero(), // unused
16755                    })
16756                    .collect::<Vec<_>>(),
16757                &buffer_snapshot,
16758                file_exists,
16759                cx,
16760            )
16761        });
16762        None
16763    }
16764
16765    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16766        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16767        self.buffer
16768            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16769    }
16770
16771    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16772        self.buffer.update(cx, |buffer, cx| {
16773            let ranges = vec![Anchor::min()..Anchor::max()];
16774            if !buffer.all_diff_hunks_expanded()
16775                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16776            {
16777                buffer.collapse_diff_hunks(ranges, cx);
16778                true
16779            } else {
16780                false
16781            }
16782        })
16783    }
16784
16785    fn toggle_diff_hunks_in_ranges(
16786        &mut self,
16787        ranges: Vec<Range<Anchor>>,
16788        cx: &mut Context<Editor>,
16789    ) {
16790        self.buffer.update(cx, |buffer, cx| {
16791            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16792            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16793        })
16794    }
16795
16796    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16797        self.buffer.update(cx, |buffer, cx| {
16798            let snapshot = buffer.snapshot(cx);
16799            let excerpt_id = range.end.excerpt_id;
16800            let point_range = range.to_point(&snapshot);
16801            let expand = !buffer.single_hunk_is_expanded(range, cx);
16802            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16803        })
16804    }
16805
16806    pub(crate) fn apply_all_diff_hunks(
16807        &mut self,
16808        _: &ApplyAllDiffHunks,
16809        window: &mut Window,
16810        cx: &mut Context<Self>,
16811    ) {
16812        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16813
16814        let buffers = self.buffer.read(cx).all_buffers();
16815        for branch_buffer in buffers {
16816            branch_buffer.update(cx, |branch_buffer, cx| {
16817                branch_buffer.merge_into_base(Vec::new(), cx);
16818            });
16819        }
16820
16821        if let Some(project) = self.project.clone() {
16822            self.save(true, project, window, cx).detach_and_log_err(cx);
16823        }
16824    }
16825
16826    pub(crate) fn apply_selected_diff_hunks(
16827        &mut self,
16828        _: &ApplyDiffHunk,
16829        window: &mut Window,
16830        cx: &mut Context<Self>,
16831    ) {
16832        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16833        let snapshot = self.snapshot(window, cx);
16834        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16835        let mut ranges_by_buffer = HashMap::default();
16836        self.transact(window, cx, |editor, _window, cx| {
16837            for hunk in hunks {
16838                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16839                    ranges_by_buffer
16840                        .entry(buffer.clone())
16841                        .or_insert_with(Vec::new)
16842                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16843                }
16844            }
16845
16846            for (buffer, ranges) in ranges_by_buffer {
16847                buffer.update(cx, |buffer, cx| {
16848                    buffer.merge_into_base(ranges, cx);
16849                });
16850            }
16851        });
16852
16853        if let Some(project) = self.project.clone() {
16854            self.save(true, project, window, cx).detach_and_log_err(cx);
16855        }
16856    }
16857
16858    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16859        if hovered != self.gutter_hovered {
16860            self.gutter_hovered = hovered;
16861            cx.notify();
16862        }
16863    }
16864
16865    pub fn insert_blocks(
16866        &mut self,
16867        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16868        autoscroll: Option<Autoscroll>,
16869        cx: &mut Context<Self>,
16870    ) -> Vec<CustomBlockId> {
16871        let blocks = self
16872            .display_map
16873            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16874        if let Some(autoscroll) = autoscroll {
16875            self.request_autoscroll(autoscroll, cx);
16876        }
16877        cx.notify();
16878        blocks
16879    }
16880
16881    pub fn resize_blocks(
16882        &mut self,
16883        heights: HashMap<CustomBlockId, u32>,
16884        autoscroll: Option<Autoscroll>,
16885        cx: &mut Context<Self>,
16886    ) {
16887        self.display_map
16888            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16889        if let Some(autoscroll) = autoscroll {
16890            self.request_autoscroll(autoscroll, cx);
16891        }
16892        cx.notify();
16893    }
16894
16895    pub fn replace_blocks(
16896        &mut self,
16897        renderers: HashMap<CustomBlockId, RenderBlock>,
16898        autoscroll: Option<Autoscroll>,
16899        cx: &mut Context<Self>,
16900    ) {
16901        self.display_map
16902            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16903        if let Some(autoscroll) = autoscroll {
16904            self.request_autoscroll(autoscroll, cx);
16905        }
16906        cx.notify();
16907    }
16908
16909    pub fn remove_blocks(
16910        &mut self,
16911        block_ids: HashSet<CustomBlockId>,
16912        autoscroll: Option<Autoscroll>,
16913        cx: &mut Context<Self>,
16914    ) {
16915        self.display_map.update(cx, |display_map, cx| {
16916            display_map.remove_blocks(block_ids, cx)
16917        });
16918        if let Some(autoscroll) = autoscroll {
16919            self.request_autoscroll(autoscroll, cx);
16920        }
16921        cx.notify();
16922    }
16923
16924    pub fn row_for_block(
16925        &self,
16926        block_id: CustomBlockId,
16927        cx: &mut Context<Self>,
16928    ) -> Option<DisplayRow> {
16929        self.display_map
16930            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16931    }
16932
16933    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16934        self.focused_block = Some(focused_block);
16935    }
16936
16937    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16938        self.focused_block.take()
16939    }
16940
16941    pub fn insert_creases(
16942        &mut self,
16943        creases: impl IntoIterator<Item = Crease<Anchor>>,
16944        cx: &mut Context<Self>,
16945    ) -> Vec<CreaseId> {
16946        self.display_map
16947            .update(cx, |map, cx| map.insert_creases(creases, cx))
16948    }
16949
16950    pub fn remove_creases(
16951        &mut self,
16952        ids: impl IntoIterator<Item = CreaseId>,
16953        cx: &mut Context<Self>,
16954    ) -> Vec<(CreaseId, Range<Anchor>)> {
16955        self.display_map
16956            .update(cx, |map, cx| map.remove_creases(ids, cx))
16957    }
16958
16959    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16960        self.display_map
16961            .update(cx, |map, cx| map.snapshot(cx))
16962            .longest_row()
16963    }
16964
16965    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16966        self.display_map
16967            .update(cx, |map, cx| map.snapshot(cx))
16968            .max_point()
16969    }
16970
16971    pub fn text(&self, cx: &App) -> String {
16972        self.buffer.read(cx).read(cx).text()
16973    }
16974
16975    pub fn is_empty(&self, cx: &App) -> bool {
16976        self.buffer.read(cx).read(cx).is_empty()
16977    }
16978
16979    pub fn text_option(&self, cx: &App) -> Option<String> {
16980        let text = self.text(cx);
16981        let text = text.trim();
16982
16983        if text.is_empty() {
16984            return None;
16985        }
16986
16987        Some(text.to_string())
16988    }
16989
16990    pub fn set_text(
16991        &mut self,
16992        text: impl Into<Arc<str>>,
16993        window: &mut Window,
16994        cx: &mut Context<Self>,
16995    ) {
16996        self.transact(window, cx, |this, _, cx| {
16997            this.buffer
16998                .read(cx)
16999                .as_singleton()
17000                .expect("you can only call set_text on editors for singleton buffers")
17001                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17002        });
17003    }
17004
17005    pub fn display_text(&self, cx: &mut App) -> String {
17006        self.display_map
17007            .update(cx, |map, cx| map.snapshot(cx))
17008            .text()
17009    }
17010
17011    fn create_minimap(
17012        &self,
17013        minimap_settings: MinimapSettings,
17014        window: &mut Window,
17015        cx: &mut Context<Self>,
17016    ) -> Option<Entity<Self>> {
17017        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17018            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17019    }
17020
17021    fn initialize_new_minimap(
17022        &self,
17023        minimap_settings: MinimapSettings,
17024        window: &mut Window,
17025        cx: &mut Context<Self>,
17026    ) -> Entity<Self> {
17027        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17028
17029        let mut minimap = Editor::new_internal(
17030            EditorMode::Minimap {
17031                parent: cx.weak_entity(),
17032            },
17033            self.buffer.clone(),
17034            self.project.clone(),
17035            Some(self.display_map.clone()),
17036            window,
17037            cx,
17038        );
17039        minimap.scroll_manager.clone_state(&self.scroll_manager);
17040        minimap.set_text_style_refinement(TextStyleRefinement {
17041            font_size: Some(MINIMAP_FONT_SIZE),
17042            font_weight: Some(MINIMAP_FONT_WEIGHT),
17043            ..Default::default()
17044        });
17045        minimap.update_minimap_configuration(minimap_settings, cx);
17046        cx.new(|_| minimap)
17047    }
17048
17049    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17050        let current_line_highlight = minimap_settings
17051            .current_line_highlight
17052            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17053        self.set_current_line_highlight(Some(current_line_highlight));
17054    }
17055
17056    pub fn minimap(&self) -> Option<&Entity<Self>> {
17057        self.minimap
17058            .as_ref()
17059            .filter(|_| self.minimap_visibility.visible())
17060    }
17061
17062    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17063        let mut wrap_guides = smallvec![];
17064
17065        if self.show_wrap_guides == Some(false) {
17066            return wrap_guides;
17067        }
17068
17069        let settings = self.buffer.read(cx).language_settings(cx);
17070        if settings.show_wrap_guides {
17071            match self.soft_wrap_mode(cx) {
17072                SoftWrap::Column(soft_wrap) => {
17073                    wrap_guides.push((soft_wrap as usize, true));
17074                }
17075                SoftWrap::Bounded(soft_wrap) => {
17076                    wrap_guides.push((soft_wrap as usize, true));
17077                }
17078                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17079            }
17080            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17081        }
17082
17083        wrap_guides
17084    }
17085
17086    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17087        let settings = self.buffer.read(cx).language_settings(cx);
17088        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17089        match mode {
17090            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17091                SoftWrap::None
17092            }
17093            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17094            language_settings::SoftWrap::PreferredLineLength => {
17095                SoftWrap::Column(settings.preferred_line_length)
17096            }
17097            language_settings::SoftWrap::Bounded => {
17098                SoftWrap::Bounded(settings.preferred_line_length)
17099            }
17100        }
17101    }
17102
17103    pub fn set_soft_wrap_mode(
17104        &mut self,
17105        mode: language_settings::SoftWrap,
17106
17107        cx: &mut Context<Self>,
17108    ) {
17109        self.soft_wrap_mode_override = Some(mode);
17110        cx.notify();
17111    }
17112
17113    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17114        self.hard_wrap = hard_wrap;
17115        cx.notify();
17116    }
17117
17118    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17119        self.text_style_refinement = Some(style);
17120    }
17121
17122    /// called by the Element so we know what style we were most recently rendered with.
17123    pub(crate) fn set_style(
17124        &mut self,
17125        style: EditorStyle,
17126        window: &mut Window,
17127        cx: &mut Context<Self>,
17128    ) {
17129        // We intentionally do not inform the display map about the minimap style
17130        // so that wrapping is not recalculated and stays consistent for the editor
17131        // and its linked minimap.
17132        if !self.mode.is_minimap() {
17133            let rem_size = window.rem_size();
17134            self.display_map.update(cx, |map, cx| {
17135                map.set_font(
17136                    style.text.font(),
17137                    style.text.font_size.to_pixels(rem_size),
17138                    cx,
17139                )
17140            });
17141        }
17142        self.style = Some(style);
17143    }
17144
17145    pub fn style(&self) -> Option<&EditorStyle> {
17146        self.style.as_ref()
17147    }
17148
17149    // Called by the element. This method is not designed to be called outside of the editor
17150    // element's layout code because it does not notify when rewrapping is computed synchronously.
17151    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17152        self.display_map
17153            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17154    }
17155
17156    pub fn set_soft_wrap(&mut self) {
17157        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17158    }
17159
17160    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17161        if self.soft_wrap_mode_override.is_some() {
17162            self.soft_wrap_mode_override.take();
17163        } else {
17164            let soft_wrap = match self.soft_wrap_mode(cx) {
17165                SoftWrap::GitDiff => return,
17166                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17167                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17168                    language_settings::SoftWrap::None
17169                }
17170            };
17171            self.soft_wrap_mode_override = Some(soft_wrap);
17172        }
17173        cx.notify();
17174    }
17175
17176    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17177        let Some(workspace) = self.workspace() else {
17178            return;
17179        };
17180        let fs = workspace.read(cx).app_state().fs.clone();
17181        let current_show = TabBarSettings::get_global(cx).show;
17182        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17183            setting.show = Some(!current_show);
17184        });
17185    }
17186
17187    pub fn toggle_indent_guides(
17188        &mut self,
17189        _: &ToggleIndentGuides,
17190        _: &mut Window,
17191        cx: &mut Context<Self>,
17192    ) {
17193        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17194            self.buffer
17195                .read(cx)
17196                .language_settings(cx)
17197                .indent_guides
17198                .enabled
17199        });
17200        self.show_indent_guides = Some(!currently_enabled);
17201        cx.notify();
17202    }
17203
17204    fn should_show_indent_guides(&self) -> Option<bool> {
17205        self.show_indent_guides
17206    }
17207
17208    pub fn toggle_line_numbers(
17209        &mut self,
17210        _: &ToggleLineNumbers,
17211        _: &mut Window,
17212        cx: &mut Context<Self>,
17213    ) {
17214        let mut editor_settings = EditorSettings::get_global(cx).clone();
17215        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17216        EditorSettings::override_global(editor_settings, cx);
17217    }
17218
17219    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17220        if let Some(show_line_numbers) = self.show_line_numbers {
17221            return show_line_numbers;
17222        }
17223        EditorSettings::get_global(cx).gutter.line_numbers
17224    }
17225
17226    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17227        self.use_relative_line_numbers
17228            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17229    }
17230
17231    pub fn toggle_relative_line_numbers(
17232        &mut self,
17233        _: &ToggleRelativeLineNumbers,
17234        _: &mut Window,
17235        cx: &mut Context<Self>,
17236    ) {
17237        let is_relative = self.should_use_relative_line_numbers(cx);
17238        self.set_relative_line_number(Some(!is_relative), cx)
17239    }
17240
17241    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17242        self.use_relative_line_numbers = is_relative;
17243        cx.notify();
17244    }
17245
17246    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17247        self.show_gutter = show_gutter;
17248        cx.notify();
17249    }
17250
17251    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17252        self.show_scrollbars = ScrollbarAxes {
17253            horizontal: show,
17254            vertical: show,
17255        };
17256        cx.notify();
17257    }
17258
17259    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17260        self.show_scrollbars.vertical = show;
17261        cx.notify();
17262    }
17263
17264    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17265        self.show_scrollbars.horizontal = show;
17266        cx.notify();
17267    }
17268
17269    pub fn set_minimap_visibility(
17270        &mut self,
17271        minimap_visibility: MinimapVisibility,
17272        window: &mut Window,
17273        cx: &mut Context<Self>,
17274    ) {
17275        if self.minimap_visibility != minimap_visibility {
17276            if minimap_visibility.visible() && self.minimap.is_none() {
17277                let minimap_settings = EditorSettings::get_global(cx).minimap;
17278                self.minimap =
17279                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17280            }
17281            self.minimap_visibility = minimap_visibility;
17282            cx.notify();
17283        }
17284    }
17285
17286    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17287        self.set_show_scrollbars(false, cx);
17288        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17289    }
17290
17291    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17292        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17293    }
17294
17295    /// Normally the text in full mode and auto height editors is padded on the
17296    /// left side by roughly half a character width for improved hit testing.
17297    ///
17298    /// Use this method to disable this for cases where this is not wanted (e.g.
17299    /// if you want to align the editor text with some other text above or below)
17300    /// or if you want to add this padding to single-line editors.
17301    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17302        self.offset_content = offset_content;
17303        cx.notify();
17304    }
17305
17306    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17307        self.show_line_numbers = Some(show_line_numbers);
17308        cx.notify();
17309    }
17310
17311    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17312        self.disable_expand_excerpt_buttons = true;
17313        cx.notify();
17314    }
17315
17316    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17317        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17318        cx.notify();
17319    }
17320
17321    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17322        self.show_code_actions = Some(show_code_actions);
17323        cx.notify();
17324    }
17325
17326    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17327        self.show_runnables = Some(show_runnables);
17328        cx.notify();
17329    }
17330
17331    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17332        self.show_breakpoints = Some(show_breakpoints);
17333        cx.notify();
17334    }
17335
17336    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17337        if self.display_map.read(cx).masked != masked {
17338            self.display_map.update(cx, |map, _| map.masked = masked);
17339        }
17340        cx.notify()
17341    }
17342
17343    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17344        self.show_wrap_guides = Some(show_wrap_guides);
17345        cx.notify();
17346    }
17347
17348    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17349        self.show_indent_guides = Some(show_indent_guides);
17350        cx.notify();
17351    }
17352
17353    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17354        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17355            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17356                if let Some(dir) = file.abs_path(cx).parent() {
17357                    return Some(dir.to_owned());
17358                }
17359            }
17360
17361            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17362                return Some(project_path.path.to_path_buf());
17363            }
17364        }
17365
17366        None
17367    }
17368
17369    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17370        self.active_excerpt(cx)?
17371            .1
17372            .read(cx)
17373            .file()
17374            .and_then(|f| f.as_local())
17375    }
17376
17377    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17378        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17379            let buffer = buffer.read(cx);
17380            if let Some(project_path) = buffer.project_path(cx) {
17381                let project = self.project.as_ref()?.read(cx);
17382                project.absolute_path(&project_path, cx)
17383            } else {
17384                buffer
17385                    .file()
17386                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17387            }
17388        })
17389    }
17390
17391    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17392        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17393            let project_path = buffer.read(cx).project_path(cx)?;
17394            let project = self.project.as_ref()?.read(cx);
17395            let entry = project.entry_for_path(&project_path, cx)?;
17396            let path = entry.path.to_path_buf();
17397            Some(path)
17398        })
17399    }
17400
17401    pub fn reveal_in_finder(
17402        &mut self,
17403        _: &RevealInFileManager,
17404        _window: &mut Window,
17405        cx: &mut Context<Self>,
17406    ) {
17407        if let Some(target) = self.target_file(cx) {
17408            cx.reveal_path(&target.abs_path(cx));
17409        }
17410    }
17411
17412    pub fn copy_path(
17413        &mut self,
17414        _: &zed_actions::workspace::CopyPath,
17415        _window: &mut Window,
17416        cx: &mut Context<Self>,
17417    ) {
17418        if let Some(path) = self.target_file_abs_path(cx) {
17419            if let Some(path) = path.to_str() {
17420                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17421            }
17422        }
17423    }
17424
17425    pub fn copy_relative_path(
17426        &mut self,
17427        _: &zed_actions::workspace::CopyRelativePath,
17428        _window: &mut Window,
17429        cx: &mut Context<Self>,
17430    ) {
17431        if let Some(path) = self.target_file_path(cx) {
17432            if let Some(path) = path.to_str() {
17433                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17434            }
17435        }
17436    }
17437
17438    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17439        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17440            buffer.read(cx).project_path(cx)
17441        } else {
17442            None
17443        }
17444    }
17445
17446    // Returns true if the editor handled a go-to-line request
17447    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17448        maybe!({
17449            let breakpoint_store = self.breakpoint_store.as_ref()?;
17450
17451            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17452            else {
17453                self.clear_row_highlights::<ActiveDebugLine>();
17454                return None;
17455            };
17456
17457            let position = active_stack_frame.position;
17458            let buffer_id = position.buffer_id?;
17459            let snapshot = self
17460                .project
17461                .as_ref()?
17462                .read(cx)
17463                .buffer_for_id(buffer_id, cx)?
17464                .read(cx)
17465                .snapshot();
17466
17467            let mut handled = false;
17468            for (id, ExcerptRange { context, .. }) in
17469                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17470            {
17471                if context.start.cmp(&position, &snapshot).is_ge()
17472                    || context.end.cmp(&position, &snapshot).is_lt()
17473                {
17474                    continue;
17475                }
17476                let snapshot = self.buffer.read(cx).snapshot(cx);
17477                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17478
17479                handled = true;
17480                self.clear_row_highlights::<ActiveDebugLine>();
17481
17482                self.go_to_line::<ActiveDebugLine>(
17483                    multibuffer_anchor,
17484                    Some(cx.theme().colors().editor_debugger_active_line_background),
17485                    window,
17486                    cx,
17487                );
17488
17489                cx.notify();
17490            }
17491
17492            handled.then_some(())
17493        })
17494        .is_some()
17495    }
17496
17497    pub fn copy_file_name_without_extension(
17498        &mut self,
17499        _: &CopyFileNameWithoutExtension,
17500        _: &mut Window,
17501        cx: &mut Context<Self>,
17502    ) {
17503        if let Some(file) = self.target_file(cx) {
17504            if let Some(file_stem) = file.path().file_stem() {
17505                if let Some(name) = file_stem.to_str() {
17506                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17507                }
17508            }
17509        }
17510    }
17511
17512    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17513        if let Some(file) = self.target_file(cx) {
17514            if let Some(file_name) = file.path().file_name() {
17515                if let Some(name) = file_name.to_str() {
17516                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17517                }
17518            }
17519        }
17520    }
17521
17522    pub fn toggle_git_blame(
17523        &mut self,
17524        _: &::git::Blame,
17525        window: &mut Window,
17526        cx: &mut Context<Self>,
17527    ) {
17528        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17529
17530        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17531            self.start_git_blame(true, window, cx);
17532        }
17533
17534        cx.notify();
17535    }
17536
17537    pub fn toggle_git_blame_inline(
17538        &mut self,
17539        _: &ToggleGitBlameInline,
17540        window: &mut Window,
17541        cx: &mut Context<Self>,
17542    ) {
17543        self.toggle_git_blame_inline_internal(true, window, cx);
17544        cx.notify();
17545    }
17546
17547    pub fn open_git_blame_commit(
17548        &mut self,
17549        _: &OpenGitBlameCommit,
17550        window: &mut Window,
17551        cx: &mut Context<Self>,
17552    ) {
17553        self.open_git_blame_commit_internal(window, cx);
17554    }
17555
17556    fn open_git_blame_commit_internal(
17557        &mut self,
17558        window: &mut Window,
17559        cx: &mut Context<Self>,
17560    ) -> Option<()> {
17561        let blame = self.blame.as_ref()?;
17562        let snapshot = self.snapshot(window, cx);
17563        let cursor = self.selections.newest::<Point>(cx).head();
17564        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17565        let blame_entry = blame
17566            .update(cx, |blame, cx| {
17567                blame
17568                    .blame_for_rows(
17569                        &[RowInfo {
17570                            buffer_id: Some(buffer.remote_id()),
17571                            buffer_row: Some(point.row),
17572                            ..Default::default()
17573                        }],
17574                        cx,
17575                    )
17576                    .next()
17577            })
17578            .flatten()?;
17579        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17580        let repo = blame.read(cx).repository(cx)?;
17581        let workspace = self.workspace()?.downgrade();
17582        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17583        None
17584    }
17585
17586    pub fn git_blame_inline_enabled(&self) -> bool {
17587        self.git_blame_inline_enabled
17588    }
17589
17590    pub fn toggle_selection_menu(
17591        &mut self,
17592        _: &ToggleSelectionMenu,
17593        _: &mut Window,
17594        cx: &mut Context<Self>,
17595    ) {
17596        self.show_selection_menu = self
17597            .show_selection_menu
17598            .map(|show_selections_menu| !show_selections_menu)
17599            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17600
17601        cx.notify();
17602    }
17603
17604    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17605        self.show_selection_menu
17606            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17607    }
17608
17609    fn start_git_blame(
17610        &mut self,
17611        user_triggered: bool,
17612        window: &mut Window,
17613        cx: &mut Context<Self>,
17614    ) {
17615        if let Some(project) = self.project.as_ref() {
17616            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17617                return;
17618            };
17619
17620            if buffer.read(cx).file().is_none() {
17621                return;
17622            }
17623
17624            let focused = self.focus_handle(cx).contains_focused(window, cx);
17625
17626            let project = project.clone();
17627            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17628            self.blame_subscription =
17629                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17630            self.blame = Some(blame);
17631        }
17632    }
17633
17634    fn toggle_git_blame_inline_internal(
17635        &mut self,
17636        user_triggered: bool,
17637        window: &mut Window,
17638        cx: &mut Context<Self>,
17639    ) {
17640        if self.git_blame_inline_enabled {
17641            self.git_blame_inline_enabled = false;
17642            self.show_git_blame_inline = false;
17643            self.show_git_blame_inline_delay_task.take();
17644        } else {
17645            self.git_blame_inline_enabled = true;
17646            self.start_git_blame_inline(user_triggered, window, cx);
17647        }
17648
17649        cx.notify();
17650    }
17651
17652    fn start_git_blame_inline(
17653        &mut self,
17654        user_triggered: bool,
17655        window: &mut Window,
17656        cx: &mut Context<Self>,
17657    ) {
17658        self.start_git_blame(user_triggered, window, cx);
17659
17660        if ProjectSettings::get_global(cx)
17661            .git
17662            .inline_blame_delay()
17663            .is_some()
17664        {
17665            self.start_inline_blame_timer(window, cx);
17666        } else {
17667            self.show_git_blame_inline = true
17668        }
17669    }
17670
17671    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17672        self.blame.as_ref()
17673    }
17674
17675    pub fn show_git_blame_gutter(&self) -> bool {
17676        self.show_git_blame_gutter
17677    }
17678
17679    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17680        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17681    }
17682
17683    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17684        self.show_git_blame_inline
17685            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17686            && !self.newest_selection_head_on_empty_line(cx)
17687            && self.has_blame_entries(cx)
17688    }
17689
17690    fn has_blame_entries(&self, cx: &App) -> bool {
17691        self.blame()
17692            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17693    }
17694
17695    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17696        let cursor_anchor = self.selections.newest_anchor().head();
17697
17698        let snapshot = self.buffer.read(cx).snapshot(cx);
17699        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17700
17701        snapshot.line_len(buffer_row) == 0
17702    }
17703
17704    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17705        let buffer_and_selection = maybe!({
17706            let selection = self.selections.newest::<Point>(cx);
17707            let selection_range = selection.range();
17708
17709            let multi_buffer = self.buffer().read(cx);
17710            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17711            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17712
17713            let (buffer, range, _) = if selection.reversed {
17714                buffer_ranges.first()
17715            } else {
17716                buffer_ranges.last()
17717            }?;
17718
17719            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17720                ..text::ToPoint::to_point(&range.end, &buffer).row;
17721            Some((
17722                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17723                selection,
17724            ))
17725        });
17726
17727        let Some((buffer, selection)) = buffer_and_selection else {
17728            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17729        };
17730
17731        let Some(project) = self.project.as_ref() else {
17732            return Task::ready(Err(anyhow!("editor does not have project")));
17733        };
17734
17735        project.update(cx, |project, cx| {
17736            project.get_permalink_to_line(&buffer, selection, cx)
17737        })
17738    }
17739
17740    pub fn copy_permalink_to_line(
17741        &mut self,
17742        _: &CopyPermalinkToLine,
17743        window: &mut Window,
17744        cx: &mut Context<Self>,
17745    ) {
17746        let permalink_task = self.get_permalink_to_line(cx);
17747        let workspace = self.workspace();
17748
17749        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17750            Ok(permalink) => {
17751                cx.update(|_, cx| {
17752                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17753                })
17754                .ok();
17755            }
17756            Err(err) => {
17757                let message = format!("Failed to copy permalink: {err}");
17758
17759                anyhow::Result::<()>::Err(err).log_err();
17760
17761                if let Some(workspace) = workspace {
17762                    workspace
17763                        .update_in(cx, |workspace, _, cx| {
17764                            struct CopyPermalinkToLine;
17765
17766                            workspace.show_toast(
17767                                Toast::new(
17768                                    NotificationId::unique::<CopyPermalinkToLine>(),
17769                                    message,
17770                                ),
17771                                cx,
17772                            )
17773                        })
17774                        .ok();
17775                }
17776            }
17777        })
17778        .detach();
17779    }
17780
17781    pub fn copy_file_location(
17782        &mut self,
17783        _: &CopyFileLocation,
17784        _: &mut Window,
17785        cx: &mut Context<Self>,
17786    ) {
17787        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17788        if let Some(file) = self.target_file(cx) {
17789            if let Some(path) = file.path().to_str() {
17790                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17791            }
17792        }
17793    }
17794
17795    pub fn open_permalink_to_line(
17796        &mut self,
17797        _: &OpenPermalinkToLine,
17798        window: &mut Window,
17799        cx: &mut Context<Self>,
17800    ) {
17801        let permalink_task = self.get_permalink_to_line(cx);
17802        let workspace = self.workspace();
17803
17804        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17805            Ok(permalink) => {
17806                cx.update(|_, cx| {
17807                    cx.open_url(permalink.as_ref());
17808                })
17809                .ok();
17810            }
17811            Err(err) => {
17812                let message = format!("Failed to open permalink: {err}");
17813
17814                anyhow::Result::<()>::Err(err).log_err();
17815
17816                if let Some(workspace) = workspace {
17817                    workspace
17818                        .update(cx, |workspace, cx| {
17819                            struct OpenPermalinkToLine;
17820
17821                            workspace.show_toast(
17822                                Toast::new(
17823                                    NotificationId::unique::<OpenPermalinkToLine>(),
17824                                    message,
17825                                ),
17826                                cx,
17827                            )
17828                        })
17829                        .ok();
17830                }
17831            }
17832        })
17833        .detach();
17834    }
17835
17836    pub fn insert_uuid_v4(
17837        &mut self,
17838        _: &InsertUuidV4,
17839        window: &mut Window,
17840        cx: &mut Context<Self>,
17841    ) {
17842        self.insert_uuid(UuidVersion::V4, window, cx);
17843    }
17844
17845    pub fn insert_uuid_v7(
17846        &mut self,
17847        _: &InsertUuidV7,
17848        window: &mut Window,
17849        cx: &mut Context<Self>,
17850    ) {
17851        self.insert_uuid(UuidVersion::V7, window, cx);
17852    }
17853
17854    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17855        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17856        self.transact(window, cx, |this, window, cx| {
17857            let edits = this
17858                .selections
17859                .all::<Point>(cx)
17860                .into_iter()
17861                .map(|selection| {
17862                    let uuid = match version {
17863                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17864                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17865                    };
17866
17867                    (selection.range(), uuid.to_string())
17868                });
17869            this.edit(edits, cx);
17870            this.refresh_inline_completion(true, false, window, cx);
17871        });
17872    }
17873
17874    pub fn open_selections_in_multibuffer(
17875        &mut self,
17876        _: &OpenSelectionsInMultibuffer,
17877        window: &mut Window,
17878        cx: &mut Context<Self>,
17879    ) {
17880        let multibuffer = self.buffer.read(cx);
17881
17882        let Some(buffer) = multibuffer.as_singleton() else {
17883            return;
17884        };
17885
17886        let Some(workspace) = self.workspace() else {
17887            return;
17888        };
17889
17890        let locations = self
17891            .selections
17892            .disjoint_anchors()
17893            .iter()
17894            .map(|selection| {
17895                let range = if selection.reversed {
17896                    selection.end.text_anchor..selection.start.text_anchor
17897                } else {
17898                    selection.start.text_anchor..selection.end.text_anchor
17899                };
17900                Location {
17901                    buffer: buffer.clone(),
17902                    range,
17903                }
17904            })
17905            .collect::<Vec<_>>();
17906
17907        let title = multibuffer.title(cx).to_string();
17908
17909        cx.spawn_in(window, async move |_, cx| {
17910            workspace.update_in(cx, |workspace, window, cx| {
17911                Self::open_locations_in_multibuffer(
17912                    workspace,
17913                    locations,
17914                    format!("Selections for '{title}'"),
17915                    false,
17916                    MultibufferSelectionMode::All,
17917                    window,
17918                    cx,
17919                );
17920            })
17921        })
17922        .detach();
17923    }
17924
17925    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17926    /// last highlight added will be used.
17927    ///
17928    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17929    pub fn highlight_rows<T: 'static>(
17930        &mut self,
17931        range: Range<Anchor>,
17932        color: Hsla,
17933        options: RowHighlightOptions,
17934        cx: &mut Context<Self>,
17935    ) {
17936        let snapshot = self.buffer().read(cx).snapshot(cx);
17937        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17938        let ix = row_highlights.binary_search_by(|highlight| {
17939            Ordering::Equal
17940                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17941                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17942        });
17943
17944        if let Err(mut ix) = ix {
17945            let index = post_inc(&mut self.highlight_order);
17946
17947            // If this range intersects with the preceding highlight, then merge it with
17948            // the preceding highlight. Otherwise insert a new highlight.
17949            let mut merged = false;
17950            if ix > 0 {
17951                let prev_highlight = &mut row_highlights[ix - 1];
17952                if prev_highlight
17953                    .range
17954                    .end
17955                    .cmp(&range.start, &snapshot)
17956                    .is_ge()
17957                {
17958                    ix -= 1;
17959                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17960                        prev_highlight.range.end = range.end;
17961                    }
17962                    merged = true;
17963                    prev_highlight.index = index;
17964                    prev_highlight.color = color;
17965                    prev_highlight.options = options;
17966                }
17967            }
17968
17969            if !merged {
17970                row_highlights.insert(
17971                    ix,
17972                    RowHighlight {
17973                        range: range.clone(),
17974                        index,
17975                        color,
17976                        options,
17977                        type_id: TypeId::of::<T>(),
17978                    },
17979                );
17980            }
17981
17982            // If any of the following highlights intersect with this one, merge them.
17983            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17984                let highlight = &row_highlights[ix];
17985                if next_highlight
17986                    .range
17987                    .start
17988                    .cmp(&highlight.range.end, &snapshot)
17989                    .is_le()
17990                {
17991                    if next_highlight
17992                        .range
17993                        .end
17994                        .cmp(&highlight.range.end, &snapshot)
17995                        .is_gt()
17996                    {
17997                        row_highlights[ix].range.end = next_highlight.range.end;
17998                    }
17999                    row_highlights.remove(ix + 1);
18000                } else {
18001                    break;
18002                }
18003            }
18004        }
18005    }
18006
18007    /// Remove any highlighted row ranges of the given type that intersect the
18008    /// given ranges.
18009    pub fn remove_highlighted_rows<T: 'static>(
18010        &mut self,
18011        ranges_to_remove: Vec<Range<Anchor>>,
18012        cx: &mut Context<Self>,
18013    ) {
18014        let snapshot = self.buffer().read(cx).snapshot(cx);
18015        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18016        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18017        row_highlights.retain(|highlight| {
18018            while let Some(range_to_remove) = ranges_to_remove.peek() {
18019                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18020                    Ordering::Less | Ordering::Equal => {
18021                        ranges_to_remove.next();
18022                    }
18023                    Ordering::Greater => {
18024                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18025                            Ordering::Less | Ordering::Equal => {
18026                                return false;
18027                            }
18028                            Ordering::Greater => break,
18029                        }
18030                    }
18031                }
18032            }
18033
18034            true
18035        })
18036    }
18037
18038    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18039    pub fn clear_row_highlights<T: 'static>(&mut self) {
18040        self.highlighted_rows.remove(&TypeId::of::<T>());
18041    }
18042
18043    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18044    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18045        self.highlighted_rows
18046            .get(&TypeId::of::<T>())
18047            .map_or(&[] as &[_], |vec| vec.as_slice())
18048            .iter()
18049            .map(|highlight| (highlight.range.clone(), highlight.color))
18050    }
18051
18052    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18053    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18054    /// Allows to ignore certain kinds of highlights.
18055    pub fn highlighted_display_rows(
18056        &self,
18057        window: &mut Window,
18058        cx: &mut App,
18059    ) -> BTreeMap<DisplayRow, LineHighlight> {
18060        let snapshot = self.snapshot(window, cx);
18061        let mut used_highlight_orders = HashMap::default();
18062        self.highlighted_rows
18063            .iter()
18064            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18065            .fold(
18066                BTreeMap::<DisplayRow, LineHighlight>::new(),
18067                |mut unique_rows, highlight| {
18068                    let start = highlight.range.start.to_display_point(&snapshot);
18069                    let end = highlight.range.end.to_display_point(&snapshot);
18070                    let start_row = start.row().0;
18071                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18072                        && end.column() == 0
18073                    {
18074                        end.row().0.saturating_sub(1)
18075                    } else {
18076                        end.row().0
18077                    };
18078                    for row in start_row..=end_row {
18079                        let used_index =
18080                            used_highlight_orders.entry(row).or_insert(highlight.index);
18081                        if highlight.index >= *used_index {
18082                            *used_index = highlight.index;
18083                            unique_rows.insert(
18084                                DisplayRow(row),
18085                                LineHighlight {
18086                                    include_gutter: highlight.options.include_gutter,
18087                                    border: None,
18088                                    background: highlight.color.into(),
18089                                    type_id: Some(highlight.type_id),
18090                                },
18091                            );
18092                        }
18093                    }
18094                    unique_rows
18095                },
18096            )
18097    }
18098
18099    pub fn highlighted_display_row_for_autoscroll(
18100        &self,
18101        snapshot: &DisplaySnapshot,
18102    ) -> Option<DisplayRow> {
18103        self.highlighted_rows
18104            .values()
18105            .flat_map(|highlighted_rows| highlighted_rows.iter())
18106            .filter_map(|highlight| {
18107                if highlight.options.autoscroll {
18108                    Some(highlight.range.start.to_display_point(snapshot).row())
18109                } else {
18110                    None
18111                }
18112            })
18113            .min()
18114    }
18115
18116    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18117        self.highlight_background::<SearchWithinRange>(
18118            ranges,
18119            |colors| colors.editor_document_highlight_read_background,
18120            cx,
18121        )
18122    }
18123
18124    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18125        self.breadcrumb_header = Some(new_header);
18126    }
18127
18128    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18129        self.clear_background_highlights::<SearchWithinRange>(cx);
18130    }
18131
18132    pub fn highlight_background<T: 'static>(
18133        &mut self,
18134        ranges: &[Range<Anchor>],
18135        color_fetcher: fn(&ThemeColors) -> Hsla,
18136        cx: &mut Context<Self>,
18137    ) {
18138        self.background_highlights
18139            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18140        self.scrollbar_marker_state.dirty = true;
18141        cx.notify();
18142    }
18143
18144    pub fn clear_background_highlights<T: 'static>(
18145        &mut self,
18146        cx: &mut Context<Self>,
18147    ) -> Option<BackgroundHighlight> {
18148        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18149        if !text_highlights.1.is_empty() {
18150            self.scrollbar_marker_state.dirty = true;
18151            cx.notify();
18152        }
18153        Some(text_highlights)
18154    }
18155
18156    pub fn highlight_gutter<T: 'static>(
18157        &mut self,
18158        ranges: &[Range<Anchor>],
18159        color_fetcher: fn(&App) -> Hsla,
18160        cx: &mut Context<Self>,
18161    ) {
18162        self.gutter_highlights
18163            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18164        cx.notify();
18165    }
18166
18167    pub fn clear_gutter_highlights<T: 'static>(
18168        &mut self,
18169        cx: &mut Context<Self>,
18170    ) -> Option<GutterHighlight> {
18171        cx.notify();
18172        self.gutter_highlights.remove(&TypeId::of::<T>())
18173    }
18174
18175    #[cfg(feature = "test-support")]
18176    pub fn all_text_background_highlights(
18177        &self,
18178        window: &mut Window,
18179        cx: &mut Context<Self>,
18180    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18181        let snapshot = self.snapshot(window, cx);
18182        let buffer = &snapshot.buffer_snapshot;
18183        let start = buffer.anchor_before(0);
18184        let end = buffer.anchor_after(buffer.len());
18185        let theme = cx.theme().colors();
18186        self.background_highlights_in_range(start..end, &snapshot, theme)
18187    }
18188
18189    #[cfg(feature = "test-support")]
18190    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18191        let snapshot = self.buffer().read(cx).snapshot(cx);
18192
18193        let highlights = self
18194            .background_highlights
18195            .get(&TypeId::of::<items::BufferSearchHighlights>());
18196
18197        if let Some((_color, ranges)) = highlights {
18198            ranges
18199                .iter()
18200                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18201                .collect_vec()
18202        } else {
18203            vec![]
18204        }
18205    }
18206
18207    fn document_highlights_for_position<'a>(
18208        &'a self,
18209        position: Anchor,
18210        buffer: &'a MultiBufferSnapshot,
18211    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18212        let read_highlights = self
18213            .background_highlights
18214            .get(&TypeId::of::<DocumentHighlightRead>())
18215            .map(|h| &h.1);
18216        let write_highlights = self
18217            .background_highlights
18218            .get(&TypeId::of::<DocumentHighlightWrite>())
18219            .map(|h| &h.1);
18220        let left_position = position.bias_left(buffer);
18221        let right_position = position.bias_right(buffer);
18222        read_highlights
18223            .into_iter()
18224            .chain(write_highlights)
18225            .flat_map(move |ranges| {
18226                let start_ix = match ranges.binary_search_by(|probe| {
18227                    let cmp = probe.end.cmp(&left_position, buffer);
18228                    if cmp.is_ge() {
18229                        Ordering::Greater
18230                    } else {
18231                        Ordering::Less
18232                    }
18233                }) {
18234                    Ok(i) | Err(i) => i,
18235                };
18236
18237                ranges[start_ix..]
18238                    .iter()
18239                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18240            })
18241    }
18242
18243    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18244        self.background_highlights
18245            .get(&TypeId::of::<T>())
18246            .map_or(false, |(_, highlights)| !highlights.is_empty())
18247    }
18248
18249    pub fn background_highlights_in_range(
18250        &self,
18251        search_range: Range<Anchor>,
18252        display_snapshot: &DisplaySnapshot,
18253        theme: &ThemeColors,
18254    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18255        let mut results = Vec::new();
18256        for (color_fetcher, ranges) in self.background_highlights.values() {
18257            let color = color_fetcher(theme);
18258            let start_ix = match ranges.binary_search_by(|probe| {
18259                let cmp = probe
18260                    .end
18261                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18262                if cmp.is_gt() {
18263                    Ordering::Greater
18264                } else {
18265                    Ordering::Less
18266                }
18267            }) {
18268                Ok(i) | Err(i) => i,
18269            };
18270            for range in &ranges[start_ix..] {
18271                if range
18272                    .start
18273                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18274                    .is_ge()
18275                {
18276                    break;
18277                }
18278
18279                let start = range.start.to_display_point(display_snapshot);
18280                let end = range.end.to_display_point(display_snapshot);
18281                results.push((start..end, color))
18282            }
18283        }
18284        results
18285    }
18286
18287    pub fn background_highlight_row_ranges<T: 'static>(
18288        &self,
18289        search_range: Range<Anchor>,
18290        display_snapshot: &DisplaySnapshot,
18291        count: usize,
18292    ) -> Vec<RangeInclusive<DisplayPoint>> {
18293        let mut results = Vec::new();
18294        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18295            return vec![];
18296        };
18297
18298        let start_ix = match ranges.binary_search_by(|probe| {
18299            let cmp = probe
18300                .end
18301                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18302            if cmp.is_gt() {
18303                Ordering::Greater
18304            } else {
18305                Ordering::Less
18306            }
18307        }) {
18308            Ok(i) | Err(i) => i,
18309        };
18310        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18311            if let (Some(start_display), Some(end_display)) = (start, end) {
18312                results.push(
18313                    start_display.to_display_point(display_snapshot)
18314                        ..=end_display.to_display_point(display_snapshot),
18315                );
18316            }
18317        };
18318        let mut start_row: Option<Point> = None;
18319        let mut end_row: Option<Point> = None;
18320        if ranges.len() > count {
18321            return Vec::new();
18322        }
18323        for range in &ranges[start_ix..] {
18324            if range
18325                .start
18326                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18327                .is_ge()
18328            {
18329                break;
18330            }
18331            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18332            if let Some(current_row) = &end_row {
18333                if end.row == current_row.row {
18334                    continue;
18335                }
18336            }
18337            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18338            if start_row.is_none() {
18339                assert_eq!(end_row, None);
18340                start_row = Some(start);
18341                end_row = Some(end);
18342                continue;
18343            }
18344            if let Some(current_end) = end_row.as_mut() {
18345                if start.row > current_end.row + 1 {
18346                    push_region(start_row, end_row);
18347                    start_row = Some(start);
18348                    end_row = Some(end);
18349                } else {
18350                    // Merge two hunks.
18351                    *current_end = end;
18352                }
18353            } else {
18354                unreachable!();
18355            }
18356        }
18357        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18358        push_region(start_row, end_row);
18359        results
18360    }
18361
18362    pub fn gutter_highlights_in_range(
18363        &self,
18364        search_range: Range<Anchor>,
18365        display_snapshot: &DisplaySnapshot,
18366        cx: &App,
18367    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18368        let mut results = Vec::new();
18369        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18370            let color = color_fetcher(cx);
18371            let start_ix = match ranges.binary_search_by(|probe| {
18372                let cmp = probe
18373                    .end
18374                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18375                if cmp.is_gt() {
18376                    Ordering::Greater
18377                } else {
18378                    Ordering::Less
18379                }
18380            }) {
18381                Ok(i) | Err(i) => i,
18382            };
18383            for range in &ranges[start_ix..] {
18384                if range
18385                    .start
18386                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18387                    .is_ge()
18388                {
18389                    break;
18390                }
18391
18392                let start = range.start.to_display_point(display_snapshot);
18393                let end = range.end.to_display_point(display_snapshot);
18394                results.push((start..end, color))
18395            }
18396        }
18397        results
18398    }
18399
18400    /// Get the text ranges corresponding to the redaction query
18401    pub fn redacted_ranges(
18402        &self,
18403        search_range: Range<Anchor>,
18404        display_snapshot: &DisplaySnapshot,
18405        cx: &App,
18406    ) -> Vec<Range<DisplayPoint>> {
18407        display_snapshot
18408            .buffer_snapshot
18409            .redacted_ranges(search_range, |file| {
18410                if let Some(file) = file {
18411                    file.is_private()
18412                        && EditorSettings::get(
18413                            Some(SettingsLocation {
18414                                worktree_id: file.worktree_id(cx),
18415                                path: file.path().as_ref(),
18416                            }),
18417                            cx,
18418                        )
18419                        .redact_private_values
18420                } else {
18421                    false
18422                }
18423            })
18424            .map(|range| {
18425                range.start.to_display_point(display_snapshot)
18426                    ..range.end.to_display_point(display_snapshot)
18427            })
18428            .collect()
18429    }
18430
18431    pub fn highlight_text<T: 'static>(
18432        &mut self,
18433        ranges: Vec<Range<Anchor>>,
18434        style: HighlightStyle,
18435        cx: &mut Context<Self>,
18436    ) {
18437        self.display_map.update(cx, |map, _| {
18438            map.highlight_text(TypeId::of::<T>(), ranges, style)
18439        });
18440        cx.notify();
18441    }
18442
18443    pub(crate) fn highlight_inlays<T: 'static>(
18444        &mut self,
18445        highlights: Vec<InlayHighlight>,
18446        style: HighlightStyle,
18447        cx: &mut Context<Self>,
18448    ) {
18449        self.display_map.update(cx, |map, _| {
18450            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18451        });
18452        cx.notify();
18453    }
18454
18455    pub fn text_highlights<'a, T: 'static>(
18456        &'a self,
18457        cx: &'a App,
18458    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18459        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18460    }
18461
18462    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18463        let cleared = self
18464            .display_map
18465            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18466        if cleared {
18467            cx.notify();
18468        }
18469    }
18470
18471    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18472        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18473            && self.focus_handle.is_focused(window)
18474    }
18475
18476    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18477        self.show_cursor_when_unfocused = is_enabled;
18478        cx.notify();
18479    }
18480
18481    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18482        cx.notify();
18483    }
18484
18485    fn on_debug_session_event(
18486        &mut self,
18487        _session: Entity<Session>,
18488        event: &SessionEvent,
18489        cx: &mut Context<Self>,
18490    ) {
18491        match event {
18492            SessionEvent::InvalidateInlineValue => {
18493                self.refresh_inline_values(cx);
18494            }
18495            _ => {}
18496        }
18497    }
18498
18499    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18500        let Some(project) = self.project.clone() else {
18501            return;
18502        };
18503
18504        if !self.inline_value_cache.enabled {
18505            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18506            self.splice_inlays(&inlays, Vec::new(), cx);
18507            return;
18508        }
18509
18510        let current_execution_position = self
18511            .highlighted_rows
18512            .get(&TypeId::of::<ActiveDebugLine>())
18513            .and_then(|lines| lines.last().map(|line| line.range.start));
18514
18515        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18516            let inline_values = editor
18517                .update(cx, |editor, cx| {
18518                    let Some(current_execution_position) = current_execution_position else {
18519                        return Some(Task::ready(Ok(Vec::new())));
18520                    };
18521
18522                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18523                        let snapshot = buffer.snapshot(cx);
18524
18525                        let excerpt = snapshot.excerpt_containing(
18526                            current_execution_position..current_execution_position,
18527                        )?;
18528
18529                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18530                    })?;
18531
18532                    let range =
18533                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18534
18535                    project.inline_values(buffer, range, cx)
18536                })
18537                .ok()
18538                .flatten()?
18539                .await
18540                .context("refreshing debugger inlays")
18541                .log_err()?;
18542
18543            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18544
18545            for (buffer_id, inline_value) in inline_values
18546                .into_iter()
18547                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18548            {
18549                buffer_inline_values
18550                    .entry(buffer_id)
18551                    .or_default()
18552                    .push(inline_value);
18553            }
18554
18555            editor
18556                .update(cx, |editor, cx| {
18557                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18558                    let mut new_inlays = Vec::default();
18559
18560                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18561                        let buffer_id = buffer_snapshot.remote_id();
18562                        buffer_inline_values
18563                            .get(&buffer_id)
18564                            .into_iter()
18565                            .flatten()
18566                            .for_each(|hint| {
18567                                let inlay = Inlay::debugger_hint(
18568                                    post_inc(&mut editor.next_inlay_id),
18569                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18570                                    hint.text(),
18571                                );
18572
18573                                new_inlays.push(inlay);
18574                            });
18575                    }
18576
18577                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18578                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18579
18580                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18581                })
18582                .ok()?;
18583            Some(())
18584        });
18585    }
18586
18587    fn on_buffer_event(
18588        &mut self,
18589        multibuffer: &Entity<MultiBuffer>,
18590        event: &multi_buffer::Event,
18591        window: &mut Window,
18592        cx: &mut Context<Self>,
18593    ) {
18594        match event {
18595            multi_buffer::Event::Edited {
18596                singleton_buffer_edited,
18597                edited_buffer: buffer_edited,
18598            } => {
18599                self.scrollbar_marker_state.dirty = true;
18600                self.active_indent_guides_state.dirty = true;
18601                self.refresh_active_diagnostics(cx);
18602                self.refresh_code_actions(window, cx);
18603                self.refresh_selected_text_highlights(true, window, cx);
18604                refresh_matching_bracket_highlights(self, window, cx);
18605                if self.has_active_inline_completion() {
18606                    self.update_visible_inline_completion(window, cx);
18607                }
18608                if let Some(buffer) = buffer_edited {
18609                    let buffer_id = buffer.read(cx).remote_id();
18610                    if !self.registered_buffers.contains_key(&buffer_id) {
18611                        if let Some(project) = self.project.as_ref() {
18612                            project.update(cx, |project, cx| {
18613                                self.registered_buffers.insert(
18614                                    buffer_id,
18615                                    project.register_buffer_with_language_servers(&buffer, cx),
18616                                );
18617                            })
18618                        }
18619                    }
18620                }
18621                cx.emit(EditorEvent::BufferEdited);
18622                cx.emit(SearchEvent::MatchesInvalidated);
18623                if *singleton_buffer_edited {
18624                    if let Some(project) = &self.project {
18625                        #[allow(clippy::mutable_key_type)]
18626                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18627                            multibuffer
18628                                .all_buffers()
18629                                .into_iter()
18630                                .filter_map(|buffer| {
18631                                    buffer.update(cx, |buffer, cx| {
18632                                        let language = buffer.language()?;
18633                                        let should_discard = project.update(cx, |project, cx| {
18634                                            project.is_local()
18635                                                && !project.has_language_servers_for(buffer, cx)
18636                                        });
18637                                        should_discard.not().then_some(language.clone())
18638                                    })
18639                                })
18640                                .collect::<HashSet<_>>()
18641                        });
18642                        if !languages_affected.is_empty() {
18643                            self.refresh_inlay_hints(
18644                                InlayHintRefreshReason::BufferEdited(languages_affected),
18645                                cx,
18646                            );
18647                        }
18648                    }
18649                }
18650
18651                let Some(project) = &self.project else { return };
18652                let (telemetry, is_via_ssh) = {
18653                    let project = project.read(cx);
18654                    let telemetry = project.client().telemetry().clone();
18655                    let is_via_ssh = project.is_via_ssh();
18656                    (telemetry, is_via_ssh)
18657                };
18658                refresh_linked_ranges(self, window, cx);
18659                telemetry.log_edit_event("editor", is_via_ssh);
18660            }
18661            multi_buffer::Event::ExcerptsAdded {
18662                buffer,
18663                predecessor,
18664                excerpts,
18665            } => {
18666                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18667                let buffer_id = buffer.read(cx).remote_id();
18668                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18669                    if let Some(project) = &self.project {
18670                        update_uncommitted_diff_for_buffer(
18671                            cx.entity(),
18672                            project,
18673                            [buffer.clone()],
18674                            self.buffer.clone(),
18675                            cx,
18676                        )
18677                        .detach();
18678                    }
18679                }
18680                cx.emit(EditorEvent::ExcerptsAdded {
18681                    buffer: buffer.clone(),
18682                    predecessor: *predecessor,
18683                    excerpts: excerpts.clone(),
18684                });
18685                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18686            }
18687            multi_buffer::Event::ExcerptsRemoved {
18688                ids,
18689                removed_buffer_ids,
18690            } => {
18691                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18692                let buffer = self.buffer.read(cx);
18693                self.registered_buffers
18694                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18695                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18696                cx.emit(EditorEvent::ExcerptsRemoved {
18697                    ids: ids.clone(),
18698                    removed_buffer_ids: removed_buffer_ids.clone(),
18699                })
18700            }
18701            multi_buffer::Event::ExcerptsEdited {
18702                excerpt_ids,
18703                buffer_ids,
18704            } => {
18705                self.display_map.update(cx, |map, cx| {
18706                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18707                });
18708                cx.emit(EditorEvent::ExcerptsEdited {
18709                    ids: excerpt_ids.clone(),
18710                })
18711            }
18712            multi_buffer::Event::ExcerptsExpanded { ids } => {
18713                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18714                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18715            }
18716            multi_buffer::Event::Reparsed(buffer_id) => {
18717                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18718                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18719
18720                cx.emit(EditorEvent::Reparsed(*buffer_id));
18721            }
18722            multi_buffer::Event::DiffHunksToggled => {
18723                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18724            }
18725            multi_buffer::Event::LanguageChanged(buffer_id) => {
18726                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18727                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18728                cx.emit(EditorEvent::Reparsed(*buffer_id));
18729                cx.notify();
18730            }
18731            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18732            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18733            multi_buffer::Event::FileHandleChanged
18734            | multi_buffer::Event::Reloaded
18735            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18736            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18737            multi_buffer::Event::DiagnosticsUpdated => {
18738                self.refresh_active_diagnostics(cx);
18739                self.refresh_inline_diagnostics(true, window, cx);
18740                self.scrollbar_marker_state.dirty = true;
18741                cx.notify();
18742            }
18743            _ => {}
18744        };
18745    }
18746
18747    pub fn start_temporary_diff_override(&mut self) {
18748        self.load_diff_task.take();
18749        self.temporary_diff_override = true;
18750    }
18751
18752    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18753        self.temporary_diff_override = false;
18754        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18755        self.buffer.update(cx, |buffer, cx| {
18756            buffer.set_all_diff_hunks_collapsed(cx);
18757        });
18758
18759        if let Some(project) = self.project.clone() {
18760            self.load_diff_task = Some(
18761                update_uncommitted_diff_for_buffer(
18762                    cx.entity(),
18763                    &project,
18764                    self.buffer.read(cx).all_buffers(),
18765                    self.buffer.clone(),
18766                    cx,
18767                )
18768                .shared(),
18769            );
18770        }
18771    }
18772
18773    fn on_display_map_changed(
18774        &mut self,
18775        _: Entity<DisplayMap>,
18776        _: &mut Window,
18777        cx: &mut Context<Self>,
18778    ) {
18779        cx.notify();
18780    }
18781
18782    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18783        let new_severity = if self.diagnostics_enabled() {
18784            EditorSettings::get_global(cx)
18785                .diagnostics_max_severity
18786                .unwrap_or(DiagnosticSeverity::Hint)
18787        } else {
18788            DiagnosticSeverity::Off
18789        };
18790        self.set_max_diagnostics_severity(new_severity, cx);
18791        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18792        self.update_edit_prediction_settings(cx);
18793        self.refresh_inline_completion(true, false, window, cx);
18794        self.refresh_inlay_hints(
18795            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18796                self.selections.newest_anchor().head(),
18797                &self.buffer.read(cx).snapshot(cx),
18798                cx,
18799            )),
18800            cx,
18801        );
18802
18803        let old_cursor_shape = self.cursor_shape;
18804
18805        {
18806            let editor_settings = EditorSettings::get_global(cx);
18807            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18808            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18809            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18810            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18811        }
18812
18813        if old_cursor_shape != self.cursor_shape {
18814            cx.emit(EditorEvent::CursorShapeChanged);
18815        }
18816
18817        let project_settings = ProjectSettings::get_global(cx);
18818        self.serialize_dirty_buffers =
18819            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18820
18821        if self.mode.is_full() {
18822            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18823            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18824            if self.show_inline_diagnostics != show_inline_diagnostics {
18825                self.show_inline_diagnostics = show_inline_diagnostics;
18826                self.refresh_inline_diagnostics(false, window, cx);
18827            }
18828
18829            if self.git_blame_inline_enabled != inline_blame_enabled {
18830                self.toggle_git_blame_inline_internal(false, window, cx);
18831            }
18832
18833            let minimap_settings = EditorSettings::get_global(cx).minimap;
18834            if self.minimap_visibility != MinimapVisibility::Disabled {
18835                if self.minimap_visibility.settings_visibility()
18836                    != minimap_settings.minimap_enabled()
18837                {
18838                    self.set_minimap_visibility(
18839                        MinimapVisibility::for_mode(self.mode(), cx),
18840                        window,
18841                        cx,
18842                    );
18843                } else if let Some(minimap_entity) = self.minimap.as_ref() {
18844                    minimap_entity.update(cx, |minimap_editor, cx| {
18845                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
18846                    })
18847                }
18848            }
18849        }
18850
18851        cx.notify();
18852    }
18853
18854    pub fn set_searchable(&mut self, searchable: bool) {
18855        self.searchable = searchable;
18856    }
18857
18858    pub fn searchable(&self) -> bool {
18859        self.searchable
18860    }
18861
18862    fn open_proposed_changes_editor(
18863        &mut self,
18864        _: &OpenProposedChangesEditor,
18865        window: &mut Window,
18866        cx: &mut Context<Self>,
18867    ) {
18868        let Some(workspace) = self.workspace() else {
18869            cx.propagate();
18870            return;
18871        };
18872
18873        let selections = self.selections.all::<usize>(cx);
18874        let multi_buffer = self.buffer.read(cx);
18875        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18876        let mut new_selections_by_buffer = HashMap::default();
18877        for selection in selections {
18878            for (buffer, range, _) in
18879                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18880            {
18881                let mut range = range.to_point(buffer);
18882                range.start.column = 0;
18883                range.end.column = buffer.line_len(range.end.row);
18884                new_selections_by_buffer
18885                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18886                    .or_insert(Vec::new())
18887                    .push(range)
18888            }
18889        }
18890
18891        let proposed_changes_buffers = new_selections_by_buffer
18892            .into_iter()
18893            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18894            .collect::<Vec<_>>();
18895        let proposed_changes_editor = cx.new(|cx| {
18896            ProposedChangesEditor::new(
18897                "Proposed changes",
18898                proposed_changes_buffers,
18899                self.project.clone(),
18900                window,
18901                cx,
18902            )
18903        });
18904
18905        window.defer(cx, move |window, cx| {
18906            workspace.update(cx, |workspace, cx| {
18907                workspace.active_pane().update(cx, |pane, cx| {
18908                    pane.add_item(
18909                        Box::new(proposed_changes_editor),
18910                        true,
18911                        true,
18912                        None,
18913                        window,
18914                        cx,
18915                    );
18916                });
18917            });
18918        });
18919    }
18920
18921    pub fn open_excerpts_in_split(
18922        &mut self,
18923        _: &OpenExcerptsSplit,
18924        window: &mut Window,
18925        cx: &mut Context<Self>,
18926    ) {
18927        self.open_excerpts_common(None, true, window, cx)
18928    }
18929
18930    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18931        self.open_excerpts_common(None, false, window, cx)
18932    }
18933
18934    fn open_excerpts_common(
18935        &mut self,
18936        jump_data: Option<JumpData>,
18937        split: bool,
18938        window: &mut Window,
18939        cx: &mut Context<Self>,
18940    ) {
18941        let Some(workspace) = self.workspace() else {
18942            cx.propagate();
18943            return;
18944        };
18945
18946        if self.buffer.read(cx).is_singleton() {
18947            cx.propagate();
18948            return;
18949        }
18950
18951        let mut new_selections_by_buffer = HashMap::default();
18952        match &jump_data {
18953            Some(JumpData::MultiBufferPoint {
18954                excerpt_id,
18955                position,
18956                anchor,
18957                line_offset_from_top,
18958            }) => {
18959                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18960                if let Some(buffer) = multi_buffer_snapshot
18961                    .buffer_id_for_excerpt(*excerpt_id)
18962                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18963                {
18964                    let buffer_snapshot = buffer.read(cx).snapshot();
18965                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18966                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18967                    } else {
18968                        buffer_snapshot.clip_point(*position, Bias::Left)
18969                    };
18970                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18971                    new_selections_by_buffer.insert(
18972                        buffer,
18973                        (
18974                            vec![jump_to_offset..jump_to_offset],
18975                            Some(*line_offset_from_top),
18976                        ),
18977                    );
18978                }
18979            }
18980            Some(JumpData::MultiBufferRow {
18981                row,
18982                line_offset_from_top,
18983            }) => {
18984                let point = MultiBufferPoint::new(row.0, 0);
18985                if let Some((buffer, buffer_point, _)) =
18986                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18987                {
18988                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18989                    new_selections_by_buffer
18990                        .entry(buffer)
18991                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18992                        .0
18993                        .push(buffer_offset..buffer_offset)
18994                }
18995            }
18996            None => {
18997                let selections = self.selections.all::<usize>(cx);
18998                let multi_buffer = self.buffer.read(cx);
18999                for selection in selections {
19000                    for (snapshot, range, _, anchor) in multi_buffer
19001                        .snapshot(cx)
19002                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19003                    {
19004                        if let Some(anchor) = anchor {
19005                            // selection is in a deleted hunk
19006                            let Some(buffer_id) = anchor.buffer_id else {
19007                                continue;
19008                            };
19009                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19010                                continue;
19011                            };
19012                            let offset = text::ToOffset::to_offset(
19013                                &anchor.text_anchor,
19014                                &buffer_handle.read(cx).snapshot(),
19015                            );
19016                            let range = offset..offset;
19017                            new_selections_by_buffer
19018                                .entry(buffer_handle)
19019                                .or_insert((Vec::new(), None))
19020                                .0
19021                                .push(range)
19022                        } else {
19023                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19024                            else {
19025                                continue;
19026                            };
19027                            new_selections_by_buffer
19028                                .entry(buffer_handle)
19029                                .or_insert((Vec::new(), None))
19030                                .0
19031                                .push(range)
19032                        }
19033                    }
19034                }
19035            }
19036        }
19037
19038        new_selections_by_buffer
19039            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19040
19041        if new_selections_by_buffer.is_empty() {
19042            return;
19043        }
19044
19045        // We defer the pane interaction because we ourselves are a workspace item
19046        // and activating a new item causes the pane to call a method on us reentrantly,
19047        // which panics if we're on the stack.
19048        window.defer(cx, move |window, cx| {
19049            workspace.update(cx, |workspace, cx| {
19050                let pane = if split {
19051                    workspace.adjacent_pane(window, cx)
19052                } else {
19053                    workspace.active_pane().clone()
19054                };
19055
19056                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19057                    let editor = buffer
19058                        .read(cx)
19059                        .file()
19060                        .is_none()
19061                        .then(|| {
19062                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19063                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19064                            // Instead, we try to activate the existing editor in the pane first.
19065                            let (editor, pane_item_index) =
19066                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19067                                    let editor = item.downcast::<Editor>()?;
19068                                    let singleton_buffer =
19069                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19070                                    if singleton_buffer == buffer {
19071                                        Some((editor, i))
19072                                    } else {
19073                                        None
19074                                    }
19075                                })?;
19076                            pane.update(cx, |pane, cx| {
19077                                pane.activate_item(pane_item_index, true, true, window, cx)
19078                            });
19079                            Some(editor)
19080                        })
19081                        .flatten()
19082                        .unwrap_or_else(|| {
19083                            workspace.open_project_item::<Self>(
19084                                pane.clone(),
19085                                buffer,
19086                                true,
19087                                true,
19088                                window,
19089                                cx,
19090                            )
19091                        });
19092
19093                    editor.update(cx, |editor, cx| {
19094                        let autoscroll = match scroll_offset {
19095                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19096                            None => Autoscroll::newest(),
19097                        };
19098                        let nav_history = editor.nav_history.take();
19099                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19100                            s.select_ranges(ranges);
19101                        });
19102                        editor.nav_history = nav_history;
19103                    });
19104                }
19105            })
19106        });
19107    }
19108
19109    // For now, don't allow opening excerpts in buffers that aren't backed by
19110    // regular project files.
19111    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19112        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19113    }
19114
19115    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19116        let snapshot = self.buffer.read(cx).read(cx);
19117        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19118        Some(
19119            ranges
19120                .iter()
19121                .map(move |range| {
19122                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19123                })
19124                .collect(),
19125        )
19126    }
19127
19128    fn selection_replacement_ranges(
19129        &self,
19130        range: Range<OffsetUtf16>,
19131        cx: &mut App,
19132    ) -> Vec<Range<OffsetUtf16>> {
19133        let selections = self.selections.all::<OffsetUtf16>(cx);
19134        let newest_selection = selections
19135            .iter()
19136            .max_by_key(|selection| selection.id)
19137            .unwrap();
19138        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19139        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19140        let snapshot = self.buffer.read(cx).read(cx);
19141        selections
19142            .into_iter()
19143            .map(|mut selection| {
19144                selection.start.0 =
19145                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19146                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19147                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19148                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19149            })
19150            .collect()
19151    }
19152
19153    fn report_editor_event(
19154        &self,
19155        event_type: &'static str,
19156        file_extension: Option<String>,
19157        cx: &App,
19158    ) {
19159        if cfg!(any(test, feature = "test-support")) {
19160            return;
19161        }
19162
19163        let Some(project) = &self.project else { return };
19164
19165        // If None, we are in a file without an extension
19166        let file = self
19167            .buffer
19168            .read(cx)
19169            .as_singleton()
19170            .and_then(|b| b.read(cx).file());
19171        let file_extension = file_extension.or(file
19172            .as_ref()
19173            .and_then(|file| Path::new(file.file_name(cx)).extension())
19174            .and_then(|e| e.to_str())
19175            .map(|a| a.to_string()));
19176
19177        let vim_mode = vim_enabled(cx);
19178
19179        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19180        let copilot_enabled = edit_predictions_provider
19181            == language::language_settings::EditPredictionProvider::Copilot;
19182        let copilot_enabled_for_language = self
19183            .buffer
19184            .read(cx)
19185            .language_settings(cx)
19186            .show_edit_predictions;
19187
19188        let project = project.read(cx);
19189        telemetry::event!(
19190            event_type,
19191            file_extension,
19192            vim_mode,
19193            copilot_enabled,
19194            copilot_enabled_for_language,
19195            edit_predictions_provider,
19196            is_via_ssh = project.is_via_ssh(),
19197        );
19198    }
19199
19200    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19201    /// with each line being an array of {text, highlight} objects.
19202    fn copy_highlight_json(
19203        &mut self,
19204        _: &CopyHighlightJson,
19205        window: &mut Window,
19206        cx: &mut Context<Self>,
19207    ) {
19208        #[derive(Serialize)]
19209        struct Chunk<'a> {
19210            text: String,
19211            highlight: Option<&'a str>,
19212        }
19213
19214        let snapshot = self.buffer.read(cx).snapshot(cx);
19215        let range = self
19216            .selected_text_range(false, window, cx)
19217            .and_then(|selection| {
19218                if selection.range.is_empty() {
19219                    None
19220                } else {
19221                    Some(selection.range)
19222                }
19223            })
19224            .unwrap_or_else(|| 0..snapshot.len());
19225
19226        let chunks = snapshot.chunks(range, true);
19227        let mut lines = Vec::new();
19228        let mut line: VecDeque<Chunk> = VecDeque::new();
19229
19230        let Some(style) = self.style.as_ref() else {
19231            return;
19232        };
19233
19234        for chunk in chunks {
19235            let highlight = chunk
19236                .syntax_highlight_id
19237                .and_then(|id| id.name(&style.syntax));
19238            let mut chunk_lines = chunk.text.split('\n').peekable();
19239            while let Some(text) = chunk_lines.next() {
19240                let mut merged_with_last_token = false;
19241                if let Some(last_token) = line.back_mut() {
19242                    if last_token.highlight == highlight {
19243                        last_token.text.push_str(text);
19244                        merged_with_last_token = true;
19245                    }
19246                }
19247
19248                if !merged_with_last_token {
19249                    line.push_back(Chunk {
19250                        text: text.into(),
19251                        highlight,
19252                    });
19253                }
19254
19255                if chunk_lines.peek().is_some() {
19256                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19257                        line.pop_front();
19258                    }
19259                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19260                        line.pop_back();
19261                    }
19262
19263                    lines.push(mem::take(&mut line));
19264                }
19265            }
19266        }
19267
19268        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19269            return;
19270        };
19271        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19272    }
19273
19274    pub fn open_context_menu(
19275        &mut self,
19276        _: &OpenContextMenu,
19277        window: &mut Window,
19278        cx: &mut Context<Self>,
19279    ) {
19280        self.request_autoscroll(Autoscroll::newest(), cx);
19281        let position = self.selections.newest_display(cx).start;
19282        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19283    }
19284
19285    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19286        &self.inlay_hint_cache
19287    }
19288
19289    pub fn replay_insert_event(
19290        &mut self,
19291        text: &str,
19292        relative_utf16_range: Option<Range<isize>>,
19293        window: &mut Window,
19294        cx: &mut Context<Self>,
19295    ) {
19296        if !self.input_enabled {
19297            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19298            return;
19299        }
19300        if let Some(relative_utf16_range) = relative_utf16_range {
19301            let selections = self.selections.all::<OffsetUtf16>(cx);
19302            self.change_selections(None, window, cx, |s| {
19303                let new_ranges = selections.into_iter().map(|range| {
19304                    let start = OffsetUtf16(
19305                        range
19306                            .head()
19307                            .0
19308                            .saturating_add_signed(relative_utf16_range.start),
19309                    );
19310                    let end = OffsetUtf16(
19311                        range
19312                            .head()
19313                            .0
19314                            .saturating_add_signed(relative_utf16_range.end),
19315                    );
19316                    start..end
19317                });
19318                s.select_ranges(new_ranges);
19319            });
19320        }
19321
19322        self.handle_input(text, window, cx);
19323    }
19324
19325    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19326        let Some(provider) = self.semantics_provider.as_ref() else {
19327            return false;
19328        };
19329
19330        let mut supports = false;
19331        self.buffer().update(cx, |this, cx| {
19332            this.for_each_buffer(|buffer| {
19333                supports |= provider.supports_inlay_hints(buffer, cx);
19334            });
19335        });
19336
19337        supports
19338    }
19339
19340    pub fn is_focused(&self, window: &Window) -> bool {
19341        self.focus_handle.is_focused(window)
19342    }
19343
19344    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19345        cx.emit(EditorEvent::Focused);
19346
19347        if let Some(descendant) = self
19348            .last_focused_descendant
19349            .take()
19350            .and_then(|descendant| descendant.upgrade())
19351        {
19352            window.focus(&descendant);
19353        } else {
19354            if let Some(blame) = self.blame.as_ref() {
19355                blame.update(cx, GitBlame::focus)
19356            }
19357
19358            self.blink_manager.update(cx, BlinkManager::enable);
19359            self.show_cursor_names(window, cx);
19360            self.buffer.update(cx, |buffer, cx| {
19361                buffer.finalize_last_transaction(cx);
19362                if self.leader_id.is_none() {
19363                    buffer.set_active_selections(
19364                        &self.selections.disjoint_anchors(),
19365                        self.selections.line_mode,
19366                        self.cursor_shape,
19367                        cx,
19368                    );
19369                }
19370            });
19371        }
19372    }
19373
19374    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19375        cx.emit(EditorEvent::FocusedIn)
19376    }
19377
19378    fn handle_focus_out(
19379        &mut self,
19380        event: FocusOutEvent,
19381        _window: &mut Window,
19382        cx: &mut Context<Self>,
19383    ) {
19384        if event.blurred != self.focus_handle {
19385            self.last_focused_descendant = Some(event.blurred);
19386        }
19387        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19388    }
19389
19390    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19391        self.blink_manager.update(cx, BlinkManager::disable);
19392        self.buffer
19393            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19394
19395        if let Some(blame) = self.blame.as_ref() {
19396            blame.update(cx, GitBlame::blur)
19397        }
19398        if !self.hover_state.focused(window, cx) {
19399            hide_hover(self, cx);
19400        }
19401        if !self
19402            .context_menu
19403            .borrow()
19404            .as_ref()
19405            .is_some_and(|context_menu| context_menu.focused(window, cx))
19406        {
19407            self.hide_context_menu(window, cx);
19408        }
19409        self.discard_inline_completion(false, cx);
19410        cx.emit(EditorEvent::Blurred);
19411        cx.notify();
19412    }
19413
19414    pub fn register_action<A: Action>(
19415        &mut self,
19416        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19417    ) -> Subscription {
19418        let id = self.next_editor_action_id.post_inc();
19419        let listener = Arc::new(listener);
19420        self.editor_actions.borrow_mut().insert(
19421            id,
19422            Box::new(move |window, _| {
19423                let listener = listener.clone();
19424                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19425                    let action = action.downcast_ref().unwrap();
19426                    if phase == DispatchPhase::Bubble {
19427                        listener(action, window, cx)
19428                    }
19429                })
19430            }),
19431        );
19432
19433        let editor_actions = self.editor_actions.clone();
19434        Subscription::new(move || {
19435            editor_actions.borrow_mut().remove(&id);
19436        })
19437    }
19438
19439    pub fn file_header_size(&self) -> u32 {
19440        FILE_HEADER_HEIGHT
19441    }
19442
19443    pub fn restore(
19444        &mut self,
19445        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19446        window: &mut Window,
19447        cx: &mut Context<Self>,
19448    ) {
19449        let workspace = self.workspace();
19450        let project = self.project.as_ref();
19451        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19452            let mut tasks = Vec::new();
19453            for (buffer_id, changes) in revert_changes {
19454                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19455                    buffer.update(cx, |buffer, cx| {
19456                        buffer.edit(
19457                            changes
19458                                .into_iter()
19459                                .map(|(range, text)| (range, text.to_string())),
19460                            None,
19461                            cx,
19462                        );
19463                    });
19464
19465                    if let Some(project) =
19466                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19467                    {
19468                        project.update(cx, |project, cx| {
19469                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19470                        })
19471                    }
19472                }
19473            }
19474            tasks
19475        });
19476        cx.spawn_in(window, async move |_, cx| {
19477            for (buffer, task) in save_tasks {
19478                let result = task.await;
19479                if result.is_err() {
19480                    let Some(path) = buffer
19481                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19482                        .ok()
19483                    else {
19484                        continue;
19485                    };
19486                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19487                        let Some(task) = cx
19488                            .update_window_entity(&workspace, |workspace, window, cx| {
19489                                workspace
19490                                    .open_path_preview(path, None, false, false, false, window, cx)
19491                            })
19492                            .ok()
19493                        else {
19494                            continue;
19495                        };
19496                        task.await.log_err();
19497                    }
19498                }
19499            }
19500        })
19501        .detach();
19502        self.change_selections(None, window, cx, |selections| selections.refresh());
19503    }
19504
19505    pub fn to_pixel_point(
19506        &self,
19507        source: multi_buffer::Anchor,
19508        editor_snapshot: &EditorSnapshot,
19509        window: &mut Window,
19510    ) -> Option<gpui::Point<Pixels>> {
19511        let source_point = source.to_display_point(editor_snapshot);
19512        self.display_to_pixel_point(source_point, editor_snapshot, window)
19513    }
19514
19515    pub fn display_to_pixel_point(
19516        &self,
19517        source: DisplayPoint,
19518        editor_snapshot: &EditorSnapshot,
19519        window: &mut Window,
19520    ) -> Option<gpui::Point<Pixels>> {
19521        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19522        let text_layout_details = self.text_layout_details(window);
19523        let scroll_top = text_layout_details
19524            .scroll_anchor
19525            .scroll_position(editor_snapshot)
19526            .y;
19527
19528        if source.row().as_f32() < scroll_top.floor() {
19529            return None;
19530        }
19531        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19532        let source_y = line_height * (source.row().as_f32() - scroll_top);
19533        Some(gpui::Point::new(source_x, source_y))
19534    }
19535
19536    pub fn has_visible_completions_menu(&self) -> bool {
19537        !self.edit_prediction_preview_is_active()
19538            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19539                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19540            })
19541    }
19542
19543    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19544        if self.mode.is_minimap() {
19545            return;
19546        }
19547        self.addons
19548            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19549    }
19550
19551    pub fn unregister_addon<T: Addon>(&mut self) {
19552        self.addons.remove(&std::any::TypeId::of::<T>());
19553    }
19554
19555    pub fn addon<T: Addon>(&self) -> Option<&T> {
19556        let type_id = std::any::TypeId::of::<T>();
19557        self.addons
19558            .get(&type_id)
19559            .and_then(|item| item.to_any().downcast_ref::<T>())
19560    }
19561
19562    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19563        let type_id = std::any::TypeId::of::<T>();
19564        self.addons
19565            .get_mut(&type_id)
19566            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19567    }
19568
19569    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19570        let text_layout_details = self.text_layout_details(window);
19571        let style = &text_layout_details.editor_style;
19572        let font_id = window.text_system().resolve_font(&style.text.font());
19573        let font_size = style.text.font_size.to_pixels(window.rem_size());
19574        let line_height = style.text.line_height_in_pixels(window.rem_size());
19575        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19576
19577        gpui::Size::new(em_width, line_height)
19578    }
19579
19580    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19581        self.load_diff_task.clone()
19582    }
19583
19584    fn read_metadata_from_db(
19585        &mut self,
19586        item_id: u64,
19587        workspace_id: WorkspaceId,
19588        window: &mut Window,
19589        cx: &mut Context<Editor>,
19590    ) {
19591        if self.is_singleton(cx)
19592            && !self.mode.is_minimap()
19593            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19594        {
19595            let buffer_snapshot = OnceCell::new();
19596
19597            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19598                if !folds.is_empty() {
19599                    let snapshot =
19600                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19601                    self.fold_ranges(
19602                        folds
19603                            .into_iter()
19604                            .map(|(start, end)| {
19605                                snapshot.clip_offset(start, Bias::Left)
19606                                    ..snapshot.clip_offset(end, Bias::Right)
19607                            })
19608                            .collect(),
19609                        false,
19610                        window,
19611                        cx,
19612                    );
19613                }
19614            }
19615
19616            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19617                if !selections.is_empty() {
19618                    let snapshot =
19619                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19620                    self.change_selections(None, window, cx, |s| {
19621                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19622                            snapshot.clip_offset(start, Bias::Left)
19623                                ..snapshot.clip_offset(end, Bias::Right)
19624                        }));
19625                    });
19626                }
19627            };
19628        }
19629
19630        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19631    }
19632}
19633
19634fn vim_enabled(cx: &App) -> bool {
19635    cx.global::<SettingsStore>()
19636        .raw_user_settings()
19637        .get("vim_mode")
19638        == Some(&serde_json::Value::Bool(true))
19639}
19640
19641fn process_completion_for_edit(
19642    completion: &Completion,
19643    intent: CompletionIntent,
19644    buffer: &Entity<Buffer>,
19645    cursor_position: &text::Anchor,
19646    cx: &mut Context<Editor>,
19647) -> CompletionEdit {
19648    let buffer = buffer.read(cx);
19649    let buffer_snapshot = buffer.snapshot();
19650    let (snippet, new_text) = if completion.is_snippet() {
19651        let mut snippet_source = completion.new_text.clone();
19652        if let Some(scope) = buffer_snapshot.language_scope_at(cursor_position) {
19653            if scope.prefers_label_for_snippet_in_completion() {
19654                if let Some(label) = completion.label() {
19655                    if matches!(
19656                        completion.kind(),
19657                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
19658                    ) {
19659                        snippet_source = label;
19660                    }
19661                }
19662            }
19663        }
19664        match Snippet::parse(&snippet_source).log_err() {
19665            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
19666            None => (None, completion.new_text.clone()),
19667        }
19668    } else {
19669        (None, completion.new_text.clone())
19670    };
19671
19672    let mut range_to_replace = {
19673        let replace_range = &completion.replace_range;
19674        if let CompletionSource::Lsp {
19675            insert_range: Some(insert_range),
19676            ..
19677        } = &completion.source
19678        {
19679            debug_assert_eq!(
19680                insert_range.start, replace_range.start,
19681                "insert_range and replace_range should start at the same position"
19682            );
19683            debug_assert!(
19684                insert_range
19685                    .start
19686                    .cmp(&cursor_position, &buffer_snapshot)
19687                    .is_le(),
19688                "insert_range should start before or at cursor position"
19689            );
19690            debug_assert!(
19691                replace_range
19692                    .start
19693                    .cmp(&cursor_position, &buffer_snapshot)
19694                    .is_le(),
19695                "replace_range should start before or at cursor position"
19696            );
19697            debug_assert!(
19698                insert_range
19699                    .end
19700                    .cmp(&cursor_position, &buffer_snapshot)
19701                    .is_le(),
19702                "insert_range should end before or at cursor position"
19703            );
19704
19705            let should_replace = match intent {
19706                CompletionIntent::CompleteWithInsert => false,
19707                CompletionIntent::CompleteWithReplace => true,
19708                CompletionIntent::Complete | CompletionIntent::Compose => {
19709                    let insert_mode =
19710                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19711                            .completions
19712                            .lsp_insert_mode;
19713                    match insert_mode {
19714                        LspInsertMode::Insert => false,
19715                        LspInsertMode::Replace => true,
19716                        LspInsertMode::ReplaceSubsequence => {
19717                            let mut text_to_replace = buffer.chars_for_range(
19718                                buffer.anchor_before(replace_range.start)
19719                                    ..buffer.anchor_after(replace_range.end),
19720                            );
19721                            let mut current_needle = text_to_replace.next();
19722                            for haystack_ch in completion.label.text.chars() {
19723                                if let Some(needle_ch) = current_needle {
19724                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
19725                                        current_needle = text_to_replace.next();
19726                                    }
19727                                }
19728                            }
19729                            current_needle.is_none()
19730                        }
19731                        LspInsertMode::ReplaceSuffix => {
19732                            if replace_range
19733                                .end
19734                                .cmp(&cursor_position, &buffer_snapshot)
19735                                .is_gt()
19736                            {
19737                                let range_after_cursor = *cursor_position..replace_range.end;
19738                                let text_after_cursor = buffer
19739                                    .text_for_range(
19740                                        buffer.anchor_before(range_after_cursor.start)
19741                                            ..buffer.anchor_after(range_after_cursor.end),
19742                                    )
19743                                    .collect::<String>()
19744                                    .to_ascii_lowercase();
19745                                completion
19746                                    .label
19747                                    .text
19748                                    .to_ascii_lowercase()
19749                                    .ends_with(&text_after_cursor)
19750                            } else {
19751                                true
19752                            }
19753                        }
19754                    }
19755                }
19756            };
19757
19758            if should_replace {
19759                replace_range.clone()
19760            } else {
19761                insert_range.clone()
19762            }
19763        } else {
19764            replace_range.clone()
19765        }
19766    };
19767
19768    if range_to_replace
19769        .end
19770        .cmp(&cursor_position, &buffer_snapshot)
19771        .is_lt()
19772    {
19773        range_to_replace.end = *cursor_position;
19774    }
19775
19776    CompletionEdit {
19777        new_text,
19778        replace_range: range_to_replace.to_offset(&buffer),
19779        snippet,
19780    }
19781}
19782
19783struct CompletionEdit {
19784    new_text: String,
19785    replace_range: Range<usize>,
19786    snippet: Option<Snippet>,
19787}
19788
19789fn insert_extra_newline_brackets(
19790    buffer: &MultiBufferSnapshot,
19791    range: Range<usize>,
19792    language: &language::LanguageScope,
19793) -> bool {
19794    let leading_whitespace_len = buffer
19795        .reversed_chars_at(range.start)
19796        .take_while(|c| c.is_whitespace() && *c != '\n')
19797        .map(|c| c.len_utf8())
19798        .sum::<usize>();
19799    let trailing_whitespace_len = buffer
19800        .chars_at(range.end)
19801        .take_while(|c| c.is_whitespace() && *c != '\n')
19802        .map(|c| c.len_utf8())
19803        .sum::<usize>();
19804    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19805
19806    language.brackets().any(|(pair, enabled)| {
19807        let pair_start = pair.start.trim_end();
19808        let pair_end = pair.end.trim_start();
19809
19810        enabled
19811            && pair.newline
19812            && buffer.contains_str_at(range.end, pair_end)
19813            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19814    })
19815}
19816
19817fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19818    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19819        [(buffer, range, _)] => (*buffer, range.clone()),
19820        _ => return false,
19821    };
19822    let pair = {
19823        let mut result: Option<BracketMatch> = None;
19824
19825        for pair in buffer
19826            .all_bracket_ranges(range.clone())
19827            .filter(move |pair| {
19828                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19829            })
19830        {
19831            let len = pair.close_range.end - pair.open_range.start;
19832
19833            if let Some(existing) = &result {
19834                let existing_len = existing.close_range.end - existing.open_range.start;
19835                if len > existing_len {
19836                    continue;
19837                }
19838            }
19839
19840            result = Some(pair);
19841        }
19842
19843        result
19844    };
19845    let Some(pair) = pair else {
19846        return false;
19847    };
19848    pair.newline_only
19849        && buffer
19850            .chars_for_range(pair.open_range.end..range.start)
19851            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19852            .all(|c| c.is_whitespace() && c != '\n')
19853}
19854
19855fn update_uncommitted_diff_for_buffer(
19856    editor: Entity<Editor>,
19857    project: &Entity<Project>,
19858    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19859    buffer: Entity<MultiBuffer>,
19860    cx: &mut App,
19861) -> Task<()> {
19862    let mut tasks = Vec::new();
19863    project.update(cx, |project, cx| {
19864        for buffer in buffers {
19865            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19866                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19867            }
19868        }
19869    });
19870    cx.spawn(async move |cx| {
19871        let diffs = future::join_all(tasks).await;
19872        if editor
19873            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19874            .unwrap_or(false)
19875        {
19876            return;
19877        }
19878
19879        buffer
19880            .update(cx, |buffer, cx| {
19881                for diff in diffs.into_iter().flatten() {
19882                    buffer.add_diff(diff, cx);
19883                }
19884            })
19885            .ok();
19886    })
19887}
19888
19889fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19890    let tab_size = tab_size.get() as usize;
19891    let mut width = offset;
19892
19893    for ch in text.chars() {
19894        width += if ch == '\t' {
19895            tab_size - (width % tab_size)
19896        } else {
19897            1
19898        };
19899    }
19900
19901    width - offset
19902}
19903
19904#[cfg(test)]
19905mod tests {
19906    use super::*;
19907
19908    #[test]
19909    fn test_string_size_with_expanded_tabs() {
19910        let nz = |val| NonZeroU32::new(val).unwrap();
19911        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19912        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19913        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19914        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19915        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19916        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19917        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19918        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19919    }
19920}
19921
19922/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19923struct WordBreakingTokenizer<'a> {
19924    input: &'a str,
19925}
19926
19927impl<'a> WordBreakingTokenizer<'a> {
19928    fn new(input: &'a str) -> Self {
19929        Self { input }
19930    }
19931}
19932
19933fn is_char_ideographic(ch: char) -> bool {
19934    use unicode_script::Script::*;
19935    use unicode_script::UnicodeScript;
19936    matches!(ch.script(), Han | Tangut | Yi)
19937}
19938
19939fn is_grapheme_ideographic(text: &str) -> bool {
19940    text.chars().any(is_char_ideographic)
19941}
19942
19943fn is_grapheme_whitespace(text: &str) -> bool {
19944    text.chars().any(|x| x.is_whitespace())
19945}
19946
19947fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19948    text.chars().next().map_or(false, |ch| {
19949        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19950    })
19951}
19952
19953#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19954enum WordBreakToken<'a> {
19955    Word { token: &'a str, grapheme_len: usize },
19956    InlineWhitespace { token: &'a str, grapheme_len: usize },
19957    Newline,
19958}
19959
19960impl<'a> Iterator for WordBreakingTokenizer<'a> {
19961    /// Yields a span, the count of graphemes in the token, and whether it was
19962    /// whitespace. Note that it also breaks at word boundaries.
19963    type Item = WordBreakToken<'a>;
19964
19965    fn next(&mut self) -> Option<Self::Item> {
19966        use unicode_segmentation::UnicodeSegmentation;
19967        if self.input.is_empty() {
19968            return None;
19969        }
19970
19971        let mut iter = self.input.graphemes(true).peekable();
19972        let mut offset = 0;
19973        let mut grapheme_len = 0;
19974        if let Some(first_grapheme) = iter.next() {
19975            let is_newline = first_grapheme == "\n";
19976            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19977            offset += first_grapheme.len();
19978            grapheme_len += 1;
19979            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19980                if let Some(grapheme) = iter.peek().copied() {
19981                    if should_stay_with_preceding_ideograph(grapheme) {
19982                        offset += grapheme.len();
19983                        grapheme_len += 1;
19984                    }
19985                }
19986            } else {
19987                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19988                let mut next_word_bound = words.peek().copied();
19989                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19990                    next_word_bound = words.next();
19991                }
19992                while let Some(grapheme) = iter.peek().copied() {
19993                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19994                        break;
19995                    };
19996                    if is_grapheme_whitespace(grapheme) != is_whitespace
19997                        || (grapheme == "\n") != is_newline
19998                    {
19999                        break;
20000                    };
20001                    offset += grapheme.len();
20002                    grapheme_len += 1;
20003                    iter.next();
20004                }
20005            }
20006            let token = &self.input[..offset];
20007            self.input = &self.input[offset..];
20008            if token == "\n" {
20009                Some(WordBreakToken::Newline)
20010            } else if is_whitespace {
20011                Some(WordBreakToken::InlineWhitespace {
20012                    token,
20013                    grapheme_len,
20014                })
20015            } else {
20016                Some(WordBreakToken::Word {
20017                    token,
20018                    grapheme_len,
20019                })
20020            }
20021        } else {
20022            None
20023        }
20024    }
20025}
20026
20027#[test]
20028fn test_word_breaking_tokenizer() {
20029    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20030        ("", &[]),
20031        ("  ", &[whitespace("  ", 2)]),
20032        ("Ʒ", &[word("Ʒ", 1)]),
20033        ("Ǽ", &[word("Ǽ", 1)]),
20034        ("", &[word("", 1)]),
20035        ("⋑⋑", &[word("⋑⋑", 2)]),
20036        (
20037            "原理,进而",
20038            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20039        ),
20040        (
20041            "hello world",
20042            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20043        ),
20044        (
20045            "hello, world",
20046            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20047        ),
20048        (
20049            "  hello world",
20050            &[
20051                whitespace("  ", 2),
20052                word("hello", 5),
20053                whitespace(" ", 1),
20054                word("world", 5),
20055            ],
20056        ),
20057        (
20058            "这是什么 \n 钢笔",
20059            &[
20060                word("", 1),
20061                word("", 1),
20062                word("", 1),
20063                word("", 1),
20064                whitespace(" ", 1),
20065                newline(),
20066                whitespace(" ", 1),
20067                word("", 1),
20068                word("", 1),
20069            ],
20070        ),
20071        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20072    ];
20073
20074    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20075        WordBreakToken::Word {
20076            token,
20077            grapheme_len,
20078        }
20079    }
20080
20081    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20082        WordBreakToken::InlineWhitespace {
20083            token,
20084            grapheme_len,
20085        }
20086    }
20087
20088    fn newline() -> WordBreakToken<'static> {
20089        WordBreakToken::Newline
20090    }
20091
20092    for (input, result) in tests {
20093        assert_eq!(
20094            WordBreakingTokenizer::new(input)
20095                .collect::<Vec<_>>()
20096                .as_slice(),
20097            *result,
20098        );
20099    }
20100}
20101
20102fn wrap_with_prefix(
20103    line_prefix: String,
20104    unwrapped_text: String,
20105    wrap_column: usize,
20106    tab_size: NonZeroU32,
20107    preserve_existing_whitespace: bool,
20108) -> String {
20109    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20110    let mut wrapped_text = String::new();
20111    let mut current_line = line_prefix.clone();
20112
20113    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20114    let mut current_line_len = line_prefix_len;
20115    let mut in_whitespace = false;
20116    for token in tokenizer {
20117        let have_preceding_whitespace = in_whitespace;
20118        match token {
20119            WordBreakToken::Word {
20120                token,
20121                grapheme_len,
20122            } => {
20123                in_whitespace = false;
20124                if current_line_len + grapheme_len > wrap_column
20125                    && current_line_len != line_prefix_len
20126                {
20127                    wrapped_text.push_str(current_line.trim_end());
20128                    wrapped_text.push('\n');
20129                    current_line.truncate(line_prefix.len());
20130                    current_line_len = line_prefix_len;
20131                }
20132                current_line.push_str(token);
20133                current_line_len += grapheme_len;
20134            }
20135            WordBreakToken::InlineWhitespace {
20136                mut token,
20137                mut grapheme_len,
20138            } => {
20139                in_whitespace = true;
20140                if have_preceding_whitespace && !preserve_existing_whitespace {
20141                    continue;
20142                }
20143                if !preserve_existing_whitespace {
20144                    token = " ";
20145                    grapheme_len = 1;
20146                }
20147                if current_line_len + grapheme_len > wrap_column {
20148                    wrapped_text.push_str(current_line.trim_end());
20149                    wrapped_text.push('\n');
20150                    current_line.truncate(line_prefix.len());
20151                    current_line_len = line_prefix_len;
20152                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20153                    current_line.push_str(token);
20154                    current_line_len += grapheme_len;
20155                }
20156            }
20157            WordBreakToken::Newline => {
20158                in_whitespace = true;
20159                if preserve_existing_whitespace {
20160                    wrapped_text.push_str(current_line.trim_end());
20161                    wrapped_text.push('\n');
20162                    current_line.truncate(line_prefix.len());
20163                    current_line_len = line_prefix_len;
20164                } else if have_preceding_whitespace {
20165                    continue;
20166                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20167                {
20168                    wrapped_text.push_str(current_line.trim_end());
20169                    wrapped_text.push('\n');
20170                    current_line.truncate(line_prefix.len());
20171                    current_line_len = line_prefix_len;
20172                } else if current_line_len != line_prefix_len {
20173                    current_line.push(' ');
20174                    current_line_len += 1;
20175                }
20176            }
20177        }
20178    }
20179
20180    if !current_line.is_empty() {
20181        wrapped_text.push_str(&current_line);
20182    }
20183    wrapped_text
20184}
20185
20186#[test]
20187fn test_wrap_with_prefix() {
20188    assert_eq!(
20189        wrap_with_prefix(
20190            "# ".to_string(),
20191            "abcdefg".to_string(),
20192            4,
20193            NonZeroU32::new(4).unwrap(),
20194            false,
20195        ),
20196        "# abcdefg"
20197    );
20198    assert_eq!(
20199        wrap_with_prefix(
20200            "".to_string(),
20201            "\thello world".to_string(),
20202            8,
20203            NonZeroU32::new(4).unwrap(),
20204            false,
20205        ),
20206        "hello\nworld"
20207    );
20208    assert_eq!(
20209        wrap_with_prefix(
20210            "// ".to_string(),
20211            "xx \nyy zz aa bb cc".to_string(),
20212            12,
20213            NonZeroU32::new(4).unwrap(),
20214            false,
20215        ),
20216        "// xx yy zz\n// aa bb cc"
20217    );
20218    assert_eq!(
20219        wrap_with_prefix(
20220            String::new(),
20221            "这是什么 \n 钢笔".to_string(),
20222            3,
20223            NonZeroU32::new(4).unwrap(),
20224            false,
20225        ),
20226        "这是什\n么 钢\n"
20227    );
20228}
20229
20230pub trait CollaborationHub {
20231    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20232    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20233    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20234}
20235
20236impl CollaborationHub for Entity<Project> {
20237    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20238        self.read(cx).collaborators()
20239    }
20240
20241    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20242        self.read(cx).user_store().read(cx).participant_indices()
20243    }
20244
20245    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20246        let this = self.read(cx);
20247        let user_ids = this.collaborators().values().map(|c| c.user_id);
20248        this.user_store().read(cx).participant_names(user_ids, cx)
20249    }
20250}
20251
20252pub trait SemanticsProvider {
20253    fn hover(
20254        &self,
20255        buffer: &Entity<Buffer>,
20256        position: text::Anchor,
20257        cx: &mut App,
20258    ) -> Option<Task<Vec<project::Hover>>>;
20259
20260    fn inline_values(
20261        &self,
20262        buffer_handle: Entity<Buffer>,
20263        range: Range<text::Anchor>,
20264        cx: &mut App,
20265    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20266
20267    fn inlay_hints(
20268        &self,
20269        buffer_handle: Entity<Buffer>,
20270        range: Range<text::Anchor>,
20271        cx: &mut App,
20272    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20273
20274    fn resolve_inlay_hint(
20275        &self,
20276        hint: InlayHint,
20277        buffer_handle: Entity<Buffer>,
20278        server_id: LanguageServerId,
20279        cx: &mut App,
20280    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20281
20282    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20283
20284    fn document_highlights(
20285        &self,
20286        buffer: &Entity<Buffer>,
20287        position: text::Anchor,
20288        cx: &mut App,
20289    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20290
20291    fn definitions(
20292        &self,
20293        buffer: &Entity<Buffer>,
20294        position: text::Anchor,
20295        kind: GotoDefinitionKind,
20296        cx: &mut App,
20297    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20298
20299    fn range_for_rename(
20300        &self,
20301        buffer: &Entity<Buffer>,
20302        position: text::Anchor,
20303        cx: &mut App,
20304    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20305
20306    fn perform_rename(
20307        &self,
20308        buffer: &Entity<Buffer>,
20309        position: text::Anchor,
20310        new_name: String,
20311        cx: &mut App,
20312    ) -> Option<Task<Result<ProjectTransaction>>>;
20313}
20314
20315pub trait CompletionProvider {
20316    fn completions(
20317        &self,
20318        excerpt_id: ExcerptId,
20319        buffer: &Entity<Buffer>,
20320        buffer_position: text::Anchor,
20321        trigger: CompletionContext,
20322        window: &mut Window,
20323        cx: &mut Context<Editor>,
20324    ) -> Task<Result<Vec<CompletionResponse>>>;
20325
20326    fn resolve_completions(
20327        &self,
20328        buffer: Entity<Buffer>,
20329        completion_indices: Vec<usize>,
20330        completions: Rc<RefCell<Box<[Completion]>>>,
20331        cx: &mut Context<Editor>,
20332    ) -> Task<Result<bool>>;
20333
20334    fn apply_additional_edits_for_completion(
20335        &self,
20336        _buffer: Entity<Buffer>,
20337        _completions: Rc<RefCell<Box<[Completion]>>>,
20338        _completion_index: usize,
20339        _push_to_history: bool,
20340        _cx: &mut Context<Editor>,
20341    ) -> Task<Result<Option<language::Transaction>>> {
20342        Task::ready(Ok(None))
20343    }
20344
20345    fn is_completion_trigger(
20346        &self,
20347        buffer: &Entity<Buffer>,
20348        position: language::Anchor,
20349        text: &str,
20350        trigger_in_words: bool,
20351        menu_is_open: bool,
20352        cx: &mut Context<Editor>,
20353    ) -> bool;
20354
20355    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20356
20357    fn sort_completions(&self) -> bool {
20358        true
20359    }
20360
20361    fn filter_completions(&self) -> bool {
20362        true
20363    }
20364}
20365
20366pub trait CodeActionProvider {
20367    fn id(&self) -> Arc<str>;
20368
20369    fn code_actions(
20370        &self,
20371        buffer: &Entity<Buffer>,
20372        range: Range<text::Anchor>,
20373        window: &mut Window,
20374        cx: &mut App,
20375    ) -> Task<Result<Vec<CodeAction>>>;
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}
20387
20388impl CodeActionProvider for Entity<Project> {
20389    fn id(&self) -> Arc<str> {
20390        "project".into()
20391    }
20392
20393    fn code_actions(
20394        &self,
20395        buffer: &Entity<Buffer>,
20396        range: Range<text::Anchor>,
20397        _window: &mut Window,
20398        cx: &mut App,
20399    ) -> Task<Result<Vec<CodeAction>>> {
20400        self.update(cx, |project, cx| {
20401            let code_lens = project.code_lens(buffer, range.clone(), cx);
20402            let code_actions = project.code_actions(buffer, range, None, cx);
20403            cx.background_spawn(async move {
20404                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20405                Ok(code_lens
20406                    .context("code lens fetch")?
20407                    .into_iter()
20408                    .chain(code_actions.context("code action fetch")?)
20409                    .collect())
20410            })
20411        })
20412    }
20413
20414    fn apply_code_action(
20415        &self,
20416        buffer_handle: Entity<Buffer>,
20417        action: CodeAction,
20418        _excerpt_id: ExcerptId,
20419        push_to_history: bool,
20420        _window: &mut Window,
20421        cx: &mut App,
20422    ) -> Task<Result<ProjectTransaction>> {
20423        self.update(cx, |project, cx| {
20424            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20425        })
20426    }
20427}
20428
20429fn snippet_completions(
20430    project: &Project,
20431    buffer: &Entity<Buffer>,
20432    buffer_position: text::Anchor,
20433    cx: &mut App,
20434) -> Task<Result<CompletionResponse>> {
20435    let languages = buffer.read(cx).languages_at(buffer_position);
20436    let snippet_store = project.snippets().read(cx);
20437
20438    let scopes: Vec<_> = languages
20439        .iter()
20440        .filter_map(|language| {
20441            let language_name = language.lsp_id();
20442            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20443
20444            if snippets.is_empty() {
20445                None
20446            } else {
20447                Some((language.default_scope(), snippets))
20448            }
20449        })
20450        .collect();
20451
20452    if scopes.is_empty() {
20453        return Task::ready(Ok(CompletionResponse {
20454            completions: vec![],
20455            is_incomplete: false,
20456        }));
20457    }
20458
20459    let snapshot = buffer.read(cx).text_snapshot();
20460    let chars: String = snapshot
20461        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20462        .collect();
20463    let executor = cx.background_executor().clone();
20464
20465    cx.background_spawn(async move {
20466        let mut is_incomplete = false;
20467        let mut completions: Vec<Completion> = Vec::new();
20468        for (scope, snippets) in scopes.into_iter() {
20469            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20470            let mut last_word = chars
20471                .chars()
20472                .take_while(|c| classifier.is_word(*c))
20473                .collect::<String>();
20474            last_word = last_word.chars().rev().collect();
20475
20476            if last_word.is_empty() {
20477                return Ok(CompletionResponse {
20478                    completions: vec![],
20479                    is_incomplete: true,
20480                });
20481            }
20482
20483            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20484            let to_lsp = |point: &text::Anchor| {
20485                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20486                point_to_lsp(end)
20487            };
20488            let lsp_end = to_lsp(&buffer_position);
20489
20490            let candidates = snippets
20491                .iter()
20492                .enumerate()
20493                .flat_map(|(ix, snippet)| {
20494                    snippet
20495                        .prefix
20496                        .iter()
20497                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20498                })
20499                .collect::<Vec<StringMatchCandidate>>();
20500
20501            const MAX_RESULTS: usize = 100;
20502            let mut matches = fuzzy::match_strings(
20503                &candidates,
20504                &last_word,
20505                last_word.chars().any(|c| c.is_uppercase()),
20506                MAX_RESULTS,
20507                &Default::default(),
20508                executor.clone(),
20509            )
20510            .await;
20511
20512            if matches.len() >= MAX_RESULTS {
20513                is_incomplete = true;
20514            }
20515
20516            // Remove all candidates where the query's start does not match the start of any word in the candidate
20517            if let Some(query_start) = last_word.chars().next() {
20518                matches.retain(|string_match| {
20519                    split_words(&string_match.string).any(|word| {
20520                        // Check that the first codepoint of the word as lowercase matches the first
20521                        // codepoint of the query as lowercase
20522                        word.chars()
20523                            .flat_map(|codepoint| codepoint.to_lowercase())
20524                            .zip(query_start.to_lowercase())
20525                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20526                    })
20527                });
20528            }
20529
20530            let matched_strings = matches
20531                .into_iter()
20532                .map(|m| m.string)
20533                .collect::<HashSet<_>>();
20534
20535            completions.extend(snippets.iter().filter_map(|snippet| {
20536                let matching_prefix = snippet
20537                    .prefix
20538                    .iter()
20539                    .find(|prefix| matched_strings.contains(*prefix))?;
20540                let start = as_offset - last_word.len();
20541                let start = snapshot.anchor_before(start);
20542                let range = start..buffer_position;
20543                let lsp_start = to_lsp(&start);
20544                let lsp_range = lsp::Range {
20545                    start: lsp_start,
20546                    end: lsp_end,
20547                };
20548                Some(Completion {
20549                    replace_range: range,
20550                    new_text: snippet.body.clone(),
20551                    source: CompletionSource::Lsp {
20552                        insert_range: None,
20553                        server_id: LanguageServerId(usize::MAX),
20554                        resolved: true,
20555                        lsp_completion: Box::new(lsp::CompletionItem {
20556                            label: snippet.prefix.first().unwrap().clone(),
20557                            kind: Some(CompletionItemKind::SNIPPET),
20558                            label_details: snippet.description.as_ref().map(|description| {
20559                                lsp::CompletionItemLabelDetails {
20560                                    detail: Some(description.clone()),
20561                                    description: None,
20562                                }
20563                            }),
20564                            insert_text_format: Some(InsertTextFormat::SNIPPET),
20565                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20566                                lsp::InsertReplaceEdit {
20567                                    new_text: snippet.body.clone(),
20568                                    insert: lsp_range,
20569                                    replace: lsp_range,
20570                                },
20571                            )),
20572                            filter_text: Some(snippet.body.clone()),
20573                            sort_text: Some(char::MAX.to_string()),
20574                            ..lsp::CompletionItem::default()
20575                        }),
20576                        lsp_defaults: None,
20577                    },
20578                    label: CodeLabel {
20579                        text: matching_prefix.clone(),
20580                        runs: Vec::new(),
20581                        filter_range: 0..matching_prefix.len(),
20582                    },
20583                    icon_path: None,
20584                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
20585                        single_line: snippet.name.clone().into(),
20586                        plain_text: snippet
20587                            .description
20588                            .clone()
20589                            .map(|description| description.into()),
20590                    }),
20591                    insert_text_mode: None,
20592                    confirm: None,
20593                })
20594            }))
20595        }
20596
20597        Ok(CompletionResponse {
20598            completions,
20599            is_incomplete,
20600        })
20601    })
20602}
20603
20604impl CompletionProvider for Entity<Project> {
20605    fn completions(
20606        &self,
20607        _excerpt_id: ExcerptId,
20608        buffer: &Entity<Buffer>,
20609        buffer_position: text::Anchor,
20610        options: CompletionContext,
20611        _window: &mut Window,
20612        cx: &mut Context<Editor>,
20613    ) -> Task<Result<Vec<CompletionResponse>>> {
20614        self.update(cx, |project, cx| {
20615            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20616            let project_completions = project.completions(buffer, buffer_position, options, cx);
20617            cx.background_spawn(async move {
20618                let mut responses = project_completions.await?;
20619                let snippets = snippets.await?;
20620                if !snippets.completions.is_empty() {
20621                    responses.push(snippets);
20622                }
20623                Ok(responses)
20624            })
20625        })
20626    }
20627
20628    fn resolve_completions(
20629        &self,
20630        buffer: Entity<Buffer>,
20631        completion_indices: Vec<usize>,
20632        completions: Rc<RefCell<Box<[Completion]>>>,
20633        cx: &mut Context<Editor>,
20634    ) -> Task<Result<bool>> {
20635        self.update(cx, |project, cx| {
20636            project.lsp_store().update(cx, |lsp_store, cx| {
20637                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20638            })
20639        })
20640    }
20641
20642    fn apply_additional_edits_for_completion(
20643        &self,
20644        buffer: Entity<Buffer>,
20645        completions: Rc<RefCell<Box<[Completion]>>>,
20646        completion_index: usize,
20647        push_to_history: bool,
20648        cx: &mut Context<Editor>,
20649    ) -> Task<Result<Option<language::Transaction>>> {
20650        self.update(cx, |project, cx| {
20651            project.lsp_store().update(cx, |lsp_store, cx| {
20652                lsp_store.apply_additional_edits_for_completion(
20653                    buffer,
20654                    completions,
20655                    completion_index,
20656                    push_to_history,
20657                    cx,
20658                )
20659            })
20660        })
20661    }
20662
20663    fn is_completion_trigger(
20664        &self,
20665        buffer: &Entity<Buffer>,
20666        position: language::Anchor,
20667        text: &str,
20668        trigger_in_words: bool,
20669        menu_is_open: bool,
20670        cx: &mut Context<Editor>,
20671    ) -> bool {
20672        let mut chars = text.chars();
20673        let char = if let Some(char) = chars.next() {
20674            char
20675        } else {
20676            return false;
20677        };
20678        if chars.next().is_some() {
20679            return false;
20680        }
20681
20682        let buffer = buffer.read(cx);
20683        let snapshot = buffer.snapshot();
20684        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
20685            return false;
20686        }
20687        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20688        if trigger_in_words && classifier.is_word(char) {
20689            return true;
20690        }
20691
20692        buffer.completion_triggers().contains(text)
20693    }
20694}
20695
20696impl SemanticsProvider for Entity<Project> {
20697    fn hover(
20698        &self,
20699        buffer: &Entity<Buffer>,
20700        position: text::Anchor,
20701        cx: &mut App,
20702    ) -> Option<Task<Vec<project::Hover>>> {
20703        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20704    }
20705
20706    fn document_highlights(
20707        &self,
20708        buffer: &Entity<Buffer>,
20709        position: text::Anchor,
20710        cx: &mut App,
20711    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20712        Some(self.update(cx, |project, cx| {
20713            project.document_highlights(buffer, position, cx)
20714        }))
20715    }
20716
20717    fn definitions(
20718        &self,
20719        buffer: &Entity<Buffer>,
20720        position: text::Anchor,
20721        kind: GotoDefinitionKind,
20722        cx: &mut App,
20723    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20724        Some(self.update(cx, |project, cx| match kind {
20725            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20726            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20727            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20728            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20729        }))
20730    }
20731
20732    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20733        // TODO: make this work for remote projects
20734        self.update(cx, |project, cx| {
20735            if project
20736                .active_debug_session(cx)
20737                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20738            {
20739                return true;
20740            }
20741
20742            buffer.update(cx, |buffer, cx| {
20743                project.any_language_server_supports_inlay_hints(buffer, cx)
20744            })
20745        })
20746    }
20747
20748    fn inline_values(
20749        &self,
20750        buffer_handle: Entity<Buffer>,
20751
20752        range: Range<text::Anchor>,
20753        cx: &mut App,
20754    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20755        self.update(cx, |project, cx| {
20756            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20757
20758            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20759        })
20760    }
20761
20762    fn inlay_hints(
20763        &self,
20764        buffer_handle: Entity<Buffer>,
20765        range: Range<text::Anchor>,
20766        cx: &mut App,
20767    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20768        Some(self.update(cx, |project, cx| {
20769            project.inlay_hints(buffer_handle, range, cx)
20770        }))
20771    }
20772
20773    fn resolve_inlay_hint(
20774        &self,
20775        hint: InlayHint,
20776        buffer_handle: Entity<Buffer>,
20777        server_id: LanguageServerId,
20778        cx: &mut App,
20779    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20780        Some(self.update(cx, |project, cx| {
20781            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20782        }))
20783    }
20784
20785    fn range_for_rename(
20786        &self,
20787        buffer: &Entity<Buffer>,
20788        position: text::Anchor,
20789        cx: &mut App,
20790    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20791        Some(self.update(cx, |project, cx| {
20792            let buffer = buffer.clone();
20793            let task = project.prepare_rename(buffer.clone(), position, cx);
20794            cx.spawn(async move |_, cx| {
20795                Ok(match task.await? {
20796                    PrepareRenameResponse::Success(range) => Some(range),
20797                    PrepareRenameResponse::InvalidPosition => None,
20798                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20799                        // Fallback on using TreeSitter info to determine identifier range
20800                        buffer.read_with(cx, |buffer, _| {
20801                            let snapshot = buffer.snapshot();
20802                            let (range, kind) = snapshot.surrounding_word(position);
20803                            if kind != Some(CharKind::Word) {
20804                                return None;
20805                            }
20806                            Some(
20807                                snapshot.anchor_before(range.start)
20808                                    ..snapshot.anchor_after(range.end),
20809                            )
20810                        })?
20811                    }
20812                })
20813            })
20814        }))
20815    }
20816
20817    fn perform_rename(
20818        &self,
20819        buffer: &Entity<Buffer>,
20820        position: text::Anchor,
20821        new_name: String,
20822        cx: &mut App,
20823    ) -> Option<Task<Result<ProjectTransaction>>> {
20824        Some(self.update(cx, |project, cx| {
20825            project.perform_rename(buffer.clone(), position, new_name, cx)
20826        }))
20827    }
20828}
20829
20830fn inlay_hint_settings(
20831    location: Anchor,
20832    snapshot: &MultiBufferSnapshot,
20833    cx: &mut Context<Editor>,
20834) -> InlayHintSettings {
20835    let file = snapshot.file_at(location);
20836    let language = snapshot.language_at(location).map(|l| l.name());
20837    language_settings(language, file, cx).inlay_hints
20838}
20839
20840fn consume_contiguous_rows(
20841    contiguous_row_selections: &mut Vec<Selection<Point>>,
20842    selection: &Selection<Point>,
20843    display_map: &DisplaySnapshot,
20844    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20845) -> (MultiBufferRow, MultiBufferRow) {
20846    contiguous_row_selections.push(selection.clone());
20847    let start_row = MultiBufferRow(selection.start.row);
20848    let mut end_row = ending_row(selection, display_map);
20849
20850    while let Some(next_selection) = selections.peek() {
20851        if next_selection.start.row <= end_row.0 {
20852            end_row = ending_row(next_selection, display_map);
20853            contiguous_row_selections.push(selections.next().unwrap().clone());
20854        } else {
20855            break;
20856        }
20857    }
20858    (start_row, end_row)
20859}
20860
20861fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20862    if next_selection.end.column > 0 || next_selection.is_empty() {
20863        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20864    } else {
20865        MultiBufferRow(next_selection.end.row)
20866    }
20867}
20868
20869impl EditorSnapshot {
20870    pub fn remote_selections_in_range<'a>(
20871        &'a self,
20872        range: &'a Range<Anchor>,
20873        collaboration_hub: &dyn CollaborationHub,
20874        cx: &'a App,
20875    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20876        let participant_names = collaboration_hub.user_names(cx);
20877        let participant_indices = collaboration_hub.user_participant_indices(cx);
20878        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20879        let collaborators_by_replica_id = collaborators_by_peer_id
20880            .values()
20881            .map(|collaborator| (collaborator.replica_id, collaborator))
20882            .collect::<HashMap<_, _>>();
20883        self.buffer_snapshot
20884            .selections_in_range(range, false)
20885            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20886                if replica_id == AGENT_REPLICA_ID {
20887                    Some(RemoteSelection {
20888                        replica_id,
20889                        selection,
20890                        cursor_shape,
20891                        line_mode,
20892                        collaborator_id: CollaboratorId::Agent,
20893                        user_name: Some("Agent".into()),
20894                        color: cx.theme().players().agent(),
20895                    })
20896                } else {
20897                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20898                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20899                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20900                    Some(RemoteSelection {
20901                        replica_id,
20902                        selection,
20903                        cursor_shape,
20904                        line_mode,
20905                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20906                        user_name,
20907                        color: if let Some(index) = participant_index {
20908                            cx.theme().players().color_for_participant(index.0)
20909                        } else {
20910                            cx.theme().players().absent()
20911                        },
20912                    })
20913                }
20914            })
20915    }
20916
20917    pub fn hunks_for_ranges(
20918        &self,
20919        ranges: impl IntoIterator<Item = Range<Point>>,
20920    ) -> Vec<MultiBufferDiffHunk> {
20921        let mut hunks = Vec::new();
20922        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20923            HashMap::default();
20924        for query_range in ranges {
20925            let query_rows =
20926                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20927            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20928                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20929            ) {
20930                // Include deleted hunks that are adjacent to the query range, because
20931                // otherwise they would be missed.
20932                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20933                if hunk.status().is_deleted() {
20934                    intersects_range |= hunk.row_range.start == query_rows.end;
20935                    intersects_range |= hunk.row_range.end == query_rows.start;
20936                }
20937                if intersects_range {
20938                    if !processed_buffer_rows
20939                        .entry(hunk.buffer_id)
20940                        .or_default()
20941                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20942                    {
20943                        continue;
20944                    }
20945                    hunks.push(hunk);
20946                }
20947            }
20948        }
20949
20950        hunks
20951    }
20952
20953    fn display_diff_hunks_for_rows<'a>(
20954        &'a self,
20955        display_rows: Range<DisplayRow>,
20956        folded_buffers: &'a HashSet<BufferId>,
20957    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20958        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20959        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20960
20961        self.buffer_snapshot
20962            .diff_hunks_in_range(buffer_start..buffer_end)
20963            .filter_map(|hunk| {
20964                if folded_buffers.contains(&hunk.buffer_id) {
20965                    return None;
20966                }
20967
20968                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20969                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20970
20971                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20972                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20973
20974                let display_hunk = if hunk_display_start.column() != 0 {
20975                    DisplayDiffHunk::Folded {
20976                        display_row: hunk_display_start.row(),
20977                    }
20978                } else {
20979                    let mut end_row = hunk_display_end.row();
20980                    if hunk_display_end.column() > 0 {
20981                        end_row.0 += 1;
20982                    }
20983                    let is_created_file = hunk.is_created_file();
20984                    DisplayDiffHunk::Unfolded {
20985                        status: hunk.status(),
20986                        diff_base_byte_range: hunk.diff_base_byte_range,
20987                        display_row_range: hunk_display_start.row()..end_row,
20988                        multi_buffer_range: Anchor::range_in_buffer(
20989                            hunk.excerpt_id,
20990                            hunk.buffer_id,
20991                            hunk.buffer_range,
20992                        ),
20993                        is_created_file,
20994                    }
20995                };
20996
20997                Some(display_hunk)
20998            })
20999    }
21000
21001    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21002        self.display_snapshot.buffer_snapshot.language_at(position)
21003    }
21004
21005    pub fn is_focused(&self) -> bool {
21006        self.is_focused
21007    }
21008
21009    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21010        self.placeholder_text.as_ref()
21011    }
21012
21013    pub fn scroll_position(&self) -> gpui::Point<f32> {
21014        self.scroll_anchor.scroll_position(&self.display_snapshot)
21015    }
21016
21017    fn gutter_dimensions(
21018        &self,
21019        font_id: FontId,
21020        font_size: Pixels,
21021        max_line_number_width: Pixels,
21022        cx: &App,
21023    ) -> Option<GutterDimensions> {
21024        if !self.show_gutter {
21025            return None;
21026        }
21027
21028        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
21029        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
21030
21031        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21032            matches!(
21033                ProjectSettings::get_global(cx).git.git_gutter,
21034                Some(GitGutterSetting::TrackedFiles)
21035            )
21036        });
21037        let gutter_settings = EditorSettings::get_global(cx).gutter;
21038        let show_line_numbers = self
21039            .show_line_numbers
21040            .unwrap_or(gutter_settings.line_numbers);
21041        let line_gutter_width = if show_line_numbers {
21042            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
21043            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
21044            max_line_number_width.max(min_width_for_number_on_gutter)
21045        } else {
21046            0.0.into()
21047        };
21048
21049        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21050        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21051
21052        let git_blame_entries_width =
21053            self.git_blame_gutter_max_author_length
21054                .map(|max_author_length| {
21055                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21056                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21057
21058                    /// The number of characters to dedicate to gaps and margins.
21059                    const SPACING_WIDTH: usize = 4;
21060
21061                    let max_char_count = max_author_length.min(renderer.max_author_length())
21062                        + ::git::SHORT_SHA_LENGTH
21063                        + MAX_RELATIVE_TIMESTAMP.len()
21064                        + SPACING_WIDTH;
21065
21066                    em_advance * max_char_count
21067                });
21068
21069        let is_singleton = self.buffer_snapshot.is_singleton();
21070
21071        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21072        left_padding += if !is_singleton {
21073            em_width * 4.0
21074        } else if show_runnables || show_breakpoints {
21075            em_width * 3.0
21076        } else if show_git_gutter && show_line_numbers {
21077            em_width * 2.0
21078        } else if show_git_gutter || show_line_numbers {
21079            em_width
21080        } else {
21081            px(0.)
21082        };
21083
21084        let shows_folds = is_singleton && gutter_settings.folds;
21085
21086        let right_padding = if shows_folds && show_line_numbers {
21087            em_width * 4.0
21088        } else if shows_folds || (!is_singleton && show_line_numbers) {
21089            em_width * 3.0
21090        } else if show_line_numbers {
21091            em_width
21092        } else {
21093            px(0.)
21094        };
21095
21096        Some(GutterDimensions {
21097            left_padding,
21098            right_padding,
21099            width: line_gutter_width + left_padding + right_padding,
21100            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21101            git_blame_entries_width,
21102        })
21103    }
21104
21105    pub fn render_crease_toggle(
21106        &self,
21107        buffer_row: MultiBufferRow,
21108        row_contains_cursor: bool,
21109        editor: Entity<Editor>,
21110        window: &mut Window,
21111        cx: &mut App,
21112    ) -> Option<AnyElement> {
21113        let folded = self.is_line_folded(buffer_row);
21114        let mut is_foldable = false;
21115
21116        if let Some(crease) = self
21117            .crease_snapshot
21118            .query_row(buffer_row, &self.buffer_snapshot)
21119        {
21120            is_foldable = true;
21121            match crease {
21122                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21123                    if let Some(render_toggle) = render_toggle {
21124                        let toggle_callback =
21125                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21126                                if folded {
21127                                    editor.update(cx, |editor, cx| {
21128                                        editor.fold_at(buffer_row, window, cx)
21129                                    });
21130                                } else {
21131                                    editor.update(cx, |editor, cx| {
21132                                        editor.unfold_at(buffer_row, window, cx)
21133                                    });
21134                                }
21135                            });
21136                        return Some((render_toggle)(
21137                            buffer_row,
21138                            folded,
21139                            toggle_callback,
21140                            window,
21141                            cx,
21142                        ));
21143                    }
21144                }
21145            }
21146        }
21147
21148        is_foldable |= self.starts_indent(buffer_row);
21149
21150        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21151            Some(
21152                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21153                    .toggle_state(folded)
21154                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21155                        if folded {
21156                            this.unfold_at(buffer_row, window, cx);
21157                        } else {
21158                            this.fold_at(buffer_row, window, cx);
21159                        }
21160                    }))
21161                    .into_any_element(),
21162            )
21163        } else {
21164            None
21165        }
21166    }
21167
21168    pub fn render_crease_trailer(
21169        &self,
21170        buffer_row: MultiBufferRow,
21171        window: &mut Window,
21172        cx: &mut App,
21173    ) -> Option<AnyElement> {
21174        let folded = self.is_line_folded(buffer_row);
21175        if let Crease::Inline { render_trailer, .. } = self
21176            .crease_snapshot
21177            .query_row(buffer_row, &self.buffer_snapshot)?
21178        {
21179            let render_trailer = render_trailer.as_ref()?;
21180            Some(render_trailer(buffer_row, folded, window, cx))
21181        } else {
21182            None
21183        }
21184    }
21185}
21186
21187impl Deref for EditorSnapshot {
21188    type Target = DisplaySnapshot;
21189
21190    fn deref(&self) -> &Self::Target {
21191        &self.display_snapshot
21192    }
21193}
21194
21195#[derive(Clone, Debug, PartialEq, Eq)]
21196pub enum EditorEvent {
21197    InputIgnored {
21198        text: Arc<str>,
21199    },
21200    InputHandled {
21201        utf16_range_to_replace: Option<Range<isize>>,
21202        text: Arc<str>,
21203    },
21204    ExcerptsAdded {
21205        buffer: Entity<Buffer>,
21206        predecessor: ExcerptId,
21207        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21208    },
21209    ExcerptsRemoved {
21210        ids: Vec<ExcerptId>,
21211        removed_buffer_ids: Vec<BufferId>,
21212    },
21213    BufferFoldToggled {
21214        ids: Vec<ExcerptId>,
21215        folded: bool,
21216    },
21217    ExcerptsEdited {
21218        ids: Vec<ExcerptId>,
21219    },
21220    ExcerptsExpanded {
21221        ids: Vec<ExcerptId>,
21222    },
21223    BufferEdited,
21224    Edited {
21225        transaction_id: clock::Lamport,
21226    },
21227    Reparsed(BufferId),
21228    Focused,
21229    FocusedIn,
21230    Blurred,
21231    DirtyChanged,
21232    Saved,
21233    TitleChanged,
21234    DiffBaseChanged,
21235    SelectionsChanged {
21236        local: bool,
21237    },
21238    ScrollPositionChanged {
21239        local: bool,
21240        autoscroll: bool,
21241    },
21242    Closed,
21243    TransactionUndone {
21244        transaction_id: clock::Lamport,
21245    },
21246    TransactionBegun {
21247        transaction_id: clock::Lamport,
21248    },
21249    Reloaded,
21250    CursorShapeChanged,
21251    PushedToNavHistory {
21252        anchor: Anchor,
21253        is_deactivate: bool,
21254    },
21255}
21256
21257impl EventEmitter<EditorEvent> for Editor {}
21258
21259impl Focusable for Editor {
21260    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21261        self.focus_handle.clone()
21262    }
21263}
21264
21265impl Render for Editor {
21266    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21267        let settings = ThemeSettings::get_global(cx);
21268
21269        let mut text_style = match self.mode {
21270            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21271                color: cx.theme().colors().editor_foreground,
21272                font_family: settings.ui_font.family.clone(),
21273                font_features: settings.ui_font.features.clone(),
21274                font_fallbacks: settings.ui_font.fallbacks.clone(),
21275                font_size: rems(0.875).into(),
21276                font_weight: settings.ui_font.weight,
21277                line_height: relative(settings.buffer_line_height.value()),
21278                ..Default::default()
21279            },
21280            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21281                color: cx.theme().colors().editor_foreground,
21282                font_family: settings.buffer_font.family.clone(),
21283                font_features: settings.buffer_font.features.clone(),
21284                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21285                font_size: settings.buffer_font_size(cx).into(),
21286                font_weight: settings.buffer_font.weight,
21287                line_height: relative(settings.buffer_line_height.value()),
21288                ..Default::default()
21289            },
21290        };
21291        if let Some(text_style_refinement) = &self.text_style_refinement {
21292            text_style.refine(text_style_refinement)
21293        }
21294
21295        let background = match self.mode {
21296            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21297            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21298            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21299            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21300        };
21301
21302        EditorElement::new(
21303            &cx.entity(),
21304            EditorStyle {
21305                background,
21306                local_player: cx.theme().players().local(),
21307                text: text_style,
21308                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21309                syntax: cx.theme().syntax().clone(),
21310                status: cx.theme().status().clone(),
21311                inlay_hints_style: make_inlay_hints_style(cx),
21312                inline_completion_styles: make_suggestion_styles(cx),
21313                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21314                show_underlines: !self.mode.is_minimap(),
21315            },
21316        )
21317    }
21318}
21319
21320impl EntityInputHandler for Editor {
21321    fn text_for_range(
21322        &mut self,
21323        range_utf16: Range<usize>,
21324        adjusted_range: &mut Option<Range<usize>>,
21325        _: &mut Window,
21326        cx: &mut Context<Self>,
21327    ) -> Option<String> {
21328        let snapshot = self.buffer.read(cx).read(cx);
21329        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21330        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21331        if (start.0..end.0) != range_utf16 {
21332            adjusted_range.replace(start.0..end.0);
21333        }
21334        Some(snapshot.text_for_range(start..end).collect())
21335    }
21336
21337    fn selected_text_range(
21338        &mut self,
21339        ignore_disabled_input: bool,
21340        _: &mut Window,
21341        cx: &mut Context<Self>,
21342    ) -> Option<UTF16Selection> {
21343        // Prevent the IME menu from appearing when holding down an alphabetic key
21344        // while input is disabled.
21345        if !ignore_disabled_input && !self.input_enabled {
21346            return None;
21347        }
21348
21349        let selection = self.selections.newest::<OffsetUtf16>(cx);
21350        let range = selection.range();
21351
21352        Some(UTF16Selection {
21353            range: range.start.0..range.end.0,
21354            reversed: selection.reversed,
21355        })
21356    }
21357
21358    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21359        let snapshot = self.buffer.read(cx).read(cx);
21360        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21361        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21362    }
21363
21364    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21365        self.clear_highlights::<InputComposition>(cx);
21366        self.ime_transaction.take();
21367    }
21368
21369    fn replace_text_in_range(
21370        &mut self,
21371        range_utf16: Option<Range<usize>>,
21372        text: &str,
21373        window: &mut Window,
21374        cx: &mut Context<Self>,
21375    ) {
21376        if !self.input_enabled {
21377            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21378            return;
21379        }
21380
21381        self.transact(window, cx, |this, window, cx| {
21382            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21383                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21384                Some(this.selection_replacement_ranges(range_utf16, cx))
21385            } else {
21386                this.marked_text_ranges(cx)
21387            };
21388
21389            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21390                let newest_selection_id = this.selections.newest_anchor().id;
21391                this.selections
21392                    .all::<OffsetUtf16>(cx)
21393                    .iter()
21394                    .zip(ranges_to_replace.iter())
21395                    .find_map(|(selection, range)| {
21396                        if selection.id == newest_selection_id {
21397                            Some(
21398                                (range.start.0 as isize - selection.head().0 as isize)
21399                                    ..(range.end.0 as isize - selection.head().0 as isize),
21400                            )
21401                        } else {
21402                            None
21403                        }
21404                    })
21405            });
21406
21407            cx.emit(EditorEvent::InputHandled {
21408                utf16_range_to_replace: range_to_replace,
21409                text: text.into(),
21410            });
21411
21412            if let Some(new_selected_ranges) = new_selected_ranges {
21413                this.change_selections(None, window, cx, |selections| {
21414                    selections.select_ranges(new_selected_ranges)
21415                });
21416                this.backspace(&Default::default(), window, cx);
21417            }
21418
21419            this.handle_input(text, window, cx);
21420        });
21421
21422        if let Some(transaction) = self.ime_transaction {
21423            self.buffer.update(cx, |buffer, cx| {
21424                buffer.group_until_transaction(transaction, cx);
21425            });
21426        }
21427
21428        self.unmark_text(window, cx);
21429    }
21430
21431    fn replace_and_mark_text_in_range(
21432        &mut self,
21433        range_utf16: Option<Range<usize>>,
21434        text: &str,
21435        new_selected_range_utf16: Option<Range<usize>>,
21436        window: &mut Window,
21437        cx: &mut Context<Self>,
21438    ) {
21439        if !self.input_enabled {
21440            return;
21441        }
21442
21443        let transaction = self.transact(window, cx, |this, window, cx| {
21444            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21445                let snapshot = this.buffer.read(cx).read(cx);
21446                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21447                    for marked_range in &mut marked_ranges {
21448                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21449                        marked_range.start.0 += relative_range_utf16.start;
21450                        marked_range.start =
21451                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21452                        marked_range.end =
21453                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21454                    }
21455                }
21456                Some(marked_ranges)
21457            } else if let Some(range_utf16) = range_utf16 {
21458                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21459                Some(this.selection_replacement_ranges(range_utf16, cx))
21460            } else {
21461                None
21462            };
21463
21464            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21465                let newest_selection_id = this.selections.newest_anchor().id;
21466                this.selections
21467                    .all::<OffsetUtf16>(cx)
21468                    .iter()
21469                    .zip(ranges_to_replace.iter())
21470                    .find_map(|(selection, range)| {
21471                        if selection.id == newest_selection_id {
21472                            Some(
21473                                (range.start.0 as isize - selection.head().0 as isize)
21474                                    ..(range.end.0 as isize - selection.head().0 as isize),
21475                            )
21476                        } else {
21477                            None
21478                        }
21479                    })
21480            });
21481
21482            cx.emit(EditorEvent::InputHandled {
21483                utf16_range_to_replace: range_to_replace,
21484                text: text.into(),
21485            });
21486
21487            if let Some(ranges) = ranges_to_replace {
21488                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21489            }
21490
21491            let marked_ranges = {
21492                let snapshot = this.buffer.read(cx).read(cx);
21493                this.selections
21494                    .disjoint_anchors()
21495                    .iter()
21496                    .map(|selection| {
21497                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21498                    })
21499                    .collect::<Vec<_>>()
21500            };
21501
21502            if text.is_empty() {
21503                this.unmark_text(window, cx);
21504            } else {
21505                this.highlight_text::<InputComposition>(
21506                    marked_ranges.clone(),
21507                    HighlightStyle {
21508                        underline: Some(UnderlineStyle {
21509                            thickness: px(1.),
21510                            color: None,
21511                            wavy: false,
21512                        }),
21513                        ..Default::default()
21514                    },
21515                    cx,
21516                );
21517            }
21518
21519            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21520            let use_autoclose = this.use_autoclose;
21521            let use_auto_surround = this.use_auto_surround;
21522            this.set_use_autoclose(false);
21523            this.set_use_auto_surround(false);
21524            this.handle_input(text, window, cx);
21525            this.set_use_autoclose(use_autoclose);
21526            this.set_use_auto_surround(use_auto_surround);
21527
21528            if let Some(new_selected_range) = new_selected_range_utf16 {
21529                let snapshot = this.buffer.read(cx).read(cx);
21530                let new_selected_ranges = marked_ranges
21531                    .into_iter()
21532                    .map(|marked_range| {
21533                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21534                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21535                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21536                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21537                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21538                    })
21539                    .collect::<Vec<_>>();
21540
21541                drop(snapshot);
21542                this.change_selections(None, window, cx, |selections| {
21543                    selections.select_ranges(new_selected_ranges)
21544                });
21545            }
21546        });
21547
21548        self.ime_transaction = self.ime_transaction.or(transaction);
21549        if let Some(transaction) = self.ime_transaction {
21550            self.buffer.update(cx, |buffer, cx| {
21551                buffer.group_until_transaction(transaction, cx);
21552            });
21553        }
21554
21555        if self.text_highlights::<InputComposition>(cx).is_none() {
21556            self.ime_transaction.take();
21557        }
21558    }
21559
21560    fn bounds_for_range(
21561        &mut self,
21562        range_utf16: Range<usize>,
21563        element_bounds: gpui::Bounds<Pixels>,
21564        window: &mut Window,
21565        cx: &mut Context<Self>,
21566    ) -> Option<gpui::Bounds<Pixels>> {
21567        let text_layout_details = self.text_layout_details(window);
21568        let gpui::Size {
21569            width: em_width,
21570            height: line_height,
21571        } = self.character_size(window);
21572
21573        let snapshot = self.snapshot(window, cx);
21574        let scroll_position = snapshot.scroll_position();
21575        let scroll_left = scroll_position.x * em_width;
21576
21577        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21578        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21579            + self.gutter_dimensions.width
21580            + self.gutter_dimensions.margin;
21581        let y = line_height * (start.row().as_f32() - scroll_position.y);
21582
21583        Some(Bounds {
21584            origin: element_bounds.origin + point(x, y),
21585            size: size(em_width, line_height),
21586        })
21587    }
21588
21589    fn character_index_for_point(
21590        &mut self,
21591        point: gpui::Point<Pixels>,
21592        _window: &mut Window,
21593        _cx: &mut Context<Self>,
21594    ) -> Option<usize> {
21595        let position_map = self.last_position_map.as_ref()?;
21596        if !position_map.text_hitbox.contains(&point) {
21597            return None;
21598        }
21599        let display_point = position_map.point_for_position(point).previous_valid;
21600        let anchor = position_map
21601            .snapshot
21602            .display_point_to_anchor(display_point, Bias::Left);
21603        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21604        Some(utf16_offset.0)
21605    }
21606}
21607
21608trait SelectionExt {
21609    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21610    fn spanned_rows(
21611        &self,
21612        include_end_if_at_line_start: bool,
21613        map: &DisplaySnapshot,
21614    ) -> Range<MultiBufferRow>;
21615}
21616
21617impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21618    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21619        let start = self
21620            .start
21621            .to_point(&map.buffer_snapshot)
21622            .to_display_point(map);
21623        let end = self
21624            .end
21625            .to_point(&map.buffer_snapshot)
21626            .to_display_point(map);
21627        if self.reversed {
21628            end..start
21629        } else {
21630            start..end
21631        }
21632    }
21633
21634    fn spanned_rows(
21635        &self,
21636        include_end_if_at_line_start: bool,
21637        map: &DisplaySnapshot,
21638    ) -> Range<MultiBufferRow> {
21639        let start = self.start.to_point(&map.buffer_snapshot);
21640        let mut end = self.end.to_point(&map.buffer_snapshot);
21641        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21642            end.row -= 1;
21643        }
21644
21645        let buffer_start = map.prev_line_boundary(start).0;
21646        let buffer_end = map.next_line_boundary(end).0;
21647        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21648    }
21649}
21650
21651impl<T: InvalidationRegion> InvalidationStack<T> {
21652    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21653    where
21654        S: Clone + ToOffset,
21655    {
21656        while let Some(region) = self.last() {
21657            let all_selections_inside_invalidation_ranges =
21658                if selections.len() == region.ranges().len() {
21659                    selections
21660                        .iter()
21661                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21662                        .all(|(selection, invalidation_range)| {
21663                            let head = selection.head().to_offset(buffer);
21664                            invalidation_range.start <= head && invalidation_range.end >= head
21665                        })
21666                } else {
21667                    false
21668                };
21669
21670            if all_selections_inside_invalidation_ranges {
21671                break;
21672            } else {
21673                self.pop();
21674            }
21675        }
21676    }
21677}
21678
21679impl<T> Default for InvalidationStack<T> {
21680    fn default() -> Self {
21681        Self(Default::default())
21682    }
21683}
21684
21685impl<T> Deref for InvalidationStack<T> {
21686    type Target = Vec<T>;
21687
21688    fn deref(&self) -> &Self::Target {
21689        &self.0
21690    }
21691}
21692
21693impl<T> DerefMut for InvalidationStack<T> {
21694    fn deref_mut(&mut self) -> &mut Self::Target {
21695        &mut self.0
21696    }
21697}
21698
21699impl InvalidationRegion for SnippetState {
21700    fn ranges(&self) -> &[Range<Anchor>] {
21701        &self.ranges[self.active_index]
21702    }
21703}
21704
21705fn inline_completion_edit_text(
21706    current_snapshot: &BufferSnapshot,
21707    edits: &[(Range<Anchor>, String)],
21708    edit_preview: &EditPreview,
21709    include_deletions: bool,
21710    cx: &App,
21711) -> HighlightedText {
21712    let edits = edits
21713        .iter()
21714        .map(|(anchor, text)| {
21715            (
21716                anchor.start.text_anchor..anchor.end.text_anchor,
21717                text.clone(),
21718            )
21719        })
21720        .collect::<Vec<_>>();
21721
21722    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21723}
21724
21725pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21726    match severity {
21727        lsp::DiagnosticSeverity::ERROR => colors.error,
21728        lsp::DiagnosticSeverity::WARNING => colors.warning,
21729        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21730        lsp::DiagnosticSeverity::HINT => colors.info,
21731        _ => colors.ignored,
21732    }
21733}
21734
21735pub fn styled_runs_for_code_label<'a>(
21736    label: &'a CodeLabel,
21737    syntax_theme: &'a theme::SyntaxTheme,
21738) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21739    let fade_out = HighlightStyle {
21740        fade_out: Some(0.35),
21741        ..Default::default()
21742    };
21743
21744    let mut prev_end = label.filter_range.end;
21745    label
21746        .runs
21747        .iter()
21748        .enumerate()
21749        .flat_map(move |(ix, (range, highlight_id))| {
21750            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21751                style
21752            } else {
21753                return Default::default();
21754            };
21755            let mut muted_style = style;
21756            muted_style.highlight(fade_out);
21757
21758            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21759            if range.start >= label.filter_range.end {
21760                if range.start > prev_end {
21761                    runs.push((prev_end..range.start, fade_out));
21762                }
21763                runs.push((range.clone(), muted_style));
21764            } else if range.end <= label.filter_range.end {
21765                runs.push((range.clone(), style));
21766            } else {
21767                runs.push((range.start..label.filter_range.end, style));
21768                runs.push((label.filter_range.end..range.end, muted_style));
21769            }
21770            prev_end = cmp::max(prev_end, range.end);
21771
21772            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21773                runs.push((prev_end..label.text.len(), fade_out));
21774            }
21775
21776            runs
21777        })
21778}
21779
21780pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21781    let mut prev_index = 0;
21782    let mut prev_codepoint: Option<char> = None;
21783    text.char_indices()
21784        .chain([(text.len(), '\0')])
21785        .filter_map(move |(index, codepoint)| {
21786            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21787            let is_boundary = index == text.len()
21788                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21789                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21790            if is_boundary {
21791                let chunk = &text[prev_index..index];
21792                prev_index = index;
21793                Some(chunk)
21794            } else {
21795                None
21796            }
21797        })
21798}
21799
21800pub trait RangeToAnchorExt: Sized {
21801    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21802
21803    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21804        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21805        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21806    }
21807}
21808
21809impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21810    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21811        let start_offset = self.start.to_offset(snapshot);
21812        let end_offset = self.end.to_offset(snapshot);
21813        if start_offset == end_offset {
21814            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21815        } else {
21816            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21817        }
21818    }
21819}
21820
21821pub trait RowExt {
21822    fn as_f32(&self) -> f32;
21823
21824    fn next_row(&self) -> Self;
21825
21826    fn previous_row(&self) -> Self;
21827
21828    fn minus(&self, other: Self) -> u32;
21829}
21830
21831impl RowExt for DisplayRow {
21832    fn as_f32(&self) -> f32 {
21833        self.0 as f32
21834    }
21835
21836    fn next_row(&self) -> Self {
21837        Self(self.0 + 1)
21838    }
21839
21840    fn previous_row(&self) -> Self {
21841        Self(self.0.saturating_sub(1))
21842    }
21843
21844    fn minus(&self, other: Self) -> u32 {
21845        self.0 - other.0
21846    }
21847}
21848
21849impl RowExt for MultiBufferRow {
21850    fn as_f32(&self) -> f32 {
21851        self.0 as f32
21852    }
21853
21854    fn next_row(&self) -> Self {
21855        Self(self.0 + 1)
21856    }
21857
21858    fn previous_row(&self) -> Self {
21859        Self(self.0.saturating_sub(1))
21860    }
21861
21862    fn minus(&self, other: Self) -> u32 {
21863        self.0 - other.0
21864    }
21865}
21866
21867trait RowRangeExt {
21868    type Row;
21869
21870    fn len(&self) -> usize;
21871
21872    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21873}
21874
21875impl RowRangeExt for Range<MultiBufferRow> {
21876    type Row = MultiBufferRow;
21877
21878    fn len(&self) -> usize {
21879        (self.end.0 - self.start.0) as usize
21880    }
21881
21882    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21883        (self.start.0..self.end.0).map(MultiBufferRow)
21884    }
21885}
21886
21887impl RowRangeExt for Range<DisplayRow> {
21888    type Row = DisplayRow;
21889
21890    fn len(&self) -> usize {
21891        (self.end.0 - self.start.0) as usize
21892    }
21893
21894    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21895        (self.start.0..self.end.0).map(DisplayRow)
21896    }
21897}
21898
21899/// If select range has more than one line, we
21900/// just point the cursor to range.start.
21901fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21902    if range.start.row == range.end.row {
21903        range
21904    } else {
21905        range.start..range.start
21906    }
21907}
21908pub struct KillRing(ClipboardItem);
21909impl Global for KillRing {}
21910
21911const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21912
21913enum BreakpointPromptEditAction {
21914    Log,
21915    Condition,
21916    HitCondition,
21917}
21918
21919struct BreakpointPromptEditor {
21920    pub(crate) prompt: Entity<Editor>,
21921    editor: WeakEntity<Editor>,
21922    breakpoint_anchor: Anchor,
21923    breakpoint: Breakpoint,
21924    edit_action: BreakpointPromptEditAction,
21925    block_ids: HashSet<CustomBlockId>,
21926    editor_margins: Arc<Mutex<EditorMargins>>,
21927    _subscriptions: Vec<Subscription>,
21928}
21929
21930impl BreakpointPromptEditor {
21931    const MAX_LINES: u8 = 4;
21932
21933    fn new(
21934        editor: WeakEntity<Editor>,
21935        breakpoint_anchor: Anchor,
21936        breakpoint: Breakpoint,
21937        edit_action: BreakpointPromptEditAction,
21938        window: &mut Window,
21939        cx: &mut Context<Self>,
21940    ) -> Self {
21941        let base_text = match edit_action {
21942            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21943            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21944            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21945        }
21946        .map(|msg| msg.to_string())
21947        .unwrap_or_default();
21948
21949        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21950        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21951
21952        let prompt = cx.new(|cx| {
21953            let mut prompt = Editor::new(
21954                EditorMode::AutoHeight {
21955                    max_lines: Self::MAX_LINES as usize,
21956                },
21957                buffer,
21958                None,
21959                window,
21960                cx,
21961            );
21962            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21963            prompt.set_show_cursor_when_unfocused(false, cx);
21964            prompt.set_placeholder_text(
21965                match edit_action {
21966                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21967                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21968                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21969                },
21970                cx,
21971            );
21972
21973            prompt
21974        });
21975
21976        Self {
21977            prompt,
21978            editor,
21979            breakpoint_anchor,
21980            breakpoint,
21981            edit_action,
21982            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21983            block_ids: Default::default(),
21984            _subscriptions: vec![],
21985        }
21986    }
21987
21988    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21989        self.block_ids.extend(block_ids)
21990    }
21991
21992    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21993        if let Some(editor) = self.editor.upgrade() {
21994            let message = self
21995                .prompt
21996                .read(cx)
21997                .buffer
21998                .read(cx)
21999                .as_singleton()
22000                .expect("A multi buffer in breakpoint prompt isn't possible")
22001                .read(cx)
22002                .as_rope()
22003                .to_string();
22004
22005            editor.update(cx, |editor, cx| {
22006                editor.edit_breakpoint_at_anchor(
22007                    self.breakpoint_anchor,
22008                    self.breakpoint.clone(),
22009                    match self.edit_action {
22010                        BreakpointPromptEditAction::Log => {
22011                            BreakpointEditAction::EditLogMessage(message.into())
22012                        }
22013                        BreakpointPromptEditAction::Condition => {
22014                            BreakpointEditAction::EditCondition(message.into())
22015                        }
22016                        BreakpointPromptEditAction::HitCondition => {
22017                            BreakpointEditAction::EditHitCondition(message.into())
22018                        }
22019                    },
22020                    cx,
22021                );
22022
22023                editor.remove_blocks(self.block_ids.clone(), None, cx);
22024                cx.focus_self(window);
22025            });
22026        }
22027    }
22028
22029    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22030        self.editor
22031            .update(cx, |editor, cx| {
22032                editor.remove_blocks(self.block_ids.clone(), None, cx);
22033                window.focus(&editor.focus_handle);
22034            })
22035            .log_err();
22036    }
22037
22038    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22039        let settings = ThemeSettings::get_global(cx);
22040        let text_style = TextStyle {
22041            color: if self.prompt.read(cx).read_only(cx) {
22042                cx.theme().colors().text_disabled
22043            } else {
22044                cx.theme().colors().text
22045            },
22046            font_family: settings.buffer_font.family.clone(),
22047            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22048            font_size: settings.buffer_font_size(cx).into(),
22049            font_weight: settings.buffer_font.weight,
22050            line_height: relative(settings.buffer_line_height.value()),
22051            ..Default::default()
22052        };
22053        EditorElement::new(
22054            &self.prompt,
22055            EditorStyle {
22056                background: cx.theme().colors().editor_background,
22057                local_player: cx.theme().players().local(),
22058                text: text_style,
22059                ..Default::default()
22060            },
22061        )
22062    }
22063}
22064
22065impl Render for BreakpointPromptEditor {
22066    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22067        let editor_margins = *self.editor_margins.lock();
22068        let gutter_dimensions = editor_margins.gutter;
22069        h_flex()
22070            .key_context("Editor")
22071            .bg(cx.theme().colors().editor_background)
22072            .border_y_1()
22073            .border_color(cx.theme().status().info_border)
22074            .size_full()
22075            .py(window.line_height() / 2.5)
22076            .on_action(cx.listener(Self::confirm))
22077            .on_action(cx.listener(Self::cancel))
22078            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22079            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22080    }
22081}
22082
22083impl Focusable for BreakpointPromptEditor {
22084    fn focus_handle(&self, cx: &App) -> FocusHandle {
22085        self.prompt.focus_handle(cx)
22086    }
22087}
22088
22089fn all_edits_insertions_or_deletions(
22090    edits: &Vec<(Range<Anchor>, String)>,
22091    snapshot: &MultiBufferSnapshot,
22092) -> bool {
22093    let mut all_insertions = true;
22094    let mut all_deletions = true;
22095
22096    for (range, new_text) in edits.iter() {
22097        let range_is_empty = range.to_offset(&snapshot).is_empty();
22098        let text_is_empty = new_text.is_empty();
22099
22100        if range_is_empty != text_is_empty {
22101            if range_is_empty {
22102                all_deletions = false;
22103            } else {
22104                all_insertions = false;
22105            }
22106        } else {
22107            return false;
22108        }
22109
22110        if !all_insertions && !all_deletions {
22111            return false;
22112        }
22113    }
22114    all_insertions || all_deletions
22115}
22116
22117struct MissingEditPredictionKeybindingTooltip;
22118
22119impl Render for MissingEditPredictionKeybindingTooltip {
22120    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22121        ui::tooltip_container(window, cx, |container, _, cx| {
22122            container
22123                .flex_shrink_0()
22124                .max_w_80()
22125                .min_h(rems_from_px(124.))
22126                .justify_between()
22127                .child(
22128                    v_flex()
22129                        .flex_1()
22130                        .text_ui_sm(cx)
22131                        .child(Label::new("Conflict with Accept Keybinding"))
22132                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22133                )
22134                .child(
22135                    h_flex()
22136                        .pb_1()
22137                        .gap_1()
22138                        .items_end()
22139                        .w_full()
22140                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22141                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22142                        }))
22143                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22144                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22145                        })),
22146                )
22147        })
22148    }
22149}
22150
22151#[derive(Debug, Clone, Copy, PartialEq)]
22152pub struct LineHighlight {
22153    pub background: Background,
22154    pub border: Option<gpui::Hsla>,
22155    pub include_gutter: bool,
22156    pub type_id: Option<TypeId>,
22157}
22158
22159fn render_diff_hunk_controls(
22160    row: u32,
22161    status: &DiffHunkStatus,
22162    hunk_range: Range<Anchor>,
22163    is_created_file: bool,
22164    line_height: Pixels,
22165    editor: &Entity<Editor>,
22166    _window: &mut Window,
22167    cx: &mut App,
22168) -> AnyElement {
22169    h_flex()
22170        .h(line_height)
22171        .mr_1()
22172        .gap_1()
22173        .px_0p5()
22174        .pb_1()
22175        .border_x_1()
22176        .border_b_1()
22177        .border_color(cx.theme().colors().border_variant)
22178        .rounded_b_lg()
22179        .bg(cx.theme().colors().editor_background)
22180        .gap_1()
22181        .block_mouse_except_scroll()
22182        .shadow_md()
22183        .child(if status.has_secondary_hunk() {
22184            Button::new(("stage", row as u64), "Stage")
22185                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22186                .tooltip({
22187                    let focus_handle = editor.focus_handle(cx);
22188                    move |window, cx| {
22189                        Tooltip::for_action_in(
22190                            "Stage Hunk",
22191                            &::git::ToggleStaged,
22192                            &focus_handle,
22193                            window,
22194                            cx,
22195                        )
22196                    }
22197                })
22198                .on_click({
22199                    let editor = editor.clone();
22200                    move |_event, _window, cx| {
22201                        editor.update(cx, |editor, cx| {
22202                            editor.stage_or_unstage_diff_hunks(
22203                                true,
22204                                vec![hunk_range.start..hunk_range.start],
22205                                cx,
22206                            );
22207                        });
22208                    }
22209                })
22210        } else {
22211            Button::new(("unstage", row as u64), "Unstage")
22212                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22213                .tooltip({
22214                    let focus_handle = editor.focus_handle(cx);
22215                    move |window, cx| {
22216                        Tooltip::for_action_in(
22217                            "Unstage Hunk",
22218                            &::git::ToggleStaged,
22219                            &focus_handle,
22220                            window,
22221                            cx,
22222                        )
22223                    }
22224                })
22225                .on_click({
22226                    let editor = editor.clone();
22227                    move |_event, _window, cx| {
22228                        editor.update(cx, |editor, cx| {
22229                            editor.stage_or_unstage_diff_hunks(
22230                                false,
22231                                vec![hunk_range.start..hunk_range.start],
22232                                cx,
22233                            );
22234                        });
22235                    }
22236                })
22237        })
22238        .child(
22239            Button::new(("restore", row as u64), "Restore")
22240                .tooltip({
22241                    let focus_handle = editor.focus_handle(cx);
22242                    move |window, cx| {
22243                        Tooltip::for_action_in(
22244                            "Restore Hunk",
22245                            &::git::Restore,
22246                            &focus_handle,
22247                            window,
22248                            cx,
22249                        )
22250                    }
22251                })
22252                .on_click({
22253                    let editor = editor.clone();
22254                    move |_event, window, cx| {
22255                        editor.update(cx, |editor, cx| {
22256                            let snapshot = editor.snapshot(window, cx);
22257                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22258                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22259                        });
22260                    }
22261                })
22262                .disabled(is_created_file),
22263        )
22264        .when(
22265            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22266            |el| {
22267                el.child(
22268                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22269                        .shape(IconButtonShape::Square)
22270                        .icon_size(IconSize::Small)
22271                        // .disabled(!has_multiple_hunks)
22272                        .tooltip({
22273                            let focus_handle = editor.focus_handle(cx);
22274                            move |window, cx| {
22275                                Tooltip::for_action_in(
22276                                    "Next Hunk",
22277                                    &GoToHunk,
22278                                    &focus_handle,
22279                                    window,
22280                                    cx,
22281                                )
22282                            }
22283                        })
22284                        .on_click({
22285                            let editor = editor.clone();
22286                            move |_event, window, cx| {
22287                                editor.update(cx, |editor, cx| {
22288                                    let snapshot = editor.snapshot(window, cx);
22289                                    let position =
22290                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22291                                    editor.go_to_hunk_before_or_after_position(
22292                                        &snapshot,
22293                                        position,
22294                                        Direction::Next,
22295                                        window,
22296                                        cx,
22297                                    );
22298                                    editor.expand_selected_diff_hunks(cx);
22299                                });
22300                            }
22301                        }),
22302                )
22303                .child(
22304                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22305                        .shape(IconButtonShape::Square)
22306                        .icon_size(IconSize::Small)
22307                        // .disabled(!has_multiple_hunks)
22308                        .tooltip({
22309                            let focus_handle = editor.focus_handle(cx);
22310                            move |window, cx| {
22311                                Tooltip::for_action_in(
22312                                    "Previous Hunk",
22313                                    &GoToPreviousHunk,
22314                                    &focus_handle,
22315                                    window,
22316                                    cx,
22317                                )
22318                            }
22319                        })
22320                        .on_click({
22321                            let editor = editor.clone();
22322                            move |_event, window, cx| {
22323                                editor.update(cx, |editor, cx| {
22324                                    let snapshot = editor.snapshot(window, cx);
22325                                    let point =
22326                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22327                                    editor.go_to_hunk_before_or_after_position(
22328                                        &snapshot,
22329                                        point,
22330                                        Direction::Prev,
22331                                        window,
22332                                        cx,
22333                                    );
22334                                    editor.expand_selected_diff_hunks(cx);
22335                                });
22336                            }
22337                        }),
22338                )
22339            },
22340        )
22341        .into_any_element()
22342}