editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt,
   78    future::{self, Shared, join},
   79};
   80use fuzzy::{StringMatch, StringMatchCandidate};
   81
   82use ::git::blame::BlameEntry;
   83use ::git::{Restore, blame::ParsedCommitMessage};
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use git::blame::{GitBlame, GlobalBlameRenderer};
   89use gpui::{
   90    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   91    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   92    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   93    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   94    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   95    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   96    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   97    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   98};
   99use highlight_matching_bracket::refresh_matching_bracket_highlights;
  100use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  101pub use hover_popover::hover_markdown_style;
  102use hover_popover::{HoverState, hide_hover};
  103use indent_guides::ActiveIndentGuidesState;
  104use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  105pub use inline_completion::Direction;
  106use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  107pub use items::MAX_TAB_TITLE_LEN;
  108use itertools::Itertools;
  109use language::{
  110    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  111    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  112    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  113    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  114    language_settings::{
  115        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  116        all_language_settings, language_settings,
  117    },
  118    point_from_lsp, text_diff_with_options,
  119};
  120use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  121use linked_editing_ranges::refresh_linked_ranges;
  122use markdown::Markdown;
  123use mouse_context_menu::MouseContextMenu;
  124use persistence::DB;
  125use project::{
  126    BreakpointWithPosition, CompletionResponse, ProjectPath,
  127    debugger::{
  128        breakpoint_store::{
  129            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  130            BreakpointStoreEvent,
  131        },
  132        session::{Session, SessionEvent},
  133    },
  134    project_settings::DiagnosticSeverity,
  135};
  136
  137pub use git::blame::BlameRenderer;
  138pub use proposed_changes_editor::{
  139    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  140};
  141use std::{cell::OnceCell, iter::Peekable, ops::Not};
  142use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  143
  144pub use lsp::CompletionContext;
  145use lsp::{
  146    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  147    LanguageServerId, LanguageServerName,
  148};
  149
  150use language::BufferSnapshot;
  151pub use lsp_ext::lsp_tasks;
  152use movement::TextLayoutDetails;
  153pub use multi_buffer::{
  154    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  155    RowInfo, ToOffset, ToPoint,
  156};
  157use multi_buffer::{
  158    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  159    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  160};
  161use parking_lot::Mutex;
  162use project::{
  163    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  164    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  165    TaskSourceKind,
  166    debugger::breakpoint_store::Breakpoint,
  167    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  168    project_settings::{GitGutterSetting, ProjectSettings},
  169};
  170use rand::prelude::*;
  171use rpc::{ErrorExt, proto::*};
  172use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  173use selections_collection::{
  174    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  175};
  176use serde::{Deserialize, Serialize};
  177use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  178use smallvec::{SmallVec, smallvec};
  179use snippet::Snippet;
  180use std::sync::Arc;
  181use std::{
  182    any::TypeId,
  183    borrow::Cow,
  184    cell::RefCell,
  185    cmp::{self, Ordering, Reverse},
  186    mem,
  187    num::NonZeroU32,
  188    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  189    path::{Path, PathBuf},
  190    rc::Rc,
  191    time::{Duration, Instant},
  192};
  193pub use sum_tree::Bias;
  194use sum_tree::TreeMap;
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  196use theme::{
  197    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  202    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  203};
  204use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  205use workspace::{
  206    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  207    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  208    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{ItemHandle, PreviewTabsSettings},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::SearchEvent,
  212};
  213
  214use crate::hover_links::{find_url, find_url_from_range};
  215use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  216
  217pub const FILE_HEADER_HEIGHT: u32 = 2;
  218pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  219pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  220const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  221const MAX_LINE_LEN: usize = 1024;
  222const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  223const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  224pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  225#[doc(hidden)]
  226pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  227const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  228
  229pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  230pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  232
  233pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  234pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  235pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  236pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  237
  238pub type RenderDiffHunkControlsFn = Arc<
  239    dyn Fn(
  240        u32,
  241        &DiffHunkStatus,
  242        Range<Anchor>,
  243        bool,
  244        Pixels,
  245        &Entity<Editor>,
  246        &mut Window,
  247        &mut App,
  248    ) -> AnyElement,
  249>;
  250
  251const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  252    alt: true,
  253    shift: true,
  254    control: false,
  255    platform: false,
  256    function: false,
  257};
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    Hint(usize),
  279    DebuggerValue(usize),
  280}
  281
  282impl InlayId {
  283    fn id(&self) -> usize {
  284        match self {
  285            Self::InlineCompletion(id) => *id,
  286            Self::Hint(id) => *id,
  287            Self::DebuggerValue(id) => *id,
  288        }
  289    }
  290}
  291
  292pub enum ActiveDebugLine {}
  293pub enum DebugStackFrameLine {}
  294enum DocumentHighlightRead {}
  295enum DocumentHighlightWrite {}
  296enum InputComposition {}
  297enum SelectedTextHighlight {}
  298
  299pub enum ConflictsOuter {}
  300pub enum ConflictsOurs {}
  301pub enum ConflictsTheirs {}
  302pub enum ConflictsOursMarker {}
  303pub enum ConflictsTheirsMarker {}
  304
  305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  306pub enum Navigated {
  307    Yes,
  308    No,
  309}
  310
  311impl Navigated {
  312    pub fn from_bool(yes: bool) -> Navigated {
  313        if yes { Navigated::Yes } else { Navigated::No }
  314    }
  315}
  316
  317#[derive(Debug, Clone, PartialEq, Eq)]
  318enum DisplayDiffHunk {
  319    Folded {
  320        display_row: DisplayRow,
  321    },
  322    Unfolded {
  323        is_created_file: bool,
  324        diff_base_byte_range: Range<usize>,
  325        display_row_range: Range<DisplayRow>,
  326        multi_buffer_range: Range<Anchor>,
  327        status: DiffHunkStatus,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init_settings(cx: &mut App) {
  337    EditorSettings::register(cx);
  338}
  339
  340pub fn init(cx: &mut App) {
  341    init_settings(cx);
  342
  343    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  344
  345    workspace::register_project_item::<Editor>(cx);
  346    workspace::FollowableViewRegistry::register::<Editor>(cx);
  347    workspace::register_serializable_item::<Editor>(cx);
  348
  349    cx.observe_new(
  350        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  351            workspace.register_action(Editor::new_file);
  352            workspace.register_action(Editor::new_file_vertical);
  353            workspace.register_action(Editor::new_file_horizontal);
  354            workspace.register_action(Editor::cancel_language_server_work);
  355        },
  356    )
  357    .detach();
  358
  359    cx.on_action(move |_: &workspace::NewFile, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373    cx.on_action(move |_: &workspace::NewWindow, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    cx.activate(true);
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388}
  389
  390pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  391    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  392}
  393
  394pub trait DiagnosticRenderer {
  395    fn render_group(
  396        &self,
  397        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  398        buffer_id: BufferId,
  399        snapshot: EditorSnapshot,
  400        editor: WeakEntity<Editor>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        cx: &mut App,
  410    ) -> Option<Entity<markdown::Markdown>>;
  411
  412    fn open_link(
  413        &self,
  414        editor: &mut Editor,
  415        link: SharedString,
  416        window: &mut Window,
  417        cx: &mut Context<Editor>,
  418    );
  419}
  420
  421pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  422
  423impl GlobalDiagnosticRenderer {
  424    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  425        cx.try_global::<Self>().map(|g| g.0.clone())
  426    }
  427}
  428
  429impl gpui::Global for GlobalDiagnosticRenderer {}
  430pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  431    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  432}
  433
  434pub struct SearchWithinRange;
  435
  436trait InvalidationRegion {
  437    fn ranges(&self) -> &[Range<Anchor>];
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum SelectPhase {
  442    Begin {
  443        position: DisplayPoint,
  444        add: bool,
  445        click_count: usize,
  446    },
  447    BeginColumnar {
  448        position: DisplayPoint,
  449        reset: bool,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug)]
  465pub enum SelectMode {
  466    Character,
  467    Word(Range<Anchor>),
  468    Line(Range<Anchor>),
  469    All,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine {
  475        auto_width: bool,
  476    },
  477    AutoHeight {
  478        max_lines: usize,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// When set to `true`, the editor's height will be determined by its content.
  486        sized_by_content: bool,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sized_by_content: false,
  499        }
  500    }
  501
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub local_player: PlayerColor,
  532    pub text: TextStyle,
  533    pub scrollbar_width: Pixels,
  534    pub syntax: Arc<SyntaxTheme>,
  535    pub status: StatusColors,
  536    pub inlay_hints_style: HighlightStyle,
  537    pub inline_completion_styles: InlineCompletionStyles,
  538    pub unnecessary_code_fade: f32,
  539    pub show_underlines: bool,
  540}
  541
  542impl Default for EditorStyle {
  543    fn default() -> Self {
  544        Self {
  545            background: Hsla::default(),
  546            local_player: PlayerColor::default(),
  547            text: TextStyle::default(),
  548            scrollbar_width: Pixels::default(),
  549            syntax: Default::default(),
  550            // HACK: Status colors don't have a real default.
  551            // We should look into removing the status colors from the editor
  552            // style and retrieve them directly from the theme.
  553            status: StatusColors::dark(),
  554            inlay_hints_style: HighlightStyle::default(),
  555            inline_completion_styles: InlineCompletionStyles {
  556                insertion: HighlightStyle::default(),
  557                whitespace: HighlightStyle::default(),
  558            },
  559            unnecessary_code_fade: Default::default(),
  560            show_underlines: true,
  561        }
  562    }
  563}
  564
  565pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  566    let show_background = language_settings::language_settings(None, None, cx)
  567        .inlay_hints
  568        .show_background;
  569
  570    HighlightStyle {
  571        color: Some(cx.theme().status().hint),
  572        background_color: show_background.then(|| cx.theme().status().hint_background),
  573        ..HighlightStyle::default()
  574    }
  575}
  576
  577pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  578    InlineCompletionStyles {
  579        insertion: HighlightStyle {
  580            color: Some(cx.theme().status().predictive),
  581            ..HighlightStyle::default()
  582        },
  583        whitespace: HighlightStyle {
  584            background_color: Some(cx.theme().status().created_background),
  585            ..HighlightStyle::default()
  586        },
  587    }
  588}
  589
  590type CompletionId = usize;
  591
  592pub(crate) enum EditDisplayMode {
  593    TabAccept,
  594    DiffPopover,
  595    Inline,
  596}
  597
  598enum InlineCompletion {
  599    Edit {
  600        edits: Vec<(Range<Anchor>, String)>,
  601        edit_preview: Option<EditPreview>,
  602        display_mode: EditDisplayMode,
  603        snapshot: BufferSnapshot,
  604    },
  605    Move {
  606        target: Anchor,
  607        snapshot: BufferSnapshot,
  608    },
  609}
  610
  611struct InlineCompletionState {
  612    inlay_ids: Vec<InlayId>,
  613    completion: InlineCompletion,
  614    completion_id: Option<SharedString>,
  615    invalidation_range: Range<Anchor>,
  616}
  617
  618enum EditPredictionSettings {
  619    Disabled,
  620    Enabled {
  621        show_in_menu: bool,
  622        preview_requires_modifier: bool,
  623    },
  624}
  625
  626enum InlineCompletionHighlight {}
  627
  628#[derive(Debug, Clone)]
  629struct InlineDiagnostic {
  630    message: SharedString,
  631    group_id: usize,
  632    is_primary: bool,
  633    start: Point,
  634    severity: lsp::DiagnosticSeverity,
  635}
  636
  637pub enum MenuInlineCompletionsPolicy {
  638    Never,
  639    ByProvider,
  640}
  641
  642pub enum EditPredictionPreview {
  643    /// Modifier is not pressed
  644    Inactive { released_too_fast: bool },
  645    /// Modifier pressed
  646    Active {
  647        since: Instant,
  648        previous_scroll_position: Option<ScrollAnchor>,
  649    },
  650}
  651
  652impl EditPredictionPreview {
  653    pub fn released_too_fast(&self) -> bool {
  654        match self {
  655            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  656            EditPredictionPreview::Active { .. } => false,
  657        }
  658    }
  659
  660    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  661        if let EditPredictionPreview::Active {
  662            previous_scroll_position,
  663            ..
  664        } = self
  665        {
  666            *previous_scroll_position = scroll_position;
  667        }
  668    }
  669}
  670
  671pub struct ContextMenuOptions {
  672    pub min_entries_visible: usize,
  673    pub max_entries_visible: usize,
  674    pub placement: Option<ContextMenuPlacement>,
  675}
  676
  677#[derive(Debug, Clone, PartialEq, Eq)]
  678pub enum ContextMenuPlacement {
  679    Above,
  680    Below,
  681}
  682
  683#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  684struct EditorActionId(usize);
  685
  686impl EditorActionId {
  687    pub fn post_inc(&mut self) -> Self {
  688        let answer = self.0;
  689
  690        *self = Self(answer + 1);
  691
  692        Self(answer)
  693    }
  694}
  695
  696// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  697// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  698
  699type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  700type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  701
  702#[derive(Default)]
  703struct ScrollbarMarkerState {
  704    scrollbar_size: Size<Pixels>,
  705    dirty: bool,
  706    markers: Arc<[PaintQuad]>,
  707    pending_refresh: Option<Task<Result<()>>>,
  708}
  709
  710impl ScrollbarMarkerState {
  711    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  712        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  713    }
  714}
  715
  716#[derive(Clone, Copy, PartialEq, Eq)]
  717pub enum MinimapVisibility {
  718    Disabled,
  719    Enabled {
  720        /// The configuration currently present in the users settings.
  721        setting_configuration: bool,
  722        /// Whether to override the currently set visibility from the users setting.
  723        toggle_override: bool,
  724    },
  725}
  726
  727impl MinimapVisibility {
  728    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  729        if mode.is_full() {
  730            Self::Enabled {
  731                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  732                toggle_override: false,
  733            }
  734        } else {
  735            Self::Disabled
  736        }
  737    }
  738
  739    fn hidden(&self) -> Self {
  740        match *self {
  741            Self::Enabled {
  742                setting_configuration,
  743                ..
  744            } => Self::Enabled {
  745                setting_configuration,
  746                toggle_override: setting_configuration,
  747            },
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751
  752    fn disabled(&self) -> bool {
  753        match *self {
  754            Self::Disabled => true,
  755            _ => false,
  756        }
  757    }
  758
  759    fn settings_visibility(&self) -> bool {
  760        match *self {
  761            Self::Enabled {
  762                setting_configuration,
  763                ..
  764            } => setting_configuration,
  765            _ => false,
  766        }
  767    }
  768
  769    fn visible(&self) -> bool {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                toggle_override,
  774            } => setting_configuration ^ toggle_override,
  775            _ => false,
  776        }
  777    }
  778
  779    fn toggle_visibility(&self) -> Self {
  780        match *self {
  781            Self::Enabled {
  782                toggle_override,
  783                setting_configuration,
  784            } => Self::Enabled {
  785                setting_configuration,
  786                toggle_override: !toggle_override,
  787            },
  788            Self::Disabled => Self::Disabled,
  789        }
  790    }
  791}
  792
  793#[derive(Clone, Debug)]
  794struct RunnableTasks {
  795    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  796    offset: multi_buffer::Anchor,
  797    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  798    column: u32,
  799    // Values of all named captures, including those starting with '_'
  800    extra_variables: HashMap<String, String>,
  801    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  802    context_range: Range<BufferOffset>,
  803}
  804
  805impl RunnableTasks {
  806    fn resolve<'a>(
  807        &'a self,
  808        cx: &'a task::TaskContext,
  809    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  810        self.templates.iter().filter_map(|(kind, template)| {
  811            template
  812                .resolve_task(&kind.to_id_base(), cx)
  813                .map(|task| (kind.clone(), task))
  814        })
  815    }
  816}
  817
  818#[derive(Clone)]
  819pub struct ResolvedTasks {
  820    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  821    position: Anchor,
  822}
  823
  824#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  825struct BufferOffset(usize);
  826
  827// Addons allow storing per-editor state in other crates (e.g. Vim)
  828pub trait Addon: 'static {
  829    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  830
  831    fn render_buffer_header_controls(
  832        &self,
  833        _: &ExcerptInfo,
  834        _: &Window,
  835        _: &App,
  836    ) -> Option<AnyElement> {
  837        None
  838    }
  839
  840    fn to_any(&self) -> &dyn std::any::Any;
  841
  842    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  843        None
  844    }
  845}
  846
  847/// A set of caret positions, registered when the editor was edited.
  848pub struct ChangeList {
  849    changes: Vec<Vec<Anchor>>,
  850    /// Currently "selected" change.
  851    position: Option<usize>,
  852}
  853
  854impl ChangeList {
  855    pub fn new() -> Self {
  856        Self {
  857            changes: Vec::new(),
  858            position: None,
  859        }
  860    }
  861
  862    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  863    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  864    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  865        if self.changes.is_empty() {
  866            return None;
  867        }
  868
  869        let prev = self.position.unwrap_or(self.changes.len());
  870        let next = if direction == Direction::Prev {
  871            prev.saturating_sub(count)
  872        } else {
  873            (prev + count).min(self.changes.len() - 1)
  874        };
  875        self.position = Some(next);
  876        self.changes.get(next).map(|anchors| anchors.as_slice())
  877    }
  878
  879    /// Adds a new change to the list, resetting the change list position.
  880    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  881        self.position.take();
  882        if pop_state {
  883            self.changes.pop();
  884        }
  885        self.changes.push(new_positions.clone());
  886    }
  887
  888    pub fn last(&self) -> Option<&[Anchor]> {
  889        self.changes.last().map(|anchors| anchors.as_slice())
  890    }
  891}
  892
  893#[derive(Clone)]
  894struct InlineBlamePopoverState {
  895    scroll_handle: ScrollHandle,
  896    commit_message: Option<ParsedCommitMessage>,
  897    markdown: Entity<Markdown>,
  898}
  899
  900struct InlineBlamePopover {
  901    position: gpui::Point<Pixels>,
  902    show_task: Option<Task<()>>,
  903    hide_task: Option<Task<()>>,
  904    popover_bounds: Option<Bounds<Pixels>>,
  905    popover_state: InlineBlamePopoverState,
  906}
  907
  908/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  909/// a breakpoint on them.
  910#[derive(Clone, Copy, Debug)]
  911struct PhantomBreakpointIndicator {
  912    display_row: DisplayRow,
  913    /// There's a small debounce between hovering over the line and showing the indicator.
  914    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  915    is_active: bool,
  916    collides_with_existing_breakpoint: bool,
  917}
  918/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  919///
  920/// See the [module level documentation](self) for more information.
  921pub struct Editor {
  922    focus_handle: FocusHandle,
  923    last_focused_descendant: Option<WeakFocusHandle>,
  924    /// The text buffer being edited
  925    buffer: Entity<MultiBuffer>,
  926    /// Map of how text in the buffer should be displayed.
  927    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  928    pub display_map: Entity<DisplayMap>,
  929    pub selections: SelectionsCollection,
  930    pub scroll_manager: ScrollManager,
  931    /// When inline assist editors are linked, they all render cursors because
  932    /// typing enters text into each of them, even the ones that aren't focused.
  933    pub(crate) show_cursor_when_unfocused: bool,
  934    columnar_selection_tail: Option<Anchor>,
  935    columnar_display_point: Option<DisplayPoint>,
  936    add_selections_state: Option<AddSelectionsState>,
  937    select_next_state: Option<SelectNextState>,
  938    select_prev_state: Option<SelectNextState>,
  939    selection_history: SelectionHistory,
  940    defer_selection_effects: bool,
  941    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  942    autoclose_regions: Vec<AutocloseRegion>,
  943    snippet_stack: InvalidationStack<SnippetState>,
  944    select_syntax_node_history: SelectSyntaxNodeHistory,
  945    ime_transaction: Option<TransactionId>,
  946    pub diagnostics_max_severity: DiagnosticSeverity,
  947    active_diagnostics: ActiveDiagnostic,
  948    show_inline_diagnostics: bool,
  949    inline_diagnostics_update: Task<()>,
  950    inline_diagnostics_enabled: bool,
  951    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  952    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  953    hard_wrap: Option<usize>,
  954
  955    // TODO: make this a access method
  956    pub project: Option<Entity<Project>>,
  957    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  958    completion_provider: Option<Rc<dyn CompletionProvider>>,
  959    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  960    blink_manager: Entity<BlinkManager>,
  961    show_cursor_names: bool,
  962    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  963    pub show_local_selections: bool,
  964    mode: EditorMode,
  965    show_breadcrumbs: bool,
  966    show_gutter: bool,
  967    show_scrollbars: ScrollbarAxes,
  968    minimap_visibility: MinimapVisibility,
  969    offset_content: bool,
  970    disable_expand_excerpt_buttons: bool,
  971    show_line_numbers: Option<bool>,
  972    use_relative_line_numbers: Option<bool>,
  973    show_git_diff_gutter: Option<bool>,
  974    show_code_actions: Option<bool>,
  975    show_runnables: Option<bool>,
  976    show_breakpoints: Option<bool>,
  977    show_wrap_guides: Option<bool>,
  978    show_indent_guides: Option<bool>,
  979    placeholder_text: Option<Arc<str>>,
  980    highlight_order: usize,
  981    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  982    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  983    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  984    scrollbar_marker_state: ScrollbarMarkerState,
  985    active_indent_guides_state: ActiveIndentGuidesState,
  986    nav_history: Option<ItemNavHistory>,
  987    context_menu: RefCell<Option<CodeContextMenu>>,
  988    context_menu_options: Option<ContextMenuOptions>,
  989    mouse_context_menu: Option<MouseContextMenu>,
  990    completion_tasks: Vec<(CompletionId, Task<()>)>,
  991    inline_blame_popover: Option<InlineBlamePopover>,
  992    signature_help_state: SignatureHelpState,
  993    auto_signature_help: Option<bool>,
  994    find_all_references_task_sources: Vec<Anchor>,
  995    next_completion_id: CompletionId,
  996    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  997    code_actions_task: Option<Task<Result<()>>>,
  998    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  999    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1000    document_highlights_task: Option<Task<()>>,
 1001    linked_editing_range_task: Option<Task<Option<()>>>,
 1002    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1003    pending_rename: Option<RenameState>,
 1004    searchable: bool,
 1005    cursor_shape: CursorShape,
 1006    current_line_highlight: Option<CurrentLineHighlight>,
 1007    collapse_matches: bool,
 1008    autoindent_mode: Option<AutoindentMode>,
 1009    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1010    input_enabled: bool,
 1011    use_modal_editing: bool,
 1012    read_only: bool,
 1013    leader_id: Option<CollaboratorId>,
 1014    remote_id: Option<ViewId>,
 1015    pub hover_state: HoverState,
 1016    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1017    gutter_hovered: bool,
 1018    hovered_link_state: Option<HoveredLinkState>,
 1019    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1020    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1021    active_inline_completion: Option<InlineCompletionState>,
 1022    /// Used to prevent flickering as the user types while the menu is open
 1023    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1024    edit_prediction_settings: EditPredictionSettings,
 1025    inline_completions_hidden_for_vim_mode: bool,
 1026    show_inline_completions_override: Option<bool>,
 1027    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1028    edit_prediction_preview: EditPredictionPreview,
 1029    edit_prediction_indent_conflict: bool,
 1030    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1031    inlay_hint_cache: InlayHintCache,
 1032    next_inlay_id: usize,
 1033    _subscriptions: Vec<Subscription>,
 1034    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1035    gutter_dimensions: GutterDimensions,
 1036    style: Option<EditorStyle>,
 1037    text_style_refinement: Option<TextStyleRefinement>,
 1038    next_editor_action_id: EditorActionId,
 1039    editor_actions:
 1040        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
 1041    use_autoclose: bool,
 1042    use_auto_surround: bool,
 1043    auto_replace_emoji_shortcode: bool,
 1044    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1045    show_git_blame_gutter: bool,
 1046    show_git_blame_inline: bool,
 1047    show_git_blame_inline_delay_task: Option<Task<()>>,
 1048    git_blame_inline_enabled: bool,
 1049    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1050    serialize_dirty_buffers: bool,
 1051    show_selection_menu: Option<bool>,
 1052    blame: Option<Entity<GitBlame>>,
 1053    blame_subscription: Option<Subscription>,
 1054    custom_context_menu: Option<
 1055        Box<
 1056            dyn 'static
 1057                + Fn(
 1058                    &mut Self,
 1059                    DisplayPoint,
 1060                    &mut Window,
 1061                    &mut Context<Self>,
 1062                ) -> Option<Entity<ui::ContextMenu>>,
 1063        >,
 1064    >,
 1065    last_bounds: Option<Bounds<Pixels>>,
 1066    last_position_map: Option<Rc<PositionMap>>,
 1067    expect_bounds_change: Option<Bounds<Pixels>>,
 1068    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1069    tasks_update_task: Option<Task<()>>,
 1070    breakpoint_store: Option<Entity<BreakpointStore>>,
 1071    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1072    in_project_search: bool,
 1073    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1074    breadcrumb_header: Option<String>,
 1075    focused_block: Option<FocusedBlock>,
 1076    next_scroll_position: NextScrollCursorCenterTopBottom,
 1077    addons: HashMap<TypeId, Box<dyn Addon>>,
 1078    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1079    load_diff_task: Option<Shared<Task<()>>>,
 1080    /// Whether we are temporarily displaying a diff other than git's
 1081    temporary_diff_override: bool,
 1082    selection_mark_mode: bool,
 1083    toggle_fold_multiple_buffers: Task<()>,
 1084    _scroll_cursor_center_top_bottom_task: Task<()>,
 1085    serialize_selections: Task<()>,
 1086    serialize_folds: Task<()>,
 1087    mouse_cursor_hidden: bool,
 1088    minimap: Option<Entity<Self>>,
 1089    hide_mouse_mode: HideMouseMode,
 1090    pub change_list: ChangeList,
 1091    inline_value_cache: InlineValueCache,
 1092}
 1093
 1094#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1095enum NextScrollCursorCenterTopBottom {
 1096    #[default]
 1097    Center,
 1098    Top,
 1099    Bottom,
 1100}
 1101
 1102impl NextScrollCursorCenterTopBottom {
 1103    fn next(&self) -> Self {
 1104        match self {
 1105            Self::Center => Self::Top,
 1106            Self::Top => Self::Bottom,
 1107            Self::Bottom => Self::Center,
 1108        }
 1109    }
 1110}
 1111
 1112#[derive(Clone)]
 1113pub struct EditorSnapshot {
 1114    pub mode: EditorMode,
 1115    show_gutter: bool,
 1116    show_line_numbers: Option<bool>,
 1117    show_git_diff_gutter: Option<bool>,
 1118    show_code_actions: Option<bool>,
 1119    show_runnables: Option<bool>,
 1120    show_breakpoints: Option<bool>,
 1121    git_blame_gutter_max_author_length: Option<usize>,
 1122    pub display_snapshot: DisplaySnapshot,
 1123    pub placeholder_text: Option<Arc<str>>,
 1124    is_focused: bool,
 1125    scroll_anchor: ScrollAnchor,
 1126    ongoing_scroll: OngoingScroll,
 1127    current_line_highlight: CurrentLineHighlight,
 1128    gutter_hovered: bool,
 1129}
 1130
 1131#[derive(Default, Debug, Clone, Copy)]
 1132pub struct GutterDimensions {
 1133    pub left_padding: Pixels,
 1134    pub right_padding: Pixels,
 1135    pub width: Pixels,
 1136    pub margin: Pixels,
 1137    pub git_blame_entries_width: Option<Pixels>,
 1138}
 1139
 1140impl GutterDimensions {
 1141    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1142        Self {
 1143            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1144            ..Default::default()
 1145        }
 1146    }
 1147
 1148    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1149        -cx.text_system().descent(font_id, font_size)
 1150    }
 1151    /// The full width of the space taken up by the gutter.
 1152    pub fn full_width(&self) -> Pixels {
 1153        self.margin + self.width
 1154    }
 1155
 1156    /// The width of the space reserved for the fold indicators,
 1157    /// use alongside 'justify_end' and `gutter_width` to
 1158    /// right align content with the line numbers
 1159    pub fn fold_area_width(&self) -> Pixels {
 1160        self.margin + self.right_padding
 1161    }
 1162}
 1163
 1164#[derive(Debug)]
 1165pub struct RemoteSelection {
 1166    pub replica_id: ReplicaId,
 1167    pub selection: Selection<Anchor>,
 1168    pub cursor_shape: CursorShape,
 1169    pub collaborator_id: CollaboratorId,
 1170    pub line_mode: bool,
 1171    pub user_name: Option<SharedString>,
 1172    pub color: PlayerColor,
 1173}
 1174
 1175#[derive(Clone, Debug)]
 1176struct SelectionHistoryEntry {
 1177    selections: Arc<[Selection<Anchor>]>,
 1178    select_next_state: Option<SelectNextState>,
 1179    select_prev_state: Option<SelectNextState>,
 1180    add_selections_state: Option<AddSelectionsState>,
 1181}
 1182
 1183enum SelectionHistoryMode {
 1184    Normal,
 1185    Undoing,
 1186    Redoing,
 1187}
 1188
 1189#[derive(Clone, PartialEq, Eq, Hash)]
 1190struct HoveredCursor {
 1191    replica_id: u16,
 1192    selection_id: usize,
 1193}
 1194
 1195impl Default for SelectionHistoryMode {
 1196    fn default() -> Self {
 1197        Self::Normal
 1198    }
 1199}
 1200
 1201struct DeferredSelectionEffectsState {
 1202    changed: bool,
 1203    should_update_completions: bool,
 1204    autoscroll: Option<Autoscroll>,
 1205    old_cursor_position: Anchor,
 1206    history_entry: SelectionHistoryEntry,
 1207}
 1208
 1209#[derive(Default)]
 1210struct SelectionHistory {
 1211    #[allow(clippy::type_complexity)]
 1212    selections_by_transaction:
 1213        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1214    mode: SelectionHistoryMode,
 1215    undo_stack: VecDeque<SelectionHistoryEntry>,
 1216    redo_stack: VecDeque<SelectionHistoryEntry>,
 1217}
 1218
 1219impl SelectionHistory {
 1220    fn insert_transaction(
 1221        &mut self,
 1222        transaction_id: TransactionId,
 1223        selections: Arc<[Selection<Anchor>]>,
 1224    ) {
 1225        self.selections_by_transaction
 1226            .insert(transaction_id, (selections, None));
 1227    }
 1228
 1229    #[allow(clippy::type_complexity)]
 1230    fn transaction(
 1231        &self,
 1232        transaction_id: TransactionId,
 1233    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1234        self.selections_by_transaction.get(&transaction_id)
 1235    }
 1236
 1237    #[allow(clippy::type_complexity)]
 1238    fn transaction_mut(
 1239        &mut self,
 1240        transaction_id: TransactionId,
 1241    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1242        self.selections_by_transaction.get_mut(&transaction_id)
 1243    }
 1244
 1245    fn push(&mut self, entry: SelectionHistoryEntry) {
 1246        if !entry.selections.is_empty() {
 1247            match self.mode {
 1248                SelectionHistoryMode::Normal => {
 1249                    self.push_undo(entry);
 1250                    self.redo_stack.clear();
 1251                }
 1252                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1253                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1254            }
 1255        }
 1256    }
 1257
 1258    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1259        if self
 1260            .undo_stack
 1261            .back()
 1262            .map_or(true, |e| e.selections != entry.selections)
 1263        {
 1264            self.undo_stack.push_back(entry);
 1265            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1266                self.undo_stack.pop_front();
 1267            }
 1268        }
 1269    }
 1270
 1271    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1272        if self
 1273            .redo_stack
 1274            .back()
 1275            .map_or(true, |e| e.selections != entry.selections)
 1276        {
 1277            self.redo_stack.push_back(entry);
 1278            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1279                self.redo_stack.pop_front();
 1280            }
 1281        }
 1282    }
 1283}
 1284
 1285#[derive(Clone, Copy)]
 1286pub struct RowHighlightOptions {
 1287    pub autoscroll: bool,
 1288    pub include_gutter: bool,
 1289}
 1290
 1291impl Default for RowHighlightOptions {
 1292    fn default() -> Self {
 1293        Self {
 1294            autoscroll: Default::default(),
 1295            include_gutter: true,
 1296        }
 1297    }
 1298}
 1299
 1300struct RowHighlight {
 1301    index: usize,
 1302    range: Range<Anchor>,
 1303    color: Hsla,
 1304    options: RowHighlightOptions,
 1305    type_id: TypeId,
 1306}
 1307
 1308#[derive(Clone, Debug)]
 1309struct AddSelectionsState {
 1310    above: bool,
 1311    stack: Vec<usize>,
 1312}
 1313
 1314#[derive(Clone)]
 1315struct SelectNextState {
 1316    query: AhoCorasick,
 1317    wordwise: bool,
 1318    done: bool,
 1319}
 1320
 1321impl std::fmt::Debug for SelectNextState {
 1322    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1323        f.debug_struct(std::any::type_name::<Self>())
 1324            .field("wordwise", &self.wordwise)
 1325            .field("done", &self.done)
 1326            .finish()
 1327    }
 1328}
 1329
 1330#[derive(Debug)]
 1331struct AutocloseRegion {
 1332    selection_id: usize,
 1333    range: Range<Anchor>,
 1334    pair: BracketPair,
 1335}
 1336
 1337#[derive(Debug)]
 1338struct SnippetState {
 1339    ranges: Vec<Vec<Range<Anchor>>>,
 1340    active_index: usize,
 1341    choices: Vec<Option<Vec<String>>>,
 1342}
 1343
 1344#[doc(hidden)]
 1345pub struct RenameState {
 1346    pub range: Range<Anchor>,
 1347    pub old_name: Arc<str>,
 1348    pub editor: Entity<Editor>,
 1349    block_id: CustomBlockId,
 1350}
 1351
 1352struct InvalidationStack<T>(Vec<T>);
 1353
 1354struct RegisteredInlineCompletionProvider {
 1355    provider: Arc<dyn InlineCompletionProviderHandle>,
 1356    _subscription: Subscription,
 1357}
 1358
 1359#[derive(Debug, PartialEq, Eq)]
 1360pub struct ActiveDiagnosticGroup {
 1361    pub active_range: Range<Anchor>,
 1362    pub active_message: String,
 1363    pub group_id: usize,
 1364    pub blocks: HashSet<CustomBlockId>,
 1365}
 1366
 1367#[derive(Debug, PartialEq, Eq)]
 1368
 1369pub(crate) enum ActiveDiagnostic {
 1370    None,
 1371    All,
 1372    Group(ActiveDiagnosticGroup),
 1373}
 1374
 1375#[derive(Serialize, Deserialize, Clone, Debug)]
 1376pub struct ClipboardSelection {
 1377    /// The number of bytes in this selection.
 1378    pub len: usize,
 1379    /// Whether this was a full-line selection.
 1380    pub is_entire_line: bool,
 1381    /// The indentation of the first line when this content was originally copied.
 1382    pub first_line_indent: u32,
 1383}
 1384
 1385// selections, scroll behavior, was newest selection reversed
 1386type SelectSyntaxNodeHistoryState = (
 1387    Box<[Selection<usize>]>,
 1388    SelectSyntaxNodeScrollBehavior,
 1389    bool,
 1390);
 1391
 1392#[derive(Default)]
 1393struct SelectSyntaxNodeHistory {
 1394    stack: Vec<SelectSyntaxNodeHistoryState>,
 1395    // disable temporarily to allow changing selections without losing the stack
 1396    pub disable_clearing: bool,
 1397}
 1398
 1399impl SelectSyntaxNodeHistory {
 1400    pub fn try_clear(&mut self) {
 1401        if !self.disable_clearing {
 1402            self.stack.clear();
 1403        }
 1404    }
 1405
 1406    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1407        self.stack.push(selection);
 1408    }
 1409
 1410    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1411        self.stack.pop()
 1412    }
 1413}
 1414
 1415enum SelectSyntaxNodeScrollBehavior {
 1416    CursorTop,
 1417    FitSelection,
 1418    CursorBottom,
 1419}
 1420
 1421#[derive(Debug)]
 1422pub(crate) struct NavigationData {
 1423    cursor_anchor: Anchor,
 1424    cursor_position: Point,
 1425    scroll_anchor: ScrollAnchor,
 1426    scroll_top_row: u32,
 1427}
 1428
 1429#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1430pub enum GotoDefinitionKind {
 1431    Symbol,
 1432    Declaration,
 1433    Type,
 1434    Implementation,
 1435}
 1436
 1437#[derive(Debug, Clone)]
 1438enum InlayHintRefreshReason {
 1439    ModifiersChanged(bool),
 1440    Toggle(bool),
 1441    SettingsChange(InlayHintSettings),
 1442    NewLinesShown,
 1443    BufferEdited(HashSet<Arc<Language>>),
 1444    RefreshRequested,
 1445    ExcerptsRemoved(Vec<ExcerptId>),
 1446}
 1447
 1448impl InlayHintRefreshReason {
 1449    fn description(&self) -> &'static str {
 1450        match self {
 1451            Self::ModifiersChanged(_) => "modifiers changed",
 1452            Self::Toggle(_) => "toggle",
 1453            Self::SettingsChange(_) => "settings change",
 1454            Self::NewLinesShown => "new lines shown",
 1455            Self::BufferEdited(_) => "buffer edited",
 1456            Self::RefreshRequested => "refresh requested",
 1457            Self::ExcerptsRemoved(_) => "excerpts removed",
 1458        }
 1459    }
 1460}
 1461
 1462pub enum FormatTarget {
 1463    Buffers,
 1464    Ranges(Vec<Range<MultiBufferPoint>>),
 1465}
 1466
 1467pub(crate) struct FocusedBlock {
 1468    id: BlockId,
 1469    focus_handle: WeakFocusHandle,
 1470}
 1471
 1472#[derive(Clone)]
 1473enum JumpData {
 1474    MultiBufferRow {
 1475        row: MultiBufferRow,
 1476        line_offset_from_top: u32,
 1477    },
 1478    MultiBufferPoint {
 1479        excerpt_id: ExcerptId,
 1480        position: Point,
 1481        anchor: text::Anchor,
 1482        line_offset_from_top: u32,
 1483    },
 1484}
 1485
 1486pub enum MultibufferSelectionMode {
 1487    First,
 1488    All,
 1489}
 1490
 1491#[derive(Clone, Copy, Debug, Default)]
 1492pub struct RewrapOptions {
 1493    pub override_language_settings: bool,
 1494    pub preserve_existing_whitespace: bool,
 1495}
 1496
 1497impl Editor {
 1498    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1499        let buffer = cx.new(|cx| Buffer::local("", cx));
 1500        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1501        Self::new(
 1502            EditorMode::SingleLine { auto_width: false },
 1503            buffer,
 1504            None,
 1505            window,
 1506            cx,
 1507        )
 1508    }
 1509
 1510    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1511        let buffer = cx.new(|cx| Buffer::local("", cx));
 1512        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1513        Self::new(EditorMode::full(), buffer, None, window, cx)
 1514    }
 1515
 1516    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1517        let buffer = cx.new(|cx| Buffer::local("", cx));
 1518        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1519        Self::new(
 1520            EditorMode::SingleLine { auto_width: true },
 1521            buffer,
 1522            None,
 1523            window,
 1524            cx,
 1525        )
 1526    }
 1527
 1528    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1529        let buffer = cx.new(|cx| Buffer::local("", cx));
 1530        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1531        Self::new(
 1532            EditorMode::AutoHeight { max_lines },
 1533            buffer,
 1534            None,
 1535            window,
 1536            cx,
 1537        )
 1538    }
 1539
 1540    pub fn for_buffer(
 1541        buffer: Entity<Buffer>,
 1542        project: Option<Entity<Project>>,
 1543        window: &mut Window,
 1544        cx: &mut Context<Self>,
 1545    ) -> Self {
 1546        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1547        Self::new(EditorMode::full(), buffer, project, window, cx)
 1548    }
 1549
 1550    pub fn for_multibuffer(
 1551        buffer: Entity<MultiBuffer>,
 1552        project: Option<Entity<Project>>,
 1553        window: &mut Window,
 1554        cx: &mut Context<Self>,
 1555    ) -> Self {
 1556        Self::new(EditorMode::full(), buffer, project, window, cx)
 1557    }
 1558
 1559    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1560        let mut clone = Self::new(
 1561            self.mode.clone(),
 1562            self.buffer.clone(),
 1563            self.project.clone(),
 1564            window,
 1565            cx,
 1566        );
 1567        self.display_map.update(cx, |display_map, cx| {
 1568            let snapshot = display_map.snapshot(cx);
 1569            clone.display_map.update(cx, |display_map, cx| {
 1570                display_map.set_state(&snapshot, cx);
 1571            });
 1572        });
 1573        clone.folds_did_change(cx);
 1574        clone.selections.clone_state(&self.selections);
 1575        clone.scroll_manager.clone_state(&self.scroll_manager);
 1576        clone.searchable = self.searchable;
 1577        clone.read_only = self.read_only;
 1578        clone
 1579    }
 1580
 1581    pub fn new(
 1582        mode: EditorMode,
 1583        buffer: Entity<MultiBuffer>,
 1584        project: Option<Entity<Project>>,
 1585        window: &mut Window,
 1586        cx: &mut Context<Self>,
 1587    ) -> Self {
 1588        Editor::new_internal(mode, buffer, project, None, window, cx)
 1589    }
 1590
 1591    fn new_internal(
 1592        mode: EditorMode,
 1593        buffer: Entity<MultiBuffer>,
 1594        project: Option<Entity<Project>>,
 1595        display_map: Option<Entity<DisplayMap>>,
 1596        window: &mut Window,
 1597        cx: &mut Context<Self>,
 1598    ) -> Self {
 1599        debug_assert!(
 1600            display_map.is_none() || mode.is_minimap(),
 1601            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1602        );
 1603
 1604        let full_mode = mode.is_full();
 1605        let diagnostics_max_severity = if full_mode {
 1606            EditorSettings::get_global(cx)
 1607                .diagnostics_max_severity
 1608                .unwrap_or(DiagnosticSeverity::Hint)
 1609        } else {
 1610            DiagnosticSeverity::Off
 1611        };
 1612        let style = window.text_style();
 1613        let font_size = style.font_size.to_pixels(window.rem_size());
 1614        let editor = cx.entity().downgrade();
 1615        let fold_placeholder = FoldPlaceholder {
 1616            constrain_width: true,
 1617            render: Arc::new(move |fold_id, fold_range, cx| {
 1618                let editor = editor.clone();
 1619                div()
 1620                    .id(fold_id)
 1621                    .bg(cx.theme().colors().ghost_element_background)
 1622                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1623                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1624                    .rounded_xs()
 1625                    .size_full()
 1626                    .cursor_pointer()
 1627                    .child("")
 1628                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1629                    .on_click(move |_, _window, cx| {
 1630                        editor
 1631                            .update(cx, |editor, cx| {
 1632                                editor.unfold_ranges(
 1633                                    &[fold_range.start..fold_range.end],
 1634                                    true,
 1635                                    false,
 1636                                    cx,
 1637                                );
 1638                                cx.stop_propagation();
 1639                            })
 1640                            .ok();
 1641                    })
 1642                    .into_any()
 1643            }),
 1644            merge_adjacent: true,
 1645            ..FoldPlaceholder::default()
 1646        };
 1647        let display_map = display_map.unwrap_or_else(|| {
 1648            cx.new(|cx| {
 1649                DisplayMap::new(
 1650                    buffer.clone(),
 1651                    style.font(),
 1652                    font_size,
 1653                    None,
 1654                    FILE_HEADER_HEIGHT,
 1655                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1656                    fold_placeholder,
 1657                    diagnostics_max_severity,
 1658                    cx,
 1659                )
 1660            })
 1661        });
 1662
 1663        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1664
 1665        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1666
 1667        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1668            .then(|| language_settings::SoftWrap::None);
 1669
 1670        let mut project_subscriptions = Vec::new();
 1671        if mode.is_full() {
 1672            if let Some(project) = project.as_ref() {
 1673                project_subscriptions.push(cx.subscribe_in(
 1674                    project,
 1675                    window,
 1676                    |editor, _, event, window, cx| match event {
 1677                        project::Event::RefreshCodeLens => {
 1678                            // we always query lens with actions, without storing them, always refreshing them
 1679                        }
 1680                        project::Event::RefreshInlayHints => {
 1681                            editor
 1682                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1683                        }
 1684                        project::Event::LanguageServerAdded(..)
 1685                        | project::Event::LanguageServerRemoved(..) => {
 1686                            if editor.tasks_update_task.is_none() {
 1687                                editor.tasks_update_task =
 1688                                    Some(editor.refresh_runnables(window, cx));
 1689                            }
 1690                        }
 1691                        project::Event::SnippetEdit(id, snippet_edits) => {
 1692                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1693                                let focus_handle = editor.focus_handle(cx);
 1694                                if focus_handle.is_focused(window) {
 1695                                    let snapshot = buffer.read(cx).snapshot();
 1696                                    for (range, snippet) in snippet_edits {
 1697                                        let editor_range =
 1698                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1699                                        editor
 1700                                            .insert_snippet(
 1701                                                &[editor_range],
 1702                                                snippet.clone(),
 1703                                                window,
 1704                                                cx,
 1705                                            )
 1706                                            .ok();
 1707                                    }
 1708                                }
 1709                            }
 1710                        }
 1711                        _ => {}
 1712                    },
 1713                ));
 1714                if let Some(task_inventory) = project
 1715                    .read(cx)
 1716                    .task_store()
 1717                    .read(cx)
 1718                    .task_inventory()
 1719                    .cloned()
 1720                {
 1721                    project_subscriptions.push(cx.observe_in(
 1722                        &task_inventory,
 1723                        window,
 1724                        |editor, _, window, cx| {
 1725                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1726                        },
 1727                    ));
 1728                };
 1729
 1730                project_subscriptions.push(cx.subscribe_in(
 1731                    &project.read(cx).breakpoint_store(),
 1732                    window,
 1733                    |editor, _, event, window, cx| match event {
 1734                        BreakpointStoreEvent::ClearDebugLines => {
 1735                            editor.clear_row_highlights::<ActiveDebugLine>();
 1736                            editor.refresh_inline_values(cx);
 1737                        }
 1738                        BreakpointStoreEvent::SetDebugLine => {
 1739                            if editor.go_to_active_debug_line(window, cx) {
 1740                                cx.stop_propagation();
 1741                            }
 1742
 1743                            editor.refresh_inline_values(cx);
 1744                        }
 1745                        _ => {}
 1746                    },
 1747                ));
 1748            }
 1749        }
 1750
 1751        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1752
 1753        let inlay_hint_settings =
 1754            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1755        let focus_handle = cx.focus_handle();
 1756        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1757            .detach();
 1758        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1759            .detach();
 1760        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1761            .detach();
 1762        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1763            .detach();
 1764
 1765        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1766            Some(false)
 1767        } else {
 1768            None
 1769        };
 1770
 1771        let breakpoint_store = match (&mode, project.as_ref()) {
 1772            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1773            _ => None,
 1774        };
 1775
 1776        let mut code_action_providers = Vec::new();
 1777        let mut load_uncommitted_diff = None;
 1778        if let Some(project) = project.clone() {
 1779            load_uncommitted_diff = Some(
 1780                update_uncommitted_diff_for_buffer(
 1781                    cx.entity(),
 1782                    &project,
 1783                    buffer.read(cx).all_buffers(),
 1784                    buffer.clone(),
 1785                    cx,
 1786                )
 1787                .shared(),
 1788            );
 1789            code_action_providers.push(Rc::new(project) as Rc<_>);
 1790        }
 1791
 1792        let mut this = Self {
 1793            focus_handle,
 1794            show_cursor_when_unfocused: false,
 1795            last_focused_descendant: None,
 1796            buffer: buffer.clone(),
 1797            display_map: display_map.clone(),
 1798            selections,
 1799            scroll_manager: ScrollManager::new(cx),
 1800            columnar_selection_tail: None,
 1801            columnar_display_point: None,
 1802            add_selections_state: None,
 1803            select_next_state: None,
 1804            select_prev_state: None,
 1805            selection_history: SelectionHistory::default(),
 1806            defer_selection_effects: false,
 1807            deferred_selection_effects_state: None,
 1808            autoclose_regions: Vec::new(),
 1809            snippet_stack: InvalidationStack::default(),
 1810            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1811            ime_transaction: None,
 1812            active_diagnostics: ActiveDiagnostic::None,
 1813            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1814            inline_diagnostics_update: Task::ready(()),
 1815            inline_diagnostics: Vec::new(),
 1816            soft_wrap_mode_override,
 1817            diagnostics_max_severity,
 1818            hard_wrap: None,
 1819            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1820            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1821            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1822            project,
 1823            blink_manager: blink_manager.clone(),
 1824            show_local_selections: true,
 1825            show_scrollbars: ScrollbarAxes {
 1826                horizontal: full_mode,
 1827                vertical: full_mode,
 1828            },
 1829            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1830            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1831            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1832            show_gutter: mode.is_full(),
 1833            show_line_numbers: None,
 1834            use_relative_line_numbers: None,
 1835            disable_expand_excerpt_buttons: false,
 1836            show_git_diff_gutter: None,
 1837            show_code_actions: None,
 1838            show_runnables: None,
 1839            show_breakpoints: None,
 1840            show_wrap_guides: None,
 1841            show_indent_guides,
 1842            placeholder_text: None,
 1843            highlight_order: 0,
 1844            highlighted_rows: HashMap::default(),
 1845            background_highlights: TreeMap::default(),
 1846            gutter_highlights: TreeMap::default(),
 1847            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1848            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1849            nav_history: None,
 1850            context_menu: RefCell::new(None),
 1851            context_menu_options: None,
 1852            mouse_context_menu: None,
 1853            completion_tasks: Vec::new(),
 1854            inline_blame_popover: None,
 1855            signature_help_state: SignatureHelpState::default(),
 1856            auto_signature_help: None,
 1857            find_all_references_task_sources: Vec::new(),
 1858            next_completion_id: 0,
 1859            next_inlay_id: 0,
 1860            code_action_providers,
 1861            available_code_actions: None,
 1862            code_actions_task: None,
 1863            quick_selection_highlight_task: None,
 1864            debounced_selection_highlight_task: None,
 1865            document_highlights_task: None,
 1866            linked_editing_range_task: None,
 1867            pending_rename: None,
 1868            searchable: true,
 1869            cursor_shape: EditorSettings::get_global(cx)
 1870                .cursor_shape
 1871                .unwrap_or_default(),
 1872            current_line_highlight: None,
 1873            autoindent_mode: Some(AutoindentMode::EachLine),
 1874            collapse_matches: false,
 1875            workspace: None,
 1876            input_enabled: true,
 1877            use_modal_editing: mode.is_full(),
 1878            read_only: mode.is_minimap(),
 1879            use_autoclose: true,
 1880            use_auto_surround: true,
 1881            auto_replace_emoji_shortcode: false,
 1882            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1883            leader_id: None,
 1884            remote_id: None,
 1885            hover_state: HoverState::default(),
 1886            pending_mouse_down: None,
 1887            hovered_link_state: None,
 1888            edit_prediction_provider: None,
 1889            active_inline_completion: None,
 1890            stale_inline_completion_in_menu: None,
 1891            edit_prediction_preview: EditPredictionPreview::Inactive {
 1892                released_too_fast: false,
 1893            },
 1894            inline_diagnostics_enabled: mode.is_full(),
 1895            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1896            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1897
 1898            gutter_hovered: false,
 1899            pixel_position_of_newest_cursor: None,
 1900            last_bounds: None,
 1901            last_position_map: None,
 1902            expect_bounds_change: None,
 1903            gutter_dimensions: GutterDimensions::default(),
 1904            style: None,
 1905            show_cursor_names: false,
 1906            hovered_cursors: HashMap::default(),
 1907            next_editor_action_id: EditorActionId::default(),
 1908            editor_actions: Rc::default(),
 1909            inline_completions_hidden_for_vim_mode: false,
 1910            show_inline_completions_override: None,
 1911            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1912            edit_prediction_settings: EditPredictionSettings::Disabled,
 1913            edit_prediction_indent_conflict: false,
 1914            edit_prediction_requires_modifier_in_indent_conflict: true,
 1915            custom_context_menu: None,
 1916            show_git_blame_gutter: false,
 1917            show_git_blame_inline: false,
 1918            show_selection_menu: None,
 1919            show_git_blame_inline_delay_task: None,
 1920            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1921            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1922            serialize_dirty_buffers: !mode.is_minimap()
 1923                && ProjectSettings::get_global(cx)
 1924                    .session
 1925                    .restore_unsaved_buffers,
 1926            blame: None,
 1927            blame_subscription: None,
 1928            tasks: BTreeMap::default(),
 1929
 1930            breakpoint_store,
 1931            gutter_breakpoint_indicator: (None, None),
 1932            _subscriptions: vec![
 1933                cx.observe(&buffer, Self::on_buffer_changed),
 1934                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1935                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1936                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1937                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1938                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1939                cx.observe_window_activation(window, |editor, window, cx| {
 1940                    let active = window.is_window_active();
 1941                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1942                        if active {
 1943                            blink_manager.enable(cx);
 1944                        } else {
 1945                            blink_manager.disable(cx);
 1946                        }
 1947                    });
 1948                    if active {
 1949                        editor.show_mouse_cursor();
 1950                    }
 1951                }),
 1952            ],
 1953            tasks_update_task: None,
 1954            linked_edit_ranges: Default::default(),
 1955            in_project_search: false,
 1956            previous_search_ranges: None,
 1957            breadcrumb_header: None,
 1958            focused_block: None,
 1959            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1960            addons: HashMap::default(),
 1961            registered_buffers: HashMap::default(),
 1962            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1963            selection_mark_mode: false,
 1964            toggle_fold_multiple_buffers: Task::ready(()),
 1965            serialize_selections: Task::ready(()),
 1966            serialize_folds: Task::ready(()),
 1967            text_style_refinement: None,
 1968            load_diff_task: load_uncommitted_diff,
 1969            temporary_diff_override: false,
 1970            mouse_cursor_hidden: false,
 1971            minimap: None,
 1972            hide_mouse_mode: EditorSettings::get_global(cx)
 1973                .hide_mouse
 1974                .unwrap_or_default(),
 1975            change_list: ChangeList::new(),
 1976            mode,
 1977        };
 1978        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1979            this._subscriptions
 1980                .push(cx.observe(breakpoints, |_, _, cx| {
 1981                    cx.notify();
 1982                }));
 1983        }
 1984        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1985        this._subscriptions.extend(project_subscriptions);
 1986
 1987        this._subscriptions.push(cx.subscribe_in(
 1988            &cx.entity(),
 1989            window,
 1990            |editor, _, e: &EditorEvent, window, cx| match e {
 1991                EditorEvent::ScrollPositionChanged { local, .. } => {
 1992                    if *local {
 1993                        let new_anchor = editor.scroll_manager.anchor();
 1994                        let snapshot = editor.snapshot(window, cx);
 1995                        editor.update_restoration_data(cx, move |data| {
 1996                            data.scroll_position = (
 1997                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1998                                new_anchor.offset,
 1999                            );
 2000                        });
 2001                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2002                        editor.inline_blame_popover.take();
 2003                    }
 2004                }
 2005                EditorEvent::Edited { .. } => {
 2006                    if !vim_enabled(cx) {
 2007                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2008                        let pop_state = editor
 2009                            .change_list
 2010                            .last()
 2011                            .map(|previous| {
 2012                                previous.len() == selections.len()
 2013                                    && previous.iter().enumerate().all(|(ix, p)| {
 2014                                        p.to_display_point(&map).row()
 2015                                            == selections[ix].head().row()
 2016                                    })
 2017                            })
 2018                            .unwrap_or(false);
 2019                        let new_positions = selections
 2020                            .into_iter()
 2021                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2022                            .collect();
 2023                        editor
 2024                            .change_list
 2025                            .push_to_change_list(pop_state, new_positions);
 2026                    }
 2027                }
 2028                _ => (),
 2029            },
 2030        ));
 2031
 2032        if let Some(dap_store) = this
 2033            .project
 2034            .as_ref()
 2035            .map(|project| project.read(cx).dap_store())
 2036        {
 2037            let weak_editor = cx.weak_entity();
 2038
 2039            this._subscriptions
 2040                .push(
 2041                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2042                        let session_entity = cx.entity();
 2043                        weak_editor
 2044                            .update(cx, |editor, cx| {
 2045                                editor._subscriptions.push(
 2046                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2047                                );
 2048                            })
 2049                            .ok();
 2050                    }),
 2051                );
 2052
 2053            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2054                this._subscriptions
 2055                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2056            }
 2057        }
 2058
 2059        this.end_selection(window, cx);
 2060        this.scroll_manager.show_scrollbars(window, cx);
 2061        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 2062
 2063        if full_mode {
 2064            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2065            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2066
 2067            if this.git_blame_inline_enabled {
 2068                this.start_git_blame_inline(false, window, cx);
 2069            }
 2070
 2071            this.go_to_active_debug_line(window, cx);
 2072
 2073            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2074                if let Some(project) = this.project.as_ref() {
 2075                    let handle = project.update(cx, |project, cx| {
 2076                        project.register_buffer_with_language_servers(&buffer, cx)
 2077                    });
 2078                    this.registered_buffers
 2079                        .insert(buffer.read(cx).remote_id(), handle);
 2080                }
 2081            }
 2082
 2083            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2084        }
 2085
 2086        this.report_editor_event("Editor Opened", None, cx);
 2087        this
 2088    }
 2089
 2090    pub fn deploy_mouse_context_menu(
 2091        &mut self,
 2092        position: gpui::Point<Pixels>,
 2093        context_menu: Entity<ContextMenu>,
 2094        window: &mut Window,
 2095        cx: &mut Context<Self>,
 2096    ) {
 2097        self.mouse_context_menu = Some(MouseContextMenu::new(
 2098            self,
 2099            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2100            context_menu,
 2101            window,
 2102            cx,
 2103        ));
 2104    }
 2105
 2106    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2107        self.mouse_context_menu
 2108            .as_ref()
 2109            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2110    }
 2111
 2112    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2113        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2114    }
 2115
 2116    fn key_context_internal(
 2117        &self,
 2118        has_active_edit_prediction: bool,
 2119        window: &Window,
 2120        cx: &App,
 2121    ) -> KeyContext {
 2122        let mut key_context = KeyContext::new_with_defaults();
 2123        key_context.add("Editor");
 2124        let mode = match self.mode {
 2125            EditorMode::SingleLine { .. } => "single_line",
 2126            EditorMode::AutoHeight { .. } => "auto_height",
 2127            EditorMode::Minimap { .. } => "minimap",
 2128            EditorMode::Full { .. } => "full",
 2129        };
 2130
 2131        if EditorSettings::jupyter_enabled(cx) {
 2132            key_context.add("jupyter");
 2133        }
 2134
 2135        key_context.set("mode", mode);
 2136        if self.pending_rename.is_some() {
 2137            key_context.add("renaming");
 2138        }
 2139
 2140        match self.context_menu.borrow().as_ref() {
 2141            Some(CodeContextMenu::Completions(_)) => {
 2142                key_context.add("menu");
 2143                key_context.add("showing_completions");
 2144            }
 2145            Some(CodeContextMenu::CodeActions(_)) => {
 2146                key_context.add("menu");
 2147                key_context.add("showing_code_actions")
 2148            }
 2149            None => {}
 2150        }
 2151
 2152        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2153        if !self.focus_handle(cx).contains_focused(window, cx)
 2154            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2155        {
 2156            for addon in self.addons.values() {
 2157                addon.extend_key_context(&mut key_context, cx)
 2158            }
 2159        }
 2160
 2161        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2162            if let Some(extension) = singleton_buffer
 2163                .read(cx)
 2164                .file()
 2165                .and_then(|file| file.path().extension()?.to_str())
 2166            {
 2167                key_context.set("extension", extension.to_string());
 2168            }
 2169        } else {
 2170            key_context.add("multibuffer");
 2171        }
 2172
 2173        if has_active_edit_prediction {
 2174            if self.edit_prediction_in_conflict() {
 2175                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2176            } else {
 2177                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2178                key_context.add("copilot_suggestion");
 2179            }
 2180        }
 2181
 2182        if self.selection_mark_mode {
 2183            key_context.add("selection_mode");
 2184        }
 2185
 2186        key_context
 2187    }
 2188
 2189    fn show_mouse_cursor(&mut self) {
 2190        self.mouse_cursor_hidden = false;
 2191    }
 2192
 2193    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2194        self.mouse_cursor_hidden = match origin {
 2195            HideMouseCursorOrigin::TypingAction => {
 2196                matches!(
 2197                    self.hide_mouse_mode,
 2198                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2199                )
 2200            }
 2201            HideMouseCursorOrigin::MovementAction => {
 2202                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2203            }
 2204        };
 2205    }
 2206
 2207    pub fn edit_prediction_in_conflict(&self) -> bool {
 2208        if !self.show_edit_predictions_in_menu() {
 2209            return false;
 2210        }
 2211
 2212        let showing_completions = self
 2213            .context_menu
 2214            .borrow()
 2215            .as_ref()
 2216            .map_or(false, |context| {
 2217                matches!(context, CodeContextMenu::Completions(_))
 2218            });
 2219
 2220        showing_completions
 2221            || self.edit_prediction_requires_modifier()
 2222            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2223            // bindings to insert tab characters.
 2224            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2225    }
 2226
 2227    pub fn accept_edit_prediction_keybind(
 2228        &self,
 2229        window: &Window,
 2230        cx: &App,
 2231    ) -> AcceptEditPredictionBinding {
 2232        let key_context = self.key_context_internal(true, window, cx);
 2233        let in_conflict = self.edit_prediction_in_conflict();
 2234
 2235        AcceptEditPredictionBinding(
 2236            window
 2237                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2238                .into_iter()
 2239                .filter(|binding| {
 2240                    !in_conflict
 2241                        || binding
 2242                            .keystrokes()
 2243                            .first()
 2244                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2245                })
 2246                .rev()
 2247                .min_by_key(|binding| {
 2248                    binding
 2249                        .keystrokes()
 2250                        .first()
 2251                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2252                }),
 2253        )
 2254    }
 2255
 2256    pub fn new_file(
 2257        workspace: &mut Workspace,
 2258        _: &workspace::NewFile,
 2259        window: &mut Window,
 2260        cx: &mut Context<Workspace>,
 2261    ) {
 2262        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2263            "Failed to create buffer",
 2264            window,
 2265            cx,
 2266            |e, _, _| match e.error_code() {
 2267                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2268                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2269                e.error_tag("required").unwrap_or("the latest version")
 2270            )),
 2271                _ => None,
 2272            },
 2273        );
 2274    }
 2275
 2276    pub fn new_in_workspace(
 2277        workspace: &mut Workspace,
 2278        window: &mut Window,
 2279        cx: &mut Context<Workspace>,
 2280    ) -> Task<Result<Entity<Editor>>> {
 2281        let project = workspace.project().clone();
 2282        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2283
 2284        cx.spawn_in(window, async move |workspace, cx| {
 2285            let buffer = create.await?;
 2286            workspace.update_in(cx, |workspace, window, cx| {
 2287                let editor =
 2288                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2289                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2290                editor
 2291            })
 2292        })
 2293    }
 2294
 2295    fn new_file_vertical(
 2296        workspace: &mut Workspace,
 2297        _: &workspace::NewFileSplitVertical,
 2298        window: &mut Window,
 2299        cx: &mut Context<Workspace>,
 2300    ) {
 2301        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2302    }
 2303
 2304    fn new_file_horizontal(
 2305        workspace: &mut Workspace,
 2306        _: &workspace::NewFileSplitHorizontal,
 2307        window: &mut Window,
 2308        cx: &mut Context<Workspace>,
 2309    ) {
 2310        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2311    }
 2312
 2313    fn new_file_in_direction(
 2314        workspace: &mut Workspace,
 2315        direction: SplitDirection,
 2316        window: &mut Window,
 2317        cx: &mut Context<Workspace>,
 2318    ) {
 2319        let project = workspace.project().clone();
 2320        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2321
 2322        cx.spawn_in(window, async move |workspace, cx| {
 2323            let buffer = create.await?;
 2324            workspace.update_in(cx, move |workspace, window, cx| {
 2325                workspace.split_item(
 2326                    direction,
 2327                    Box::new(
 2328                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2329                    ),
 2330                    window,
 2331                    cx,
 2332                )
 2333            })?;
 2334            anyhow::Ok(())
 2335        })
 2336        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2337            match e.error_code() {
 2338                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2339                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2340                e.error_tag("required").unwrap_or("the latest version")
 2341            )),
 2342                _ => None,
 2343            }
 2344        });
 2345    }
 2346
 2347    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2348        self.leader_id
 2349    }
 2350
 2351    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2352        &self.buffer
 2353    }
 2354
 2355    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2356        self.workspace.as_ref()?.0.upgrade()
 2357    }
 2358
 2359    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2360        self.buffer().read(cx).title(cx)
 2361    }
 2362
 2363    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2364        let git_blame_gutter_max_author_length = self
 2365            .render_git_blame_gutter(cx)
 2366            .then(|| {
 2367                if let Some(blame) = self.blame.as_ref() {
 2368                    let max_author_length =
 2369                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2370                    Some(max_author_length)
 2371                } else {
 2372                    None
 2373                }
 2374            })
 2375            .flatten();
 2376
 2377        EditorSnapshot {
 2378            mode: self.mode.clone(),
 2379            show_gutter: self.show_gutter,
 2380            show_line_numbers: self.show_line_numbers,
 2381            show_git_diff_gutter: self.show_git_diff_gutter,
 2382            show_code_actions: self.show_code_actions,
 2383            show_runnables: self.show_runnables,
 2384            show_breakpoints: self.show_breakpoints,
 2385            git_blame_gutter_max_author_length,
 2386            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2387            scroll_anchor: self.scroll_manager.anchor(),
 2388            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2389            placeholder_text: self.placeholder_text.clone(),
 2390            is_focused: self.focus_handle.is_focused(window),
 2391            current_line_highlight: self
 2392                .current_line_highlight
 2393                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2394            gutter_hovered: self.gutter_hovered,
 2395        }
 2396    }
 2397
 2398    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2399        self.buffer.read(cx).language_at(point, cx)
 2400    }
 2401
 2402    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2403        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2404    }
 2405
 2406    pub fn active_excerpt(
 2407        &self,
 2408        cx: &App,
 2409    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2410        self.buffer
 2411            .read(cx)
 2412            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2413    }
 2414
 2415    pub fn mode(&self) -> &EditorMode {
 2416        &self.mode
 2417    }
 2418
 2419    pub fn set_mode(&mut self, mode: EditorMode) {
 2420        self.mode = mode;
 2421    }
 2422
 2423    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2424        self.collaboration_hub.as_deref()
 2425    }
 2426
 2427    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2428        self.collaboration_hub = Some(hub);
 2429    }
 2430
 2431    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2432        self.in_project_search = in_project_search;
 2433    }
 2434
 2435    pub fn set_custom_context_menu(
 2436        &mut self,
 2437        f: impl 'static
 2438        + Fn(
 2439            &mut Self,
 2440            DisplayPoint,
 2441            &mut Window,
 2442            &mut Context<Self>,
 2443        ) -> Option<Entity<ui::ContextMenu>>,
 2444    ) {
 2445        self.custom_context_menu = Some(Box::new(f))
 2446    }
 2447
 2448    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2449        self.completion_provider = provider;
 2450    }
 2451
 2452    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2453        self.semantics_provider.clone()
 2454    }
 2455
 2456    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2457        self.semantics_provider = provider;
 2458    }
 2459
 2460    pub fn set_edit_prediction_provider<T>(
 2461        &mut self,
 2462        provider: Option<Entity<T>>,
 2463        window: &mut Window,
 2464        cx: &mut Context<Self>,
 2465    ) where
 2466        T: EditPredictionProvider,
 2467    {
 2468        self.edit_prediction_provider =
 2469            provider.map(|provider| RegisteredInlineCompletionProvider {
 2470                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2471                    if this.focus_handle.is_focused(window) {
 2472                        this.update_visible_inline_completion(window, cx);
 2473                    }
 2474                }),
 2475                provider: Arc::new(provider),
 2476            });
 2477        self.update_edit_prediction_settings(cx);
 2478        self.refresh_inline_completion(false, false, window, cx);
 2479    }
 2480
 2481    pub fn placeholder_text(&self) -> Option<&str> {
 2482        self.placeholder_text.as_deref()
 2483    }
 2484
 2485    pub fn set_placeholder_text(
 2486        &mut self,
 2487        placeholder_text: impl Into<Arc<str>>,
 2488        cx: &mut Context<Self>,
 2489    ) {
 2490        let placeholder_text = Some(placeholder_text.into());
 2491        if self.placeholder_text != placeholder_text {
 2492            self.placeholder_text = placeholder_text;
 2493            cx.notify();
 2494        }
 2495    }
 2496
 2497    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2498        self.cursor_shape = cursor_shape;
 2499
 2500        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2501        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2502
 2503        cx.notify();
 2504    }
 2505
 2506    pub fn set_current_line_highlight(
 2507        &mut self,
 2508        current_line_highlight: Option<CurrentLineHighlight>,
 2509    ) {
 2510        self.current_line_highlight = current_line_highlight;
 2511    }
 2512
 2513    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2514        self.collapse_matches = collapse_matches;
 2515    }
 2516
 2517    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2518        let buffers = self.buffer.read(cx).all_buffers();
 2519        let Some(project) = self.project.as_ref() else {
 2520            return;
 2521        };
 2522        project.update(cx, |project, cx| {
 2523            for buffer in buffers {
 2524                self.registered_buffers
 2525                    .entry(buffer.read(cx).remote_id())
 2526                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2527            }
 2528        })
 2529    }
 2530
 2531    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2532        if self.collapse_matches {
 2533            return range.start..range.start;
 2534        }
 2535        range.clone()
 2536    }
 2537
 2538    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2539        if self.display_map.read(cx).clip_at_line_ends != clip {
 2540            self.display_map
 2541                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2542        }
 2543    }
 2544
 2545    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2546        self.input_enabled = input_enabled;
 2547    }
 2548
 2549    pub fn set_inline_completions_hidden_for_vim_mode(
 2550        &mut self,
 2551        hidden: bool,
 2552        window: &mut Window,
 2553        cx: &mut Context<Self>,
 2554    ) {
 2555        if hidden != self.inline_completions_hidden_for_vim_mode {
 2556            self.inline_completions_hidden_for_vim_mode = hidden;
 2557            if hidden {
 2558                self.update_visible_inline_completion(window, cx);
 2559            } else {
 2560                self.refresh_inline_completion(true, false, window, cx);
 2561            }
 2562        }
 2563    }
 2564
 2565    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2566        self.menu_inline_completions_policy = value;
 2567    }
 2568
 2569    pub fn set_autoindent(&mut self, autoindent: bool) {
 2570        if autoindent {
 2571            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2572        } else {
 2573            self.autoindent_mode = None;
 2574        }
 2575    }
 2576
 2577    pub fn read_only(&self, cx: &App) -> bool {
 2578        self.read_only || self.buffer.read(cx).read_only()
 2579    }
 2580
 2581    pub fn set_read_only(&mut self, read_only: bool) {
 2582        self.read_only = read_only;
 2583    }
 2584
 2585    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2586        self.use_autoclose = autoclose;
 2587    }
 2588
 2589    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2590        self.use_auto_surround = auto_surround;
 2591    }
 2592
 2593    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2594        self.auto_replace_emoji_shortcode = auto_replace;
 2595    }
 2596
 2597    pub fn toggle_edit_predictions(
 2598        &mut self,
 2599        _: &ToggleEditPrediction,
 2600        window: &mut Window,
 2601        cx: &mut Context<Self>,
 2602    ) {
 2603        if self.show_inline_completions_override.is_some() {
 2604            self.set_show_edit_predictions(None, window, cx);
 2605        } else {
 2606            let show_edit_predictions = !self.edit_predictions_enabled();
 2607            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2608        }
 2609    }
 2610
 2611    pub fn set_show_edit_predictions(
 2612        &mut self,
 2613        show_edit_predictions: Option<bool>,
 2614        window: &mut Window,
 2615        cx: &mut Context<Self>,
 2616    ) {
 2617        self.show_inline_completions_override = show_edit_predictions;
 2618        self.update_edit_prediction_settings(cx);
 2619
 2620        if let Some(false) = show_edit_predictions {
 2621            self.discard_inline_completion(false, cx);
 2622        } else {
 2623            self.refresh_inline_completion(false, true, window, cx);
 2624        }
 2625    }
 2626
 2627    fn inline_completions_disabled_in_scope(
 2628        &self,
 2629        buffer: &Entity<Buffer>,
 2630        buffer_position: language::Anchor,
 2631        cx: &App,
 2632    ) -> bool {
 2633        let snapshot = buffer.read(cx).snapshot();
 2634        let settings = snapshot.settings_at(buffer_position, cx);
 2635
 2636        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2637            return false;
 2638        };
 2639
 2640        scope.override_name().map_or(false, |scope_name| {
 2641            settings
 2642                .edit_predictions_disabled_in
 2643                .iter()
 2644                .any(|s| s == scope_name)
 2645        })
 2646    }
 2647
 2648    pub fn set_use_modal_editing(&mut self, to: bool) {
 2649        self.use_modal_editing = to;
 2650    }
 2651
 2652    pub fn use_modal_editing(&self) -> bool {
 2653        self.use_modal_editing
 2654    }
 2655
 2656    fn selections_did_change(
 2657        &mut self,
 2658        local: bool,
 2659        old_cursor_position: &Anchor,
 2660        should_update_completions: bool,
 2661        window: &mut Window,
 2662        cx: &mut Context<Self>,
 2663    ) {
 2664        window.invalidate_character_coordinates();
 2665
 2666        // Copy selections to primary selection buffer
 2667        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2668        if local {
 2669            let selections = self.selections.all::<usize>(cx);
 2670            let buffer_handle = self.buffer.read(cx).read(cx);
 2671
 2672            let mut text = String::new();
 2673            for (index, selection) in selections.iter().enumerate() {
 2674                let text_for_selection = buffer_handle
 2675                    .text_for_range(selection.start..selection.end)
 2676                    .collect::<String>();
 2677
 2678                text.push_str(&text_for_selection);
 2679                if index != selections.len() - 1 {
 2680                    text.push('\n');
 2681                }
 2682            }
 2683
 2684            if !text.is_empty() {
 2685                cx.write_to_primary(ClipboardItem::new_string(text));
 2686            }
 2687        }
 2688
 2689        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2690            self.buffer.update(cx, |buffer, cx| {
 2691                buffer.set_active_selections(
 2692                    &self.selections.disjoint_anchors(),
 2693                    self.selections.line_mode,
 2694                    self.cursor_shape,
 2695                    cx,
 2696                )
 2697            });
 2698        }
 2699        let display_map = self
 2700            .display_map
 2701            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2702        let buffer = &display_map.buffer_snapshot;
 2703        self.add_selections_state = None;
 2704        self.select_next_state = None;
 2705        self.select_prev_state = None;
 2706        self.select_syntax_node_history.try_clear();
 2707        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2708        self.snippet_stack
 2709            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2710        self.take_rename(false, window, cx);
 2711
 2712        let new_cursor_position = self.selections.newest_anchor().head();
 2713
 2714        self.push_to_nav_history(
 2715            *old_cursor_position,
 2716            Some(new_cursor_position.to_point(buffer)),
 2717            false,
 2718            cx,
 2719        );
 2720
 2721        if local {
 2722            let new_cursor_position = self.selections.newest_anchor().head();
 2723
 2724            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2725                if !self.registered_buffers.contains_key(&buffer_id) {
 2726                    if let Some(project) = self.project.as_ref() {
 2727                        project.update(cx, |project, cx| {
 2728                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2729                                return;
 2730                            };
 2731                            self.registered_buffers.insert(
 2732                                buffer_id,
 2733                                project.register_buffer_with_language_servers(&buffer, cx),
 2734                            );
 2735                        })
 2736                    }
 2737                }
 2738            }
 2739
 2740            let mut context_menu = self.context_menu.borrow_mut();
 2741            let completion_menu = match context_menu.as_ref() {
 2742                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2743                Some(CodeContextMenu::CodeActions(_)) => {
 2744                    *context_menu = None;
 2745                    None
 2746                }
 2747                None => None,
 2748            };
 2749            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2750            drop(context_menu);
 2751
 2752            if should_update_completions {
 2753                if let Some(completion_position) = completion_position {
 2754                    let new_cursor_offset = new_cursor_position.to_offset(buffer);
 2755                    let position_matches =
 2756                        new_cursor_offset == completion_position.to_offset(buffer);
 2757                    let continue_showing = if position_matches {
 2758                        let (word_range, kind) = buffer.surrounding_word(new_cursor_offset, true);
 2759                        if let Some(CharKind::Word) = kind {
 2760                            word_range.start < new_cursor_offset
 2761                        } else {
 2762                            false
 2763                        }
 2764                    } else {
 2765                        false
 2766                    };
 2767
 2768                    if continue_showing {
 2769                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2770                    } else {
 2771                        self.hide_context_menu(window, cx);
 2772                    }
 2773                }
 2774            }
 2775
 2776            hide_hover(self, cx);
 2777
 2778            if old_cursor_position.to_display_point(&display_map).row()
 2779                != new_cursor_position.to_display_point(&display_map).row()
 2780            {
 2781                self.available_code_actions.take();
 2782            }
 2783            self.refresh_code_actions(window, cx);
 2784            self.refresh_document_highlights(cx);
 2785            self.refresh_selected_text_highlights(false, window, cx);
 2786            refresh_matching_bracket_highlights(self, window, cx);
 2787            self.update_visible_inline_completion(window, cx);
 2788            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2789            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2790            self.inline_blame_popover.take();
 2791            if self.git_blame_inline_enabled {
 2792                self.start_inline_blame_timer(window, cx);
 2793            }
 2794        }
 2795
 2796        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2797        cx.emit(EditorEvent::SelectionsChanged { local });
 2798
 2799        let selections = &self.selections.disjoint;
 2800        if selections.len() == 1 {
 2801            cx.emit(SearchEvent::ActiveMatchChanged)
 2802        }
 2803        if local {
 2804            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2805                let inmemory_selections = selections
 2806                    .iter()
 2807                    .map(|s| {
 2808                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2809                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2810                    })
 2811                    .collect();
 2812                self.update_restoration_data(cx, |data| {
 2813                    data.selections = inmemory_selections;
 2814                });
 2815
 2816                if WorkspaceSettings::get(None, cx).restore_on_startup
 2817                    != RestoreOnStartupBehavior::None
 2818                {
 2819                    if let Some(workspace_id) =
 2820                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2821                    {
 2822                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2823                        let selections = selections.clone();
 2824                        let background_executor = cx.background_executor().clone();
 2825                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2826                        self.serialize_selections = cx.background_spawn(async move {
 2827                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2828                    let db_selections = selections
 2829                        .iter()
 2830                        .map(|selection| {
 2831                            (
 2832                                selection.start.to_offset(&snapshot),
 2833                                selection.end.to_offset(&snapshot),
 2834                            )
 2835                        })
 2836                        .collect();
 2837
 2838                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2839                        .await
 2840                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2841                        .log_err();
 2842                });
 2843                    }
 2844                }
 2845            }
 2846        }
 2847
 2848        cx.notify();
 2849    }
 2850
 2851    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2852        use text::ToOffset as _;
 2853        use text::ToPoint as _;
 2854
 2855        if self.mode.is_minimap()
 2856            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2857        {
 2858            return;
 2859        }
 2860
 2861        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2862            return;
 2863        };
 2864
 2865        let snapshot = singleton.read(cx).snapshot();
 2866        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2867            let display_snapshot = display_map.snapshot(cx);
 2868
 2869            display_snapshot
 2870                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2871                .map(|fold| {
 2872                    fold.range.start.text_anchor.to_point(&snapshot)
 2873                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2874                })
 2875                .collect()
 2876        });
 2877        self.update_restoration_data(cx, |data| {
 2878            data.folds = inmemory_folds;
 2879        });
 2880
 2881        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2882            return;
 2883        };
 2884        let background_executor = cx.background_executor().clone();
 2885        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2886        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2887            display_map
 2888                .snapshot(cx)
 2889                .folds_in_range(0..snapshot.len())
 2890                .map(|fold| {
 2891                    (
 2892                        fold.range.start.text_anchor.to_offset(&snapshot),
 2893                        fold.range.end.text_anchor.to_offset(&snapshot),
 2894                    )
 2895                })
 2896                .collect()
 2897        });
 2898        self.serialize_folds = cx.background_spawn(async move {
 2899            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2900            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2901                .await
 2902                .with_context(|| {
 2903                    format!(
 2904                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2905                    )
 2906                })
 2907                .log_err();
 2908        });
 2909    }
 2910
 2911    pub fn sync_selections(
 2912        &mut self,
 2913        other: Entity<Editor>,
 2914        cx: &mut Context<Self>,
 2915    ) -> gpui::Subscription {
 2916        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2917        self.selections.change_with(cx, |selections| {
 2918            selections.select_anchors(other_selections);
 2919        });
 2920
 2921        let other_subscription =
 2922            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2923                EditorEvent::SelectionsChanged { local: true } => {
 2924                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2925                    if other_selections.is_empty() {
 2926                        return;
 2927                    }
 2928                    this.selections.change_with(cx, |selections| {
 2929                        selections.select_anchors(other_selections);
 2930                    });
 2931                }
 2932                _ => {}
 2933            });
 2934
 2935        let this_subscription =
 2936            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2937                EditorEvent::SelectionsChanged { local: true } => {
 2938                    let these_selections = this.selections.disjoint.to_vec();
 2939                    if these_selections.is_empty() {
 2940                        return;
 2941                    }
 2942                    other.update(cx, |other_editor, cx| {
 2943                        other_editor.selections.change_with(cx, |selections| {
 2944                            selections.select_anchors(these_selections);
 2945                        })
 2946                    });
 2947                }
 2948                _ => {}
 2949            });
 2950
 2951        Subscription::join(other_subscription, this_subscription)
 2952    }
 2953
 2954    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 2955    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 2956    /// effects of selection change occur at the end of the transaction.
 2957    pub fn change_selections<R>(
 2958        &mut self,
 2959        autoscroll: Option<Autoscroll>,
 2960        window: &mut Window,
 2961        cx: &mut Context<Self>,
 2962        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2963    ) -> R {
 2964        self.change_selections_inner(true, autoscroll, window, cx, change)
 2965    }
 2966
 2967    pub(crate) fn change_selections_without_updating_completions<R>(
 2968        &mut self,
 2969        autoscroll: Option<Autoscroll>,
 2970        window: &mut Window,
 2971        cx: &mut Context<Self>,
 2972        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2973    ) -> R {
 2974        self.change_selections_inner(false, autoscroll, window, cx, change)
 2975    }
 2976
 2977    fn change_selections_inner<R>(
 2978        &mut self,
 2979        should_update_completions: bool,
 2980        autoscroll: Option<Autoscroll>,
 2981        window: &mut Window,
 2982        cx: &mut Context<Self>,
 2983        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2984    ) -> R {
 2985        if let Some(state) = &mut self.deferred_selection_effects_state {
 2986            state.autoscroll = autoscroll.or(state.autoscroll);
 2987            state.should_update_completions = should_update_completions;
 2988            let (changed, result) = self.selections.change_with(cx, change);
 2989            state.changed |= changed;
 2990            return result;
 2991        }
 2992        let mut state = DeferredSelectionEffectsState {
 2993            changed: false,
 2994            should_update_completions,
 2995            autoscroll,
 2996            old_cursor_position: self.selections.newest_anchor().head(),
 2997            history_entry: SelectionHistoryEntry {
 2998                selections: self.selections.disjoint_anchors(),
 2999                select_next_state: self.select_next_state.clone(),
 3000                select_prev_state: self.select_prev_state.clone(),
 3001                add_selections_state: self.add_selections_state.clone(),
 3002            },
 3003        };
 3004        let (changed, result) = self.selections.change_with(cx, change);
 3005        state.changed = state.changed || changed;
 3006        if self.defer_selection_effects {
 3007            self.deferred_selection_effects_state = Some(state);
 3008        } else {
 3009            self.apply_selection_effects(state, window, cx);
 3010        }
 3011        result
 3012    }
 3013
 3014    /// Defers the effects of selection change, so that the effects of multiple calls to
 3015    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3016    /// to selection history and the state of popovers based on selection position aren't
 3017    /// erroneously updated.
 3018    pub fn with_selection_effects_deferred<R>(
 3019        &mut self,
 3020        window: &mut Window,
 3021        cx: &mut Context<Self>,
 3022        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3023    ) -> R {
 3024        let already_deferred = self.defer_selection_effects;
 3025        self.defer_selection_effects = true;
 3026        let result = update(self, window, cx);
 3027        if !already_deferred {
 3028            self.defer_selection_effects = false;
 3029            if let Some(state) = self.deferred_selection_effects_state.take() {
 3030                self.apply_selection_effects(state, window, cx);
 3031            }
 3032        }
 3033        result
 3034    }
 3035
 3036    fn apply_selection_effects(
 3037        &mut self,
 3038        state: DeferredSelectionEffectsState,
 3039        window: &mut Window,
 3040        cx: &mut Context<Self>,
 3041    ) {
 3042        if state.changed {
 3043            self.selection_history.push(state.history_entry);
 3044
 3045            if let Some(autoscroll) = state.autoscroll {
 3046                self.request_autoscroll(autoscroll, cx);
 3047            }
 3048
 3049            let old_cursor_position = &state.old_cursor_position;
 3050
 3051            self.selections_did_change(
 3052                true,
 3053                &old_cursor_position,
 3054                state.should_update_completions,
 3055                window,
 3056                cx,
 3057            );
 3058
 3059            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3060                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3061            }
 3062        }
 3063    }
 3064
 3065    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3066    where
 3067        I: IntoIterator<Item = (Range<S>, T)>,
 3068        S: ToOffset,
 3069        T: Into<Arc<str>>,
 3070    {
 3071        if self.read_only(cx) {
 3072            return;
 3073        }
 3074
 3075        self.buffer
 3076            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3077    }
 3078
 3079    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3080    where
 3081        I: IntoIterator<Item = (Range<S>, T)>,
 3082        S: ToOffset,
 3083        T: Into<Arc<str>>,
 3084    {
 3085        if self.read_only(cx) {
 3086            return;
 3087        }
 3088
 3089        self.buffer.update(cx, |buffer, cx| {
 3090            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3091        });
 3092    }
 3093
 3094    pub fn edit_with_block_indent<I, S, T>(
 3095        &mut self,
 3096        edits: I,
 3097        original_indent_columns: Vec<Option<u32>>,
 3098        cx: &mut Context<Self>,
 3099    ) where
 3100        I: IntoIterator<Item = (Range<S>, T)>,
 3101        S: ToOffset,
 3102        T: Into<Arc<str>>,
 3103    {
 3104        if self.read_only(cx) {
 3105            return;
 3106        }
 3107
 3108        self.buffer.update(cx, |buffer, cx| {
 3109            buffer.edit(
 3110                edits,
 3111                Some(AutoindentMode::Block {
 3112                    original_indent_columns,
 3113                }),
 3114                cx,
 3115            )
 3116        });
 3117    }
 3118
 3119    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3120        self.hide_context_menu(window, cx);
 3121
 3122        match phase {
 3123            SelectPhase::Begin {
 3124                position,
 3125                add,
 3126                click_count,
 3127            } => self.begin_selection(position, add, click_count, window, cx),
 3128            SelectPhase::BeginColumnar {
 3129                position,
 3130                goal_column,
 3131                reset,
 3132            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3133            SelectPhase::Extend {
 3134                position,
 3135                click_count,
 3136            } => self.extend_selection(position, click_count, window, cx),
 3137            SelectPhase::Update {
 3138                position,
 3139                goal_column,
 3140                scroll_delta,
 3141            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3142            SelectPhase::End => self.end_selection(window, cx),
 3143        }
 3144    }
 3145
 3146    fn extend_selection(
 3147        &mut self,
 3148        position: DisplayPoint,
 3149        click_count: usize,
 3150        window: &mut Window,
 3151        cx: &mut Context<Self>,
 3152    ) {
 3153        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3154        let tail = self.selections.newest::<usize>(cx).tail();
 3155        self.begin_selection(position, false, click_count, window, cx);
 3156
 3157        let position = position.to_offset(&display_map, Bias::Left);
 3158        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3159
 3160        let mut pending_selection = self
 3161            .selections
 3162            .pending_anchor()
 3163            .expect("extend_selection not called with pending selection");
 3164        if position >= tail {
 3165            pending_selection.start = tail_anchor;
 3166        } else {
 3167            pending_selection.end = tail_anchor;
 3168            pending_selection.reversed = true;
 3169        }
 3170
 3171        let mut pending_mode = self.selections.pending_mode().unwrap();
 3172        match &mut pending_mode {
 3173            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3174            _ => {}
 3175        }
 3176
 3177        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3178
 3179        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3180            s.set_pending(pending_selection, pending_mode)
 3181        });
 3182    }
 3183
 3184    fn begin_selection(
 3185        &mut self,
 3186        position: DisplayPoint,
 3187        add: bool,
 3188        click_count: usize,
 3189        window: &mut Window,
 3190        cx: &mut Context<Self>,
 3191    ) {
 3192        if !self.focus_handle.is_focused(window) {
 3193            self.last_focused_descendant = None;
 3194            window.focus(&self.focus_handle);
 3195        }
 3196
 3197        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3198        let buffer = &display_map.buffer_snapshot;
 3199        let position = display_map.clip_point(position, Bias::Left);
 3200
 3201        let start;
 3202        let end;
 3203        let mode;
 3204        let mut auto_scroll;
 3205        match click_count {
 3206            1 => {
 3207                start = buffer.anchor_before(position.to_point(&display_map));
 3208                end = start;
 3209                mode = SelectMode::Character;
 3210                auto_scroll = true;
 3211            }
 3212            2 => {
 3213                let range = movement::surrounding_word(&display_map, position);
 3214                start = buffer.anchor_before(range.start.to_point(&display_map));
 3215                end = buffer.anchor_before(range.end.to_point(&display_map));
 3216                mode = SelectMode::Word(start..end);
 3217                auto_scroll = true;
 3218            }
 3219            3 => {
 3220                let position = display_map
 3221                    .clip_point(position, Bias::Left)
 3222                    .to_point(&display_map);
 3223                let line_start = display_map.prev_line_boundary(position).0;
 3224                let next_line_start = buffer.clip_point(
 3225                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3226                    Bias::Left,
 3227                );
 3228                start = buffer.anchor_before(line_start);
 3229                end = buffer.anchor_before(next_line_start);
 3230                mode = SelectMode::Line(start..end);
 3231                auto_scroll = true;
 3232            }
 3233            _ => {
 3234                start = buffer.anchor_before(0);
 3235                end = buffer.anchor_before(buffer.len());
 3236                mode = SelectMode::All;
 3237                auto_scroll = false;
 3238            }
 3239        }
 3240        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3241
 3242        let point_to_delete: Option<usize> = {
 3243            let selected_points: Vec<Selection<Point>> =
 3244                self.selections.disjoint_in_range(start..end, cx);
 3245
 3246            if !add || click_count > 1 {
 3247                None
 3248            } else if !selected_points.is_empty() {
 3249                Some(selected_points[0].id)
 3250            } else {
 3251                let clicked_point_already_selected =
 3252                    self.selections.disjoint.iter().find(|selection| {
 3253                        selection.start.to_point(buffer) == start.to_point(buffer)
 3254                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3255                    });
 3256
 3257                clicked_point_already_selected.map(|selection| selection.id)
 3258            }
 3259        };
 3260
 3261        let selections_count = self.selections.count();
 3262
 3263        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3264            if let Some(point_to_delete) = point_to_delete {
 3265                s.delete(point_to_delete);
 3266
 3267                if selections_count == 1 {
 3268                    s.set_pending_anchor_range(start..end, mode);
 3269                }
 3270            } else {
 3271                if !add {
 3272                    s.clear_disjoint();
 3273                }
 3274
 3275                s.set_pending_anchor_range(start..end, mode);
 3276            }
 3277        });
 3278    }
 3279
 3280    fn begin_columnar_selection(
 3281        &mut self,
 3282        position: DisplayPoint,
 3283        goal_column: u32,
 3284        reset: bool,
 3285        window: &mut Window,
 3286        cx: &mut Context<Self>,
 3287    ) {
 3288        if !self.focus_handle.is_focused(window) {
 3289            self.last_focused_descendant = None;
 3290            window.focus(&self.focus_handle);
 3291        }
 3292
 3293        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3294
 3295        if reset {
 3296            let pointer_position = display_map
 3297                .buffer_snapshot
 3298                .anchor_before(position.to_point(&display_map));
 3299
 3300            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3301                s.clear_disjoint();
 3302                s.set_pending_anchor_range(
 3303                    pointer_position..pointer_position,
 3304                    SelectMode::Character,
 3305                );
 3306            });
 3307            if position.column() != goal_column {
 3308                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3309            } else {
 3310                self.columnar_display_point = None;
 3311            }
 3312        }
 3313
 3314        let tail = self.selections.newest::<Point>(cx).tail();
 3315        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3316
 3317        if !reset {
 3318            self.columnar_display_point = None;
 3319            self.select_columns(
 3320                tail.to_display_point(&display_map),
 3321                position,
 3322                goal_column,
 3323                &display_map,
 3324                window,
 3325                cx,
 3326            );
 3327        }
 3328    }
 3329
 3330    fn update_selection(
 3331        &mut self,
 3332        position: DisplayPoint,
 3333        goal_column: u32,
 3334        scroll_delta: gpui::Point<f32>,
 3335        window: &mut Window,
 3336        cx: &mut Context<Self>,
 3337    ) {
 3338        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3339
 3340        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3341            let tail = self
 3342                .columnar_display_point
 3343                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3344            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3345        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3346            let buffer = self.buffer.read(cx).snapshot(cx);
 3347            let head;
 3348            let tail;
 3349            let mode = self.selections.pending_mode().unwrap();
 3350            match &mode {
 3351                SelectMode::Character => {
 3352                    head = position.to_point(&display_map);
 3353                    tail = pending.tail().to_point(&buffer);
 3354                }
 3355                SelectMode::Word(original_range) => {
 3356                    let original_display_range = original_range.start.to_display_point(&display_map)
 3357                        ..original_range.end.to_display_point(&display_map);
 3358                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3359                        ..original_display_range.end.to_point(&display_map);
 3360                    if movement::is_inside_word(&display_map, position)
 3361                        || original_display_range.contains(&position)
 3362                    {
 3363                        let word_range = movement::surrounding_word(&display_map, position);
 3364                        if word_range.start < original_display_range.start {
 3365                            head = word_range.start.to_point(&display_map);
 3366                        } else {
 3367                            head = word_range.end.to_point(&display_map);
 3368                        }
 3369                    } else {
 3370                        head = position.to_point(&display_map);
 3371                    }
 3372
 3373                    if head <= original_buffer_range.start {
 3374                        tail = original_buffer_range.end;
 3375                    } else {
 3376                        tail = original_buffer_range.start;
 3377                    }
 3378                }
 3379                SelectMode::Line(original_range) => {
 3380                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3381
 3382                    let position = display_map
 3383                        .clip_point(position, Bias::Left)
 3384                        .to_point(&display_map);
 3385                    let line_start = display_map.prev_line_boundary(position).0;
 3386                    let next_line_start = buffer.clip_point(
 3387                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3388                        Bias::Left,
 3389                    );
 3390
 3391                    if line_start < original_range.start {
 3392                        head = line_start
 3393                    } else {
 3394                        head = next_line_start
 3395                    }
 3396
 3397                    if head <= original_range.start {
 3398                        tail = original_range.end;
 3399                    } else {
 3400                        tail = original_range.start;
 3401                    }
 3402                }
 3403                SelectMode::All => {
 3404                    return;
 3405                }
 3406            };
 3407
 3408            if head < tail {
 3409                pending.start = buffer.anchor_before(head);
 3410                pending.end = buffer.anchor_before(tail);
 3411                pending.reversed = true;
 3412            } else {
 3413                pending.start = buffer.anchor_before(tail);
 3414                pending.end = buffer.anchor_before(head);
 3415                pending.reversed = false;
 3416            }
 3417
 3418            self.change_selections(None, window, cx, |s| {
 3419                s.set_pending(pending, mode);
 3420            });
 3421        } else {
 3422            log::error!("update_selection dispatched with no pending selection");
 3423            return;
 3424        }
 3425
 3426        self.apply_scroll_delta(scroll_delta, window, cx);
 3427        cx.notify();
 3428    }
 3429
 3430    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3431        self.columnar_selection_tail.take();
 3432        if self.selections.pending_anchor().is_some() {
 3433            let selections = self.selections.all::<usize>(cx);
 3434            self.change_selections(None, window, cx, |s| {
 3435                s.select(selections);
 3436                s.clear_pending();
 3437            });
 3438        }
 3439    }
 3440
 3441    fn select_columns(
 3442        &mut self,
 3443        tail: DisplayPoint,
 3444        head: DisplayPoint,
 3445        goal_column: u32,
 3446        display_map: &DisplaySnapshot,
 3447        window: &mut Window,
 3448        cx: &mut Context<Self>,
 3449    ) {
 3450        let start_row = cmp::min(tail.row(), head.row());
 3451        let end_row = cmp::max(tail.row(), head.row());
 3452        let start_column = cmp::min(tail.column(), goal_column);
 3453        let end_column = cmp::max(tail.column(), goal_column);
 3454        let reversed = start_column < tail.column();
 3455
 3456        let selection_ranges = (start_row.0..=end_row.0)
 3457            .map(DisplayRow)
 3458            .filter_map(|row| {
 3459                if !display_map.is_block_line(row) {
 3460                    let start = display_map
 3461                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3462                        .to_point(display_map);
 3463                    let end = display_map
 3464                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3465                        .to_point(display_map);
 3466                    if reversed {
 3467                        Some(end..start)
 3468                    } else {
 3469                        Some(start..end)
 3470                    }
 3471                } else {
 3472                    None
 3473                }
 3474            })
 3475            .collect::<Vec<_>>();
 3476
 3477        let mut non_empty_ranges = selection_ranges
 3478            .iter()
 3479            .filter(|selection_range| selection_range.start != selection_range.end)
 3480            .peekable();
 3481
 3482        let ranges = if non_empty_ranges.peek().is_some() {
 3483            non_empty_ranges.cloned().collect()
 3484        } else {
 3485            selection_ranges
 3486        };
 3487
 3488        self.change_selections(None, window, cx, |s| {
 3489            s.select_ranges(ranges);
 3490        });
 3491        cx.notify();
 3492    }
 3493
 3494    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3495        self.selections
 3496            .all_adjusted(cx)
 3497            .iter()
 3498            .any(|selection| !selection.is_empty())
 3499    }
 3500
 3501    pub fn has_pending_nonempty_selection(&self) -> bool {
 3502        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3503            Some(Selection { start, end, .. }) => start != end,
 3504            None => false,
 3505        };
 3506
 3507        pending_nonempty_selection
 3508            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3509    }
 3510
 3511    pub fn has_pending_selection(&self) -> bool {
 3512        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3513    }
 3514
 3515    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3516        self.selection_mark_mode = false;
 3517
 3518        if self.clear_expanded_diff_hunks(cx) {
 3519            cx.notify();
 3520            return;
 3521        }
 3522        if self.dismiss_menus_and_popups(true, window, cx) {
 3523            return;
 3524        }
 3525
 3526        if self.mode.is_full()
 3527            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3528        {
 3529            return;
 3530        }
 3531
 3532        cx.propagate();
 3533    }
 3534
 3535    pub fn dismiss_menus_and_popups(
 3536        &mut self,
 3537        is_user_requested: bool,
 3538        window: &mut Window,
 3539        cx: &mut Context<Self>,
 3540    ) -> bool {
 3541        if self.take_rename(false, window, cx).is_some() {
 3542            return true;
 3543        }
 3544
 3545        if hide_hover(self, cx) {
 3546            return true;
 3547        }
 3548
 3549        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3550            return true;
 3551        }
 3552
 3553        if self.hide_context_menu(window, cx).is_some() {
 3554            return true;
 3555        }
 3556
 3557        if self.mouse_context_menu.take().is_some() {
 3558            return true;
 3559        }
 3560
 3561        if is_user_requested && self.discard_inline_completion(true, cx) {
 3562            return true;
 3563        }
 3564
 3565        if self.snippet_stack.pop().is_some() {
 3566            return true;
 3567        }
 3568
 3569        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3570            self.dismiss_diagnostics(cx);
 3571            return true;
 3572        }
 3573
 3574        false
 3575    }
 3576
 3577    fn linked_editing_ranges_for(
 3578        &self,
 3579        selection: Range<text::Anchor>,
 3580        cx: &App,
 3581    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3582        if self.linked_edit_ranges.is_empty() {
 3583            return None;
 3584        }
 3585        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3586            selection.end.buffer_id.and_then(|end_buffer_id| {
 3587                if selection.start.buffer_id != Some(end_buffer_id) {
 3588                    return None;
 3589                }
 3590                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3591                let snapshot = buffer.read(cx).snapshot();
 3592                self.linked_edit_ranges
 3593                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3594                    .map(|ranges| (ranges, snapshot, buffer))
 3595            })?;
 3596        use text::ToOffset as TO;
 3597        // find offset from the start of current range to current cursor position
 3598        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3599
 3600        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3601        let start_difference = start_offset - start_byte_offset;
 3602        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3603        let end_difference = end_offset - start_byte_offset;
 3604        // Current range has associated linked ranges.
 3605        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3606        for range in linked_ranges.iter() {
 3607            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3608            let end_offset = start_offset + end_difference;
 3609            let start_offset = start_offset + start_difference;
 3610            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3611                continue;
 3612            }
 3613            if self.selections.disjoint_anchor_ranges().any(|s| {
 3614                if s.start.buffer_id != selection.start.buffer_id
 3615                    || s.end.buffer_id != selection.end.buffer_id
 3616                {
 3617                    return false;
 3618                }
 3619                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3620                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3621            }) {
 3622                continue;
 3623            }
 3624            let start = buffer_snapshot.anchor_after(start_offset);
 3625            let end = buffer_snapshot.anchor_after(end_offset);
 3626            linked_edits
 3627                .entry(buffer.clone())
 3628                .or_default()
 3629                .push(start..end);
 3630        }
 3631        Some(linked_edits)
 3632    }
 3633
 3634    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3635        let text: Arc<str> = text.into();
 3636
 3637        if self.read_only(cx) {
 3638            return;
 3639        }
 3640
 3641        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3642
 3643        let selections = self.selections.all_adjusted(cx);
 3644        let mut bracket_inserted = false;
 3645        let mut edits = Vec::new();
 3646        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3647        let mut new_selections = Vec::with_capacity(selections.len());
 3648        let mut new_autoclose_regions = Vec::new();
 3649        let snapshot = self.buffer.read(cx).read(cx);
 3650        let mut clear_linked_edit_ranges = false;
 3651
 3652        for (selection, autoclose_region) in
 3653            self.selections_with_autoclose_regions(selections, &snapshot)
 3654        {
 3655            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3656                // Determine if the inserted text matches the opening or closing
 3657                // bracket of any of this language's bracket pairs.
 3658                let mut bracket_pair = None;
 3659                let mut is_bracket_pair_start = false;
 3660                let mut is_bracket_pair_end = false;
 3661                if !text.is_empty() {
 3662                    let mut bracket_pair_matching_end = None;
 3663                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3664                    //  and they are removing the character that triggered IME popup.
 3665                    for (pair, enabled) in scope.brackets() {
 3666                        if !pair.close && !pair.surround {
 3667                            continue;
 3668                        }
 3669
 3670                        if enabled && pair.start.ends_with(text.as_ref()) {
 3671                            let prefix_len = pair.start.len() - text.len();
 3672                            let preceding_text_matches_prefix = prefix_len == 0
 3673                                || (selection.start.column >= (prefix_len as u32)
 3674                                    && snapshot.contains_str_at(
 3675                                        Point::new(
 3676                                            selection.start.row,
 3677                                            selection.start.column - (prefix_len as u32),
 3678                                        ),
 3679                                        &pair.start[..prefix_len],
 3680                                    ));
 3681                            if preceding_text_matches_prefix {
 3682                                bracket_pair = Some(pair.clone());
 3683                                is_bracket_pair_start = true;
 3684                                break;
 3685                            }
 3686                        }
 3687                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3688                        {
 3689                            // take first bracket pair matching end, but don't break in case a later bracket
 3690                            // pair matches start
 3691                            bracket_pair_matching_end = Some(pair.clone());
 3692                        }
 3693                    }
 3694                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3695                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3696                        is_bracket_pair_end = true;
 3697                    }
 3698                }
 3699
 3700                if let Some(bracket_pair) = bracket_pair {
 3701                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3702                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3703                    let auto_surround =
 3704                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3705                    if selection.is_empty() {
 3706                        if is_bracket_pair_start {
 3707                            // If the inserted text is a suffix of an opening bracket and the
 3708                            // selection is preceded by the rest of the opening bracket, then
 3709                            // insert the closing bracket.
 3710                            let following_text_allows_autoclose = snapshot
 3711                                .chars_at(selection.start)
 3712                                .next()
 3713                                .map_or(true, |c| scope.should_autoclose_before(c));
 3714
 3715                            let preceding_text_allows_autoclose = selection.start.column == 0
 3716                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3717                                    true,
 3718                                    |c| {
 3719                                        bracket_pair.start != bracket_pair.end
 3720                                            || !snapshot
 3721                                                .char_classifier_at(selection.start)
 3722                                                .is_word(c)
 3723                                    },
 3724                                );
 3725
 3726                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3727                                && bracket_pair.start.len() == 1
 3728                            {
 3729                                let target = bracket_pair.start.chars().next().unwrap();
 3730                                let current_line_count = snapshot
 3731                                    .reversed_chars_at(selection.start)
 3732                                    .take_while(|&c| c != '\n')
 3733                                    .filter(|&c| c == target)
 3734                                    .count();
 3735                                current_line_count % 2 == 1
 3736                            } else {
 3737                                false
 3738                            };
 3739
 3740                            if autoclose
 3741                                && bracket_pair.close
 3742                                && following_text_allows_autoclose
 3743                                && preceding_text_allows_autoclose
 3744                                && !is_closing_quote
 3745                            {
 3746                                let anchor = snapshot.anchor_before(selection.end);
 3747                                new_selections.push((selection.map(|_| anchor), text.len()));
 3748                                new_autoclose_regions.push((
 3749                                    anchor,
 3750                                    text.len(),
 3751                                    selection.id,
 3752                                    bracket_pair.clone(),
 3753                                ));
 3754                                edits.push((
 3755                                    selection.range(),
 3756                                    format!("{}{}", text, bracket_pair.end).into(),
 3757                                ));
 3758                                bracket_inserted = true;
 3759                                continue;
 3760                            }
 3761                        }
 3762
 3763                        if let Some(region) = autoclose_region {
 3764                            // If the selection is followed by an auto-inserted closing bracket,
 3765                            // then don't insert that closing bracket again; just move the selection
 3766                            // past the closing bracket.
 3767                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3768                                && text.as_ref() == region.pair.end.as_str();
 3769                            if should_skip {
 3770                                let anchor = snapshot.anchor_after(selection.end);
 3771                                new_selections
 3772                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3773                                continue;
 3774                            }
 3775                        }
 3776
 3777                        let always_treat_brackets_as_autoclosed = snapshot
 3778                            .language_settings_at(selection.start, cx)
 3779                            .always_treat_brackets_as_autoclosed;
 3780                        if always_treat_brackets_as_autoclosed
 3781                            && is_bracket_pair_end
 3782                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3783                        {
 3784                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3785                            // and the inserted text is a closing bracket and the selection is followed
 3786                            // by the closing bracket then move the selection past the closing bracket.
 3787                            let anchor = snapshot.anchor_after(selection.end);
 3788                            new_selections.push((selection.map(|_| anchor), text.len()));
 3789                            continue;
 3790                        }
 3791                    }
 3792                    // If an opening bracket is 1 character long and is typed while
 3793                    // text is selected, then surround that text with the bracket pair.
 3794                    else if auto_surround
 3795                        && bracket_pair.surround
 3796                        && is_bracket_pair_start
 3797                        && bracket_pair.start.chars().count() == 1
 3798                    {
 3799                        edits.push((selection.start..selection.start, text.clone()));
 3800                        edits.push((
 3801                            selection.end..selection.end,
 3802                            bracket_pair.end.as_str().into(),
 3803                        ));
 3804                        bracket_inserted = true;
 3805                        new_selections.push((
 3806                            Selection {
 3807                                id: selection.id,
 3808                                start: snapshot.anchor_after(selection.start),
 3809                                end: snapshot.anchor_before(selection.end),
 3810                                reversed: selection.reversed,
 3811                                goal: selection.goal,
 3812                            },
 3813                            0,
 3814                        ));
 3815                        continue;
 3816                    }
 3817                }
 3818            }
 3819
 3820            if self.auto_replace_emoji_shortcode
 3821                && selection.is_empty()
 3822                && text.as_ref().ends_with(':')
 3823            {
 3824                if let Some(possible_emoji_short_code) =
 3825                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3826                {
 3827                    if !possible_emoji_short_code.is_empty() {
 3828                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3829                            let emoji_shortcode_start = Point::new(
 3830                                selection.start.row,
 3831                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3832                            );
 3833
 3834                            // Remove shortcode from buffer
 3835                            edits.push((
 3836                                emoji_shortcode_start..selection.start,
 3837                                "".to_string().into(),
 3838                            ));
 3839                            new_selections.push((
 3840                                Selection {
 3841                                    id: selection.id,
 3842                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3843                                    end: snapshot.anchor_before(selection.start),
 3844                                    reversed: selection.reversed,
 3845                                    goal: selection.goal,
 3846                                },
 3847                                0,
 3848                            ));
 3849
 3850                            // Insert emoji
 3851                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3852                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3853                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3854
 3855                            continue;
 3856                        }
 3857                    }
 3858                }
 3859            }
 3860
 3861            // If not handling any auto-close operation, then just replace the selected
 3862            // text with the given input and move the selection to the end of the
 3863            // newly inserted text.
 3864            let anchor = snapshot.anchor_after(selection.end);
 3865            if !self.linked_edit_ranges.is_empty() {
 3866                let start_anchor = snapshot.anchor_before(selection.start);
 3867
 3868                let is_word_char = text.chars().next().map_or(true, |char| {
 3869                    let classifier = snapshot
 3870                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3871                        .ignore_punctuation(true);
 3872                    classifier.is_word(char)
 3873                });
 3874
 3875                if is_word_char {
 3876                    if let Some(ranges) = self
 3877                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3878                    {
 3879                        for (buffer, edits) in ranges {
 3880                            linked_edits
 3881                                .entry(buffer.clone())
 3882                                .or_default()
 3883                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3884                        }
 3885                    }
 3886                } else {
 3887                    clear_linked_edit_ranges = true;
 3888                }
 3889            }
 3890
 3891            new_selections.push((selection.map(|_| anchor), 0));
 3892            edits.push((selection.start..selection.end, text.clone()));
 3893        }
 3894
 3895        drop(snapshot);
 3896
 3897        self.transact(window, cx, |this, window, cx| {
 3898            if clear_linked_edit_ranges {
 3899                this.linked_edit_ranges.clear();
 3900            }
 3901            let initial_buffer_versions =
 3902                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3903
 3904            this.buffer.update(cx, |buffer, cx| {
 3905                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3906            });
 3907            for (buffer, edits) in linked_edits {
 3908                buffer.update(cx, |buffer, cx| {
 3909                    let snapshot = buffer.snapshot();
 3910                    let edits = edits
 3911                        .into_iter()
 3912                        .map(|(range, text)| {
 3913                            use text::ToPoint as TP;
 3914                            let end_point = TP::to_point(&range.end, &snapshot);
 3915                            let start_point = TP::to_point(&range.start, &snapshot);
 3916                            (start_point..end_point, text)
 3917                        })
 3918                        .sorted_by_key(|(range, _)| range.start);
 3919                    buffer.edit(edits, None, cx);
 3920                })
 3921            }
 3922            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3923            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3924            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3925            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3926                .zip(new_selection_deltas)
 3927                .map(|(selection, delta)| Selection {
 3928                    id: selection.id,
 3929                    start: selection.start + delta,
 3930                    end: selection.end + delta,
 3931                    reversed: selection.reversed,
 3932                    goal: SelectionGoal::None,
 3933                })
 3934                .collect::<Vec<_>>();
 3935
 3936            let mut i = 0;
 3937            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3938                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3939                let start = map.buffer_snapshot.anchor_before(position);
 3940                let end = map.buffer_snapshot.anchor_after(position);
 3941                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3942                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3943                        Ordering::Less => i += 1,
 3944                        Ordering::Greater => break,
 3945                        Ordering::Equal => {
 3946                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3947                                Ordering::Less => i += 1,
 3948                                Ordering::Equal => break,
 3949                                Ordering::Greater => break,
 3950                            }
 3951                        }
 3952                    }
 3953                }
 3954                this.autoclose_regions.insert(
 3955                    i,
 3956                    AutocloseRegion {
 3957                        selection_id,
 3958                        range: start..end,
 3959                        pair,
 3960                    },
 3961                );
 3962            }
 3963
 3964            let had_active_inline_completion = this.has_active_inline_completion();
 3965            this.change_selections_without_updating_completions(
 3966                Some(Autoscroll::fit()),
 3967                window,
 3968                cx,
 3969                |s| s.select(new_selections),
 3970            );
 3971
 3972            if !bracket_inserted {
 3973                if let Some(on_type_format_task) =
 3974                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3975                {
 3976                    on_type_format_task.detach_and_log_err(cx);
 3977                }
 3978            }
 3979
 3980            let editor_settings = EditorSettings::get_global(cx);
 3981            if bracket_inserted
 3982                && (editor_settings.auto_signature_help
 3983                    || editor_settings.show_signature_help_after_edits)
 3984            {
 3985                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3986            }
 3987
 3988            let trigger_in_words =
 3989                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3990            if this.hard_wrap.is_some() {
 3991                let latest: Range<Point> = this.selections.newest(cx).range();
 3992                if latest.is_empty()
 3993                    && this
 3994                        .buffer()
 3995                        .read(cx)
 3996                        .snapshot(cx)
 3997                        .line_len(MultiBufferRow(latest.start.row))
 3998                        == latest.start.column
 3999                {
 4000                    this.rewrap_impl(
 4001                        RewrapOptions {
 4002                            override_language_settings: true,
 4003                            preserve_existing_whitespace: true,
 4004                        },
 4005                        cx,
 4006                    )
 4007                }
 4008            }
 4009            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4010            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4011            this.refresh_inline_completion(true, false, window, cx);
 4012            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4013        });
 4014    }
 4015
 4016    fn find_possible_emoji_shortcode_at_position(
 4017        snapshot: &MultiBufferSnapshot,
 4018        position: Point,
 4019    ) -> Option<String> {
 4020        let mut chars = Vec::new();
 4021        let mut found_colon = false;
 4022        for char in snapshot.reversed_chars_at(position).take(100) {
 4023            // Found a possible emoji shortcode in the middle of the buffer
 4024            if found_colon {
 4025                if char.is_whitespace() {
 4026                    chars.reverse();
 4027                    return Some(chars.iter().collect());
 4028                }
 4029                // If the previous character is not a whitespace, we are in the middle of a word
 4030                // and we only want to complete the shortcode if the word is made up of other emojis
 4031                let mut containing_word = String::new();
 4032                for ch in snapshot
 4033                    .reversed_chars_at(position)
 4034                    .skip(chars.len() + 1)
 4035                    .take(100)
 4036                {
 4037                    if ch.is_whitespace() {
 4038                        break;
 4039                    }
 4040                    containing_word.push(ch);
 4041                }
 4042                let containing_word = containing_word.chars().rev().collect::<String>();
 4043                if util::word_consists_of_emojis(containing_word.as_str()) {
 4044                    chars.reverse();
 4045                    return Some(chars.iter().collect());
 4046                }
 4047            }
 4048
 4049            if char.is_whitespace() || !char.is_ascii() {
 4050                return None;
 4051            }
 4052            if char == ':' {
 4053                found_colon = true;
 4054            } else {
 4055                chars.push(char);
 4056            }
 4057        }
 4058        // Found a possible emoji shortcode at the beginning of the buffer
 4059        chars.reverse();
 4060        Some(chars.iter().collect())
 4061    }
 4062
 4063    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4064        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4065        self.transact(window, cx, |this, window, cx| {
 4066            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4067                let selections = this.selections.all::<usize>(cx);
 4068                let multi_buffer = this.buffer.read(cx);
 4069                let buffer = multi_buffer.snapshot(cx);
 4070                selections
 4071                    .iter()
 4072                    .map(|selection| {
 4073                        let start_point = selection.start.to_point(&buffer);
 4074                        let mut existing_indent =
 4075                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4076                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4077                        let start = selection.start;
 4078                        let end = selection.end;
 4079                        let selection_is_empty = start == end;
 4080                        let language_scope = buffer.language_scope_at(start);
 4081                        let (
 4082                            comment_delimiter,
 4083                            doc_delimiter,
 4084                            insert_extra_newline,
 4085                            indent_on_newline,
 4086                            indent_on_extra_newline,
 4087                        ) = if let Some(language) = &language_scope {
 4088                            let mut insert_extra_newline =
 4089                                insert_extra_newline_brackets(&buffer, start..end, language)
 4090                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4091
 4092                            // Comment extension on newline is allowed only for cursor selections
 4093                            let comment_delimiter = maybe!({
 4094                                if !selection_is_empty {
 4095                                    return None;
 4096                                }
 4097
 4098                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4099                                    return None;
 4100                                }
 4101
 4102                                let delimiters = language.line_comment_prefixes();
 4103                                let max_len_of_delimiter =
 4104                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4105                                let (snapshot, range) =
 4106                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4107
 4108                                let num_of_whitespaces = snapshot
 4109                                    .chars_for_range(range.clone())
 4110                                    .take_while(|c| c.is_whitespace())
 4111                                    .count();
 4112                                let comment_candidate = snapshot
 4113                                    .chars_for_range(range)
 4114                                    .skip(num_of_whitespaces)
 4115                                    .take(max_len_of_delimiter)
 4116                                    .collect::<String>();
 4117                                let (delimiter, trimmed_len) = delimiters
 4118                                    .iter()
 4119                                    .filter_map(|delimiter| {
 4120                                        let prefix = delimiter.trim_end();
 4121                                        if comment_candidate.starts_with(prefix) {
 4122                                            Some((delimiter, prefix.len()))
 4123                                        } else {
 4124                                            None
 4125                                        }
 4126                                    })
 4127                                    .max_by_key(|(_, len)| *len)?;
 4128
 4129                                let cursor_is_placed_after_comment_marker =
 4130                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4131                                if cursor_is_placed_after_comment_marker {
 4132                                    Some(delimiter.clone())
 4133                                } else {
 4134                                    None
 4135                                }
 4136                            });
 4137
 4138                            let mut indent_on_newline = IndentSize::spaces(0);
 4139                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4140
 4141                            let doc_delimiter = maybe!({
 4142                                if !selection_is_empty {
 4143                                    return None;
 4144                                }
 4145
 4146                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4147                                    return None;
 4148                                }
 4149
 4150                                let DocumentationConfig {
 4151                                    start: start_tag,
 4152                                    end: end_tag,
 4153                                    prefix: delimiter,
 4154                                    tab_size: len,
 4155                                } = language.documentation()?;
 4156
 4157                                let is_within_block_comment = buffer
 4158                                    .language_scope_at(start_point)
 4159                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4160                                if !is_within_block_comment {
 4161                                    return None;
 4162                                }
 4163
 4164                                let (snapshot, range) =
 4165                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4166
 4167                                let num_of_whitespaces = snapshot
 4168                                    .chars_for_range(range.clone())
 4169                                    .take_while(|c| c.is_whitespace())
 4170                                    .count();
 4171
 4172                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4173                                let column = start_point.column;
 4174                                let cursor_is_after_start_tag = {
 4175                                    let start_tag_len = start_tag.len();
 4176                                    let start_tag_line = snapshot
 4177                                        .chars_for_range(range.clone())
 4178                                        .skip(num_of_whitespaces)
 4179                                        .take(start_tag_len)
 4180                                        .collect::<String>();
 4181                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4182                                        num_of_whitespaces + start_tag_len <= column as usize
 4183                                    } else {
 4184                                        false
 4185                                    }
 4186                                };
 4187
 4188                                let cursor_is_after_delimiter = {
 4189                                    let delimiter_trim = delimiter.trim_end();
 4190                                    let delimiter_line = snapshot
 4191                                        .chars_for_range(range.clone())
 4192                                        .skip(num_of_whitespaces)
 4193                                        .take(delimiter_trim.len())
 4194                                        .collect::<String>();
 4195                                    if delimiter_line.starts_with(delimiter_trim) {
 4196                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4197                                    } else {
 4198                                        false
 4199                                    }
 4200                                };
 4201
 4202                                let cursor_is_before_end_tag_if_exists = {
 4203                                    let mut char_position = 0u32;
 4204                                    let mut end_tag_offset = None;
 4205
 4206                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4207                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4208                                            let chars_before_match =
 4209                                                chunk[..byte_pos].chars().count() as u32;
 4210                                            end_tag_offset =
 4211                                                Some(char_position + chars_before_match);
 4212                                            break 'outer;
 4213                                        }
 4214                                        char_position += chunk.chars().count() as u32;
 4215                                    }
 4216
 4217                                    if let Some(end_tag_offset) = end_tag_offset {
 4218                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4219                                        if cursor_is_after_start_tag {
 4220                                            if cursor_is_before_end_tag {
 4221                                                insert_extra_newline = true;
 4222                                            }
 4223                                            let cursor_is_at_start_of_end_tag =
 4224                                                column == end_tag_offset;
 4225                                            if cursor_is_at_start_of_end_tag {
 4226                                                indent_on_extra_newline.len = (*len).into();
 4227                                            }
 4228                                        }
 4229                                        cursor_is_before_end_tag
 4230                                    } else {
 4231                                        true
 4232                                    }
 4233                                };
 4234
 4235                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4236                                    && cursor_is_before_end_tag_if_exists
 4237                                {
 4238                                    if cursor_is_after_start_tag {
 4239                                        indent_on_newline.len = (*len).into();
 4240                                    }
 4241                                    Some(delimiter.clone())
 4242                                } else {
 4243                                    None
 4244                                }
 4245                            });
 4246
 4247                            (
 4248                                comment_delimiter,
 4249                                doc_delimiter,
 4250                                insert_extra_newline,
 4251                                indent_on_newline,
 4252                                indent_on_extra_newline,
 4253                            )
 4254                        } else {
 4255                            (
 4256                                None,
 4257                                None,
 4258                                false,
 4259                                IndentSize::default(),
 4260                                IndentSize::default(),
 4261                            )
 4262                        };
 4263
 4264                        let prevent_auto_indent = doc_delimiter.is_some();
 4265                        let delimiter = comment_delimiter.or(doc_delimiter);
 4266
 4267                        let capacity_for_delimiter =
 4268                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4269                        let mut new_text = String::with_capacity(
 4270                            1 + capacity_for_delimiter
 4271                                + existing_indent.len as usize
 4272                                + indent_on_newline.len as usize
 4273                                + indent_on_extra_newline.len as usize,
 4274                        );
 4275                        new_text.push('\n');
 4276                        new_text.extend(existing_indent.chars());
 4277                        new_text.extend(indent_on_newline.chars());
 4278
 4279                        if let Some(delimiter) = &delimiter {
 4280                            new_text.push_str(delimiter);
 4281                        }
 4282
 4283                        if insert_extra_newline {
 4284                            new_text.push('\n');
 4285                            new_text.extend(existing_indent.chars());
 4286                            new_text.extend(indent_on_extra_newline.chars());
 4287                        }
 4288
 4289                        let anchor = buffer.anchor_after(end);
 4290                        let new_selection = selection.map(|_| anchor);
 4291                        (
 4292                            ((start..end, new_text), prevent_auto_indent),
 4293                            (insert_extra_newline, new_selection),
 4294                        )
 4295                    })
 4296                    .unzip()
 4297            };
 4298
 4299            let mut auto_indent_edits = Vec::new();
 4300            let mut edits = Vec::new();
 4301            for (edit, prevent_auto_indent) in edits_with_flags {
 4302                if prevent_auto_indent {
 4303                    edits.push(edit);
 4304                } else {
 4305                    auto_indent_edits.push(edit);
 4306                }
 4307            }
 4308            if !edits.is_empty() {
 4309                this.edit(edits, cx);
 4310            }
 4311            if !auto_indent_edits.is_empty() {
 4312                this.edit_with_autoindent(auto_indent_edits, cx);
 4313            }
 4314
 4315            let buffer = this.buffer.read(cx).snapshot(cx);
 4316            let new_selections = selection_info
 4317                .into_iter()
 4318                .map(|(extra_newline_inserted, new_selection)| {
 4319                    let mut cursor = new_selection.end.to_point(&buffer);
 4320                    if extra_newline_inserted {
 4321                        cursor.row -= 1;
 4322                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4323                    }
 4324                    new_selection.map(|_| cursor)
 4325                })
 4326                .collect();
 4327
 4328            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4329                s.select(new_selections)
 4330            });
 4331            this.refresh_inline_completion(true, false, window, cx);
 4332        });
 4333    }
 4334
 4335    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4336        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4337
 4338        let buffer = self.buffer.read(cx);
 4339        let snapshot = buffer.snapshot(cx);
 4340
 4341        let mut edits = Vec::new();
 4342        let mut rows = Vec::new();
 4343
 4344        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4345            let cursor = selection.head();
 4346            let row = cursor.row;
 4347
 4348            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4349
 4350            let newline = "\n".to_string();
 4351            edits.push((start_of_line..start_of_line, newline));
 4352
 4353            rows.push(row + rows_inserted as u32);
 4354        }
 4355
 4356        self.transact(window, cx, |editor, window, cx| {
 4357            editor.edit(edits, cx);
 4358
 4359            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4360                let mut index = 0;
 4361                s.move_cursors_with(|map, _, _| {
 4362                    let row = rows[index];
 4363                    index += 1;
 4364
 4365                    let point = Point::new(row, 0);
 4366                    let boundary = map.next_line_boundary(point).1;
 4367                    let clipped = map.clip_point(boundary, Bias::Left);
 4368
 4369                    (clipped, SelectionGoal::None)
 4370                });
 4371            });
 4372
 4373            let mut indent_edits = Vec::new();
 4374            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4375            for row in rows {
 4376                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4377                for (row, indent) in indents {
 4378                    if indent.len == 0 {
 4379                        continue;
 4380                    }
 4381
 4382                    let text = match indent.kind {
 4383                        IndentKind::Space => " ".repeat(indent.len as usize),
 4384                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4385                    };
 4386                    let point = Point::new(row.0, 0);
 4387                    indent_edits.push((point..point, text));
 4388                }
 4389            }
 4390            editor.edit(indent_edits, cx);
 4391        });
 4392    }
 4393
 4394    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4395        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4396
 4397        let buffer = self.buffer.read(cx);
 4398        let snapshot = buffer.snapshot(cx);
 4399
 4400        let mut edits = Vec::new();
 4401        let mut rows = Vec::new();
 4402        let mut rows_inserted = 0;
 4403
 4404        for selection in self.selections.all_adjusted(cx) {
 4405            let cursor = selection.head();
 4406            let row = cursor.row;
 4407
 4408            let point = Point::new(row + 1, 0);
 4409            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4410
 4411            let newline = "\n".to_string();
 4412            edits.push((start_of_line..start_of_line, newline));
 4413
 4414            rows_inserted += 1;
 4415            rows.push(row + rows_inserted);
 4416        }
 4417
 4418        self.transact(window, cx, |editor, window, cx| {
 4419            editor.edit(edits, cx);
 4420
 4421            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4422                let mut index = 0;
 4423                s.move_cursors_with(|map, _, _| {
 4424                    let row = rows[index];
 4425                    index += 1;
 4426
 4427                    let point = Point::new(row, 0);
 4428                    let boundary = map.next_line_boundary(point).1;
 4429                    let clipped = map.clip_point(boundary, Bias::Left);
 4430
 4431                    (clipped, SelectionGoal::None)
 4432                });
 4433            });
 4434
 4435            let mut indent_edits = Vec::new();
 4436            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4437            for row in rows {
 4438                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4439                for (row, indent) in indents {
 4440                    if indent.len == 0 {
 4441                        continue;
 4442                    }
 4443
 4444                    let text = match indent.kind {
 4445                        IndentKind::Space => " ".repeat(indent.len as usize),
 4446                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4447                    };
 4448                    let point = Point::new(row.0, 0);
 4449                    indent_edits.push((point..point, text));
 4450                }
 4451            }
 4452            editor.edit(indent_edits, cx);
 4453        });
 4454    }
 4455
 4456    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4457        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4458            original_indent_columns: Vec::new(),
 4459        });
 4460        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4461    }
 4462
 4463    fn insert_with_autoindent_mode(
 4464        &mut self,
 4465        text: &str,
 4466        autoindent_mode: Option<AutoindentMode>,
 4467        window: &mut Window,
 4468        cx: &mut Context<Self>,
 4469    ) {
 4470        if self.read_only(cx) {
 4471            return;
 4472        }
 4473
 4474        let text: Arc<str> = text.into();
 4475        self.transact(window, cx, |this, window, cx| {
 4476            let old_selections = this.selections.all_adjusted(cx);
 4477            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4478                let anchors = {
 4479                    let snapshot = buffer.read(cx);
 4480                    old_selections
 4481                        .iter()
 4482                        .map(|s| {
 4483                            let anchor = snapshot.anchor_after(s.head());
 4484                            s.map(|_| anchor)
 4485                        })
 4486                        .collect::<Vec<_>>()
 4487                };
 4488                buffer.edit(
 4489                    old_selections
 4490                        .iter()
 4491                        .map(|s| (s.start..s.end, text.clone())),
 4492                    autoindent_mode,
 4493                    cx,
 4494                );
 4495                anchors
 4496            });
 4497
 4498            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4499                s.select_anchors(selection_anchors);
 4500            });
 4501
 4502            cx.notify();
 4503        });
 4504    }
 4505
 4506    fn trigger_completion_on_input(
 4507        &mut self,
 4508        text: &str,
 4509        trigger_in_words: bool,
 4510        window: &mut Window,
 4511        cx: &mut Context<Self>,
 4512    ) {
 4513        let ignore_completion_provider = self
 4514            .context_menu
 4515            .borrow()
 4516            .as_ref()
 4517            .map(|menu| match menu {
 4518                CodeContextMenu::Completions(completions_menu) => {
 4519                    completions_menu.ignore_completion_provider
 4520                }
 4521                CodeContextMenu::CodeActions(_) => false,
 4522            })
 4523            .unwrap_or(false);
 4524
 4525        if ignore_completion_provider {
 4526            self.show_word_completions(&ShowWordCompletions, window, cx);
 4527        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4528            self.show_completions(
 4529                &ShowCompletions {
 4530                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4531                },
 4532                window,
 4533                cx,
 4534            );
 4535        } else {
 4536            self.hide_context_menu(window, cx);
 4537        }
 4538    }
 4539
 4540    fn is_completion_trigger(
 4541        &self,
 4542        text: &str,
 4543        trigger_in_words: bool,
 4544        cx: &mut Context<Self>,
 4545    ) -> bool {
 4546        let position = self.selections.newest_anchor().head();
 4547        let multibuffer = self.buffer.read(cx);
 4548        let Some(buffer) = position
 4549            .buffer_id
 4550            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4551        else {
 4552            return false;
 4553        };
 4554
 4555        if let Some(completion_provider) = &self.completion_provider {
 4556            completion_provider.is_completion_trigger(
 4557                &buffer,
 4558                position.text_anchor,
 4559                text,
 4560                trigger_in_words,
 4561                cx,
 4562            )
 4563        } else {
 4564            false
 4565        }
 4566    }
 4567
 4568    /// If any empty selections is touching the start of its innermost containing autoclose
 4569    /// region, expand it to select the brackets.
 4570    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4571        let selections = self.selections.all::<usize>(cx);
 4572        let buffer = self.buffer.read(cx).read(cx);
 4573        let new_selections = self
 4574            .selections_with_autoclose_regions(selections, &buffer)
 4575            .map(|(mut selection, region)| {
 4576                if !selection.is_empty() {
 4577                    return selection;
 4578                }
 4579
 4580                if let Some(region) = region {
 4581                    let mut range = region.range.to_offset(&buffer);
 4582                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4583                        range.start -= region.pair.start.len();
 4584                        if buffer.contains_str_at(range.start, &region.pair.start)
 4585                            && buffer.contains_str_at(range.end, &region.pair.end)
 4586                        {
 4587                            range.end += region.pair.end.len();
 4588                            selection.start = range.start;
 4589                            selection.end = range.end;
 4590
 4591                            return selection;
 4592                        }
 4593                    }
 4594                }
 4595
 4596                let always_treat_brackets_as_autoclosed = buffer
 4597                    .language_settings_at(selection.start, cx)
 4598                    .always_treat_brackets_as_autoclosed;
 4599
 4600                if !always_treat_brackets_as_autoclosed {
 4601                    return selection;
 4602                }
 4603
 4604                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4605                    for (pair, enabled) in scope.brackets() {
 4606                        if !enabled || !pair.close {
 4607                            continue;
 4608                        }
 4609
 4610                        if buffer.contains_str_at(selection.start, &pair.end) {
 4611                            let pair_start_len = pair.start.len();
 4612                            if buffer.contains_str_at(
 4613                                selection.start.saturating_sub(pair_start_len),
 4614                                &pair.start,
 4615                            ) {
 4616                                selection.start -= pair_start_len;
 4617                                selection.end += pair.end.len();
 4618
 4619                                return selection;
 4620                            }
 4621                        }
 4622                    }
 4623                }
 4624
 4625                selection
 4626            })
 4627            .collect();
 4628
 4629        drop(buffer);
 4630        self.change_selections(None, window, cx, |selections| {
 4631            selections.select(new_selections)
 4632        });
 4633    }
 4634
 4635    /// Iterate the given selections, and for each one, find the smallest surrounding
 4636    /// autoclose region. This uses the ordering of the selections and the autoclose
 4637    /// regions to avoid repeated comparisons.
 4638    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4639        &'a self,
 4640        selections: impl IntoIterator<Item = Selection<D>>,
 4641        buffer: &'a MultiBufferSnapshot,
 4642    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4643        let mut i = 0;
 4644        let mut regions = self.autoclose_regions.as_slice();
 4645        selections.into_iter().map(move |selection| {
 4646            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4647
 4648            let mut enclosing = None;
 4649            while let Some(pair_state) = regions.get(i) {
 4650                if pair_state.range.end.to_offset(buffer) < range.start {
 4651                    regions = &regions[i + 1..];
 4652                    i = 0;
 4653                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4654                    break;
 4655                } else {
 4656                    if pair_state.selection_id == selection.id {
 4657                        enclosing = Some(pair_state);
 4658                    }
 4659                    i += 1;
 4660                }
 4661            }
 4662
 4663            (selection, enclosing)
 4664        })
 4665    }
 4666
 4667    /// Remove any autoclose regions that no longer contain their selection.
 4668    fn invalidate_autoclose_regions(
 4669        &mut self,
 4670        mut selections: &[Selection<Anchor>],
 4671        buffer: &MultiBufferSnapshot,
 4672    ) {
 4673        self.autoclose_regions.retain(|state| {
 4674            let mut i = 0;
 4675            while let Some(selection) = selections.get(i) {
 4676                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4677                    selections = &selections[1..];
 4678                    continue;
 4679                }
 4680                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4681                    break;
 4682                }
 4683                if selection.id == state.selection_id {
 4684                    return true;
 4685                } else {
 4686                    i += 1;
 4687                }
 4688            }
 4689            false
 4690        });
 4691    }
 4692
 4693    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4694        let offset = position.to_offset(buffer);
 4695        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4696        if offset > word_range.start && kind == Some(CharKind::Word) {
 4697            Some(
 4698                buffer
 4699                    .text_for_range(word_range.start..offset)
 4700                    .collect::<String>(),
 4701            )
 4702        } else {
 4703            None
 4704        }
 4705    }
 4706
 4707    pub fn toggle_inline_values(
 4708        &mut self,
 4709        _: &ToggleInlineValues,
 4710        _: &mut Window,
 4711        cx: &mut Context<Self>,
 4712    ) {
 4713        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4714
 4715        self.refresh_inline_values(cx);
 4716    }
 4717
 4718    pub fn toggle_inlay_hints(
 4719        &mut self,
 4720        _: &ToggleInlayHints,
 4721        _: &mut Window,
 4722        cx: &mut Context<Self>,
 4723    ) {
 4724        self.refresh_inlay_hints(
 4725            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4726            cx,
 4727        );
 4728    }
 4729
 4730    pub fn inlay_hints_enabled(&self) -> bool {
 4731        self.inlay_hint_cache.enabled
 4732    }
 4733
 4734    pub fn inline_values_enabled(&self) -> bool {
 4735        self.inline_value_cache.enabled
 4736    }
 4737
 4738    #[cfg(any(test, feature = "test-support"))]
 4739    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4740        self.display_map
 4741            .read(cx)
 4742            .current_inlays()
 4743            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4744            .cloned()
 4745            .collect()
 4746    }
 4747
 4748    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4749        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4750            return;
 4751        }
 4752
 4753        let reason_description = reason.description();
 4754        let ignore_debounce = matches!(
 4755            reason,
 4756            InlayHintRefreshReason::SettingsChange(_)
 4757                | InlayHintRefreshReason::Toggle(_)
 4758                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4759                | InlayHintRefreshReason::ModifiersChanged(_)
 4760        );
 4761        let (invalidate_cache, required_languages) = match reason {
 4762            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4763                match self.inlay_hint_cache.modifiers_override(enabled) {
 4764                    Some(enabled) => {
 4765                        if enabled {
 4766                            (InvalidationStrategy::RefreshRequested, None)
 4767                        } else {
 4768                            self.splice_inlays(
 4769                                &self
 4770                                    .visible_inlay_hints(cx)
 4771                                    .iter()
 4772                                    .map(|inlay| inlay.id)
 4773                                    .collect::<Vec<InlayId>>(),
 4774                                Vec::new(),
 4775                                cx,
 4776                            );
 4777                            return;
 4778                        }
 4779                    }
 4780                    None => return,
 4781                }
 4782            }
 4783            InlayHintRefreshReason::Toggle(enabled) => {
 4784                if self.inlay_hint_cache.toggle(enabled) {
 4785                    if enabled {
 4786                        (InvalidationStrategy::RefreshRequested, None)
 4787                    } else {
 4788                        self.splice_inlays(
 4789                            &self
 4790                                .visible_inlay_hints(cx)
 4791                                .iter()
 4792                                .map(|inlay| inlay.id)
 4793                                .collect::<Vec<InlayId>>(),
 4794                            Vec::new(),
 4795                            cx,
 4796                        );
 4797                        return;
 4798                    }
 4799                } else {
 4800                    return;
 4801                }
 4802            }
 4803            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4804                match self.inlay_hint_cache.update_settings(
 4805                    &self.buffer,
 4806                    new_settings,
 4807                    self.visible_inlay_hints(cx),
 4808                    cx,
 4809                ) {
 4810                    ControlFlow::Break(Some(InlaySplice {
 4811                        to_remove,
 4812                        to_insert,
 4813                    })) => {
 4814                        self.splice_inlays(&to_remove, to_insert, cx);
 4815                        return;
 4816                    }
 4817                    ControlFlow::Break(None) => return,
 4818                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4819                }
 4820            }
 4821            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4822                if let Some(InlaySplice {
 4823                    to_remove,
 4824                    to_insert,
 4825                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4826                {
 4827                    self.splice_inlays(&to_remove, to_insert, cx);
 4828                }
 4829                self.display_map.update(cx, |display_map, _| {
 4830                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4831                });
 4832                return;
 4833            }
 4834            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4835            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4836                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4837            }
 4838            InlayHintRefreshReason::RefreshRequested => {
 4839                (InvalidationStrategy::RefreshRequested, None)
 4840            }
 4841        };
 4842
 4843        if let Some(InlaySplice {
 4844            to_remove,
 4845            to_insert,
 4846        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4847            reason_description,
 4848            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4849            invalidate_cache,
 4850            ignore_debounce,
 4851            cx,
 4852        ) {
 4853            self.splice_inlays(&to_remove, to_insert, cx);
 4854        }
 4855    }
 4856
 4857    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4858        self.display_map
 4859            .read(cx)
 4860            .current_inlays()
 4861            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4862            .cloned()
 4863            .collect()
 4864    }
 4865
 4866    pub fn excerpts_for_inlay_hints_query(
 4867        &self,
 4868        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4869        cx: &mut Context<Editor>,
 4870    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4871        let Some(project) = self.project.as_ref() else {
 4872            return HashMap::default();
 4873        };
 4874        let project = project.read(cx);
 4875        let multi_buffer = self.buffer().read(cx);
 4876        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4877        let multi_buffer_visible_start = self
 4878            .scroll_manager
 4879            .anchor()
 4880            .anchor
 4881            .to_point(&multi_buffer_snapshot);
 4882        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4883            multi_buffer_visible_start
 4884                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4885            Bias::Left,
 4886        );
 4887        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4888        multi_buffer_snapshot
 4889            .range_to_buffer_ranges(multi_buffer_visible_range)
 4890            .into_iter()
 4891            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4892            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4893                let buffer_file = project::File::from_dyn(buffer.file())?;
 4894                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4895                let worktree_entry = buffer_worktree
 4896                    .read(cx)
 4897                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4898                if worktree_entry.is_ignored {
 4899                    return None;
 4900                }
 4901
 4902                let language = buffer.language()?;
 4903                if let Some(restrict_to_languages) = restrict_to_languages {
 4904                    if !restrict_to_languages.contains(language) {
 4905                        return None;
 4906                    }
 4907                }
 4908                Some((
 4909                    excerpt_id,
 4910                    (
 4911                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4912                        buffer.version().clone(),
 4913                        excerpt_visible_range,
 4914                    ),
 4915                ))
 4916            })
 4917            .collect()
 4918    }
 4919
 4920    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4921        TextLayoutDetails {
 4922            text_system: window.text_system().clone(),
 4923            editor_style: self.style.clone().unwrap(),
 4924            rem_size: window.rem_size(),
 4925            scroll_anchor: self.scroll_manager.anchor(),
 4926            visible_rows: self.visible_line_count(),
 4927            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4928        }
 4929    }
 4930
 4931    pub fn splice_inlays(
 4932        &self,
 4933        to_remove: &[InlayId],
 4934        to_insert: Vec<Inlay>,
 4935        cx: &mut Context<Self>,
 4936    ) {
 4937        self.display_map.update(cx, |display_map, cx| {
 4938            display_map.splice_inlays(to_remove, to_insert, cx)
 4939        });
 4940        cx.notify();
 4941    }
 4942
 4943    fn trigger_on_type_formatting(
 4944        &self,
 4945        input: String,
 4946        window: &mut Window,
 4947        cx: &mut Context<Self>,
 4948    ) -> Option<Task<Result<()>>> {
 4949        if input.len() != 1 {
 4950            return None;
 4951        }
 4952
 4953        let project = self.project.as_ref()?;
 4954        let position = self.selections.newest_anchor().head();
 4955        let (buffer, buffer_position) = self
 4956            .buffer
 4957            .read(cx)
 4958            .text_anchor_for_position(position, cx)?;
 4959
 4960        let settings = language_settings::language_settings(
 4961            buffer
 4962                .read(cx)
 4963                .language_at(buffer_position)
 4964                .map(|l| l.name()),
 4965            buffer.read(cx).file(),
 4966            cx,
 4967        );
 4968        if !settings.use_on_type_format {
 4969            return None;
 4970        }
 4971
 4972        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4973        // hence we do LSP request & edit on host side only — add formats to host's history.
 4974        let push_to_lsp_host_history = true;
 4975        // If this is not the host, append its history with new edits.
 4976        let push_to_client_history = project.read(cx).is_via_collab();
 4977
 4978        let on_type_formatting = project.update(cx, |project, cx| {
 4979            project.on_type_format(
 4980                buffer.clone(),
 4981                buffer_position,
 4982                input,
 4983                push_to_lsp_host_history,
 4984                cx,
 4985            )
 4986        });
 4987        Some(cx.spawn_in(window, async move |editor, cx| {
 4988            if let Some(transaction) = on_type_formatting.await? {
 4989                if push_to_client_history {
 4990                    buffer
 4991                        .update(cx, |buffer, _| {
 4992                            buffer.push_transaction(transaction, Instant::now());
 4993                            buffer.finalize_last_transaction();
 4994                        })
 4995                        .ok();
 4996                }
 4997                editor.update(cx, |editor, cx| {
 4998                    editor.refresh_document_highlights(cx);
 4999                })?;
 5000            }
 5001            Ok(())
 5002        }))
 5003    }
 5004
 5005    pub fn show_word_completions(
 5006        &mut self,
 5007        _: &ShowWordCompletions,
 5008        window: &mut Window,
 5009        cx: &mut Context<Self>,
 5010    ) {
 5011        self.open_or_update_completions_menu(true, None, window, cx);
 5012    }
 5013
 5014    pub fn show_completions(
 5015        &mut self,
 5016        options: &ShowCompletions,
 5017        window: &mut Window,
 5018        cx: &mut Context<Self>,
 5019    ) {
 5020        self.open_or_update_completions_menu(false, options.trigger.as_deref(), window, cx);
 5021    }
 5022
 5023    fn open_or_update_completions_menu(
 5024        &mut self,
 5025        ignore_completion_provider: bool,
 5026        trigger: Option<&str>,
 5027        window: &mut Window,
 5028        cx: &mut Context<Self>,
 5029    ) {
 5030        if self.pending_rename.is_some() {
 5031            return;
 5032        }
 5033
 5034        let position = self.selections.newest_anchor().head();
 5035        if position.diff_base_anchor.is_some() {
 5036            return;
 5037        }
 5038        let (buffer, buffer_position) =
 5039            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5040                output
 5041            } else {
 5042                return;
 5043            };
 5044        let buffer_snapshot = buffer.read(cx).snapshot();
 5045
 5046        let query: Option<Arc<String>> =
 5047            Self::completion_query(&self.buffer.read(cx).read(cx), position)
 5048                .map(|query| query.into());
 5049
 5050        let provider = if ignore_completion_provider {
 5051            None
 5052        } else {
 5053            self.completion_provider.clone()
 5054        };
 5055
 5056        let sort_completions = provider
 5057            .as_ref()
 5058            .map_or(false, |provider| provider.sort_completions());
 5059
 5060        let filter_completions = provider
 5061            .as_ref()
 5062            .map_or(true, |provider| provider.filter_completions());
 5063
 5064        // When `is_incomplete` is false, can filter completions instead of re-querying when the
 5065        // current query is a suffix of the initial query.
 5066        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5067            if !menu.is_incomplete && filter_completions {
 5068                // If the new query is a suffix of the old query (typing more characters) and
 5069                // the previous result was complete, the existing completions can be filtered.
 5070                //
 5071                // Note that this is always true for snippet completions.
 5072                let query_matches = match (&menu.initial_query, &query) {
 5073                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5074                    (None, _) => true,
 5075                    _ => false,
 5076                };
 5077                if query_matches {
 5078                    let position_matches = if menu.initial_position == position {
 5079                        true
 5080                    } else {
 5081                        let snapshot = self.buffer.read(cx).read(cx);
 5082                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5083                    };
 5084                    if position_matches {
 5085                        menu.filter(query.clone(), provider.clone(), window, cx);
 5086                        return;
 5087                    }
 5088                }
 5089            }
 5090        };
 5091
 5092        let trigger_kind = match trigger {
 5093            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5094                CompletionTriggerKind::TRIGGER_CHARACTER
 5095            }
 5096            _ => CompletionTriggerKind::INVOKED,
 5097        };
 5098        let completion_context = CompletionContext {
 5099            trigger_character: trigger.and_then(|trigger| {
 5100                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5101                    Some(String::from(trigger))
 5102                } else {
 5103                    None
 5104                }
 5105            }),
 5106            trigger_kind,
 5107        };
 5108
 5109        let (replace_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 5110        let (replace_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 5111            let word_to_exclude = buffer_snapshot
 5112                .text_for_range(replace_range.clone())
 5113                .collect::<String>();
 5114            (
 5115                buffer_snapshot.anchor_before(replace_range.start)
 5116                    ..buffer_snapshot.anchor_after(replace_range.end),
 5117                Some(word_to_exclude),
 5118            )
 5119        } else {
 5120            (buffer_position..buffer_position, None)
 5121        };
 5122
 5123        let language = buffer_snapshot
 5124            .language_at(buffer_position)
 5125            .map(|language| language.name());
 5126
 5127        let completion_settings =
 5128            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5129
 5130        let show_completion_documentation = buffer_snapshot
 5131            .settings_at(buffer_position, cx)
 5132            .show_completion_documentation;
 5133
 5134        // The document can be large, so stay in reasonable bounds when searching for words,
 5135        // otherwise completion pop-up might be slow to appear.
 5136        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5137        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5138        let min_word_search = buffer_snapshot.clip_point(
 5139            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5140            Bias::Left,
 5141        );
 5142        let max_word_search = buffer_snapshot.clip_point(
 5143            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5144            Bias::Right,
 5145        );
 5146        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5147            ..buffer_snapshot.point_to_offset(max_word_search);
 5148
 5149        let skip_digits = query
 5150            .as_ref()
 5151            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5152
 5153        let (mut words, provider_responses) = match &provider {
 5154            Some(provider) => {
 5155                let provider_responses = provider.completions(
 5156                    position.excerpt_id,
 5157                    &buffer,
 5158                    buffer_position,
 5159                    completion_context,
 5160                    window,
 5161                    cx,
 5162                );
 5163
 5164                let words = match completion_settings.words {
 5165                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5166                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5167                        .background_spawn(async move {
 5168                            buffer_snapshot.words_in_range(WordsQuery {
 5169                                fuzzy_contents: None,
 5170                                range: word_search_range,
 5171                                skip_digits,
 5172                            })
 5173                        }),
 5174                };
 5175
 5176                (words, provider_responses)
 5177            }
 5178            None => (
 5179                cx.background_spawn(async move {
 5180                    buffer_snapshot.words_in_range(WordsQuery {
 5181                        fuzzy_contents: None,
 5182                        range: word_search_range,
 5183                        skip_digits,
 5184                    })
 5185                }),
 5186                Task::ready(Ok(Vec::new())),
 5187            ),
 5188        };
 5189
 5190        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5191
 5192        let id = post_inc(&mut self.next_completion_id);
 5193        let task = cx.spawn_in(window, async move |editor, cx| {
 5194            let Ok(()) = editor.update(cx, |this, _| {
 5195                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5196            }) else {
 5197                return;
 5198            };
 5199
 5200            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5201            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5202            let mut completions = Vec::new();
 5203            let mut is_incomplete = false;
 5204            if let Some(provider_responses) = provider_responses.await.log_err() {
 5205                if !provider_responses.is_empty() {
 5206                    for response in provider_responses {
 5207                        completions.extend(response.completions);
 5208                        is_incomplete = is_incomplete || response.is_incomplete;
 5209                    }
 5210                    if completion_settings.words == WordsCompletionMode::Fallback {
 5211                        words = Task::ready(BTreeMap::default());
 5212                    }
 5213                }
 5214            }
 5215
 5216            let mut words = words.await;
 5217            if let Some(word_to_exclude) = &word_to_exclude {
 5218                words.remove(word_to_exclude);
 5219            }
 5220            for lsp_completion in &completions {
 5221                words.remove(&lsp_completion.new_text);
 5222            }
 5223            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5224                replace_range: replace_range.clone(),
 5225                new_text: word.clone(),
 5226                label: CodeLabel::plain(word, None),
 5227                icon_path: None,
 5228                documentation: None,
 5229                source: CompletionSource::BufferWord {
 5230                    word_range,
 5231                    resolved: false,
 5232                },
 5233                insert_text_mode: Some(InsertTextMode::AS_IS),
 5234                confirm: None,
 5235            }));
 5236
 5237            let menu = if completions.is_empty() {
 5238                None
 5239            } else {
 5240                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5241                    let languages = editor
 5242                        .workspace
 5243                        .as_ref()
 5244                        .and_then(|(workspace, _)| workspace.upgrade())
 5245                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5246                    let menu = CompletionsMenu::new(
 5247                        id,
 5248                        sort_completions,
 5249                        show_completion_documentation,
 5250                        ignore_completion_provider,
 5251                        position,
 5252                        query.clone(),
 5253                        is_incomplete,
 5254                        buffer.clone(),
 5255                        completions.into(),
 5256                        snippet_sort_order,
 5257                        languages,
 5258                        language,
 5259                        cx,
 5260                    );
 5261
 5262                    let query = if filter_completions { query } else { None };
 5263                    let matches_task = if let Some(query) = query {
 5264                        menu.do_async_filtering(query, cx)
 5265                    } else {
 5266                        Task::ready(menu.unfiltered_matches())
 5267                    };
 5268                    (menu, matches_task)
 5269                }) else {
 5270                    return;
 5271                };
 5272
 5273                let matches = matches_task.await;
 5274
 5275                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5276                    // Newer menu already set, so exit.
 5277                    match editor.context_menu.borrow().as_ref() {
 5278                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5279                            if prev_menu.id > id {
 5280                                return;
 5281                            }
 5282                        }
 5283                        _ => {}
 5284                    };
 5285
 5286                    // Only valid to take prev_menu because it the new menu is immediately set
 5287                    // below, or the menu is hidden.
 5288                    match editor.context_menu.borrow_mut().take() {
 5289                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5290                            let position_matches =
 5291                                if prev_menu.initial_position == menu.initial_position {
 5292                                    true
 5293                                } else {
 5294                                    let snapshot = editor.buffer.read(cx).read(cx);
 5295                                    prev_menu.initial_position.to_offset(&snapshot)
 5296                                        == menu.initial_position.to_offset(&snapshot)
 5297                                };
 5298                            if position_matches {
 5299                                // Preserve markdown cache before `set_filter_results` because it will
 5300                                // try to populate the documentation cache.
 5301                                menu.preserve_markdown_cache(prev_menu);
 5302                            }
 5303                        }
 5304                        _ => {}
 5305                    };
 5306
 5307                    menu.set_filter_results(matches, provider, window, cx);
 5308                }) else {
 5309                    return;
 5310                };
 5311
 5312                menu.visible().then_some(menu)
 5313            };
 5314
 5315            editor
 5316                .update_in(cx, |editor, window, cx| {
 5317                    if editor.focus_handle.is_focused(window) {
 5318                        if let Some(menu) = menu {
 5319                            *editor.context_menu.borrow_mut() =
 5320                                Some(CodeContextMenu::Completions(menu));
 5321
 5322                            crate::hover_popover::hide_hover(editor, cx);
 5323                            if editor.show_edit_predictions_in_menu() {
 5324                                editor.update_visible_inline_completion(window, cx);
 5325                            } else {
 5326                                editor.discard_inline_completion(false, cx);
 5327                            }
 5328
 5329                            cx.notify();
 5330                            return;
 5331                        }
 5332                    }
 5333
 5334                    if editor.completion_tasks.len() <= 1 {
 5335                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5336                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5337                        // If it was already hidden and we don't show inline completions in the menu, we should
 5338                        // also show the inline-completion when available.
 5339                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5340                            editor.update_visible_inline_completion(window, cx);
 5341                        }
 5342                    }
 5343                })
 5344                .ok();
 5345        });
 5346
 5347        self.completion_tasks.push((id, task));
 5348    }
 5349
 5350    #[cfg(feature = "test-support")]
 5351    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5352        let menu = self.context_menu.borrow();
 5353        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5354            let completions = menu.completions.borrow();
 5355            Some(completions.to_vec())
 5356        } else {
 5357            None
 5358        }
 5359    }
 5360
 5361    pub fn with_completions_menu_matching_id<R>(
 5362        &self,
 5363        id: CompletionId,
 5364        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5365    ) -> R {
 5366        let mut context_menu = self.context_menu.borrow_mut();
 5367        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5368            return f(None);
 5369        };
 5370        if completions_menu.id != id {
 5371            return f(None);
 5372        }
 5373        f(Some(completions_menu))
 5374    }
 5375
 5376    pub fn confirm_completion(
 5377        &mut self,
 5378        action: &ConfirmCompletion,
 5379        window: &mut Window,
 5380        cx: &mut Context<Self>,
 5381    ) -> Option<Task<Result<()>>> {
 5382        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5383        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5384    }
 5385
 5386    pub fn confirm_completion_insert(
 5387        &mut self,
 5388        _: &ConfirmCompletionInsert,
 5389        window: &mut Window,
 5390        cx: &mut Context<Self>,
 5391    ) -> Option<Task<Result<()>>> {
 5392        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5393        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5394    }
 5395
 5396    pub fn confirm_completion_replace(
 5397        &mut self,
 5398        _: &ConfirmCompletionReplace,
 5399        window: &mut Window,
 5400        cx: &mut Context<Self>,
 5401    ) -> Option<Task<Result<()>>> {
 5402        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5403        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5404    }
 5405
 5406    pub fn compose_completion(
 5407        &mut self,
 5408        action: &ComposeCompletion,
 5409        window: &mut Window,
 5410        cx: &mut Context<Self>,
 5411    ) -> Option<Task<Result<()>>> {
 5412        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5413        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5414    }
 5415
 5416    fn do_completion(
 5417        &mut self,
 5418        item_ix: Option<usize>,
 5419        intent: CompletionIntent,
 5420        window: &mut Window,
 5421        cx: &mut Context<Editor>,
 5422    ) -> Option<Task<Result<()>>> {
 5423        use language::ToOffset as _;
 5424
 5425        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5426        else {
 5427            return None;
 5428        };
 5429
 5430        let candidate_id = {
 5431            let entries = completions_menu.entries.borrow();
 5432            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5433            if self.show_edit_predictions_in_menu() {
 5434                self.discard_inline_completion(true, cx);
 5435            }
 5436            mat.candidate_id
 5437        };
 5438
 5439        let completion = completions_menu
 5440            .completions
 5441            .borrow()
 5442            .get(candidate_id)?
 5443            .clone();
 5444        cx.stop_propagation();
 5445
 5446        let buffer_handle = completions_menu.buffer.clone();
 5447
 5448        let CompletionEdit {
 5449            new_text,
 5450            snippet,
 5451            replace_range,
 5452        } = process_completion_for_edit(
 5453            &completion,
 5454            intent,
 5455            &buffer_handle,
 5456            &completions_menu.initial_position.text_anchor,
 5457            cx,
 5458        );
 5459
 5460        let buffer = buffer_handle.read(cx);
 5461        let snapshot = self.buffer.read(cx).snapshot(cx);
 5462        let newest_anchor = self.selections.newest_anchor();
 5463        let replace_range_multibuffer = {
 5464            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5465            let multibuffer_anchor = snapshot
 5466                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5467                .unwrap()
 5468                ..snapshot
 5469                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5470                    .unwrap();
 5471            multibuffer_anchor.start.to_offset(&snapshot)
 5472                ..multibuffer_anchor.end.to_offset(&snapshot)
 5473        };
 5474        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5475            return None;
 5476        }
 5477
 5478        let old_text = buffer
 5479            .text_for_range(replace_range.clone())
 5480            .collect::<String>();
 5481        let lookbehind = newest_anchor
 5482            .start
 5483            .text_anchor
 5484            .to_offset(buffer)
 5485            .saturating_sub(replace_range.start);
 5486        let lookahead = replace_range
 5487            .end
 5488            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5489        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5490        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5491
 5492        let selections = self.selections.all::<usize>(cx);
 5493        let mut ranges = Vec::new();
 5494        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5495
 5496        for selection in &selections {
 5497            let range = if selection.id == newest_anchor.id {
 5498                replace_range_multibuffer.clone()
 5499            } else {
 5500                let mut range = selection.range();
 5501
 5502                // if prefix is present, don't duplicate it
 5503                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5504                    range.start = range.start.saturating_sub(lookbehind);
 5505
 5506                    // if suffix is also present, mimic the newest cursor and replace it
 5507                    if selection.id != newest_anchor.id
 5508                        && snapshot.contains_str_at(range.end, suffix)
 5509                    {
 5510                        range.end += lookahead;
 5511                    }
 5512                }
 5513                range
 5514            };
 5515
 5516            ranges.push(range.clone());
 5517
 5518            if !self.linked_edit_ranges.is_empty() {
 5519                let start_anchor = snapshot.anchor_before(range.start);
 5520                let end_anchor = snapshot.anchor_after(range.end);
 5521                if let Some(ranges) = self
 5522                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5523                {
 5524                    for (buffer, edits) in ranges {
 5525                        linked_edits
 5526                            .entry(buffer.clone())
 5527                            .or_default()
 5528                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5529                    }
 5530                }
 5531            }
 5532        }
 5533
 5534        let mut common_prefix_len = 0;
 5535        for (a, b) in old_text.chars().zip(new_text.chars()) {
 5536            if a == b {
 5537                common_prefix_len += a.len_utf8();
 5538            } else {
 5539                break;
 5540            }
 5541        }
 5542
 5543        cx.emit(EditorEvent::InputHandled {
 5544            utf16_range_to_replace: None,
 5545            text: new_text[common_prefix_len..].into(),
 5546        });
 5547
 5548        self.transact(window, cx, |this, window, cx| {
 5549            if let Some(mut snippet) = snippet {
 5550                snippet.text = new_text.to_string();
 5551                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5552            } else {
 5553                this.buffer.update(cx, |buffer, cx| {
 5554                    let auto_indent = match completion.insert_text_mode {
 5555                        Some(InsertTextMode::AS_IS) => None,
 5556                        _ => this.autoindent_mode.clone(),
 5557                    };
 5558                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5559                    buffer.edit(edits, auto_indent, cx);
 5560                });
 5561            }
 5562            for (buffer, edits) in linked_edits {
 5563                buffer.update(cx, |buffer, cx| {
 5564                    let snapshot = buffer.snapshot();
 5565                    let edits = edits
 5566                        .into_iter()
 5567                        .map(|(range, text)| {
 5568                            use text::ToPoint as TP;
 5569                            let end_point = TP::to_point(&range.end, &snapshot);
 5570                            let start_point = TP::to_point(&range.start, &snapshot);
 5571                            (start_point..end_point, text)
 5572                        })
 5573                        .sorted_by_key(|(range, _)| range.start);
 5574                    buffer.edit(edits, None, cx);
 5575                })
 5576            }
 5577
 5578            this.refresh_inline_completion(true, false, window, cx);
 5579        });
 5580
 5581        let show_new_completions_on_confirm = completion
 5582            .confirm
 5583            .as_ref()
 5584            .map_or(false, |confirm| confirm(intent, window, cx));
 5585        if show_new_completions_on_confirm {
 5586            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5587        }
 5588
 5589        let provider = self.completion_provider.as_ref()?;
 5590        drop(completion);
 5591        let apply_edits = provider.apply_additional_edits_for_completion(
 5592            buffer_handle,
 5593            completions_menu.completions.clone(),
 5594            candidate_id,
 5595            true,
 5596            cx,
 5597        );
 5598
 5599        let editor_settings = EditorSettings::get_global(cx);
 5600        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5601            // After the code completion is finished, users often want to know what signatures are needed.
 5602            // so we should automatically call signature_help
 5603            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5604        }
 5605
 5606        Some(cx.foreground_executor().spawn(async move {
 5607            apply_edits.await?;
 5608            Ok(())
 5609        }))
 5610    }
 5611
 5612    pub fn toggle_code_actions(
 5613        &mut self,
 5614        action: &ToggleCodeActions,
 5615        window: &mut Window,
 5616        cx: &mut Context<Self>,
 5617    ) {
 5618        let quick_launch = action.quick_launch;
 5619        let mut context_menu = self.context_menu.borrow_mut();
 5620        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5621            if code_actions.deployed_from == action.deployed_from {
 5622                // Toggle if we're selecting the same one
 5623                *context_menu = None;
 5624                cx.notify();
 5625                return;
 5626            } else {
 5627                // Otherwise, clear it and start a new one
 5628                *context_menu = None;
 5629                cx.notify();
 5630            }
 5631        }
 5632        drop(context_menu);
 5633        let snapshot = self.snapshot(window, cx);
 5634        let deployed_from = action.deployed_from.clone();
 5635        let mut task = self.code_actions_task.take();
 5636        let action = action.clone();
 5637        cx.spawn_in(window, async move |editor, cx| {
 5638            while let Some(prev_task) = task {
 5639                prev_task.await.log_err();
 5640                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5641            }
 5642
 5643            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5644                if editor.focus_handle.is_focused(window) {
 5645                    let multibuffer_point = match &action.deployed_from {
 5646                        Some(CodeActionSource::Indicator(row)) => {
 5647                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5648                        }
 5649                        _ => editor.selections.newest::<Point>(cx).head(),
 5650                    };
 5651                    let (buffer, buffer_row) = snapshot
 5652                        .buffer_snapshot
 5653                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5654                        .and_then(|(buffer_snapshot, range)| {
 5655                            editor
 5656                                .buffer
 5657                                .read(cx)
 5658                                .buffer(buffer_snapshot.remote_id())
 5659                                .map(|buffer| (buffer, range.start.row))
 5660                        })?;
 5661                    let (_, code_actions) = editor
 5662                        .available_code_actions
 5663                        .clone()
 5664                        .and_then(|(location, code_actions)| {
 5665                            let snapshot = location.buffer.read(cx).snapshot();
 5666                            let point_range = location.range.to_point(&snapshot);
 5667                            let point_range = point_range.start.row..=point_range.end.row;
 5668                            if point_range.contains(&buffer_row) {
 5669                                Some((location, code_actions))
 5670                            } else {
 5671                                None
 5672                            }
 5673                        })
 5674                        .unzip();
 5675                    let buffer_id = buffer.read(cx).remote_id();
 5676                    let tasks = editor
 5677                        .tasks
 5678                        .get(&(buffer_id, buffer_row))
 5679                        .map(|t| Arc::new(t.to_owned()));
 5680                    if tasks.is_none() && code_actions.is_none() {
 5681                        return None;
 5682                    }
 5683
 5684                    editor.completion_tasks.clear();
 5685                    editor.discard_inline_completion(false, cx);
 5686                    let task_context =
 5687                        tasks
 5688                            .as_ref()
 5689                            .zip(editor.project.clone())
 5690                            .map(|(tasks, project)| {
 5691                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5692                            });
 5693
 5694                    Some(cx.spawn_in(window, async move |editor, cx| {
 5695                        let task_context = match task_context {
 5696                            Some(task_context) => task_context.await,
 5697                            None => None,
 5698                        };
 5699                        let resolved_tasks =
 5700                            tasks
 5701                                .zip(task_context.clone())
 5702                                .map(|(tasks, task_context)| ResolvedTasks {
 5703                                    templates: tasks.resolve(&task_context).collect(),
 5704                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5705                                        multibuffer_point.row,
 5706                                        tasks.column,
 5707                                    )),
 5708                                });
 5709                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5710                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5711                                maybe!({
 5712                                    let project = editor.project.as_ref()?;
 5713                                    let dap_store = project.read(cx).dap_store();
 5714                                    let mut scenarios = vec![];
 5715                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5716                                    let buffer = buffer.read(cx);
 5717                                    let language = buffer.language()?;
 5718                                    let file = buffer.file();
 5719                                    let debug_adapter =
 5720                                        language_settings(language.name().into(), file, cx)
 5721                                            .debuggers
 5722                                            .first()
 5723                                            .map(SharedString::from)
 5724                                            .or_else(|| {
 5725                                                language
 5726                                                    .config()
 5727                                                    .debuggers
 5728                                                    .first()
 5729                                                    .map(SharedString::from)
 5730                                            })?;
 5731
 5732                                    dap_store.update(cx, |dap_store, cx| {
 5733                                        for (_, task) in &resolved_tasks.templates {
 5734                                            if let Some(scenario) = dap_store
 5735                                                .debug_scenario_for_build_task(
 5736                                                    task.original_task().clone(),
 5737                                                    debug_adapter.clone().into(),
 5738                                                    task.display_label().to_owned().into(),
 5739                                                    cx,
 5740                                                )
 5741                                            {
 5742                                                scenarios.push(scenario);
 5743                                            }
 5744                                        }
 5745                                    });
 5746                                    Some(scenarios)
 5747                                })
 5748                                .unwrap_or_default()
 5749                            } else {
 5750                                vec![]
 5751                            }
 5752                        })?;
 5753                        let spawn_straight_away = quick_launch
 5754                            && resolved_tasks
 5755                                .as_ref()
 5756                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5757                            && code_actions
 5758                                .as_ref()
 5759                                .map_or(true, |actions| actions.is_empty())
 5760                            && debug_scenarios.is_empty();
 5761                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5762                            crate::hover_popover::hide_hover(editor, cx);
 5763                            *editor.context_menu.borrow_mut() =
 5764                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5765                                    buffer,
 5766                                    actions: CodeActionContents::new(
 5767                                        resolved_tasks,
 5768                                        code_actions,
 5769                                        debug_scenarios,
 5770                                        task_context.unwrap_or_default(),
 5771                                    ),
 5772                                    selected_item: Default::default(),
 5773                                    scroll_handle: UniformListScrollHandle::default(),
 5774                                    deployed_from,
 5775                                }));
 5776                            if spawn_straight_away {
 5777                                if let Some(task) = editor.confirm_code_action(
 5778                                    &ConfirmCodeAction { item_ix: Some(0) },
 5779                                    window,
 5780                                    cx,
 5781                                ) {
 5782                                    cx.notify();
 5783                                    return task;
 5784                                }
 5785                            }
 5786                            cx.notify();
 5787                            Task::ready(Ok(()))
 5788                        }) {
 5789                            task.await
 5790                        } else {
 5791                            Ok(())
 5792                        }
 5793                    }))
 5794                } else {
 5795                    Some(Task::ready(Ok(())))
 5796                }
 5797            })?;
 5798            if let Some(task) = spawned_test_task {
 5799                task.await?;
 5800            }
 5801
 5802            anyhow::Ok(())
 5803        })
 5804        .detach_and_log_err(cx);
 5805    }
 5806
 5807    pub fn confirm_code_action(
 5808        &mut self,
 5809        action: &ConfirmCodeAction,
 5810        window: &mut Window,
 5811        cx: &mut Context<Self>,
 5812    ) -> Option<Task<Result<()>>> {
 5813        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5814
 5815        let actions_menu =
 5816            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5817                menu
 5818            } else {
 5819                return None;
 5820            };
 5821
 5822        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5823        let action = actions_menu.actions.get(action_ix)?;
 5824        let title = action.label();
 5825        let buffer = actions_menu.buffer;
 5826        let workspace = self.workspace()?;
 5827
 5828        match action {
 5829            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5830                workspace.update(cx, |workspace, cx| {
 5831                    workspace.schedule_resolved_task(
 5832                        task_source_kind,
 5833                        resolved_task,
 5834                        false,
 5835                        window,
 5836                        cx,
 5837                    );
 5838
 5839                    Some(Task::ready(Ok(())))
 5840                })
 5841            }
 5842            CodeActionsItem::CodeAction {
 5843                excerpt_id,
 5844                action,
 5845                provider,
 5846            } => {
 5847                let apply_code_action =
 5848                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5849                let workspace = workspace.downgrade();
 5850                Some(cx.spawn_in(window, async move |editor, cx| {
 5851                    let project_transaction = apply_code_action.await?;
 5852                    Self::open_project_transaction(
 5853                        &editor,
 5854                        workspace,
 5855                        project_transaction,
 5856                        title,
 5857                        cx,
 5858                    )
 5859                    .await
 5860                }))
 5861            }
 5862            CodeActionsItem::DebugScenario(scenario) => {
 5863                let context = actions_menu.actions.context.clone();
 5864
 5865                workspace.update(cx, |workspace, cx| {
 5866                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5867                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5868                });
 5869                Some(Task::ready(Ok(())))
 5870            }
 5871        }
 5872    }
 5873
 5874    pub async fn open_project_transaction(
 5875        this: &WeakEntity<Editor>,
 5876        workspace: WeakEntity<Workspace>,
 5877        transaction: ProjectTransaction,
 5878        title: String,
 5879        cx: &mut AsyncWindowContext,
 5880    ) -> Result<()> {
 5881        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5882        cx.update(|_, cx| {
 5883            entries.sort_unstable_by_key(|(buffer, _)| {
 5884                buffer.read(cx).file().map(|f| f.path().clone())
 5885            });
 5886        })?;
 5887
 5888        // If the project transaction's edits are all contained within this editor, then
 5889        // avoid opening a new editor to display them.
 5890
 5891        if let Some((buffer, transaction)) = entries.first() {
 5892            if entries.len() == 1 {
 5893                let excerpt = this.update(cx, |editor, cx| {
 5894                    editor
 5895                        .buffer()
 5896                        .read(cx)
 5897                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5898                })?;
 5899                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5900                    if excerpted_buffer == *buffer {
 5901                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5902                            let excerpt_range = excerpt_range.to_offset(buffer);
 5903                            buffer
 5904                                .edited_ranges_for_transaction::<usize>(transaction)
 5905                                .all(|range| {
 5906                                    excerpt_range.start <= range.start
 5907                                        && excerpt_range.end >= range.end
 5908                                })
 5909                        })?;
 5910
 5911                        if all_edits_within_excerpt {
 5912                            return Ok(());
 5913                        }
 5914                    }
 5915                }
 5916            }
 5917        } else {
 5918            return Ok(());
 5919        }
 5920
 5921        let mut ranges_to_highlight = Vec::new();
 5922        let excerpt_buffer = cx.new(|cx| {
 5923            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5924            for (buffer_handle, transaction) in &entries {
 5925                let edited_ranges = buffer_handle
 5926                    .read(cx)
 5927                    .edited_ranges_for_transaction::<Point>(transaction)
 5928                    .collect::<Vec<_>>();
 5929                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5930                    PathKey::for_buffer(buffer_handle, cx),
 5931                    buffer_handle.clone(),
 5932                    edited_ranges,
 5933                    DEFAULT_MULTIBUFFER_CONTEXT,
 5934                    cx,
 5935                );
 5936
 5937                ranges_to_highlight.extend(ranges);
 5938            }
 5939            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5940            multibuffer
 5941        })?;
 5942
 5943        workspace.update_in(cx, |workspace, window, cx| {
 5944            let project = workspace.project().clone();
 5945            let editor =
 5946                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5947            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5948            editor.update(cx, |editor, cx| {
 5949                editor.highlight_background::<Self>(
 5950                    &ranges_to_highlight,
 5951                    |theme| theme.editor_highlighted_line_background,
 5952                    cx,
 5953                );
 5954            });
 5955        })?;
 5956
 5957        Ok(())
 5958    }
 5959
 5960    pub fn clear_code_action_providers(&mut self) {
 5961        self.code_action_providers.clear();
 5962        self.available_code_actions.take();
 5963    }
 5964
 5965    pub fn add_code_action_provider(
 5966        &mut self,
 5967        provider: Rc<dyn CodeActionProvider>,
 5968        window: &mut Window,
 5969        cx: &mut Context<Self>,
 5970    ) {
 5971        if self
 5972            .code_action_providers
 5973            .iter()
 5974            .any(|existing_provider| existing_provider.id() == provider.id())
 5975        {
 5976            return;
 5977        }
 5978
 5979        self.code_action_providers.push(provider);
 5980        self.refresh_code_actions(window, cx);
 5981    }
 5982
 5983    pub fn remove_code_action_provider(
 5984        &mut self,
 5985        id: Arc<str>,
 5986        window: &mut Window,
 5987        cx: &mut Context<Self>,
 5988    ) {
 5989        self.code_action_providers
 5990            .retain(|provider| provider.id() != id);
 5991        self.refresh_code_actions(window, cx);
 5992    }
 5993
 5994    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 5995        !self.code_action_providers.is_empty()
 5996            && EditorSettings::get_global(cx).toolbar.code_actions
 5997    }
 5998
 5999    pub fn has_available_code_actions(&self) -> bool {
 6000        self.available_code_actions
 6001            .as_ref()
 6002            .is_some_and(|(_, actions)| !actions.is_empty())
 6003    }
 6004
 6005    fn render_inline_code_actions(
 6006        &self,
 6007        icon_size: ui::IconSize,
 6008        display_row: DisplayRow,
 6009        is_active: bool,
 6010        cx: &mut Context<Self>,
 6011    ) -> AnyElement {
 6012        let show_tooltip = !self.context_menu_visible();
 6013        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6014            .icon_size(icon_size)
 6015            .shape(ui::IconButtonShape::Square)
 6016            .style(ButtonStyle::Transparent)
 6017            .icon_color(ui::Color::Hidden)
 6018            .toggle_state(is_active)
 6019            .when(show_tooltip, |this| {
 6020                this.tooltip({
 6021                    let focus_handle = self.focus_handle.clone();
 6022                    move |window, cx| {
 6023                        Tooltip::for_action_in(
 6024                            "Toggle Code Actions",
 6025                            &ToggleCodeActions {
 6026                                deployed_from: None,
 6027                                quick_launch: false,
 6028                            },
 6029                            &focus_handle,
 6030                            window,
 6031                            cx,
 6032                        )
 6033                    }
 6034                })
 6035            })
 6036            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6037                window.focus(&editor.focus_handle(cx));
 6038                editor.toggle_code_actions(
 6039                    &crate::actions::ToggleCodeActions {
 6040                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6041                            display_row,
 6042                        )),
 6043                        quick_launch: false,
 6044                    },
 6045                    window,
 6046                    cx,
 6047                );
 6048            }))
 6049            .into_any_element()
 6050    }
 6051
 6052    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6053        &self.context_menu
 6054    }
 6055
 6056    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6057        let newest_selection = self.selections.newest_anchor().clone();
 6058        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6059        let buffer = self.buffer.read(cx);
 6060        if newest_selection.head().diff_base_anchor.is_some() {
 6061            return None;
 6062        }
 6063        let (start_buffer, start) =
 6064            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6065        let (end_buffer, end) =
 6066            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6067        if start_buffer != end_buffer {
 6068            return None;
 6069        }
 6070
 6071        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6072            cx.background_executor()
 6073                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6074                .await;
 6075
 6076            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6077                let providers = this.code_action_providers.clone();
 6078                let tasks = this
 6079                    .code_action_providers
 6080                    .iter()
 6081                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6082                    .collect::<Vec<_>>();
 6083                (providers, tasks)
 6084            })?;
 6085
 6086            let mut actions = Vec::new();
 6087            for (provider, provider_actions) in
 6088                providers.into_iter().zip(future::join_all(tasks).await)
 6089            {
 6090                if let Some(provider_actions) = provider_actions.log_err() {
 6091                    actions.extend(provider_actions.into_iter().map(|action| {
 6092                        AvailableCodeAction {
 6093                            excerpt_id: newest_selection.start.excerpt_id,
 6094                            action,
 6095                            provider: provider.clone(),
 6096                        }
 6097                    }));
 6098                }
 6099            }
 6100
 6101            this.update(cx, |this, cx| {
 6102                this.available_code_actions = if actions.is_empty() {
 6103                    None
 6104                } else {
 6105                    Some((
 6106                        Location {
 6107                            buffer: start_buffer,
 6108                            range: start..end,
 6109                        },
 6110                        actions.into(),
 6111                    ))
 6112                };
 6113                cx.notify();
 6114            })
 6115        }));
 6116        None
 6117    }
 6118
 6119    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6120        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6121            self.show_git_blame_inline = false;
 6122
 6123            self.show_git_blame_inline_delay_task =
 6124                Some(cx.spawn_in(window, async move |this, cx| {
 6125                    cx.background_executor().timer(delay).await;
 6126
 6127                    this.update(cx, |this, cx| {
 6128                        this.show_git_blame_inline = true;
 6129                        cx.notify();
 6130                    })
 6131                    .log_err();
 6132                }));
 6133        }
 6134    }
 6135
 6136    fn show_blame_popover(
 6137        &mut self,
 6138        blame_entry: &BlameEntry,
 6139        position: gpui::Point<Pixels>,
 6140        cx: &mut Context<Self>,
 6141    ) {
 6142        if let Some(state) = &mut self.inline_blame_popover {
 6143            state.hide_task.take();
 6144            cx.notify();
 6145        } else {
 6146            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6147            let show_task = cx.spawn(async move |editor, cx| {
 6148                cx.background_executor()
 6149                    .timer(std::time::Duration::from_millis(delay))
 6150                    .await;
 6151                editor
 6152                    .update(cx, |editor, cx| {
 6153                        if let Some(state) = &mut editor.inline_blame_popover {
 6154                            state.show_task = None;
 6155                            cx.notify();
 6156                        }
 6157                    })
 6158                    .ok();
 6159            });
 6160            let Some(blame) = self.blame.as_ref() else {
 6161                return;
 6162            };
 6163            let blame = blame.read(cx);
 6164            let details = blame.details_for_entry(&blame_entry);
 6165            let markdown = cx.new(|cx| {
 6166                Markdown::new(
 6167                    details
 6168                        .as_ref()
 6169                        .map(|message| message.message.clone())
 6170                        .unwrap_or_default(),
 6171                    None,
 6172                    None,
 6173                    cx,
 6174                )
 6175            });
 6176            self.inline_blame_popover = Some(InlineBlamePopover {
 6177                position,
 6178                show_task: Some(show_task),
 6179                hide_task: None,
 6180                popover_bounds: None,
 6181                popover_state: InlineBlamePopoverState {
 6182                    scroll_handle: ScrollHandle::new(),
 6183                    commit_message: details,
 6184                    markdown,
 6185                },
 6186            });
 6187        }
 6188    }
 6189
 6190    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6191        if let Some(state) = &mut self.inline_blame_popover {
 6192            if state.show_task.is_some() {
 6193                self.inline_blame_popover.take();
 6194                cx.notify();
 6195            } else {
 6196                let hide_task = cx.spawn(async move |editor, cx| {
 6197                    cx.background_executor()
 6198                        .timer(std::time::Duration::from_millis(100))
 6199                        .await;
 6200                    editor
 6201                        .update(cx, |editor, cx| {
 6202                            editor.inline_blame_popover.take();
 6203                            cx.notify();
 6204                        })
 6205                        .ok();
 6206                });
 6207                state.hide_task = Some(hide_task);
 6208            }
 6209        }
 6210    }
 6211
 6212    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6213        if self.pending_rename.is_some() {
 6214            return None;
 6215        }
 6216
 6217        let provider = self.semantics_provider.clone()?;
 6218        let buffer = self.buffer.read(cx);
 6219        let newest_selection = self.selections.newest_anchor().clone();
 6220        let cursor_position = newest_selection.head();
 6221        let (cursor_buffer, cursor_buffer_position) =
 6222            buffer.text_anchor_for_position(cursor_position, cx)?;
 6223        let (tail_buffer, tail_buffer_position) =
 6224            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6225        if cursor_buffer != tail_buffer {
 6226            return None;
 6227        }
 6228
 6229        let snapshot = cursor_buffer.read(cx).snapshot();
 6230        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6231        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6232        if start_word_range != end_word_range {
 6233            self.document_highlights_task.take();
 6234            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6235            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6236            return None;
 6237        }
 6238
 6239        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6240        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6241            cx.background_executor()
 6242                .timer(Duration::from_millis(debounce))
 6243                .await;
 6244
 6245            let highlights = if let Some(highlights) = cx
 6246                .update(|cx| {
 6247                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6248                })
 6249                .ok()
 6250                .flatten()
 6251            {
 6252                highlights.await.log_err()
 6253            } else {
 6254                None
 6255            };
 6256
 6257            if let Some(highlights) = highlights {
 6258                this.update(cx, |this, cx| {
 6259                    if this.pending_rename.is_some() {
 6260                        return;
 6261                    }
 6262
 6263                    let buffer_id = cursor_position.buffer_id;
 6264                    let buffer = this.buffer.read(cx);
 6265                    if !buffer
 6266                        .text_anchor_for_position(cursor_position, cx)
 6267                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6268                    {
 6269                        return;
 6270                    }
 6271
 6272                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6273                    let mut write_ranges = Vec::new();
 6274                    let mut read_ranges = Vec::new();
 6275                    for highlight in highlights {
 6276                        for (excerpt_id, excerpt_range) in
 6277                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6278                        {
 6279                            let start = highlight
 6280                                .range
 6281                                .start
 6282                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6283                            let end = highlight
 6284                                .range
 6285                                .end
 6286                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6287                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6288                                continue;
 6289                            }
 6290
 6291                            let range = Anchor {
 6292                                buffer_id,
 6293                                excerpt_id,
 6294                                text_anchor: start,
 6295                                diff_base_anchor: None,
 6296                            }..Anchor {
 6297                                buffer_id,
 6298                                excerpt_id,
 6299                                text_anchor: end,
 6300                                diff_base_anchor: None,
 6301                            };
 6302                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6303                                write_ranges.push(range);
 6304                            } else {
 6305                                read_ranges.push(range);
 6306                            }
 6307                        }
 6308                    }
 6309
 6310                    this.highlight_background::<DocumentHighlightRead>(
 6311                        &read_ranges,
 6312                        |theme| theme.editor_document_highlight_read_background,
 6313                        cx,
 6314                    );
 6315                    this.highlight_background::<DocumentHighlightWrite>(
 6316                        &write_ranges,
 6317                        |theme| theme.editor_document_highlight_write_background,
 6318                        cx,
 6319                    );
 6320                    cx.notify();
 6321                })
 6322                .log_err();
 6323            }
 6324        }));
 6325        None
 6326    }
 6327
 6328    fn prepare_highlight_query_from_selection(
 6329        &mut self,
 6330        cx: &mut Context<Editor>,
 6331    ) -> Option<(String, Range<Anchor>)> {
 6332        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6333            return None;
 6334        }
 6335        if !EditorSettings::get_global(cx).selection_highlight {
 6336            return None;
 6337        }
 6338        if self.selections.count() != 1 || self.selections.line_mode {
 6339            return None;
 6340        }
 6341        let selection = self.selections.newest::<Point>(cx);
 6342        if selection.is_empty() || selection.start.row != selection.end.row {
 6343            return None;
 6344        }
 6345        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6346        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6347        let query = multi_buffer_snapshot
 6348            .text_for_range(selection_anchor_range.clone())
 6349            .collect::<String>();
 6350        if query.trim().is_empty() {
 6351            return None;
 6352        }
 6353        Some((query, selection_anchor_range))
 6354    }
 6355
 6356    fn update_selection_occurrence_highlights(
 6357        &mut self,
 6358        query_text: String,
 6359        query_range: Range<Anchor>,
 6360        multi_buffer_range_to_query: Range<Point>,
 6361        use_debounce: bool,
 6362        window: &mut Window,
 6363        cx: &mut Context<Editor>,
 6364    ) -> Task<()> {
 6365        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6366        cx.spawn_in(window, async move |editor, cx| {
 6367            if use_debounce {
 6368                cx.background_executor()
 6369                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6370                    .await;
 6371            }
 6372            let match_task = cx.background_spawn(async move {
 6373                let buffer_ranges = multi_buffer_snapshot
 6374                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6375                    .into_iter()
 6376                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6377                let mut match_ranges = Vec::new();
 6378                let Ok(regex) = project::search::SearchQuery::text(
 6379                    query_text.clone(),
 6380                    false,
 6381                    false,
 6382                    false,
 6383                    Default::default(),
 6384                    Default::default(),
 6385                    false,
 6386                    None,
 6387                ) else {
 6388                    return Vec::default();
 6389                };
 6390                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6391                    match_ranges.extend(
 6392                        regex
 6393                            .search(&buffer_snapshot, Some(search_range.clone()))
 6394                            .await
 6395                            .into_iter()
 6396                            .filter_map(|match_range| {
 6397                                let match_start = buffer_snapshot
 6398                                    .anchor_after(search_range.start + match_range.start);
 6399                                let match_end = buffer_snapshot
 6400                                    .anchor_before(search_range.start + match_range.end);
 6401                                let match_anchor_range = Anchor::range_in_buffer(
 6402                                    excerpt_id,
 6403                                    buffer_snapshot.remote_id(),
 6404                                    match_start..match_end,
 6405                                );
 6406                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6407                            }),
 6408                    );
 6409                }
 6410                match_ranges
 6411            });
 6412            let match_ranges = match_task.await;
 6413            editor
 6414                .update_in(cx, |editor, _, cx| {
 6415                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6416                    if !match_ranges.is_empty() {
 6417                        editor.highlight_background::<SelectedTextHighlight>(
 6418                            &match_ranges,
 6419                            |theme| theme.editor_document_highlight_bracket_background,
 6420                            cx,
 6421                        )
 6422                    }
 6423                })
 6424                .log_err();
 6425        })
 6426    }
 6427
 6428    fn refresh_selected_text_highlights(
 6429        &mut self,
 6430        on_buffer_edit: bool,
 6431        window: &mut Window,
 6432        cx: &mut Context<Editor>,
 6433    ) {
 6434        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6435        else {
 6436            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6437            self.quick_selection_highlight_task.take();
 6438            self.debounced_selection_highlight_task.take();
 6439            return;
 6440        };
 6441        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6442        if on_buffer_edit
 6443            || self
 6444                .quick_selection_highlight_task
 6445                .as_ref()
 6446                .map_or(true, |(prev_anchor_range, _)| {
 6447                    prev_anchor_range != &query_range
 6448                })
 6449        {
 6450            let multi_buffer_visible_start = self
 6451                .scroll_manager
 6452                .anchor()
 6453                .anchor
 6454                .to_point(&multi_buffer_snapshot);
 6455            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6456                multi_buffer_visible_start
 6457                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6458                Bias::Left,
 6459            );
 6460            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6461            self.quick_selection_highlight_task = Some((
 6462                query_range.clone(),
 6463                self.update_selection_occurrence_highlights(
 6464                    query_text.clone(),
 6465                    query_range.clone(),
 6466                    multi_buffer_visible_range,
 6467                    false,
 6468                    window,
 6469                    cx,
 6470                ),
 6471            ));
 6472        }
 6473        if on_buffer_edit
 6474            || self
 6475                .debounced_selection_highlight_task
 6476                .as_ref()
 6477                .map_or(true, |(prev_anchor_range, _)| {
 6478                    prev_anchor_range != &query_range
 6479                })
 6480        {
 6481            let multi_buffer_start = multi_buffer_snapshot
 6482                .anchor_before(0)
 6483                .to_point(&multi_buffer_snapshot);
 6484            let multi_buffer_end = multi_buffer_snapshot
 6485                .anchor_after(multi_buffer_snapshot.len())
 6486                .to_point(&multi_buffer_snapshot);
 6487            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6488            self.debounced_selection_highlight_task = Some((
 6489                query_range.clone(),
 6490                self.update_selection_occurrence_highlights(
 6491                    query_text,
 6492                    query_range,
 6493                    multi_buffer_full_range,
 6494                    true,
 6495                    window,
 6496                    cx,
 6497                ),
 6498            ));
 6499        }
 6500    }
 6501
 6502    pub fn refresh_inline_completion(
 6503        &mut self,
 6504        debounce: bool,
 6505        user_requested: bool,
 6506        window: &mut Window,
 6507        cx: &mut Context<Self>,
 6508    ) -> Option<()> {
 6509        let provider = self.edit_prediction_provider()?;
 6510        let cursor = self.selections.newest_anchor().head();
 6511        let (buffer, cursor_buffer_position) =
 6512            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6513
 6514        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6515            self.discard_inline_completion(false, cx);
 6516            return None;
 6517        }
 6518
 6519        if !user_requested
 6520            && (!self.should_show_edit_predictions()
 6521                || !self.is_focused(window)
 6522                || buffer.read(cx).is_empty())
 6523        {
 6524            self.discard_inline_completion(false, cx);
 6525            return None;
 6526        }
 6527
 6528        self.update_visible_inline_completion(window, cx);
 6529        provider.refresh(
 6530            self.project.clone(),
 6531            buffer,
 6532            cursor_buffer_position,
 6533            debounce,
 6534            cx,
 6535        );
 6536        Some(())
 6537    }
 6538
 6539    fn show_edit_predictions_in_menu(&self) -> bool {
 6540        match self.edit_prediction_settings {
 6541            EditPredictionSettings::Disabled => false,
 6542            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6543        }
 6544    }
 6545
 6546    pub fn edit_predictions_enabled(&self) -> bool {
 6547        match self.edit_prediction_settings {
 6548            EditPredictionSettings::Disabled => false,
 6549            EditPredictionSettings::Enabled { .. } => true,
 6550        }
 6551    }
 6552
 6553    fn edit_prediction_requires_modifier(&self) -> bool {
 6554        match self.edit_prediction_settings {
 6555            EditPredictionSettings::Disabled => false,
 6556            EditPredictionSettings::Enabled {
 6557                preview_requires_modifier,
 6558                ..
 6559            } => preview_requires_modifier,
 6560        }
 6561    }
 6562
 6563    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6564        if self.edit_prediction_provider.is_none() {
 6565            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6566        } else {
 6567            let selection = self.selections.newest_anchor();
 6568            let cursor = selection.head();
 6569
 6570            if let Some((buffer, cursor_buffer_position)) =
 6571                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6572            {
 6573                self.edit_prediction_settings =
 6574                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6575            }
 6576        }
 6577    }
 6578
 6579    fn edit_prediction_settings_at_position(
 6580        &self,
 6581        buffer: &Entity<Buffer>,
 6582        buffer_position: language::Anchor,
 6583        cx: &App,
 6584    ) -> EditPredictionSettings {
 6585        if !self.mode.is_full()
 6586            || !self.show_inline_completions_override.unwrap_or(true)
 6587            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6588        {
 6589            return EditPredictionSettings::Disabled;
 6590        }
 6591
 6592        let buffer = buffer.read(cx);
 6593
 6594        let file = buffer.file();
 6595
 6596        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6597            return EditPredictionSettings::Disabled;
 6598        };
 6599
 6600        let by_provider = matches!(
 6601            self.menu_inline_completions_policy,
 6602            MenuInlineCompletionsPolicy::ByProvider
 6603        );
 6604
 6605        let show_in_menu = by_provider
 6606            && self
 6607                .edit_prediction_provider
 6608                .as_ref()
 6609                .map_or(false, |provider| {
 6610                    provider.provider.show_completions_in_menu()
 6611                });
 6612
 6613        let preview_requires_modifier =
 6614            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6615
 6616        EditPredictionSettings::Enabled {
 6617            show_in_menu,
 6618            preview_requires_modifier,
 6619        }
 6620    }
 6621
 6622    fn should_show_edit_predictions(&self) -> bool {
 6623        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6624    }
 6625
 6626    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6627        matches!(
 6628            self.edit_prediction_preview,
 6629            EditPredictionPreview::Active { .. }
 6630        )
 6631    }
 6632
 6633    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6634        let cursor = self.selections.newest_anchor().head();
 6635        if let Some((buffer, cursor_position)) =
 6636            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6637        {
 6638            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6639        } else {
 6640            false
 6641        }
 6642    }
 6643
 6644    pub fn supports_minimap(&self, cx: &App) -> bool {
 6645        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6646    }
 6647
 6648    fn edit_predictions_enabled_in_buffer(
 6649        &self,
 6650        buffer: &Entity<Buffer>,
 6651        buffer_position: language::Anchor,
 6652        cx: &App,
 6653    ) -> bool {
 6654        maybe!({
 6655            if self.read_only(cx) {
 6656                return Some(false);
 6657            }
 6658            let provider = self.edit_prediction_provider()?;
 6659            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6660                return Some(false);
 6661            }
 6662            let buffer = buffer.read(cx);
 6663            let Some(file) = buffer.file() else {
 6664                return Some(true);
 6665            };
 6666            let settings = all_language_settings(Some(file), cx);
 6667            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6668        })
 6669        .unwrap_or(false)
 6670    }
 6671
 6672    fn cycle_inline_completion(
 6673        &mut self,
 6674        direction: Direction,
 6675        window: &mut Window,
 6676        cx: &mut Context<Self>,
 6677    ) -> Option<()> {
 6678        let provider = self.edit_prediction_provider()?;
 6679        let cursor = self.selections.newest_anchor().head();
 6680        let (buffer, cursor_buffer_position) =
 6681            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6682        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6683            return None;
 6684        }
 6685
 6686        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6687        self.update_visible_inline_completion(window, cx);
 6688
 6689        Some(())
 6690    }
 6691
 6692    pub fn show_inline_completion(
 6693        &mut self,
 6694        _: &ShowEditPrediction,
 6695        window: &mut Window,
 6696        cx: &mut Context<Self>,
 6697    ) {
 6698        if !self.has_active_inline_completion() {
 6699            self.refresh_inline_completion(false, true, window, cx);
 6700            return;
 6701        }
 6702
 6703        self.update_visible_inline_completion(window, cx);
 6704    }
 6705
 6706    pub fn display_cursor_names(
 6707        &mut self,
 6708        _: &DisplayCursorNames,
 6709        window: &mut Window,
 6710        cx: &mut Context<Self>,
 6711    ) {
 6712        self.show_cursor_names(window, cx);
 6713    }
 6714
 6715    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6716        self.show_cursor_names = true;
 6717        cx.notify();
 6718        cx.spawn_in(window, async move |this, cx| {
 6719            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6720            this.update(cx, |this, cx| {
 6721                this.show_cursor_names = false;
 6722                cx.notify()
 6723            })
 6724            .ok()
 6725        })
 6726        .detach();
 6727    }
 6728
 6729    pub fn next_edit_prediction(
 6730        &mut self,
 6731        _: &NextEditPrediction,
 6732        window: &mut Window,
 6733        cx: &mut Context<Self>,
 6734    ) {
 6735        if self.has_active_inline_completion() {
 6736            self.cycle_inline_completion(Direction::Next, window, cx);
 6737        } else {
 6738            let is_copilot_disabled = self
 6739                .refresh_inline_completion(false, true, window, cx)
 6740                .is_none();
 6741            if is_copilot_disabled {
 6742                cx.propagate();
 6743            }
 6744        }
 6745    }
 6746
 6747    pub fn previous_edit_prediction(
 6748        &mut self,
 6749        _: &PreviousEditPrediction,
 6750        window: &mut Window,
 6751        cx: &mut Context<Self>,
 6752    ) {
 6753        if self.has_active_inline_completion() {
 6754            self.cycle_inline_completion(Direction::Prev, window, cx);
 6755        } else {
 6756            let is_copilot_disabled = self
 6757                .refresh_inline_completion(false, true, window, cx)
 6758                .is_none();
 6759            if is_copilot_disabled {
 6760                cx.propagate();
 6761            }
 6762        }
 6763    }
 6764
 6765    pub fn accept_edit_prediction(
 6766        &mut self,
 6767        _: &AcceptEditPrediction,
 6768        window: &mut Window,
 6769        cx: &mut Context<Self>,
 6770    ) {
 6771        if self.show_edit_predictions_in_menu() {
 6772            self.hide_context_menu(window, cx);
 6773        }
 6774
 6775        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6776            return;
 6777        };
 6778
 6779        self.report_inline_completion_event(
 6780            active_inline_completion.completion_id.clone(),
 6781            true,
 6782            cx,
 6783        );
 6784
 6785        match &active_inline_completion.completion {
 6786            InlineCompletion::Move { target, .. } => {
 6787                let target = *target;
 6788
 6789                if let Some(position_map) = &self.last_position_map {
 6790                    if position_map
 6791                        .visible_row_range
 6792                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6793                        || !self.edit_prediction_requires_modifier()
 6794                    {
 6795                        self.unfold_ranges(&[target..target], true, false, cx);
 6796                        // Note that this is also done in vim's handler of the Tab action.
 6797                        self.change_selections(
 6798                            Some(Autoscroll::newest()),
 6799                            window,
 6800                            cx,
 6801                            |selections| {
 6802                                selections.select_anchor_ranges([target..target]);
 6803                            },
 6804                        );
 6805                        self.clear_row_highlights::<EditPredictionPreview>();
 6806
 6807                        self.edit_prediction_preview
 6808                            .set_previous_scroll_position(None);
 6809                    } else {
 6810                        self.edit_prediction_preview
 6811                            .set_previous_scroll_position(Some(
 6812                                position_map.snapshot.scroll_anchor,
 6813                            ));
 6814
 6815                        self.highlight_rows::<EditPredictionPreview>(
 6816                            target..target,
 6817                            cx.theme().colors().editor_highlighted_line_background,
 6818                            RowHighlightOptions {
 6819                                autoscroll: true,
 6820                                ..Default::default()
 6821                            },
 6822                            cx,
 6823                        );
 6824                        self.request_autoscroll(Autoscroll::fit(), cx);
 6825                    }
 6826                }
 6827            }
 6828            InlineCompletion::Edit { edits, .. } => {
 6829                if let Some(provider) = self.edit_prediction_provider() {
 6830                    provider.accept(cx);
 6831                }
 6832
 6833                // Store the transaction ID and selections before applying the edit
 6834                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6835
 6836                let snapshot = self.buffer.read(cx).snapshot(cx);
 6837                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6838
 6839                self.buffer.update(cx, |buffer, cx| {
 6840                    buffer.edit(edits.iter().cloned(), None, cx)
 6841                });
 6842
 6843                self.change_selections(None, window, cx, |s| {
 6844                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6845                });
 6846
 6847                let selections = self.selections.disjoint_anchors();
 6848                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6849                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6850                    if has_new_transaction {
 6851                        self.selection_history
 6852                            .insert_transaction(transaction_id_now, selections);
 6853                    }
 6854                }
 6855
 6856                self.update_visible_inline_completion(window, cx);
 6857                if self.active_inline_completion.is_none() {
 6858                    self.refresh_inline_completion(true, true, window, cx);
 6859                }
 6860
 6861                cx.notify();
 6862            }
 6863        }
 6864
 6865        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6866    }
 6867
 6868    pub fn accept_partial_inline_completion(
 6869        &mut self,
 6870        _: &AcceptPartialEditPrediction,
 6871        window: &mut Window,
 6872        cx: &mut Context<Self>,
 6873    ) {
 6874        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6875            return;
 6876        };
 6877        if self.selections.count() != 1 {
 6878            return;
 6879        }
 6880
 6881        self.report_inline_completion_event(
 6882            active_inline_completion.completion_id.clone(),
 6883            true,
 6884            cx,
 6885        );
 6886
 6887        match &active_inline_completion.completion {
 6888            InlineCompletion::Move { target, .. } => {
 6889                let target = *target;
 6890                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6891                    selections.select_anchor_ranges([target..target]);
 6892                });
 6893            }
 6894            InlineCompletion::Edit { edits, .. } => {
 6895                // Find an insertion that starts at the cursor position.
 6896                let snapshot = self.buffer.read(cx).snapshot(cx);
 6897                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6898                let insertion = edits.iter().find_map(|(range, text)| {
 6899                    let range = range.to_offset(&snapshot);
 6900                    if range.is_empty() && range.start == cursor_offset {
 6901                        Some(text)
 6902                    } else {
 6903                        None
 6904                    }
 6905                });
 6906
 6907                if let Some(text) = insertion {
 6908                    let mut partial_completion = text
 6909                        .chars()
 6910                        .by_ref()
 6911                        .take_while(|c| c.is_alphabetic())
 6912                        .collect::<String>();
 6913                    if partial_completion.is_empty() {
 6914                        partial_completion = text
 6915                            .chars()
 6916                            .by_ref()
 6917                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6918                            .collect::<String>();
 6919                    }
 6920
 6921                    cx.emit(EditorEvent::InputHandled {
 6922                        utf16_range_to_replace: None,
 6923                        text: partial_completion.clone().into(),
 6924                    });
 6925
 6926                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6927
 6928                    self.refresh_inline_completion(true, true, window, cx);
 6929                    cx.notify();
 6930                } else {
 6931                    self.accept_edit_prediction(&Default::default(), window, cx);
 6932                }
 6933            }
 6934        }
 6935    }
 6936
 6937    fn discard_inline_completion(
 6938        &mut self,
 6939        should_report_inline_completion_event: bool,
 6940        cx: &mut Context<Self>,
 6941    ) -> bool {
 6942        if should_report_inline_completion_event {
 6943            let completion_id = self
 6944                .active_inline_completion
 6945                .as_ref()
 6946                .and_then(|active_completion| active_completion.completion_id.clone());
 6947
 6948            self.report_inline_completion_event(completion_id, false, cx);
 6949        }
 6950
 6951        if let Some(provider) = self.edit_prediction_provider() {
 6952            provider.discard(cx);
 6953        }
 6954
 6955        self.take_active_inline_completion(cx)
 6956    }
 6957
 6958    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6959        let Some(provider) = self.edit_prediction_provider() else {
 6960            return;
 6961        };
 6962
 6963        let Some((_, buffer, _)) = self
 6964            .buffer
 6965            .read(cx)
 6966            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6967        else {
 6968            return;
 6969        };
 6970
 6971        let extension = buffer
 6972            .read(cx)
 6973            .file()
 6974            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6975
 6976        let event_type = match accepted {
 6977            true => "Edit Prediction Accepted",
 6978            false => "Edit Prediction Discarded",
 6979        };
 6980        telemetry::event!(
 6981            event_type,
 6982            provider = provider.name(),
 6983            prediction_id = id,
 6984            suggestion_accepted = accepted,
 6985            file_extension = extension,
 6986        );
 6987    }
 6988
 6989    pub fn has_active_inline_completion(&self) -> bool {
 6990        self.active_inline_completion.is_some()
 6991    }
 6992
 6993    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6994        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6995            return false;
 6996        };
 6997
 6998        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6999        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7000        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7001        true
 7002    }
 7003
 7004    /// Returns true when we're displaying the edit prediction popover below the cursor
 7005    /// like we are not previewing and the LSP autocomplete menu is visible
 7006    /// or we are in `when_holding_modifier` mode.
 7007    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7008        if self.edit_prediction_preview_is_active()
 7009            || !self.show_edit_predictions_in_menu()
 7010            || !self.edit_predictions_enabled()
 7011        {
 7012            return false;
 7013        }
 7014
 7015        if self.has_visible_completions_menu() {
 7016            return true;
 7017        }
 7018
 7019        has_completion && self.edit_prediction_requires_modifier()
 7020    }
 7021
 7022    fn handle_modifiers_changed(
 7023        &mut self,
 7024        modifiers: Modifiers,
 7025        position_map: &PositionMap,
 7026        window: &mut Window,
 7027        cx: &mut Context<Self>,
 7028    ) {
 7029        if self.show_edit_predictions_in_menu() {
 7030            self.update_edit_prediction_preview(&modifiers, window, cx);
 7031        }
 7032
 7033        self.update_selection_mode(&modifiers, position_map, window, cx);
 7034
 7035        let mouse_position = window.mouse_position();
 7036        if !position_map.text_hitbox.is_hovered(window) {
 7037            return;
 7038        }
 7039
 7040        self.update_hovered_link(
 7041            position_map.point_for_position(mouse_position),
 7042            &position_map.snapshot,
 7043            modifiers,
 7044            window,
 7045            cx,
 7046        )
 7047    }
 7048
 7049    fn update_selection_mode(
 7050        &mut self,
 7051        modifiers: &Modifiers,
 7052        position_map: &PositionMap,
 7053        window: &mut Window,
 7054        cx: &mut Context<Self>,
 7055    ) {
 7056        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 7057            return;
 7058        }
 7059
 7060        let mouse_position = window.mouse_position();
 7061        let point_for_position = position_map.point_for_position(mouse_position);
 7062        let position = point_for_position.previous_valid;
 7063
 7064        self.select(
 7065            SelectPhase::BeginColumnar {
 7066                position,
 7067                reset: false,
 7068                goal_column: point_for_position.exact_unclipped.column(),
 7069            },
 7070            window,
 7071            cx,
 7072        );
 7073    }
 7074
 7075    fn update_edit_prediction_preview(
 7076        &mut self,
 7077        modifiers: &Modifiers,
 7078        window: &mut Window,
 7079        cx: &mut Context<Self>,
 7080    ) {
 7081        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 7082        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 7083            return;
 7084        };
 7085
 7086        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 7087            if matches!(
 7088                self.edit_prediction_preview,
 7089                EditPredictionPreview::Inactive { .. }
 7090            ) {
 7091                self.edit_prediction_preview = EditPredictionPreview::Active {
 7092                    previous_scroll_position: None,
 7093                    since: Instant::now(),
 7094                };
 7095
 7096                self.update_visible_inline_completion(window, cx);
 7097                cx.notify();
 7098            }
 7099        } else if let EditPredictionPreview::Active {
 7100            previous_scroll_position,
 7101            since,
 7102        } = self.edit_prediction_preview
 7103        {
 7104            if let (Some(previous_scroll_position), Some(position_map)) =
 7105                (previous_scroll_position, self.last_position_map.as_ref())
 7106            {
 7107                self.set_scroll_position(
 7108                    previous_scroll_position
 7109                        .scroll_position(&position_map.snapshot.display_snapshot),
 7110                    window,
 7111                    cx,
 7112                );
 7113            }
 7114
 7115            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7116                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7117            };
 7118            self.clear_row_highlights::<EditPredictionPreview>();
 7119            self.update_visible_inline_completion(window, cx);
 7120            cx.notify();
 7121        }
 7122    }
 7123
 7124    fn update_visible_inline_completion(
 7125        &mut self,
 7126        _window: &mut Window,
 7127        cx: &mut Context<Self>,
 7128    ) -> Option<()> {
 7129        let selection = self.selections.newest_anchor();
 7130        let cursor = selection.head();
 7131        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7132        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7133        let excerpt_id = cursor.excerpt_id;
 7134
 7135        let show_in_menu = self.show_edit_predictions_in_menu();
 7136        let completions_menu_has_precedence = !show_in_menu
 7137            && (self.context_menu.borrow().is_some()
 7138                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7139
 7140        if completions_menu_has_precedence
 7141            || !offset_selection.is_empty()
 7142            || self
 7143                .active_inline_completion
 7144                .as_ref()
 7145                .map_or(false, |completion| {
 7146                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7147                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7148                    !invalidation_range.contains(&offset_selection.head())
 7149                })
 7150        {
 7151            self.discard_inline_completion(false, cx);
 7152            return None;
 7153        }
 7154
 7155        self.take_active_inline_completion(cx);
 7156        let Some(provider) = self.edit_prediction_provider() else {
 7157            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7158            return None;
 7159        };
 7160
 7161        let (buffer, cursor_buffer_position) =
 7162            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7163
 7164        self.edit_prediction_settings =
 7165            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7166
 7167        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7168
 7169        if self.edit_prediction_indent_conflict {
 7170            let cursor_point = cursor.to_point(&multibuffer);
 7171
 7172            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7173
 7174            if let Some((_, indent)) = indents.iter().next() {
 7175                if indent.len == cursor_point.column {
 7176                    self.edit_prediction_indent_conflict = false;
 7177                }
 7178            }
 7179        }
 7180
 7181        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7182        let edits = inline_completion
 7183            .edits
 7184            .into_iter()
 7185            .flat_map(|(range, new_text)| {
 7186                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7187                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7188                Some((start..end, new_text))
 7189            })
 7190            .collect::<Vec<_>>();
 7191        if edits.is_empty() {
 7192            return None;
 7193        }
 7194
 7195        let first_edit_start = edits.first().unwrap().0.start;
 7196        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7197        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7198
 7199        let last_edit_end = edits.last().unwrap().0.end;
 7200        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7201        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7202
 7203        let cursor_row = cursor.to_point(&multibuffer).row;
 7204
 7205        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7206
 7207        let mut inlay_ids = Vec::new();
 7208        let invalidation_row_range;
 7209        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7210            Some(cursor_row..edit_end_row)
 7211        } else if cursor_row > edit_end_row {
 7212            Some(edit_start_row..cursor_row)
 7213        } else {
 7214            None
 7215        };
 7216        let is_move =
 7217            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7218        let completion = if is_move {
 7219            invalidation_row_range =
 7220                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7221            let target = first_edit_start;
 7222            InlineCompletion::Move { target, snapshot }
 7223        } else {
 7224            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7225                && !self.inline_completions_hidden_for_vim_mode;
 7226
 7227            if show_completions_in_buffer {
 7228                if edits
 7229                    .iter()
 7230                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7231                {
 7232                    let mut inlays = Vec::new();
 7233                    for (range, new_text) in &edits {
 7234                        let inlay = Inlay::inline_completion(
 7235                            post_inc(&mut self.next_inlay_id),
 7236                            range.start,
 7237                            new_text.as_str(),
 7238                        );
 7239                        inlay_ids.push(inlay.id);
 7240                        inlays.push(inlay);
 7241                    }
 7242
 7243                    self.splice_inlays(&[], inlays, cx);
 7244                } else {
 7245                    let background_color = cx.theme().status().deleted_background;
 7246                    self.highlight_text::<InlineCompletionHighlight>(
 7247                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7248                        HighlightStyle {
 7249                            background_color: Some(background_color),
 7250                            ..Default::default()
 7251                        },
 7252                        cx,
 7253                    );
 7254                }
 7255            }
 7256
 7257            invalidation_row_range = edit_start_row..edit_end_row;
 7258
 7259            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7260                if provider.show_tab_accept_marker() {
 7261                    EditDisplayMode::TabAccept
 7262                } else {
 7263                    EditDisplayMode::Inline
 7264                }
 7265            } else {
 7266                EditDisplayMode::DiffPopover
 7267            };
 7268
 7269            InlineCompletion::Edit {
 7270                edits,
 7271                edit_preview: inline_completion.edit_preview,
 7272                display_mode,
 7273                snapshot,
 7274            }
 7275        };
 7276
 7277        let invalidation_range = multibuffer
 7278            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7279            ..multibuffer.anchor_after(Point::new(
 7280                invalidation_row_range.end,
 7281                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7282            ));
 7283
 7284        self.stale_inline_completion_in_menu = None;
 7285        self.active_inline_completion = Some(InlineCompletionState {
 7286            inlay_ids,
 7287            completion,
 7288            completion_id: inline_completion.id,
 7289            invalidation_range,
 7290        });
 7291
 7292        cx.notify();
 7293
 7294        Some(())
 7295    }
 7296
 7297    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7298        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7299    }
 7300
 7301    fn clear_tasks(&mut self) {
 7302        self.tasks.clear()
 7303    }
 7304
 7305    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7306        if self.tasks.insert(key, value).is_some() {
 7307            // This case should hopefully be rare, but just in case...
 7308            log::error!(
 7309                "multiple different run targets found on a single line, only the last target will be rendered"
 7310            )
 7311        }
 7312    }
 7313
 7314    /// Get all display points of breakpoints that will be rendered within editor
 7315    ///
 7316    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7317    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7318    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7319    fn active_breakpoints(
 7320        &self,
 7321        range: Range<DisplayRow>,
 7322        window: &mut Window,
 7323        cx: &mut Context<Self>,
 7324    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7325        let mut breakpoint_display_points = HashMap::default();
 7326
 7327        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7328            return breakpoint_display_points;
 7329        };
 7330
 7331        let snapshot = self.snapshot(window, cx);
 7332
 7333        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7334        let Some(project) = self.project.as_ref() else {
 7335            return breakpoint_display_points;
 7336        };
 7337
 7338        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7339            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7340
 7341        for (buffer_snapshot, range, excerpt_id) in
 7342            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7343        {
 7344            let Some(buffer) = project
 7345                .read(cx)
 7346                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7347            else {
 7348                continue;
 7349            };
 7350            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7351                &buffer,
 7352                Some(
 7353                    buffer_snapshot.anchor_before(range.start)
 7354                        ..buffer_snapshot.anchor_after(range.end),
 7355                ),
 7356                buffer_snapshot,
 7357                cx,
 7358            );
 7359            for (breakpoint, state) in breakpoints {
 7360                let multi_buffer_anchor =
 7361                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7362                let position = multi_buffer_anchor
 7363                    .to_point(&multi_buffer_snapshot)
 7364                    .to_display_point(&snapshot);
 7365
 7366                breakpoint_display_points.insert(
 7367                    position.row(),
 7368                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7369                );
 7370            }
 7371        }
 7372
 7373        breakpoint_display_points
 7374    }
 7375
 7376    fn breakpoint_context_menu(
 7377        &self,
 7378        anchor: Anchor,
 7379        window: &mut Window,
 7380        cx: &mut Context<Self>,
 7381    ) -> Entity<ui::ContextMenu> {
 7382        let weak_editor = cx.weak_entity();
 7383        let focus_handle = self.focus_handle(cx);
 7384
 7385        let row = self
 7386            .buffer
 7387            .read(cx)
 7388            .snapshot(cx)
 7389            .summary_for_anchor::<Point>(&anchor)
 7390            .row;
 7391
 7392        let breakpoint = self
 7393            .breakpoint_at_row(row, window, cx)
 7394            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7395
 7396        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7397            "Edit Log Breakpoint"
 7398        } else {
 7399            "Set Log Breakpoint"
 7400        };
 7401
 7402        let condition_breakpoint_msg = if breakpoint
 7403            .as_ref()
 7404            .is_some_and(|bp| bp.1.condition.is_some())
 7405        {
 7406            "Edit Condition Breakpoint"
 7407        } else {
 7408            "Set Condition Breakpoint"
 7409        };
 7410
 7411        let hit_condition_breakpoint_msg = if breakpoint
 7412            .as_ref()
 7413            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7414        {
 7415            "Edit Hit Condition Breakpoint"
 7416        } else {
 7417            "Set Hit Condition Breakpoint"
 7418        };
 7419
 7420        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7421            "Unset Breakpoint"
 7422        } else {
 7423            "Set Breakpoint"
 7424        };
 7425
 7426        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7427            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7428
 7429        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7430            BreakpointState::Enabled => Some("Disable"),
 7431            BreakpointState::Disabled => Some("Enable"),
 7432        });
 7433
 7434        let (anchor, breakpoint) =
 7435            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7436
 7437        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7438            menu.on_blur_subscription(Subscription::new(|| {}))
 7439                .context(focus_handle)
 7440                .when(run_to_cursor, |this| {
 7441                    let weak_editor = weak_editor.clone();
 7442                    this.entry("Run to cursor", None, move |window, cx| {
 7443                        weak_editor
 7444                            .update(cx, |editor, cx| {
 7445                                editor.change_selections(None, window, cx, |s| {
 7446                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7447                                });
 7448                            })
 7449                            .ok();
 7450
 7451                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7452                    })
 7453                    .separator()
 7454                })
 7455                .when_some(toggle_state_msg, |this, msg| {
 7456                    this.entry(msg, None, {
 7457                        let weak_editor = weak_editor.clone();
 7458                        let breakpoint = breakpoint.clone();
 7459                        move |_window, cx| {
 7460                            weak_editor
 7461                                .update(cx, |this, cx| {
 7462                                    this.edit_breakpoint_at_anchor(
 7463                                        anchor,
 7464                                        breakpoint.as_ref().clone(),
 7465                                        BreakpointEditAction::InvertState,
 7466                                        cx,
 7467                                    );
 7468                                })
 7469                                .log_err();
 7470                        }
 7471                    })
 7472                })
 7473                .entry(set_breakpoint_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::Toggle,
 7483                                    cx,
 7484                                );
 7485                            })
 7486                            .log_err();
 7487                    }
 7488                })
 7489                .entry(log_breakpoint_msg, None, {
 7490                    let breakpoint = breakpoint.clone();
 7491                    let weak_editor = weak_editor.clone();
 7492                    move |window, cx| {
 7493                        weak_editor
 7494                            .update(cx, |this, cx| {
 7495                                this.add_edit_breakpoint_block(
 7496                                    anchor,
 7497                                    breakpoint.as_ref(),
 7498                                    BreakpointPromptEditAction::Log,
 7499                                    window,
 7500                                    cx,
 7501                                );
 7502                            })
 7503                            .log_err();
 7504                    }
 7505                })
 7506                .entry(condition_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::Condition,
 7516                                    window,
 7517                                    cx,
 7518                                );
 7519                            })
 7520                            .log_err();
 7521                    }
 7522                })
 7523                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7524                    weak_editor
 7525                        .update(cx, |this, cx| {
 7526                            this.add_edit_breakpoint_block(
 7527                                anchor,
 7528                                breakpoint.as_ref(),
 7529                                BreakpointPromptEditAction::HitCondition,
 7530                                window,
 7531                                cx,
 7532                            );
 7533                        })
 7534                        .log_err();
 7535                })
 7536        })
 7537    }
 7538
 7539    fn render_breakpoint(
 7540        &self,
 7541        position: Anchor,
 7542        row: DisplayRow,
 7543        breakpoint: &Breakpoint,
 7544        state: Option<BreakpointSessionState>,
 7545        cx: &mut Context<Self>,
 7546    ) -> IconButton {
 7547        let is_rejected = state.is_some_and(|s| !s.verified);
 7548        // Is it a breakpoint that shows up when hovering over gutter?
 7549        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7550            (false, false),
 7551            |PhantomBreakpointIndicator {
 7552                 is_active,
 7553                 display_row,
 7554                 collides_with_existing_breakpoint,
 7555             }| {
 7556                (
 7557                    is_active && display_row == row,
 7558                    collides_with_existing_breakpoint,
 7559                )
 7560            },
 7561        );
 7562
 7563        let (color, icon) = {
 7564            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7565                (false, false) => ui::IconName::DebugBreakpoint,
 7566                (true, false) => ui::IconName::DebugLogBreakpoint,
 7567                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7568                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7569            };
 7570
 7571            let color = if is_phantom {
 7572                Color::Hint
 7573            } else if is_rejected {
 7574                Color::Disabled
 7575            } else {
 7576                Color::Debugger
 7577            };
 7578
 7579            (color, icon)
 7580        };
 7581
 7582        let breakpoint = Arc::from(breakpoint.clone());
 7583
 7584        let alt_as_text = gpui::Keystroke {
 7585            modifiers: Modifiers::secondary_key(),
 7586            ..Default::default()
 7587        };
 7588        let primary_action_text = if breakpoint.is_disabled() {
 7589            "Enable breakpoint"
 7590        } else if is_phantom && !collides_with_existing {
 7591            "Set breakpoint"
 7592        } else {
 7593            "Unset breakpoint"
 7594        };
 7595        let focus_handle = self.focus_handle.clone();
 7596
 7597        let meta = if is_rejected {
 7598            SharedString::from("No executable code is associated with this line.")
 7599        } else if collides_with_existing && !breakpoint.is_disabled() {
 7600            SharedString::from(format!(
 7601                "{alt_as_text}-click to disable,\nright-click for more options."
 7602            ))
 7603        } else {
 7604            SharedString::from("Right-click for more options.")
 7605        };
 7606        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7607            .icon_size(IconSize::XSmall)
 7608            .size(ui::ButtonSize::None)
 7609            .when(is_rejected, |this| {
 7610                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7611            })
 7612            .icon_color(color)
 7613            .style(ButtonStyle::Transparent)
 7614            .on_click(cx.listener({
 7615                let breakpoint = breakpoint.clone();
 7616
 7617                move |editor, event: &ClickEvent, window, cx| {
 7618                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7619                        BreakpointEditAction::InvertState
 7620                    } else {
 7621                        BreakpointEditAction::Toggle
 7622                    };
 7623
 7624                    window.focus(&editor.focus_handle(cx));
 7625                    editor.edit_breakpoint_at_anchor(
 7626                        position,
 7627                        breakpoint.as_ref().clone(),
 7628                        edit_action,
 7629                        cx,
 7630                    );
 7631                }
 7632            }))
 7633            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7634                editor.set_breakpoint_context_menu(
 7635                    row,
 7636                    Some(position),
 7637                    event.down.position,
 7638                    window,
 7639                    cx,
 7640                );
 7641            }))
 7642            .tooltip(move |window, cx| {
 7643                Tooltip::with_meta_in(
 7644                    primary_action_text,
 7645                    Some(&ToggleBreakpoint),
 7646                    meta.clone(),
 7647                    &focus_handle,
 7648                    window,
 7649                    cx,
 7650                )
 7651            })
 7652    }
 7653
 7654    fn build_tasks_context(
 7655        project: &Entity<Project>,
 7656        buffer: &Entity<Buffer>,
 7657        buffer_row: u32,
 7658        tasks: &Arc<RunnableTasks>,
 7659        cx: &mut Context<Self>,
 7660    ) -> Task<Option<task::TaskContext>> {
 7661        let position = Point::new(buffer_row, tasks.column);
 7662        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7663        let location = Location {
 7664            buffer: buffer.clone(),
 7665            range: range_start..range_start,
 7666        };
 7667        // Fill in the environmental variables from the tree-sitter captures
 7668        let mut captured_task_variables = TaskVariables::default();
 7669        for (capture_name, value) in tasks.extra_variables.clone() {
 7670            captured_task_variables.insert(
 7671                task::VariableName::Custom(capture_name.into()),
 7672                value.clone(),
 7673            );
 7674        }
 7675        project.update(cx, |project, cx| {
 7676            project.task_store().update(cx, |task_store, cx| {
 7677                task_store.task_context_for_location(captured_task_variables, location, cx)
 7678            })
 7679        })
 7680    }
 7681
 7682    pub fn spawn_nearest_task(
 7683        &mut self,
 7684        action: &SpawnNearestTask,
 7685        window: &mut Window,
 7686        cx: &mut Context<Self>,
 7687    ) {
 7688        let Some((workspace, _)) = self.workspace.clone() else {
 7689            return;
 7690        };
 7691        let Some(project) = self.project.clone() else {
 7692            return;
 7693        };
 7694
 7695        // Try to find a closest, enclosing node using tree-sitter that has a
 7696        // task
 7697        let Some((buffer, buffer_row, tasks)) = self
 7698            .find_enclosing_node_task(cx)
 7699            // Or find the task that's closest in row-distance.
 7700            .or_else(|| self.find_closest_task(cx))
 7701        else {
 7702            return;
 7703        };
 7704
 7705        let reveal_strategy = action.reveal;
 7706        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7707        cx.spawn_in(window, async move |_, cx| {
 7708            let context = task_context.await?;
 7709            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7710
 7711            let resolved = &mut resolved_task.resolved;
 7712            resolved.reveal = reveal_strategy;
 7713
 7714            workspace
 7715                .update_in(cx, |workspace, window, cx| {
 7716                    workspace.schedule_resolved_task(
 7717                        task_source_kind,
 7718                        resolved_task,
 7719                        false,
 7720                        window,
 7721                        cx,
 7722                    );
 7723                })
 7724                .ok()
 7725        })
 7726        .detach();
 7727    }
 7728
 7729    fn find_closest_task(
 7730        &mut self,
 7731        cx: &mut Context<Self>,
 7732    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7733        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7734
 7735        let ((buffer_id, row), tasks) = self
 7736            .tasks
 7737            .iter()
 7738            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7739
 7740        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7741        let tasks = Arc::new(tasks.to_owned());
 7742        Some((buffer, *row, tasks))
 7743    }
 7744
 7745    fn find_enclosing_node_task(
 7746        &mut self,
 7747        cx: &mut Context<Self>,
 7748    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7749        let snapshot = self.buffer.read(cx).snapshot(cx);
 7750        let offset = self.selections.newest::<usize>(cx).head();
 7751        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7752        let buffer_id = excerpt.buffer().remote_id();
 7753
 7754        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7755        let mut cursor = layer.node().walk();
 7756
 7757        while cursor.goto_first_child_for_byte(offset).is_some() {
 7758            if cursor.node().end_byte() == offset {
 7759                cursor.goto_next_sibling();
 7760            }
 7761        }
 7762
 7763        // Ascend to the smallest ancestor that contains the range and has a task.
 7764        loop {
 7765            let node = cursor.node();
 7766            let node_range = node.byte_range();
 7767            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7768
 7769            // Check if this node contains our offset
 7770            if node_range.start <= offset && node_range.end >= offset {
 7771                // If it contains offset, check for task
 7772                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7773                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7774                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7775                }
 7776            }
 7777
 7778            if !cursor.goto_parent() {
 7779                break;
 7780            }
 7781        }
 7782        None
 7783    }
 7784
 7785    fn render_run_indicator(
 7786        &self,
 7787        _style: &EditorStyle,
 7788        is_active: bool,
 7789        row: DisplayRow,
 7790        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7791        cx: &mut Context<Self>,
 7792    ) -> IconButton {
 7793        let color = Color::Muted;
 7794        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7795
 7796        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7797            .shape(ui::IconButtonShape::Square)
 7798            .icon_size(IconSize::XSmall)
 7799            .icon_color(color)
 7800            .toggle_state(is_active)
 7801            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7802                let quick_launch = e.down.button == MouseButton::Left;
 7803                window.focus(&editor.focus_handle(cx));
 7804                editor.toggle_code_actions(
 7805                    &ToggleCodeActions {
 7806                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7807                        quick_launch,
 7808                    },
 7809                    window,
 7810                    cx,
 7811                );
 7812            }))
 7813            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7814                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7815            }))
 7816    }
 7817
 7818    pub fn context_menu_visible(&self) -> bool {
 7819        !self.edit_prediction_preview_is_active()
 7820            && self
 7821                .context_menu
 7822                .borrow()
 7823                .as_ref()
 7824                .map_or(false, |menu| menu.visible())
 7825    }
 7826
 7827    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7828        self.context_menu
 7829            .borrow()
 7830            .as_ref()
 7831            .map(|menu| menu.origin())
 7832    }
 7833
 7834    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7835        self.context_menu_options = Some(options);
 7836    }
 7837
 7838    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7839    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7840
 7841    fn render_edit_prediction_popover(
 7842        &mut self,
 7843        text_bounds: &Bounds<Pixels>,
 7844        content_origin: gpui::Point<Pixels>,
 7845        right_margin: Pixels,
 7846        editor_snapshot: &EditorSnapshot,
 7847        visible_row_range: Range<DisplayRow>,
 7848        scroll_top: f32,
 7849        scroll_bottom: f32,
 7850        line_layouts: &[LineWithInvisibles],
 7851        line_height: Pixels,
 7852        scroll_pixel_position: gpui::Point<Pixels>,
 7853        newest_selection_head: Option<DisplayPoint>,
 7854        editor_width: Pixels,
 7855        style: &EditorStyle,
 7856        window: &mut Window,
 7857        cx: &mut App,
 7858    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7859        if self.mode().is_minimap() {
 7860            return None;
 7861        }
 7862        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7863
 7864        if self.edit_prediction_visible_in_cursor_popover(true) {
 7865            return None;
 7866        }
 7867
 7868        match &active_inline_completion.completion {
 7869            InlineCompletion::Move { target, .. } => {
 7870                let target_display_point = target.to_display_point(editor_snapshot);
 7871
 7872                if self.edit_prediction_requires_modifier() {
 7873                    if !self.edit_prediction_preview_is_active() {
 7874                        return None;
 7875                    }
 7876
 7877                    self.render_edit_prediction_modifier_jump_popover(
 7878                        text_bounds,
 7879                        content_origin,
 7880                        visible_row_range,
 7881                        line_layouts,
 7882                        line_height,
 7883                        scroll_pixel_position,
 7884                        newest_selection_head,
 7885                        target_display_point,
 7886                        window,
 7887                        cx,
 7888                    )
 7889                } else {
 7890                    self.render_edit_prediction_eager_jump_popover(
 7891                        text_bounds,
 7892                        content_origin,
 7893                        editor_snapshot,
 7894                        visible_row_range,
 7895                        scroll_top,
 7896                        scroll_bottom,
 7897                        line_height,
 7898                        scroll_pixel_position,
 7899                        target_display_point,
 7900                        editor_width,
 7901                        window,
 7902                        cx,
 7903                    )
 7904                }
 7905            }
 7906            InlineCompletion::Edit {
 7907                display_mode: EditDisplayMode::Inline,
 7908                ..
 7909            } => None,
 7910            InlineCompletion::Edit {
 7911                display_mode: EditDisplayMode::TabAccept,
 7912                edits,
 7913                ..
 7914            } => {
 7915                let range = &edits.first()?.0;
 7916                let target_display_point = range.end.to_display_point(editor_snapshot);
 7917
 7918                self.render_edit_prediction_end_of_line_popover(
 7919                    "Accept",
 7920                    editor_snapshot,
 7921                    visible_row_range,
 7922                    target_display_point,
 7923                    line_height,
 7924                    scroll_pixel_position,
 7925                    content_origin,
 7926                    editor_width,
 7927                    window,
 7928                    cx,
 7929                )
 7930            }
 7931            InlineCompletion::Edit {
 7932                edits,
 7933                edit_preview,
 7934                display_mode: EditDisplayMode::DiffPopover,
 7935                snapshot,
 7936            } => self.render_edit_prediction_diff_popover(
 7937                text_bounds,
 7938                content_origin,
 7939                right_margin,
 7940                editor_snapshot,
 7941                visible_row_range,
 7942                line_layouts,
 7943                line_height,
 7944                scroll_pixel_position,
 7945                newest_selection_head,
 7946                editor_width,
 7947                style,
 7948                edits,
 7949                edit_preview,
 7950                snapshot,
 7951                window,
 7952                cx,
 7953            ),
 7954        }
 7955    }
 7956
 7957    fn render_edit_prediction_modifier_jump_popover(
 7958        &mut self,
 7959        text_bounds: &Bounds<Pixels>,
 7960        content_origin: gpui::Point<Pixels>,
 7961        visible_row_range: Range<DisplayRow>,
 7962        line_layouts: &[LineWithInvisibles],
 7963        line_height: Pixels,
 7964        scroll_pixel_position: gpui::Point<Pixels>,
 7965        newest_selection_head: Option<DisplayPoint>,
 7966        target_display_point: DisplayPoint,
 7967        window: &mut Window,
 7968        cx: &mut App,
 7969    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7970        let scrolled_content_origin =
 7971            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7972
 7973        const SCROLL_PADDING_Y: Pixels = px(12.);
 7974
 7975        if target_display_point.row() < visible_row_range.start {
 7976            return self.render_edit_prediction_scroll_popover(
 7977                |_| SCROLL_PADDING_Y,
 7978                IconName::ArrowUp,
 7979                visible_row_range,
 7980                line_layouts,
 7981                newest_selection_head,
 7982                scrolled_content_origin,
 7983                window,
 7984                cx,
 7985            );
 7986        } else if target_display_point.row() >= visible_row_range.end {
 7987            return self.render_edit_prediction_scroll_popover(
 7988                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7989                IconName::ArrowDown,
 7990                visible_row_range,
 7991                line_layouts,
 7992                newest_selection_head,
 7993                scrolled_content_origin,
 7994                window,
 7995                cx,
 7996            );
 7997        }
 7998
 7999        const POLE_WIDTH: Pixels = px(2.);
 8000
 8001        let line_layout =
 8002            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8003        let target_column = target_display_point.column() as usize;
 8004
 8005        let target_x = line_layout.x_for_index(target_column);
 8006        let target_y =
 8007            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8008
 8009        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8010
 8011        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8012        border_color.l += 0.001;
 8013
 8014        let mut element = v_flex()
 8015            .items_end()
 8016            .when(flag_on_right, |el| el.items_start())
 8017            .child(if flag_on_right {
 8018                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8019                    .rounded_bl(px(0.))
 8020                    .rounded_tl(px(0.))
 8021                    .border_l_2()
 8022                    .border_color(border_color)
 8023            } else {
 8024                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8025                    .rounded_br(px(0.))
 8026                    .rounded_tr(px(0.))
 8027                    .border_r_2()
 8028                    .border_color(border_color)
 8029            })
 8030            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8031            .into_any();
 8032
 8033        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8034
 8035        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8036            - point(
 8037                if flag_on_right {
 8038                    POLE_WIDTH
 8039                } else {
 8040                    size.width - POLE_WIDTH
 8041                },
 8042                size.height - line_height,
 8043            );
 8044
 8045        origin.x = origin.x.max(content_origin.x);
 8046
 8047        element.prepaint_at(origin, window, cx);
 8048
 8049        Some((element, origin))
 8050    }
 8051
 8052    fn render_edit_prediction_scroll_popover(
 8053        &mut self,
 8054        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8055        scroll_icon: IconName,
 8056        visible_row_range: Range<DisplayRow>,
 8057        line_layouts: &[LineWithInvisibles],
 8058        newest_selection_head: Option<DisplayPoint>,
 8059        scrolled_content_origin: gpui::Point<Pixels>,
 8060        window: &mut Window,
 8061        cx: &mut App,
 8062    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8063        let mut element = self
 8064            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8065            .into_any();
 8066
 8067        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8068
 8069        let cursor = newest_selection_head?;
 8070        let cursor_row_layout =
 8071            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8072        let cursor_column = cursor.column() as usize;
 8073
 8074        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8075
 8076        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8077
 8078        element.prepaint_at(origin, window, cx);
 8079        Some((element, origin))
 8080    }
 8081
 8082    fn render_edit_prediction_eager_jump_popover(
 8083        &mut self,
 8084        text_bounds: &Bounds<Pixels>,
 8085        content_origin: gpui::Point<Pixels>,
 8086        editor_snapshot: &EditorSnapshot,
 8087        visible_row_range: Range<DisplayRow>,
 8088        scroll_top: f32,
 8089        scroll_bottom: f32,
 8090        line_height: Pixels,
 8091        scroll_pixel_position: gpui::Point<Pixels>,
 8092        target_display_point: DisplayPoint,
 8093        editor_width: Pixels,
 8094        window: &mut Window,
 8095        cx: &mut App,
 8096    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8097        if target_display_point.row().as_f32() < scroll_top {
 8098            let mut element = self
 8099                .render_edit_prediction_line_popover(
 8100                    "Jump to Edit",
 8101                    Some(IconName::ArrowUp),
 8102                    window,
 8103                    cx,
 8104                )?
 8105                .into_any();
 8106
 8107            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8108            let offset = point(
 8109                (text_bounds.size.width - size.width) / 2.,
 8110                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8111            );
 8112
 8113            let origin = text_bounds.origin + offset;
 8114            element.prepaint_at(origin, window, cx);
 8115            Some((element, origin))
 8116        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8117            let mut element = self
 8118                .render_edit_prediction_line_popover(
 8119                    "Jump to Edit",
 8120                    Some(IconName::ArrowDown),
 8121                    window,
 8122                    cx,
 8123                )?
 8124                .into_any();
 8125
 8126            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8127            let offset = point(
 8128                (text_bounds.size.width - size.width) / 2.,
 8129                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8130            );
 8131
 8132            let origin = text_bounds.origin + offset;
 8133            element.prepaint_at(origin, window, cx);
 8134            Some((element, origin))
 8135        } else {
 8136            self.render_edit_prediction_end_of_line_popover(
 8137                "Jump to Edit",
 8138                editor_snapshot,
 8139                visible_row_range,
 8140                target_display_point,
 8141                line_height,
 8142                scroll_pixel_position,
 8143                content_origin,
 8144                editor_width,
 8145                window,
 8146                cx,
 8147            )
 8148        }
 8149    }
 8150
 8151    fn render_edit_prediction_end_of_line_popover(
 8152        self: &mut Editor,
 8153        label: &'static str,
 8154        editor_snapshot: &EditorSnapshot,
 8155        visible_row_range: Range<DisplayRow>,
 8156        target_display_point: DisplayPoint,
 8157        line_height: Pixels,
 8158        scroll_pixel_position: gpui::Point<Pixels>,
 8159        content_origin: gpui::Point<Pixels>,
 8160        editor_width: Pixels,
 8161        window: &mut Window,
 8162        cx: &mut App,
 8163    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8164        let target_line_end = DisplayPoint::new(
 8165            target_display_point.row(),
 8166            editor_snapshot.line_len(target_display_point.row()),
 8167        );
 8168
 8169        let mut element = self
 8170            .render_edit_prediction_line_popover(label, None, window, cx)?
 8171            .into_any();
 8172
 8173        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8174
 8175        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8176
 8177        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8178        let mut origin = start_point
 8179            + line_origin
 8180            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8181        origin.x = origin.x.max(content_origin.x);
 8182
 8183        let max_x = content_origin.x + editor_width - size.width;
 8184
 8185        if origin.x > max_x {
 8186            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8187
 8188            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8189                origin.y += offset;
 8190                IconName::ArrowUp
 8191            } else {
 8192                origin.y -= offset;
 8193                IconName::ArrowDown
 8194            };
 8195
 8196            element = self
 8197                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8198                .into_any();
 8199
 8200            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8201
 8202            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8203        }
 8204
 8205        element.prepaint_at(origin, window, cx);
 8206        Some((element, origin))
 8207    }
 8208
 8209    fn render_edit_prediction_diff_popover(
 8210        self: &Editor,
 8211        text_bounds: &Bounds<Pixels>,
 8212        content_origin: gpui::Point<Pixels>,
 8213        right_margin: Pixels,
 8214        editor_snapshot: &EditorSnapshot,
 8215        visible_row_range: Range<DisplayRow>,
 8216        line_layouts: &[LineWithInvisibles],
 8217        line_height: Pixels,
 8218        scroll_pixel_position: gpui::Point<Pixels>,
 8219        newest_selection_head: Option<DisplayPoint>,
 8220        editor_width: Pixels,
 8221        style: &EditorStyle,
 8222        edits: &Vec<(Range<Anchor>, String)>,
 8223        edit_preview: &Option<language::EditPreview>,
 8224        snapshot: &language::BufferSnapshot,
 8225        window: &mut Window,
 8226        cx: &mut App,
 8227    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8228        let edit_start = edits
 8229            .first()
 8230            .unwrap()
 8231            .0
 8232            .start
 8233            .to_display_point(editor_snapshot);
 8234        let edit_end = edits
 8235            .last()
 8236            .unwrap()
 8237            .0
 8238            .end
 8239            .to_display_point(editor_snapshot);
 8240
 8241        let is_visible = visible_row_range.contains(&edit_start.row())
 8242            || visible_row_range.contains(&edit_end.row());
 8243        if !is_visible {
 8244            return None;
 8245        }
 8246
 8247        let highlighted_edits =
 8248            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8249
 8250        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8251        let line_count = highlighted_edits.text.lines().count();
 8252
 8253        const BORDER_WIDTH: Pixels = px(1.);
 8254
 8255        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8256        let has_keybind = keybind.is_some();
 8257
 8258        let mut element = h_flex()
 8259            .items_start()
 8260            .child(
 8261                h_flex()
 8262                    .bg(cx.theme().colors().editor_background)
 8263                    .border(BORDER_WIDTH)
 8264                    .shadow_sm()
 8265                    .border_color(cx.theme().colors().border)
 8266                    .rounded_l_lg()
 8267                    .when(line_count > 1, |el| el.rounded_br_lg())
 8268                    .pr_1()
 8269                    .child(styled_text),
 8270            )
 8271            .child(
 8272                h_flex()
 8273                    .h(line_height + BORDER_WIDTH * 2.)
 8274                    .px_1p5()
 8275                    .gap_1()
 8276                    // Workaround: For some reason, there's a gap if we don't do this
 8277                    .ml(-BORDER_WIDTH)
 8278                    .shadow(vec![gpui::BoxShadow {
 8279                        color: gpui::black().opacity(0.05),
 8280                        offset: point(px(1.), px(1.)),
 8281                        blur_radius: px(2.),
 8282                        spread_radius: px(0.),
 8283                    }])
 8284                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8285                    .border(BORDER_WIDTH)
 8286                    .border_color(cx.theme().colors().border)
 8287                    .rounded_r_lg()
 8288                    .id("edit_prediction_diff_popover_keybind")
 8289                    .when(!has_keybind, |el| {
 8290                        let status_colors = cx.theme().status();
 8291
 8292                        el.bg(status_colors.error_background)
 8293                            .border_color(status_colors.error.opacity(0.6))
 8294                            .child(Icon::new(IconName::Info).color(Color::Error))
 8295                            .cursor_default()
 8296                            .hoverable_tooltip(move |_window, cx| {
 8297                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8298                            })
 8299                    })
 8300                    .children(keybind),
 8301            )
 8302            .into_any();
 8303
 8304        let longest_row =
 8305            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8306        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8307            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8308        } else {
 8309            layout_line(
 8310                longest_row,
 8311                editor_snapshot,
 8312                style,
 8313                editor_width,
 8314                |_| false,
 8315                window,
 8316                cx,
 8317            )
 8318            .width
 8319        };
 8320
 8321        let viewport_bounds =
 8322            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8323                right: -right_margin,
 8324                ..Default::default()
 8325            });
 8326
 8327        let x_after_longest =
 8328            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8329                - scroll_pixel_position.x;
 8330
 8331        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8332
 8333        // Fully visible if it can be displayed within the window (allow overlapping other
 8334        // panes). However, this is only allowed if the popover starts within text_bounds.
 8335        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8336            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8337
 8338        let mut origin = if can_position_to_the_right {
 8339            point(
 8340                x_after_longest,
 8341                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8342                    - scroll_pixel_position.y,
 8343            )
 8344        } else {
 8345            let cursor_row = newest_selection_head.map(|head| head.row());
 8346            let above_edit = edit_start
 8347                .row()
 8348                .0
 8349                .checked_sub(line_count as u32)
 8350                .map(DisplayRow);
 8351            let below_edit = Some(edit_end.row() + 1);
 8352            let above_cursor =
 8353                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8354            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8355
 8356            // Place the edit popover adjacent to the edit if there is a location
 8357            // available that is onscreen and does not obscure the cursor. Otherwise,
 8358            // place it adjacent to the cursor.
 8359            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8360                .into_iter()
 8361                .flatten()
 8362                .find(|&start_row| {
 8363                    let end_row = start_row + line_count as u32;
 8364                    visible_row_range.contains(&start_row)
 8365                        && visible_row_range.contains(&end_row)
 8366                        && cursor_row.map_or(true, |cursor_row| {
 8367                            !((start_row..end_row).contains(&cursor_row))
 8368                        })
 8369                })?;
 8370
 8371            content_origin
 8372                + point(
 8373                    -scroll_pixel_position.x,
 8374                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8375                )
 8376        };
 8377
 8378        origin.x -= BORDER_WIDTH;
 8379
 8380        window.defer_draw(element, origin, 1);
 8381
 8382        // Do not return an element, since it will already be drawn due to defer_draw.
 8383        None
 8384    }
 8385
 8386    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8387        px(30.)
 8388    }
 8389
 8390    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8391        if self.read_only(cx) {
 8392            cx.theme().players().read_only()
 8393        } else {
 8394            self.style.as_ref().unwrap().local_player
 8395        }
 8396    }
 8397
 8398    fn render_edit_prediction_accept_keybind(
 8399        &self,
 8400        window: &mut Window,
 8401        cx: &App,
 8402    ) -> Option<AnyElement> {
 8403        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8404        let accept_keystroke = accept_binding.keystroke()?;
 8405
 8406        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8407
 8408        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8409            Color::Accent
 8410        } else {
 8411            Color::Muted
 8412        };
 8413
 8414        h_flex()
 8415            .px_0p5()
 8416            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8417            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8418            .text_size(TextSize::XSmall.rems(cx))
 8419            .child(h_flex().children(ui::render_modifiers(
 8420                &accept_keystroke.modifiers,
 8421                PlatformStyle::platform(),
 8422                Some(modifiers_color),
 8423                Some(IconSize::XSmall.rems().into()),
 8424                true,
 8425            )))
 8426            .when(is_platform_style_mac, |parent| {
 8427                parent.child(accept_keystroke.key.clone())
 8428            })
 8429            .when(!is_platform_style_mac, |parent| {
 8430                parent.child(
 8431                    Key::new(
 8432                        util::capitalize(&accept_keystroke.key),
 8433                        Some(Color::Default),
 8434                    )
 8435                    .size(Some(IconSize::XSmall.rems().into())),
 8436                )
 8437            })
 8438            .into_any()
 8439            .into()
 8440    }
 8441
 8442    fn render_edit_prediction_line_popover(
 8443        &self,
 8444        label: impl Into<SharedString>,
 8445        icon: Option<IconName>,
 8446        window: &mut Window,
 8447        cx: &App,
 8448    ) -> Option<Stateful<Div>> {
 8449        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8450
 8451        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8452        let has_keybind = keybind.is_some();
 8453
 8454        let result = h_flex()
 8455            .id("ep-line-popover")
 8456            .py_0p5()
 8457            .pl_1()
 8458            .pr(padding_right)
 8459            .gap_1()
 8460            .rounded_md()
 8461            .border_1()
 8462            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8463            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8464            .shadow_sm()
 8465            .when(!has_keybind, |el| {
 8466                let status_colors = cx.theme().status();
 8467
 8468                el.bg(status_colors.error_background)
 8469                    .border_color(status_colors.error.opacity(0.6))
 8470                    .pl_2()
 8471                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8472                    .cursor_default()
 8473                    .hoverable_tooltip(move |_window, cx| {
 8474                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8475                    })
 8476            })
 8477            .children(keybind)
 8478            .child(
 8479                Label::new(label)
 8480                    .size(LabelSize::Small)
 8481                    .when(!has_keybind, |el| {
 8482                        el.color(cx.theme().status().error.into()).strikethrough()
 8483                    }),
 8484            )
 8485            .when(!has_keybind, |el| {
 8486                el.child(
 8487                    h_flex().ml_1().child(
 8488                        Icon::new(IconName::Info)
 8489                            .size(IconSize::Small)
 8490                            .color(cx.theme().status().error.into()),
 8491                    ),
 8492                )
 8493            })
 8494            .when_some(icon, |element, icon| {
 8495                element.child(
 8496                    div()
 8497                        .mt(px(1.5))
 8498                        .child(Icon::new(icon).size(IconSize::Small)),
 8499                )
 8500            });
 8501
 8502        Some(result)
 8503    }
 8504
 8505    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8506        let accent_color = cx.theme().colors().text_accent;
 8507        let editor_bg_color = cx.theme().colors().editor_background;
 8508        editor_bg_color.blend(accent_color.opacity(0.1))
 8509    }
 8510
 8511    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8512        let accent_color = cx.theme().colors().text_accent;
 8513        let editor_bg_color = cx.theme().colors().editor_background;
 8514        editor_bg_color.blend(accent_color.opacity(0.6))
 8515    }
 8516
 8517    fn render_edit_prediction_cursor_popover(
 8518        &self,
 8519        min_width: Pixels,
 8520        max_width: Pixels,
 8521        cursor_point: Point,
 8522        style: &EditorStyle,
 8523        accept_keystroke: Option<&gpui::Keystroke>,
 8524        _window: &Window,
 8525        cx: &mut Context<Editor>,
 8526    ) -> Option<AnyElement> {
 8527        let provider = self.edit_prediction_provider.as_ref()?;
 8528
 8529        if provider.provider.needs_terms_acceptance(cx) {
 8530            return Some(
 8531                h_flex()
 8532                    .min_w(min_width)
 8533                    .flex_1()
 8534                    .px_2()
 8535                    .py_1()
 8536                    .gap_3()
 8537                    .elevation_2(cx)
 8538                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8539                    .id("accept-terms")
 8540                    .cursor_pointer()
 8541                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8542                    .on_click(cx.listener(|this, _event, window, cx| {
 8543                        cx.stop_propagation();
 8544                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8545                        window.dispatch_action(
 8546                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8547                            cx,
 8548                        );
 8549                    }))
 8550                    .child(
 8551                        h_flex()
 8552                            .flex_1()
 8553                            .gap_2()
 8554                            .child(Icon::new(IconName::ZedPredict))
 8555                            .child(Label::new("Accept Terms of Service"))
 8556                            .child(div().w_full())
 8557                            .child(
 8558                                Icon::new(IconName::ArrowUpRight)
 8559                                    .color(Color::Muted)
 8560                                    .size(IconSize::Small),
 8561                            )
 8562                            .into_any_element(),
 8563                    )
 8564                    .into_any(),
 8565            );
 8566        }
 8567
 8568        let is_refreshing = provider.provider.is_refreshing(cx);
 8569
 8570        fn pending_completion_container() -> Div {
 8571            h_flex()
 8572                .h_full()
 8573                .flex_1()
 8574                .gap_2()
 8575                .child(Icon::new(IconName::ZedPredict))
 8576        }
 8577
 8578        let completion = match &self.active_inline_completion {
 8579            Some(prediction) => {
 8580                if !self.has_visible_completions_menu() {
 8581                    const RADIUS: Pixels = px(6.);
 8582                    const BORDER_WIDTH: Pixels = px(1.);
 8583
 8584                    return Some(
 8585                        h_flex()
 8586                            .elevation_2(cx)
 8587                            .border(BORDER_WIDTH)
 8588                            .border_color(cx.theme().colors().border)
 8589                            .when(accept_keystroke.is_none(), |el| {
 8590                                el.border_color(cx.theme().status().error)
 8591                            })
 8592                            .rounded(RADIUS)
 8593                            .rounded_tl(px(0.))
 8594                            .overflow_hidden()
 8595                            .child(div().px_1p5().child(match &prediction.completion {
 8596                                InlineCompletion::Move { target, snapshot } => {
 8597                                    use text::ToPoint as _;
 8598                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8599                                    {
 8600                                        Icon::new(IconName::ZedPredictDown)
 8601                                    } else {
 8602                                        Icon::new(IconName::ZedPredictUp)
 8603                                    }
 8604                                }
 8605                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8606                            }))
 8607                            .child(
 8608                                h_flex()
 8609                                    .gap_1()
 8610                                    .py_1()
 8611                                    .px_2()
 8612                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8613                                    .border_l_1()
 8614                                    .border_color(cx.theme().colors().border)
 8615                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8616                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8617                                        el.child(
 8618                                            Label::new("Hold")
 8619                                                .size(LabelSize::Small)
 8620                                                .when(accept_keystroke.is_none(), |el| {
 8621                                                    el.strikethrough()
 8622                                                })
 8623                                                .line_height_style(LineHeightStyle::UiLabel),
 8624                                        )
 8625                                    })
 8626                                    .id("edit_prediction_cursor_popover_keybind")
 8627                                    .when(accept_keystroke.is_none(), |el| {
 8628                                        let status_colors = cx.theme().status();
 8629
 8630                                        el.bg(status_colors.error_background)
 8631                                            .border_color(status_colors.error.opacity(0.6))
 8632                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8633                                            .cursor_default()
 8634                                            .hoverable_tooltip(move |_window, cx| {
 8635                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8636                                                    .into()
 8637                                            })
 8638                                    })
 8639                                    .when_some(
 8640                                        accept_keystroke.as_ref(),
 8641                                        |el, accept_keystroke| {
 8642                                            el.child(h_flex().children(ui::render_modifiers(
 8643                                                &accept_keystroke.modifiers,
 8644                                                PlatformStyle::platform(),
 8645                                                Some(Color::Default),
 8646                                                Some(IconSize::XSmall.rems().into()),
 8647                                                false,
 8648                                            )))
 8649                                        },
 8650                                    ),
 8651                            )
 8652                            .into_any(),
 8653                    );
 8654                }
 8655
 8656                self.render_edit_prediction_cursor_popover_preview(
 8657                    prediction,
 8658                    cursor_point,
 8659                    style,
 8660                    cx,
 8661                )?
 8662            }
 8663
 8664            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8665                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8666                    stale_completion,
 8667                    cursor_point,
 8668                    style,
 8669                    cx,
 8670                )?,
 8671
 8672                None => {
 8673                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8674                }
 8675            },
 8676
 8677            None => pending_completion_container().child(Label::new("No Prediction")),
 8678        };
 8679
 8680        let completion = if is_refreshing {
 8681            completion
 8682                .with_animation(
 8683                    "loading-completion",
 8684                    Animation::new(Duration::from_secs(2))
 8685                        .repeat()
 8686                        .with_easing(pulsating_between(0.4, 0.8)),
 8687                    |label, delta| label.opacity(delta),
 8688                )
 8689                .into_any_element()
 8690        } else {
 8691            completion.into_any_element()
 8692        };
 8693
 8694        let has_completion = self.active_inline_completion.is_some();
 8695
 8696        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8697        Some(
 8698            h_flex()
 8699                .min_w(min_width)
 8700                .max_w(max_width)
 8701                .flex_1()
 8702                .elevation_2(cx)
 8703                .border_color(cx.theme().colors().border)
 8704                .child(
 8705                    div()
 8706                        .flex_1()
 8707                        .py_1()
 8708                        .px_2()
 8709                        .overflow_hidden()
 8710                        .child(completion),
 8711                )
 8712                .when_some(accept_keystroke, |el, accept_keystroke| {
 8713                    if !accept_keystroke.modifiers.modified() {
 8714                        return el;
 8715                    }
 8716
 8717                    el.child(
 8718                        h_flex()
 8719                            .h_full()
 8720                            .border_l_1()
 8721                            .rounded_r_lg()
 8722                            .border_color(cx.theme().colors().border)
 8723                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8724                            .gap_1()
 8725                            .py_1()
 8726                            .px_2()
 8727                            .child(
 8728                                h_flex()
 8729                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8730                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8731                                    .child(h_flex().children(ui::render_modifiers(
 8732                                        &accept_keystroke.modifiers,
 8733                                        PlatformStyle::platform(),
 8734                                        Some(if !has_completion {
 8735                                            Color::Muted
 8736                                        } else {
 8737                                            Color::Default
 8738                                        }),
 8739                                        None,
 8740                                        false,
 8741                                    ))),
 8742                            )
 8743                            .child(Label::new("Preview").into_any_element())
 8744                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8745                    )
 8746                })
 8747                .into_any(),
 8748        )
 8749    }
 8750
 8751    fn render_edit_prediction_cursor_popover_preview(
 8752        &self,
 8753        completion: &InlineCompletionState,
 8754        cursor_point: Point,
 8755        style: &EditorStyle,
 8756        cx: &mut Context<Editor>,
 8757    ) -> Option<Div> {
 8758        use text::ToPoint as _;
 8759
 8760        fn render_relative_row_jump(
 8761            prefix: impl Into<String>,
 8762            current_row: u32,
 8763            target_row: u32,
 8764        ) -> Div {
 8765            let (row_diff, arrow) = if target_row < current_row {
 8766                (current_row - target_row, IconName::ArrowUp)
 8767            } else {
 8768                (target_row - current_row, IconName::ArrowDown)
 8769            };
 8770
 8771            h_flex()
 8772                .child(
 8773                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8774                        .color(Color::Muted)
 8775                        .size(LabelSize::Small),
 8776                )
 8777                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8778        }
 8779
 8780        match &completion.completion {
 8781            InlineCompletion::Move {
 8782                target, snapshot, ..
 8783            } => Some(
 8784                h_flex()
 8785                    .px_2()
 8786                    .gap_2()
 8787                    .flex_1()
 8788                    .child(
 8789                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8790                            Icon::new(IconName::ZedPredictDown)
 8791                        } else {
 8792                            Icon::new(IconName::ZedPredictUp)
 8793                        },
 8794                    )
 8795                    .child(Label::new("Jump to Edit")),
 8796            ),
 8797
 8798            InlineCompletion::Edit {
 8799                edits,
 8800                edit_preview,
 8801                snapshot,
 8802                display_mode: _,
 8803            } => {
 8804                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8805
 8806                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8807                    &snapshot,
 8808                    &edits,
 8809                    edit_preview.as_ref()?,
 8810                    true,
 8811                    cx,
 8812                )
 8813                .first_line_preview();
 8814
 8815                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8816                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8817
 8818                let preview = h_flex()
 8819                    .gap_1()
 8820                    .min_w_16()
 8821                    .child(styled_text)
 8822                    .when(has_more_lines, |parent| parent.child(""));
 8823
 8824                let left = if first_edit_row != cursor_point.row {
 8825                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8826                        .into_any_element()
 8827                } else {
 8828                    Icon::new(IconName::ZedPredict).into_any_element()
 8829                };
 8830
 8831                Some(
 8832                    h_flex()
 8833                        .h_full()
 8834                        .flex_1()
 8835                        .gap_2()
 8836                        .pr_1()
 8837                        .overflow_x_hidden()
 8838                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8839                        .child(left)
 8840                        .child(preview),
 8841                )
 8842            }
 8843        }
 8844    }
 8845
 8846    pub fn render_context_menu(
 8847        &self,
 8848        style: &EditorStyle,
 8849        max_height_in_lines: u32,
 8850        window: &mut Window,
 8851        cx: &mut Context<Editor>,
 8852    ) -> Option<AnyElement> {
 8853        let menu = self.context_menu.borrow();
 8854        let menu = menu.as_ref()?;
 8855        if !menu.visible() {
 8856            return None;
 8857        };
 8858        Some(menu.render(style, max_height_in_lines, window, cx))
 8859    }
 8860
 8861    fn render_context_menu_aside(
 8862        &mut self,
 8863        max_size: Size<Pixels>,
 8864        window: &mut Window,
 8865        cx: &mut Context<Editor>,
 8866    ) -> Option<AnyElement> {
 8867        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8868            if menu.visible() {
 8869                menu.render_aside(max_size, window, cx)
 8870            } else {
 8871                None
 8872            }
 8873        })
 8874    }
 8875
 8876    fn hide_context_menu(
 8877        &mut self,
 8878        window: &mut Window,
 8879        cx: &mut Context<Self>,
 8880    ) -> Option<CodeContextMenu> {
 8881        cx.notify();
 8882        self.completion_tasks.clear();
 8883        let context_menu = self.context_menu.borrow_mut().take();
 8884        self.stale_inline_completion_in_menu.take();
 8885        self.update_visible_inline_completion(window, cx);
 8886        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8887            if let Some(completion_provider) = &self.completion_provider {
 8888                completion_provider.selection_changed(None, window, cx);
 8889            }
 8890        }
 8891        context_menu
 8892    }
 8893
 8894    fn show_snippet_choices(
 8895        &mut self,
 8896        choices: &Vec<String>,
 8897        selection: Range<Anchor>,
 8898        cx: &mut Context<Self>,
 8899    ) {
 8900        if selection.start.buffer_id.is_none() {
 8901            return;
 8902        }
 8903        let buffer_id = selection.start.buffer_id.unwrap();
 8904        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8905        let id = post_inc(&mut self.next_completion_id);
 8906        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8907
 8908        if let Some(buffer) = buffer {
 8909            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8910                CompletionsMenu::new_snippet_choices(
 8911                    id,
 8912                    true,
 8913                    choices,
 8914                    selection,
 8915                    buffer,
 8916                    snippet_sort_order,
 8917                ),
 8918            ));
 8919        }
 8920    }
 8921
 8922    pub fn insert_snippet(
 8923        &mut self,
 8924        insertion_ranges: &[Range<usize>],
 8925        snippet: Snippet,
 8926        window: &mut Window,
 8927        cx: &mut Context<Self>,
 8928    ) -> Result<()> {
 8929        struct Tabstop<T> {
 8930            is_end_tabstop: bool,
 8931            ranges: Vec<Range<T>>,
 8932            choices: Option<Vec<String>>,
 8933        }
 8934
 8935        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8936            let snippet_text: Arc<str> = snippet.text.clone().into();
 8937            let edits = insertion_ranges
 8938                .iter()
 8939                .cloned()
 8940                .map(|range| (range, snippet_text.clone()));
 8941            let autoindent_mode = AutoindentMode::Block {
 8942                original_indent_columns: Vec::new(),
 8943            };
 8944            buffer.edit(edits, Some(autoindent_mode), cx);
 8945
 8946            let snapshot = &*buffer.read(cx);
 8947            let snippet = &snippet;
 8948            snippet
 8949                .tabstops
 8950                .iter()
 8951                .map(|tabstop| {
 8952                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8953                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8954                    });
 8955                    let mut tabstop_ranges = tabstop
 8956                        .ranges
 8957                        .iter()
 8958                        .flat_map(|tabstop_range| {
 8959                            let mut delta = 0_isize;
 8960                            insertion_ranges.iter().map(move |insertion_range| {
 8961                                let insertion_start = insertion_range.start as isize + delta;
 8962                                delta +=
 8963                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8964
 8965                                let start = ((insertion_start + tabstop_range.start) as usize)
 8966                                    .min(snapshot.len());
 8967                                let end = ((insertion_start + tabstop_range.end) as usize)
 8968                                    .min(snapshot.len());
 8969                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8970                            })
 8971                        })
 8972                        .collect::<Vec<_>>();
 8973                    // Sort in reverse order so that the first range is the newest created
 8974                    // selection. Completions will use it and autoscroll will prioritize it.
 8975                    tabstop_ranges.sort_unstable_by(|a, b| b.start.cmp(&a.start, snapshot));
 8976
 8977                    Tabstop {
 8978                        is_end_tabstop,
 8979                        ranges: tabstop_ranges,
 8980                        choices: tabstop.choices.clone(),
 8981                    }
 8982                })
 8983                .collect::<Vec<_>>()
 8984        });
 8985        if let Some(tabstop) = tabstops.first() {
 8986            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8987                s.select_ranges(tabstop.ranges.iter().cloned());
 8988            });
 8989
 8990            if let Some(choices) = &tabstop.choices {
 8991                if let Some(selection) = tabstop.ranges.first() {
 8992                    self.show_snippet_choices(choices, selection.clone(), cx)
 8993                }
 8994            }
 8995
 8996            // If we're already at the last tabstop and it's at the end of the snippet,
 8997            // we're done, we don't need to keep the state around.
 8998            if !tabstop.is_end_tabstop {
 8999                let choices = tabstops
 9000                    .iter()
 9001                    .map(|tabstop| tabstop.choices.clone())
 9002                    .collect();
 9003
 9004                let ranges = tabstops
 9005                    .into_iter()
 9006                    .map(|tabstop| tabstop.ranges)
 9007                    .collect::<Vec<_>>();
 9008
 9009                self.snippet_stack.push(SnippetState {
 9010                    active_index: 0,
 9011                    ranges,
 9012                    choices,
 9013                });
 9014            }
 9015
 9016            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9017            if self.autoclose_regions.is_empty() {
 9018                let snapshot = self.buffer.read(cx).snapshot(cx);
 9019                for selection in &mut self.selections.all::<Point>(cx) {
 9020                    let selection_head = selection.head();
 9021                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9022                        continue;
 9023                    };
 9024
 9025                    let mut bracket_pair = None;
 9026                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9027                    let prev_chars = snapshot
 9028                        .reversed_chars_at(selection_head)
 9029                        .collect::<String>();
 9030                    for (pair, enabled) in scope.brackets() {
 9031                        if enabled
 9032                            && pair.close
 9033                            && prev_chars.starts_with(pair.start.as_str())
 9034                            && next_chars.starts_with(pair.end.as_str())
 9035                        {
 9036                            bracket_pair = Some(pair.clone());
 9037                            break;
 9038                        }
 9039                    }
 9040                    if let Some(pair) = bracket_pair {
 9041                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9042                        let autoclose_enabled =
 9043                            self.use_autoclose && snapshot_settings.use_autoclose;
 9044                        if autoclose_enabled {
 9045                            let start = snapshot.anchor_after(selection_head);
 9046                            let end = snapshot.anchor_after(selection_head);
 9047                            self.autoclose_regions.push(AutocloseRegion {
 9048                                selection_id: selection.id,
 9049                                range: start..end,
 9050                                pair,
 9051                            });
 9052                        }
 9053                    }
 9054                }
 9055            }
 9056        }
 9057        Ok(())
 9058    }
 9059
 9060    pub fn move_to_next_snippet_tabstop(
 9061        &mut self,
 9062        window: &mut Window,
 9063        cx: &mut Context<Self>,
 9064    ) -> bool {
 9065        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9066    }
 9067
 9068    pub fn move_to_prev_snippet_tabstop(
 9069        &mut self,
 9070        window: &mut Window,
 9071        cx: &mut Context<Self>,
 9072    ) -> bool {
 9073        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9074    }
 9075
 9076    pub fn move_to_snippet_tabstop(
 9077        &mut self,
 9078        bias: Bias,
 9079        window: &mut Window,
 9080        cx: &mut Context<Self>,
 9081    ) -> bool {
 9082        if let Some(mut snippet) = self.snippet_stack.pop() {
 9083            match bias {
 9084                Bias::Left => {
 9085                    if snippet.active_index > 0 {
 9086                        snippet.active_index -= 1;
 9087                    } else {
 9088                        self.snippet_stack.push(snippet);
 9089                        return false;
 9090                    }
 9091                }
 9092                Bias::Right => {
 9093                    if snippet.active_index + 1 < snippet.ranges.len() {
 9094                        snippet.active_index += 1;
 9095                    } else {
 9096                        self.snippet_stack.push(snippet);
 9097                        return false;
 9098                    }
 9099                }
 9100            }
 9101            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9102                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9103                    s.select_ranges(current_ranges.iter().cloned())
 9104                });
 9105
 9106                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9107                    if let Some(selection) = current_ranges.first() {
 9108                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9109                    }
 9110                }
 9111
 9112                // If snippet state is not at the last tabstop, push it back on the stack
 9113                if snippet.active_index + 1 < snippet.ranges.len() {
 9114                    self.snippet_stack.push(snippet);
 9115                }
 9116                return true;
 9117            }
 9118        }
 9119
 9120        false
 9121    }
 9122
 9123    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9124        self.transact(window, cx, |this, window, cx| {
 9125            this.select_all(&SelectAll, window, cx);
 9126            this.insert("", window, cx);
 9127        });
 9128    }
 9129
 9130    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9131        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9132        self.transact(window, cx, |this, window, cx| {
 9133            this.select_autoclose_pair(window, cx);
 9134            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9135            if !this.linked_edit_ranges.is_empty() {
 9136                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9137                let snapshot = this.buffer.read(cx).snapshot(cx);
 9138
 9139                for selection in selections.iter() {
 9140                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9141                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9142                    if selection_start.buffer_id != selection_end.buffer_id {
 9143                        continue;
 9144                    }
 9145                    if let Some(ranges) =
 9146                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9147                    {
 9148                        for (buffer, entries) in ranges {
 9149                            linked_ranges.entry(buffer).or_default().extend(entries);
 9150                        }
 9151                    }
 9152                }
 9153            }
 9154
 9155            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9156            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9157            for selection in &mut selections {
 9158                if selection.is_empty() {
 9159                    let old_head = selection.head();
 9160                    let mut new_head =
 9161                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9162                            .to_point(&display_map);
 9163                    if let Some((buffer, line_buffer_range)) = display_map
 9164                        .buffer_snapshot
 9165                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9166                    {
 9167                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9168                        let indent_len = match indent_size.kind {
 9169                            IndentKind::Space => {
 9170                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9171                            }
 9172                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9173                        };
 9174                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9175                            let indent_len = indent_len.get();
 9176                            new_head = cmp::min(
 9177                                new_head,
 9178                                MultiBufferPoint::new(
 9179                                    old_head.row,
 9180                                    ((old_head.column - 1) / indent_len) * indent_len,
 9181                                ),
 9182                            );
 9183                        }
 9184                    }
 9185
 9186                    selection.set_head(new_head, SelectionGoal::None);
 9187                }
 9188            }
 9189
 9190            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9191                s.select(selections)
 9192            });
 9193            this.insert("", window, cx);
 9194            let empty_str: Arc<str> = Arc::from("");
 9195            for (buffer, edits) in linked_ranges {
 9196                let snapshot = buffer.read(cx).snapshot();
 9197                use text::ToPoint as TP;
 9198
 9199                let edits = edits
 9200                    .into_iter()
 9201                    .map(|range| {
 9202                        let end_point = TP::to_point(&range.end, &snapshot);
 9203                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9204
 9205                        if end_point == start_point {
 9206                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9207                                .saturating_sub(1);
 9208                            start_point =
 9209                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9210                        };
 9211
 9212                        (start_point..end_point, empty_str.clone())
 9213                    })
 9214                    .sorted_by_key(|(range, _)| range.start)
 9215                    .collect::<Vec<_>>();
 9216                buffer.update(cx, |this, cx| {
 9217                    this.edit(edits, None, cx);
 9218                })
 9219            }
 9220            this.refresh_inline_completion(true, false, window, cx);
 9221            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9222        });
 9223    }
 9224
 9225    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9226        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9227        self.transact(window, cx, |this, window, cx| {
 9228            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9229                s.move_with(|map, selection| {
 9230                    if selection.is_empty() {
 9231                        let cursor = movement::right(map, selection.head());
 9232                        selection.end = cursor;
 9233                        selection.reversed = true;
 9234                        selection.goal = SelectionGoal::None;
 9235                    }
 9236                })
 9237            });
 9238            this.insert("", window, cx);
 9239            this.refresh_inline_completion(true, false, window, cx);
 9240        });
 9241    }
 9242
 9243    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9244        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9245        if self.move_to_prev_snippet_tabstop(window, cx) {
 9246            return;
 9247        }
 9248        self.outdent(&Outdent, window, cx);
 9249    }
 9250
 9251    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9252        if self.move_to_next_snippet_tabstop(window, cx) {
 9253            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9254            return;
 9255        }
 9256        if self.read_only(cx) {
 9257            return;
 9258        }
 9259        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9260        let mut selections = self.selections.all_adjusted(cx);
 9261        let buffer = self.buffer.read(cx);
 9262        let snapshot = buffer.snapshot(cx);
 9263        let rows_iter = selections.iter().map(|s| s.head().row);
 9264        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9265
 9266        let has_some_cursor_in_whitespace = selections
 9267            .iter()
 9268            .filter(|selection| selection.is_empty())
 9269            .any(|selection| {
 9270                let cursor = selection.head();
 9271                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9272                cursor.column < current_indent.len
 9273            });
 9274
 9275        let mut edits = Vec::new();
 9276        let mut prev_edited_row = 0;
 9277        let mut row_delta = 0;
 9278        for selection in &mut selections {
 9279            if selection.start.row != prev_edited_row {
 9280                row_delta = 0;
 9281            }
 9282            prev_edited_row = selection.end.row;
 9283
 9284            // If the selection is non-empty, then increase the indentation of the selected lines.
 9285            if !selection.is_empty() {
 9286                row_delta =
 9287                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9288                continue;
 9289            }
 9290
 9291            let cursor = selection.head();
 9292            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9293            if let Some(suggested_indent) =
 9294                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9295            {
 9296                // Don't do anything if already at suggested indent
 9297                // and there is any other cursor which is not
 9298                if has_some_cursor_in_whitespace
 9299                    && cursor.column == current_indent.len
 9300                    && current_indent.len == suggested_indent.len
 9301                {
 9302                    continue;
 9303                }
 9304
 9305                // Adjust line and move cursor to suggested indent
 9306                // if cursor is not at suggested indent
 9307                if cursor.column < suggested_indent.len
 9308                    && cursor.column <= current_indent.len
 9309                    && current_indent.len <= suggested_indent.len
 9310                {
 9311                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9312                    selection.end = selection.start;
 9313                    if row_delta == 0 {
 9314                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9315                            cursor.row,
 9316                            current_indent,
 9317                            suggested_indent,
 9318                        ));
 9319                        row_delta = suggested_indent.len - current_indent.len;
 9320                    }
 9321                    continue;
 9322                }
 9323
 9324                // If current indent is more than suggested indent
 9325                // only move cursor to current indent and skip indent
 9326                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9327                    selection.start = Point::new(cursor.row, current_indent.len);
 9328                    selection.end = selection.start;
 9329                    continue;
 9330                }
 9331            }
 9332
 9333            // Otherwise, insert a hard or soft tab.
 9334            let settings = buffer.language_settings_at(cursor, cx);
 9335            let tab_size = if settings.hard_tabs {
 9336                IndentSize::tab()
 9337            } else {
 9338                let tab_size = settings.tab_size.get();
 9339                let indent_remainder = snapshot
 9340                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9341                    .flat_map(str::chars)
 9342                    .fold(row_delta % tab_size, |counter: u32, c| {
 9343                        if c == '\t' {
 9344                            0
 9345                        } else {
 9346                            (counter + 1) % tab_size
 9347                        }
 9348                    });
 9349
 9350                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9351                IndentSize::spaces(chars_to_next_tab_stop)
 9352            };
 9353            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9354            selection.end = selection.start;
 9355            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9356            row_delta += tab_size.len;
 9357        }
 9358
 9359        self.transact(window, cx, |this, window, cx| {
 9360            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9361            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9362                s.select(selections)
 9363            });
 9364            this.refresh_inline_completion(true, false, window, cx);
 9365        });
 9366    }
 9367
 9368    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9369        if self.read_only(cx) {
 9370            return;
 9371        }
 9372        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9373        let mut selections = self.selections.all::<Point>(cx);
 9374        let mut prev_edited_row = 0;
 9375        let mut row_delta = 0;
 9376        let mut edits = Vec::new();
 9377        let buffer = self.buffer.read(cx);
 9378        let snapshot = buffer.snapshot(cx);
 9379        for selection in &mut selections {
 9380            if selection.start.row != prev_edited_row {
 9381                row_delta = 0;
 9382            }
 9383            prev_edited_row = selection.end.row;
 9384
 9385            row_delta =
 9386                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9387        }
 9388
 9389        self.transact(window, cx, |this, window, cx| {
 9390            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9391            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9392                s.select(selections)
 9393            });
 9394        });
 9395    }
 9396
 9397    fn indent_selection(
 9398        buffer: &MultiBuffer,
 9399        snapshot: &MultiBufferSnapshot,
 9400        selection: &mut Selection<Point>,
 9401        edits: &mut Vec<(Range<Point>, String)>,
 9402        delta_for_start_row: u32,
 9403        cx: &App,
 9404    ) -> u32 {
 9405        let settings = buffer.language_settings_at(selection.start, cx);
 9406        let tab_size = settings.tab_size.get();
 9407        let indent_kind = if settings.hard_tabs {
 9408            IndentKind::Tab
 9409        } else {
 9410            IndentKind::Space
 9411        };
 9412        let mut start_row = selection.start.row;
 9413        let mut end_row = selection.end.row + 1;
 9414
 9415        // If a selection ends at the beginning of a line, don't indent
 9416        // that last line.
 9417        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9418            end_row -= 1;
 9419        }
 9420
 9421        // Avoid re-indenting a row that has already been indented by a
 9422        // previous selection, but still update this selection's column
 9423        // to reflect that indentation.
 9424        if delta_for_start_row > 0 {
 9425            start_row += 1;
 9426            selection.start.column += delta_for_start_row;
 9427            if selection.end.row == selection.start.row {
 9428                selection.end.column += delta_for_start_row;
 9429            }
 9430        }
 9431
 9432        let mut delta_for_end_row = 0;
 9433        let has_multiple_rows = start_row + 1 != end_row;
 9434        for row in start_row..end_row {
 9435            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9436            let indent_delta = match (current_indent.kind, indent_kind) {
 9437                (IndentKind::Space, IndentKind::Space) => {
 9438                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9439                    IndentSize::spaces(columns_to_next_tab_stop)
 9440                }
 9441                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9442                (_, IndentKind::Tab) => IndentSize::tab(),
 9443            };
 9444
 9445            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9446                0
 9447            } else {
 9448                selection.start.column
 9449            };
 9450            let row_start = Point::new(row, start);
 9451            edits.push((
 9452                row_start..row_start,
 9453                indent_delta.chars().collect::<String>(),
 9454            ));
 9455
 9456            // Update this selection's endpoints to reflect the indentation.
 9457            if row == selection.start.row {
 9458                selection.start.column += indent_delta.len;
 9459            }
 9460            if row == selection.end.row {
 9461                selection.end.column += indent_delta.len;
 9462                delta_for_end_row = indent_delta.len;
 9463            }
 9464        }
 9465
 9466        if selection.start.row == selection.end.row {
 9467            delta_for_start_row + delta_for_end_row
 9468        } else {
 9469            delta_for_end_row
 9470        }
 9471    }
 9472
 9473    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9474        if self.read_only(cx) {
 9475            return;
 9476        }
 9477        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9478        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9479        let selections = self.selections.all::<Point>(cx);
 9480        let mut deletion_ranges = Vec::new();
 9481        let mut last_outdent = None;
 9482        {
 9483            let buffer = self.buffer.read(cx);
 9484            let snapshot = buffer.snapshot(cx);
 9485            for selection in &selections {
 9486                let settings = buffer.language_settings_at(selection.start, cx);
 9487                let tab_size = settings.tab_size.get();
 9488                let mut rows = selection.spanned_rows(false, &display_map);
 9489
 9490                // Avoid re-outdenting a row that has already been outdented by a
 9491                // previous selection.
 9492                if let Some(last_row) = last_outdent {
 9493                    if last_row == rows.start {
 9494                        rows.start = rows.start.next_row();
 9495                    }
 9496                }
 9497                let has_multiple_rows = rows.len() > 1;
 9498                for row in rows.iter_rows() {
 9499                    let indent_size = snapshot.indent_size_for_line(row);
 9500                    if indent_size.len > 0 {
 9501                        let deletion_len = match indent_size.kind {
 9502                            IndentKind::Space => {
 9503                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9504                                if columns_to_prev_tab_stop == 0 {
 9505                                    tab_size
 9506                                } else {
 9507                                    columns_to_prev_tab_stop
 9508                                }
 9509                            }
 9510                            IndentKind::Tab => 1,
 9511                        };
 9512                        let start = if has_multiple_rows
 9513                            || deletion_len > selection.start.column
 9514                            || indent_size.len < selection.start.column
 9515                        {
 9516                            0
 9517                        } else {
 9518                            selection.start.column - deletion_len
 9519                        };
 9520                        deletion_ranges.push(
 9521                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9522                        );
 9523                        last_outdent = Some(row);
 9524                    }
 9525                }
 9526            }
 9527        }
 9528
 9529        self.transact(window, cx, |this, window, cx| {
 9530            this.buffer.update(cx, |buffer, cx| {
 9531                let empty_str: Arc<str> = Arc::default();
 9532                buffer.edit(
 9533                    deletion_ranges
 9534                        .into_iter()
 9535                        .map(|range| (range, empty_str.clone())),
 9536                    None,
 9537                    cx,
 9538                );
 9539            });
 9540            let selections = this.selections.all::<usize>(cx);
 9541            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9542                s.select(selections)
 9543            });
 9544        });
 9545    }
 9546
 9547    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9548        if self.read_only(cx) {
 9549            return;
 9550        }
 9551        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9552        let selections = self
 9553            .selections
 9554            .all::<usize>(cx)
 9555            .into_iter()
 9556            .map(|s| s.range());
 9557
 9558        self.transact(window, cx, |this, window, cx| {
 9559            this.buffer.update(cx, |buffer, cx| {
 9560                buffer.autoindent_ranges(selections, cx);
 9561            });
 9562            let selections = this.selections.all::<usize>(cx);
 9563            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9564                s.select(selections)
 9565            });
 9566        });
 9567    }
 9568
 9569    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9570        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9571        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9572        let selections = self.selections.all::<Point>(cx);
 9573
 9574        let mut new_cursors = Vec::new();
 9575        let mut edit_ranges = Vec::new();
 9576        let mut selections = selections.iter().peekable();
 9577        while let Some(selection) = selections.next() {
 9578            let mut rows = selection.spanned_rows(false, &display_map);
 9579            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9580
 9581            // Accumulate contiguous regions of rows that we want to delete.
 9582            while let Some(next_selection) = selections.peek() {
 9583                let next_rows = next_selection.spanned_rows(false, &display_map);
 9584                if next_rows.start <= rows.end {
 9585                    rows.end = next_rows.end;
 9586                    selections.next().unwrap();
 9587                } else {
 9588                    break;
 9589                }
 9590            }
 9591
 9592            let buffer = &display_map.buffer_snapshot;
 9593            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9594            let edit_end;
 9595            let cursor_buffer_row;
 9596            if buffer.max_point().row >= rows.end.0 {
 9597                // If there's a line after the range, delete the \n from the end of the row range
 9598                // and position the cursor on the next line.
 9599                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9600                cursor_buffer_row = rows.end;
 9601            } else {
 9602                // If there isn't a line after the range, delete the \n from the line before the
 9603                // start of the row range and position the cursor there.
 9604                edit_start = edit_start.saturating_sub(1);
 9605                edit_end = buffer.len();
 9606                cursor_buffer_row = rows.start.previous_row();
 9607            }
 9608
 9609            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9610            *cursor.column_mut() =
 9611                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9612
 9613            new_cursors.push((
 9614                selection.id,
 9615                buffer.anchor_after(cursor.to_point(&display_map)),
 9616            ));
 9617            edit_ranges.push(edit_start..edit_end);
 9618        }
 9619
 9620        self.transact(window, cx, |this, window, cx| {
 9621            let buffer = this.buffer.update(cx, |buffer, cx| {
 9622                let empty_str: Arc<str> = Arc::default();
 9623                buffer.edit(
 9624                    edit_ranges
 9625                        .into_iter()
 9626                        .map(|range| (range, empty_str.clone())),
 9627                    None,
 9628                    cx,
 9629                );
 9630                buffer.snapshot(cx)
 9631            });
 9632            let new_selections = new_cursors
 9633                .into_iter()
 9634                .map(|(id, cursor)| {
 9635                    let cursor = cursor.to_point(&buffer);
 9636                    Selection {
 9637                        id,
 9638                        start: cursor,
 9639                        end: cursor,
 9640                        reversed: false,
 9641                        goal: SelectionGoal::None,
 9642                    }
 9643                })
 9644                .collect();
 9645
 9646            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9647                s.select(new_selections);
 9648            });
 9649        });
 9650    }
 9651
 9652    pub fn join_lines_impl(
 9653        &mut self,
 9654        insert_whitespace: bool,
 9655        window: &mut Window,
 9656        cx: &mut Context<Self>,
 9657    ) {
 9658        if self.read_only(cx) {
 9659            return;
 9660        }
 9661        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9662        for selection in self.selections.all::<Point>(cx) {
 9663            let start = MultiBufferRow(selection.start.row);
 9664            // Treat single line selections as if they include the next line. Otherwise this action
 9665            // would do nothing for single line selections individual cursors.
 9666            let end = if selection.start.row == selection.end.row {
 9667                MultiBufferRow(selection.start.row + 1)
 9668            } else {
 9669                MultiBufferRow(selection.end.row)
 9670            };
 9671
 9672            if let Some(last_row_range) = row_ranges.last_mut() {
 9673                if start <= last_row_range.end {
 9674                    last_row_range.end = end;
 9675                    continue;
 9676                }
 9677            }
 9678            row_ranges.push(start..end);
 9679        }
 9680
 9681        let snapshot = self.buffer.read(cx).snapshot(cx);
 9682        let mut cursor_positions = Vec::new();
 9683        for row_range in &row_ranges {
 9684            let anchor = snapshot.anchor_before(Point::new(
 9685                row_range.end.previous_row().0,
 9686                snapshot.line_len(row_range.end.previous_row()),
 9687            ));
 9688            cursor_positions.push(anchor..anchor);
 9689        }
 9690
 9691        self.transact(window, cx, |this, window, cx| {
 9692            for row_range in row_ranges.into_iter().rev() {
 9693                for row in row_range.iter_rows().rev() {
 9694                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9695                    let next_line_row = row.next_row();
 9696                    let indent = snapshot.indent_size_for_line(next_line_row);
 9697                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9698
 9699                    let replace =
 9700                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9701                            " "
 9702                        } else {
 9703                            ""
 9704                        };
 9705
 9706                    this.buffer.update(cx, |buffer, cx| {
 9707                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9708                    });
 9709                }
 9710            }
 9711
 9712            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9713                s.select_anchor_ranges(cursor_positions)
 9714            });
 9715        });
 9716    }
 9717
 9718    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9719        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9720        self.join_lines_impl(true, window, cx);
 9721    }
 9722
 9723    pub fn sort_lines_case_sensitive(
 9724        &mut self,
 9725        _: &SortLinesCaseSensitive,
 9726        window: &mut Window,
 9727        cx: &mut Context<Self>,
 9728    ) {
 9729        self.manipulate_lines(window, cx, |lines| lines.sort())
 9730    }
 9731
 9732    pub fn sort_lines_case_insensitive(
 9733        &mut self,
 9734        _: &SortLinesCaseInsensitive,
 9735        window: &mut Window,
 9736        cx: &mut Context<Self>,
 9737    ) {
 9738        self.manipulate_lines(window, cx, |lines| {
 9739            lines.sort_by_key(|line| line.to_lowercase())
 9740        })
 9741    }
 9742
 9743    pub fn unique_lines_case_insensitive(
 9744        &mut self,
 9745        _: &UniqueLinesCaseInsensitive,
 9746        window: &mut Window,
 9747        cx: &mut Context<Self>,
 9748    ) {
 9749        self.manipulate_lines(window, cx, |lines| {
 9750            let mut seen = HashSet::default();
 9751            lines.retain(|line| seen.insert(line.to_lowercase()));
 9752        })
 9753    }
 9754
 9755    pub fn unique_lines_case_sensitive(
 9756        &mut self,
 9757        _: &UniqueLinesCaseSensitive,
 9758        window: &mut Window,
 9759        cx: &mut Context<Self>,
 9760    ) {
 9761        self.manipulate_lines(window, cx, |lines| {
 9762            let mut seen = HashSet::default();
 9763            lines.retain(|line| seen.insert(*line));
 9764        })
 9765    }
 9766
 9767    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9768        let Some(project) = self.project.clone() else {
 9769            return;
 9770        };
 9771        self.reload(project, window, cx)
 9772            .detach_and_notify_err(window, cx);
 9773    }
 9774
 9775    pub fn restore_file(
 9776        &mut self,
 9777        _: &::git::RestoreFile,
 9778        window: &mut Window,
 9779        cx: &mut Context<Self>,
 9780    ) {
 9781        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9782        let mut buffer_ids = HashSet::default();
 9783        let snapshot = self.buffer().read(cx).snapshot(cx);
 9784        for selection in self.selections.all::<usize>(cx) {
 9785            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9786        }
 9787
 9788        let buffer = self.buffer().read(cx);
 9789        let ranges = buffer_ids
 9790            .into_iter()
 9791            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9792            .collect::<Vec<_>>();
 9793
 9794        self.restore_hunks_in_ranges(ranges, window, cx);
 9795    }
 9796
 9797    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9798        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9799        let selections = self
 9800            .selections
 9801            .all(cx)
 9802            .into_iter()
 9803            .map(|s| s.range())
 9804            .collect();
 9805        self.restore_hunks_in_ranges(selections, window, cx);
 9806    }
 9807
 9808    pub fn restore_hunks_in_ranges(
 9809        &mut self,
 9810        ranges: Vec<Range<Point>>,
 9811        window: &mut Window,
 9812        cx: &mut Context<Editor>,
 9813    ) {
 9814        let mut revert_changes = HashMap::default();
 9815        let chunk_by = self
 9816            .snapshot(window, cx)
 9817            .hunks_for_ranges(ranges)
 9818            .into_iter()
 9819            .chunk_by(|hunk| hunk.buffer_id);
 9820        for (buffer_id, hunks) in &chunk_by {
 9821            let hunks = hunks.collect::<Vec<_>>();
 9822            for hunk in &hunks {
 9823                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9824            }
 9825            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9826        }
 9827        drop(chunk_by);
 9828        if !revert_changes.is_empty() {
 9829            self.transact(window, cx, |editor, window, cx| {
 9830                editor.restore(revert_changes, window, cx);
 9831            });
 9832        }
 9833    }
 9834
 9835    pub fn open_active_item_in_terminal(
 9836        &mut self,
 9837        _: &OpenInTerminal,
 9838        window: &mut Window,
 9839        cx: &mut Context<Self>,
 9840    ) {
 9841        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9842            let project_path = buffer.read(cx).project_path(cx)?;
 9843            let project = self.project.as_ref()?.read(cx);
 9844            let entry = project.entry_for_path(&project_path, cx)?;
 9845            let parent = match &entry.canonical_path {
 9846                Some(canonical_path) => canonical_path.to_path_buf(),
 9847                None => project.absolute_path(&project_path, cx)?,
 9848            }
 9849            .parent()?
 9850            .to_path_buf();
 9851            Some(parent)
 9852        }) {
 9853            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9854        }
 9855    }
 9856
 9857    fn set_breakpoint_context_menu(
 9858        &mut self,
 9859        display_row: DisplayRow,
 9860        position: Option<Anchor>,
 9861        clicked_point: gpui::Point<Pixels>,
 9862        window: &mut Window,
 9863        cx: &mut Context<Self>,
 9864    ) {
 9865        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9866            return;
 9867        }
 9868        let source = self
 9869            .buffer
 9870            .read(cx)
 9871            .snapshot(cx)
 9872            .anchor_before(Point::new(display_row.0, 0u32));
 9873
 9874        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9875
 9876        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9877            self,
 9878            source,
 9879            clicked_point,
 9880            context_menu,
 9881            window,
 9882            cx,
 9883        );
 9884    }
 9885
 9886    fn add_edit_breakpoint_block(
 9887        &mut self,
 9888        anchor: Anchor,
 9889        breakpoint: &Breakpoint,
 9890        edit_action: BreakpointPromptEditAction,
 9891        window: &mut Window,
 9892        cx: &mut Context<Self>,
 9893    ) {
 9894        let weak_editor = cx.weak_entity();
 9895        let bp_prompt = cx.new(|cx| {
 9896            BreakpointPromptEditor::new(
 9897                weak_editor,
 9898                anchor,
 9899                breakpoint.clone(),
 9900                edit_action,
 9901                window,
 9902                cx,
 9903            )
 9904        });
 9905
 9906        let height = bp_prompt.update(cx, |this, cx| {
 9907            this.prompt
 9908                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9909        });
 9910        let cloned_prompt = bp_prompt.clone();
 9911        let blocks = vec![BlockProperties {
 9912            style: BlockStyle::Sticky,
 9913            placement: BlockPlacement::Above(anchor),
 9914            height: Some(height),
 9915            render: Arc::new(move |cx| {
 9916                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9917                cloned_prompt.clone().into_any_element()
 9918            }),
 9919            priority: 0,
 9920            render_in_minimap: true,
 9921        }];
 9922
 9923        let focus_handle = bp_prompt.focus_handle(cx);
 9924        window.focus(&focus_handle);
 9925
 9926        let block_ids = self.insert_blocks(blocks, None, cx);
 9927        bp_prompt.update(cx, |prompt, _| {
 9928            prompt.add_block_ids(block_ids);
 9929        });
 9930    }
 9931
 9932    pub(crate) fn breakpoint_at_row(
 9933        &self,
 9934        row: u32,
 9935        window: &mut Window,
 9936        cx: &mut Context<Self>,
 9937    ) -> Option<(Anchor, Breakpoint)> {
 9938        let snapshot = self.snapshot(window, cx);
 9939        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9940
 9941        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9942    }
 9943
 9944    pub(crate) fn breakpoint_at_anchor(
 9945        &self,
 9946        breakpoint_position: Anchor,
 9947        snapshot: &EditorSnapshot,
 9948        cx: &mut Context<Self>,
 9949    ) -> Option<(Anchor, Breakpoint)> {
 9950        let project = self.project.clone()?;
 9951
 9952        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9953            snapshot
 9954                .buffer_snapshot
 9955                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9956        })?;
 9957
 9958        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9959        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
 9960        let buffer_snapshot = buffer.read(cx).snapshot();
 9961
 9962        let row = buffer_snapshot
 9963            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9964            .row;
 9965
 9966        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9967        let anchor_end = snapshot
 9968            .buffer_snapshot
 9969            .anchor_after(Point::new(row, line_len));
 9970
 9971        let bp = self
 9972            .breakpoint_store
 9973            .as_ref()?
 9974            .read_with(cx, |breakpoint_store, cx| {
 9975                breakpoint_store
 9976                    .breakpoints(
 9977                        &buffer,
 9978                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9979                        &buffer_snapshot,
 9980                        cx,
 9981                    )
 9982                    .next()
 9983                    .and_then(|(bp, _)| {
 9984                        let breakpoint_row = buffer_snapshot
 9985                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9986                            .row;
 9987
 9988                        if breakpoint_row == row {
 9989                            snapshot
 9990                                .buffer_snapshot
 9991                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9992                                .map(|position| (position, bp.bp.clone()))
 9993                        } else {
 9994                            None
 9995                        }
 9996                    })
 9997            });
 9998        bp
 9999    }
10000
10001    pub fn edit_log_breakpoint(
10002        &mut self,
10003        _: &EditLogBreakpoint,
10004        window: &mut Window,
10005        cx: &mut Context<Self>,
10006    ) {
10007        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10008            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10009                message: None,
10010                state: BreakpointState::Enabled,
10011                condition: None,
10012                hit_condition: None,
10013            });
10014
10015            self.add_edit_breakpoint_block(
10016                anchor,
10017                &breakpoint,
10018                BreakpointPromptEditAction::Log,
10019                window,
10020                cx,
10021            );
10022        }
10023    }
10024
10025    fn breakpoints_at_cursors(
10026        &self,
10027        window: &mut Window,
10028        cx: &mut Context<Self>,
10029    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10030        let snapshot = self.snapshot(window, cx);
10031        let cursors = self
10032            .selections
10033            .disjoint_anchors()
10034            .into_iter()
10035            .map(|selection| {
10036                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10037
10038                let breakpoint_position = self
10039                    .breakpoint_at_row(cursor_position.row, window, cx)
10040                    .map(|bp| bp.0)
10041                    .unwrap_or_else(|| {
10042                        snapshot
10043                            .display_snapshot
10044                            .buffer_snapshot
10045                            .anchor_after(Point::new(cursor_position.row, 0))
10046                    });
10047
10048                let breakpoint = self
10049                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10050                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10051
10052                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10053            })
10054            // 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.
10055            .collect::<HashMap<Anchor, _>>();
10056
10057        cursors.into_iter().collect()
10058    }
10059
10060    pub fn enable_breakpoint(
10061        &mut self,
10062        _: &crate::actions::EnableBreakpoint,
10063        window: &mut Window,
10064        cx: &mut Context<Self>,
10065    ) {
10066        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10067            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10068                continue;
10069            };
10070            self.edit_breakpoint_at_anchor(
10071                anchor,
10072                breakpoint,
10073                BreakpointEditAction::InvertState,
10074                cx,
10075            );
10076        }
10077    }
10078
10079    pub fn disable_breakpoint(
10080        &mut self,
10081        _: &crate::actions::DisableBreakpoint,
10082        window: &mut Window,
10083        cx: &mut Context<Self>,
10084    ) {
10085        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10086            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10087                continue;
10088            };
10089            self.edit_breakpoint_at_anchor(
10090                anchor,
10091                breakpoint,
10092                BreakpointEditAction::InvertState,
10093                cx,
10094            );
10095        }
10096    }
10097
10098    pub fn toggle_breakpoint(
10099        &mut self,
10100        _: &crate::actions::ToggleBreakpoint,
10101        window: &mut Window,
10102        cx: &mut Context<Self>,
10103    ) {
10104        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10105            if let Some(breakpoint) = breakpoint {
10106                self.edit_breakpoint_at_anchor(
10107                    anchor,
10108                    breakpoint,
10109                    BreakpointEditAction::Toggle,
10110                    cx,
10111                );
10112            } else {
10113                self.edit_breakpoint_at_anchor(
10114                    anchor,
10115                    Breakpoint::new_standard(),
10116                    BreakpointEditAction::Toggle,
10117                    cx,
10118                );
10119            }
10120        }
10121    }
10122
10123    pub fn edit_breakpoint_at_anchor(
10124        &mut self,
10125        breakpoint_position: Anchor,
10126        breakpoint: Breakpoint,
10127        edit_action: BreakpointEditAction,
10128        cx: &mut Context<Self>,
10129    ) {
10130        let Some(breakpoint_store) = &self.breakpoint_store else {
10131            return;
10132        };
10133
10134        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10135            if breakpoint_position == Anchor::min() {
10136                self.buffer()
10137                    .read(cx)
10138                    .excerpt_buffer_ids()
10139                    .into_iter()
10140                    .next()
10141            } else {
10142                None
10143            }
10144        }) else {
10145            return;
10146        };
10147
10148        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10149            return;
10150        };
10151
10152        breakpoint_store.update(cx, |breakpoint_store, cx| {
10153            breakpoint_store.toggle_breakpoint(
10154                buffer,
10155                BreakpointWithPosition {
10156                    position: breakpoint_position.text_anchor,
10157                    bp: breakpoint,
10158                },
10159                edit_action,
10160                cx,
10161            );
10162        });
10163
10164        cx.notify();
10165    }
10166
10167    #[cfg(any(test, feature = "test-support"))]
10168    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10169        self.breakpoint_store.clone()
10170    }
10171
10172    pub fn prepare_restore_change(
10173        &self,
10174        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10175        hunk: &MultiBufferDiffHunk,
10176        cx: &mut App,
10177    ) -> Option<()> {
10178        if hunk.is_created_file() {
10179            return None;
10180        }
10181        let buffer = self.buffer.read(cx);
10182        let diff = buffer.diff_for(hunk.buffer_id)?;
10183        let buffer = buffer.buffer(hunk.buffer_id)?;
10184        let buffer = buffer.read(cx);
10185        let original_text = diff
10186            .read(cx)
10187            .base_text()
10188            .as_rope()
10189            .slice(hunk.diff_base_byte_range.clone());
10190        let buffer_snapshot = buffer.snapshot();
10191        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10192        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10193            probe
10194                .0
10195                .start
10196                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10197                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10198        }) {
10199            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10200            Some(())
10201        } else {
10202            None
10203        }
10204    }
10205
10206    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10207        self.manipulate_lines(window, cx, |lines| lines.reverse())
10208    }
10209
10210    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10211        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10212    }
10213
10214    fn manipulate_lines<Fn>(
10215        &mut self,
10216        window: &mut Window,
10217        cx: &mut Context<Self>,
10218        mut callback: Fn,
10219    ) where
10220        Fn: FnMut(&mut Vec<&str>),
10221    {
10222        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10223
10224        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10225        let buffer = self.buffer.read(cx).snapshot(cx);
10226
10227        let mut edits = Vec::new();
10228
10229        let selections = self.selections.all::<Point>(cx);
10230        let mut selections = selections.iter().peekable();
10231        let mut contiguous_row_selections = Vec::new();
10232        let mut new_selections = Vec::new();
10233        let mut added_lines = 0;
10234        let mut removed_lines = 0;
10235
10236        while let Some(selection) = selections.next() {
10237            let (start_row, end_row) = consume_contiguous_rows(
10238                &mut contiguous_row_selections,
10239                selection,
10240                &display_map,
10241                &mut selections,
10242            );
10243
10244            let start_point = Point::new(start_row.0, 0);
10245            let end_point = Point::new(
10246                end_row.previous_row().0,
10247                buffer.line_len(end_row.previous_row()),
10248            );
10249            let text = buffer
10250                .text_for_range(start_point..end_point)
10251                .collect::<String>();
10252
10253            let mut lines = text.split('\n').collect_vec();
10254
10255            let lines_before = lines.len();
10256            callback(&mut lines);
10257            let lines_after = lines.len();
10258
10259            edits.push((start_point..end_point, lines.join("\n")));
10260
10261            // Selections must change based on added and removed line count
10262            let start_row =
10263                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10264            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10265            new_selections.push(Selection {
10266                id: selection.id,
10267                start: start_row,
10268                end: end_row,
10269                goal: SelectionGoal::None,
10270                reversed: selection.reversed,
10271            });
10272
10273            if lines_after > lines_before {
10274                added_lines += lines_after - lines_before;
10275            } else if lines_before > lines_after {
10276                removed_lines += lines_before - lines_after;
10277            }
10278        }
10279
10280        self.transact(window, cx, |this, window, cx| {
10281            let buffer = this.buffer.update(cx, |buffer, cx| {
10282                buffer.edit(edits, None, cx);
10283                buffer.snapshot(cx)
10284            });
10285
10286            // Recalculate offsets on newly edited buffer
10287            let new_selections = new_selections
10288                .iter()
10289                .map(|s| {
10290                    let start_point = Point::new(s.start.0, 0);
10291                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10292                    Selection {
10293                        id: s.id,
10294                        start: buffer.point_to_offset(start_point),
10295                        end: buffer.point_to_offset(end_point),
10296                        goal: s.goal,
10297                        reversed: s.reversed,
10298                    }
10299                })
10300                .collect();
10301
10302            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10303                s.select(new_selections);
10304            });
10305
10306            this.request_autoscroll(Autoscroll::fit(), cx);
10307        });
10308    }
10309
10310    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10311        self.manipulate_text(window, cx, |text| {
10312            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10313            if has_upper_case_characters {
10314                text.to_lowercase()
10315            } else {
10316                text.to_uppercase()
10317            }
10318        })
10319    }
10320
10321    pub fn convert_to_upper_case(
10322        &mut self,
10323        _: &ConvertToUpperCase,
10324        window: &mut Window,
10325        cx: &mut Context<Self>,
10326    ) {
10327        self.manipulate_text(window, cx, |text| text.to_uppercase())
10328    }
10329
10330    pub fn convert_to_lower_case(
10331        &mut self,
10332        _: &ConvertToLowerCase,
10333        window: &mut Window,
10334        cx: &mut Context<Self>,
10335    ) {
10336        self.manipulate_text(window, cx, |text| text.to_lowercase())
10337    }
10338
10339    pub fn convert_to_title_case(
10340        &mut self,
10341        _: &ConvertToTitleCase,
10342        window: &mut Window,
10343        cx: &mut Context<Self>,
10344    ) {
10345        self.manipulate_text(window, cx, |text| {
10346            text.split('\n')
10347                .map(|line| line.to_case(Case::Title))
10348                .join("\n")
10349        })
10350    }
10351
10352    pub fn convert_to_snake_case(
10353        &mut self,
10354        _: &ConvertToSnakeCase,
10355        window: &mut Window,
10356        cx: &mut Context<Self>,
10357    ) {
10358        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10359    }
10360
10361    pub fn convert_to_kebab_case(
10362        &mut self,
10363        _: &ConvertToKebabCase,
10364        window: &mut Window,
10365        cx: &mut Context<Self>,
10366    ) {
10367        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10368    }
10369
10370    pub fn convert_to_upper_camel_case(
10371        &mut self,
10372        _: &ConvertToUpperCamelCase,
10373        window: &mut Window,
10374        cx: &mut Context<Self>,
10375    ) {
10376        self.manipulate_text(window, cx, |text| {
10377            text.split('\n')
10378                .map(|line| line.to_case(Case::UpperCamel))
10379                .join("\n")
10380        })
10381    }
10382
10383    pub fn convert_to_lower_camel_case(
10384        &mut self,
10385        _: &ConvertToLowerCamelCase,
10386        window: &mut Window,
10387        cx: &mut Context<Self>,
10388    ) {
10389        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10390    }
10391
10392    pub fn convert_to_opposite_case(
10393        &mut self,
10394        _: &ConvertToOppositeCase,
10395        window: &mut Window,
10396        cx: &mut Context<Self>,
10397    ) {
10398        self.manipulate_text(window, cx, |text| {
10399            text.chars()
10400                .fold(String::with_capacity(text.len()), |mut t, c| {
10401                    if c.is_uppercase() {
10402                        t.extend(c.to_lowercase());
10403                    } else {
10404                        t.extend(c.to_uppercase());
10405                    }
10406                    t
10407                })
10408        })
10409    }
10410
10411    pub fn convert_to_rot13(
10412        &mut self,
10413        _: &ConvertToRot13,
10414        window: &mut Window,
10415        cx: &mut Context<Self>,
10416    ) {
10417        self.manipulate_text(window, cx, |text| {
10418            text.chars()
10419                .map(|c| match c {
10420                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10421                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10422                    _ => c,
10423                })
10424                .collect()
10425        })
10426    }
10427
10428    pub fn convert_to_rot47(
10429        &mut self,
10430        _: &ConvertToRot47,
10431        window: &mut Window,
10432        cx: &mut Context<Self>,
10433    ) {
10434        self.manipulate_text(window, cx, |text| {
10435            text.chars()
10436                .map(|c| {
10437                    let code_point = c as u32;
10438                    if code_point >= 33 && code_point <= 126 {
10439                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10440                    }
10441                    c
10442                })
10443                .collect()
10444        })
10445    }
10446
10447    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10448    where
10449        Fn: FnMut(&str) -> String,
10450    {
10451        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10452        let buffer = self.buffer.read(cx).snapshot(cx);
10453
10454        let mut new_selections = Vec::new();
10455        let mut edits = Vec::new();
10456        let mut selection_adjustment = 0i32;
10457
10458        for selection in self.selections.all::<usize>(cx) {
10459            let selection_is_empty = selection.is_empty();
10460
10461            let (start, end) = if selection_is_empty {
10462                let word_range = movement::surrounding_word(
10463                    &display_map,
10464                    selection.start.to_display_point(&display_map),
10465                );
10466                let start = word_range.start.to_offset(&display_map, Bias::Left);
10467                let end = word_range.end.to_offset(&display_map, Bias::Left);
10468                (start, end)
10469            } else {
10470                (selection.start, selection.end)
10471            };
10472
10473            let text = buffer.text_for_range(start..end).collect::<String>();
10474            let old_length = text.len() as i32;
10475            let text = callback(&text);
10476
10477            new_selections.push(Selection {
10478                start: (start as i32 - selection_adjustment) as usize,
10479                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10480                goal: SelectionGoal::None,
10481                ..selection
10482            });
10483
10484            selection_adjustment += old_length - text.len() as i32;
10485
10486            edits.push((start..end, text));
10487        }
10488
10489        self.transact(window, cx, |this, window, cx| {
10490            this.buffer.update(cx, |buffer, cx| {
10491                buffer.edit(edits, None, cx);
10492            });
10493
10494            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10495                s.select(new_selections);
10496            });
10497
10498            this.request_autoscroll(Autoscroll::fit(), cx);
10499        });
10500    }
10501
10502    pub fn duplicate(
10503        &mut self,
10504        upwards: bool,
10505        whole_lines: bool,
10506        window: &mut Window,
10507        cx: &mut Context<Self>,
10508    ) {
10509        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10510
10511        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10512        let buffer = &display_map.buffer_snapshot;
10513        let selections = self.selections.all::<Point>(cx);
10514
10515        let mut edits = Vec::new();
10516        let mut selections_iter = selections.iter().peekable();
10517        while let Some(selection) = selections_iter.next() {
10518            let mut rows = selection.spanned_rows(false, &display_map);
10519            // duplicate line-wise
10520            if whole_lines || selection.start == selection.end {
10521                // Avoid duplicating the same lines twice.
10522                while let Some(next_selection) = selections_iter.peek() {
10523                    let next_rows = next_selection.spanned_rows(false, &display_map);
10524                    if next_rows.start < rows.end {
10525                        rows.end = next_rows.end;
10526                        selections_iter.next().unwrap();
10527                    } else {
10528                        break;
10529                    }
10530                }
10531
10532                // Copy the text from the selected row region and splice it either at the start
10533                // or end of the region.
10534                let start = Point::new(rows.start.0, 0);
10535                let end = Point::new(
10536                    rows.end.previous_row().0,
10537                    buffer.line_len(rows.end.previous_row()),
10538                );
10539                let text = buffer
10540                    .text_for_range(start..end)
10541                    .chain(Some("\n"))
10542                    .collect::<String>();
10543                let insert_location = if upwards {
10544                    Point::new(rows.end.0, 0)
10545                } else {
10546                    start
10547                };
10548                edits.push((insert_location..insert_location, text));
10549            } else {
10550                // duplicate character-wise
10551                let start = selection.start;
10552                let end = selection.end;
10553                let text = buffer.text_for_range(start..end).collect::<String>();
10554                edits.push((selection.end..selection.end, text));
10555            }
10556        }
10557
10558        self.transact(window, cx, |this, _, cx| {
10559            this.buffer.update(cx, |buffer, cx| {
10560                buffer.edit(edits, None, cx);
10561            });
10562
10563            this.request_autoscroll(Autoscroll::fit(), cx);
10564        });
10565    }
10566
10567    pub fn duplicate_line_up(
10568        &mut self,
10569        _: &DuplicateLineUp,
10570        window: &mut Window,
10571        cx: &mut Context<Self>,
10572    ) {
10573        self.duplicate(true, true, window, cx);
10574    }
10575
10576    pub fn duplicate_line_down(
10577        &mut self,
10578        _: &DuplicateLineDown,
10579        window: &mut Window,
10580        cx: &mut Context<Self>,
10581    ) {
10582        self.duplicate(false, true, window, cx);
10583    }
10584
10585    pub fn duplicate_selection(
10586        &mut self,
10587        _: &DuplicateSelection,
10588        window: &mut Window,
10589        cx: &mut Context<Self>,
10590    ) {
10591        self.duplicate(false, false, window, cx);
10592    }
10593
10594    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10595        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10596
10597        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10598        let buffer = self.buffer.read(cx).snapshot(cx);
10599
10600        let mut edits = Vec::new();
10601        let mut unfold_ranges = Vec::new();
10602        let mut refold_creases = Vec::new();
10603
10604        let selections = self.selections.all::<Point>(cx);
10605        let mut selections = selections.iter().peekable();
10606        let mut contiguous_row_selections = Vec::new();
10607        let mut new_selections = Vec::new();
10608
10609        while let Some(selection) = selections.next() {
10610            // Find all the selections that span a contiguous row range
10611            let (start_row, end_row) = consume_contiguous_rows(
10612                &mut contiguous_row_selections,
10613                selection,
10614                &display_map,
10615                &mut selections,
10616            );
10617
10618            // Move the text spanned by the row range to be before the line preceding the row range
10619            if start_row.0 > 0 {
10620                let range_to_move = Point::new(
10621                    start_row.previous_row().0,
10622                    buffer.line_len(start_row.previous_row()),
10623                )
10624                    ..Point::new(
10625                        end_row.previous_row().0,
10626                        buffer.line_len(end_row.previous_row()),
10627                    );
10628                let insertion_point = display_map
10629                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10630                    .0;
10631
10632                // Don't move lines across excerpts
10633                if buffer
10634                    .excerpt_containing(insertion_point..range_to_move.end)
10635                    .is_some()
10636                {
10637                    let text = buffer
10638                        .text_for_range(range_to_move.clone())
10639                        .flat_map(|s| s.chars())
10640                        .skip(1)
10641                        .chain(['\n'])
10642                        .collect::<String>();
10643
10644                    edits.push((
10645                        buffer.anchor_after(range_to_move.start)
10646                            ..buffer.anchor_before(range_to_move.end),
10647                        String::new(),
10648                    ));
10649                    let insertion_anchor = buffer.anchor_after(insertion_point);
10650                    edits.push((insertion_anchor..insertion_anchor, text));
10651
10652                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10653
10654                    // Move selections up
10655                    new_selections.extend(contiguous_row_selections.drain(..).map(
10656                        |mut selection| {
10657                            selection.start.row -= row_delta;
10658                            selection.end.row -= row_delta;
10659                            selection
10660                        },
10661                    ));
10662
10663                    // Move folds up
10664                    unfold_ranges.push(range_to_move.clone());
10665                    for fold in display_map.folds_in_range(
10666                        buffer.anchor_before(range_to_move.start)
10667                            ..buffer.anchor_after(range_to_move.end),
10668                    ) {
10669                        let mut start = fold.range.start.to_point(&buffer);
10670                        let mut end = fold.range.end.to_point(&buffer);
10671                        start.row -= row_delta;
10672                        end.row -= row_delta;
10673                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10674                    }
10675                }
10676            }
10677
10678            // If we didn't move line(s), preserve the existing selections
10679            new_selections.append(&mut contiguous_row_selections);
10680        }
10681
10682        self.transact(window, cx, |this, window, cx| {
10683            this.unfold_ranges(&unfold_ranges, true, true, cx);
10684            this.buffer.update(cx, |buffer, cx| {
10685                for (range, text) in edits {
10686                    buffer.edit([(range, text)], None, cx);
10687                }
10688            });
10689            this.fold_creases(refold_creases, true, window, cx);
10690            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10691                s.select(new_selections);
10692            })
10693        });
10694    }
10695
10696    pub fn move_line_down(
10697        &mut self,
10698        _: &MoveLineDown,
10699        window: &mut Window,
10700        cx: &mut Context<Self>,
10701    ) {
10702        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10703
10704        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10705        let buffer = self.buffer.read(cx).snapshot(cx);
10706
10707        let mut edits = Vec::new();
10708        let mut unfold_ranges = Vec::new();
10709        let mut refold_creases = Vec::new();
10710
10711        let selections = self.selections.all::<Point>(cx);
10712        let mut selections = selections.iter().peekable();
10713        let mut contiguous_row_selections = Vec::new();
10714        let mut new_selections = Vec::new();
10715
10716        while let Some(selection) = selections.next() {
10717            // Find all the selections that span a contiguous row range
10718            let (start_row, end_row) = consume_contiguous_rows(
10719                &mut contiguous_row_selections,
10720                selection,
10721                &display_map,
10722                &mut selections,
10723            );
10724
10725            // Move the text spanned by the row range to be after the last line of the row range
10726            if end_row.0 <= buffer.max_point().row {
10727                let range_to_move =
10728                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10729                let insertion_point = display_map
10730                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10731                    .0;
10732
10733                // Don't move lines across excerpt boundaries
10734                if buffer
10735                    .excerpt_containing(range_to_move.start..insertion_point)
10736                    .is_some()
10737                {
10738                    let mut text = String::from("\n");
10739                    text.extend(buffer.text_for_range(range_to_move.clone()));
10740                    text.pop(); // Drop trailing newline
10741                    edits.push((
10742                        buffer.anchor_after(range_to_move.start)
10743                            ..buffer.anchor_before(range_to_move.end),
10744                        String::new(),
10745                    ));
10746                    let insertion_anchor = buffer.anchor_after(insertion_point);
10747                    edits.push((insertion_anchor..insertion_anchor, text));
10748
10749                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10750
10751                    // Move selections down
10752                    new_selections.extend(contiguous_row_selections.drain(..).map(
10753                        |mut selection| {
10754                            selection.start.row += row_delta;
10755                            selection.end.row += row_delta;
10756                            selection
10757                        },
10758                    ));
10759
10760                    // Move folds down
10761                    unfold_ranges.push(range_to_move.clone());
10762                    for fold in display_map.folds_in_range(
10763                        buffer.anchor_before(range_to_move.start)
10764                            ..buffer.anchor_after(range_to_move.end),
10765                    ) {
10766                        let mut start = fold.range.start.to_point(&buffer);
10767                        let mut end = fold.range.end.to_point(&buffer);
10768                        start.row += row_delta;
10769                        end.row += row_delta;
10770                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10771                    }
10772                }
10773            }
10774
10775            // If we didn't move line(s), preserve the existing selections
10776            new_selections.append(&mut contiguous_row_selections);
10777        }
10778
10779        self.transact(window, cx, |this, window, cx| {
10780            this.unfold_ranges(&unfold_ranges, true, true, cx);
10781            this.buffer.update(cx, |buffer, cx| {
10782                for (range, text) in edits {
10783                    buffer.edit([(range, text)], None, cx);
10784                }
10785            });
10786            this.fold_creases(refold_creases, true, window, cx);
10787            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10788                s.select(new_selections)
10789            });
10790        });
10791    }
10792
10793    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10794        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10795        let text_layout_details = &self.text_layout_details(window);
10796        self.transact(window, cx, |this, window, cx| {
10797            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10798                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10799                s.move_with(|display_map, selection| {
10800                    if !selection.is_empty() {
10801                        return;
10802                    }
10803
10804                    let mut head = selection.head();
10805                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10806                    if head.column() == display_map.line_len(head.row()) {
10807                        transpose_offset = display_map
10808                            .buffer_snapshot
10809                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10810                    }
10811
10812                    if transpose_offset == 0 {
10813                        return;
10814                    }
10815
10816                    *head.column_mut() += 1;
10817                    head = display_map.clip_point(head, Bias::Right);
10818                    let goal = SelectionGoal::HorizontalPosition(
10819                        display_map
10820                            .x_for_display_point(head, text_layout_details)
10821                            .into(),
10822                    );
10823                    selection.collapse_to(head, goal);
10824
10825                    let transpose_start = display_map
10826                        .buffer_snapshot
10827                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10828                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10829                        let transpose_end = display_map
10830                            .buffer_snapshot
10831                            .clip_offset(transpose_offset + 1, Bias::Right);
10832                        if let Some(ch) =
10833                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10834                        {
10835                            edits.push((transpose_start..transpose_offset, String::new()));
10836                            edits.push((transpose_end..transpose_end, ch.to_string()));
10837                        }
10838                    }
10839                });
10840                edits
10841            });
10842            this.buffer
10843                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10844            let selections = this.selections.all::<usize>(cx);
10845            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10846                s.select(selections);
10847            });
10848        });
10849    }
10850
10851    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10852        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10853        self.rewrap_impl(RewrapOptions::default(), cx)
10854    }
10855
10856    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10857        let buffer = self.buffer.read(cx).snapshot(cx);
10858        let selections = self.selections.all::<Point>(cx);
10859        let mut selections = selections.iter().peekable();
10860
10861        let mut edits = Vec::new();
10862        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10863
10864        while let Some(selection) = selections.next() {
10865            let mut start_row = selection.start.row;
10866            let mut end_row = selection.end.row;
10867
10868            // Skip selections that overlap with a range that has already been rewrapped.
10869            let selection_range = start_row..end_row;
10870            if rewrapped_row_ranges
10871                .iter()
10872                .any(|range| range.overlaps(&selection_range))
10873            {
10874                continue;
10875            }
10876
10877            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10878
10879            // Since not all lines in the selection may be at the same indent
10880            // level, choose the indent size that is the most common between all
10881            // of the lines.
10882            //
10883            // If there is a tie, we use the deepest indent.
10884            let (indent_size, indent_end) = {
10885                let mut indent_size_occurrences = HashMap::default();
10886                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10887
10888                for row in start_row..=end_row {
10889                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10890                    rows_by_indent_size.entry(indent).or_default().push(row);
10891                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10892                }
10893
10894                let indent_size = indent_size_occurrences
10895                    .into_iter()
10896                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10897                    .map(|(indent, _)| indent)
10898                    .unwrap_or_default();
10899                let row = rows_by_indent_size[&indent_size][0];
10900                let indent_end = Point::new(row, indent_size.len);
10901
10902                (indent_size, indent_end)
10903            };
10904
10905            let mut line_prefix = indent_size.chars().collect::<String>();
10906
10907            let mut inside_comment = false;
10908            if let Some(comment_prefix) =
10909                buffer
10910                    .language_scope_at(selection.head())
10911                    .and_then(|language| {
10912                        language
10913                            .line_comment_prefixes()
10914                            .iter()
10915                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10916                            .cloned()
10917                    })
10918            {
10919                line_prefix.push_str(&comment_prefix);
10920                inside_comment = true;
10921            }
10922
10923            let language_settings = buffer.language_settings_at(selection.head(), cx);
10924            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10925                RewrapBehavior::InComments => inside_comment,
10926                RewrapBehavior::InSelections => !selection.is_empty(),
10927                RewrapBehavior::Anywhere => true,
10928            };
10929
10930            let should_rewrap = options.override_language_settings
10931                || allow_rewrap_based_on_language
10932                || self.hard_wrap.is_some();
10933            if !should_rewrap {
10934                continue;
10935            }
10936
10937            if selection.is_empty() {
10938                'expand_upwards: while start_row > 0 {
10939                    let prev_row = start_row - 1;
10940                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10941                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10942                    {
10943                        start_row = prev_row;
10944                    } else {
10945                        break 'expand_upwards;
10946                    }
10947                }
10948
10949                'expand_downwards: while end_row < buffer.max_point().row {
10950                    let next_row = end_row + 1;
10951                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10952                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10953                    {
10954                        end_row = next_row;
10955                    } else {
10956                        break 'expand_downwards;
10957                    }
10958                }
10959            }
10960
10961            let start = Point::new(start_row, 0);
10962            let start_offset = start.to_offset(&buffer);
10963            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10964            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10965            let Some(lines_without_prefixes) = selection_text
10966                .lines()
10967                .map(|line| {
10968                    line.strip_prefix(&line_prefix)
10969                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10970                        .with_context(|| {
10971                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10972                        })
10973                })
10974                .collect::<Result<Vec<_>, _>>()
10975                .log_err()
10976            else {
10977                continue;
10978            };
10979
10980            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10981                buffer
10982                    .language_settings_at(Point::new(start_row, 0), cx)
10983                    .preferred_line_length as usize
10984            });
10985            let wrapped_text = wrap_with_prefix(
10986                line_prefix,
10987                lines_without_prefixes.join("\n"),
10988                wrap_column,
10989                tab_size,
10990                options.preserve_existing_whitespace,
10991            );
10992
10993            // TODO: should always use char-based diff while still supporting cursor behavior that
10994            // matches vim.
10995            let mut diff_options = DiffOptions::default();
10996            if options.override_language_settings {
10997                diff_options.max_word_diff_len = 0;
10998                diff_options.max_word_diff_line_count = 0;
10999            } else {
11000                diff_options.max_word_diff_len = usize::MAX;
11001                diff_options.max_word_diff_line_count = usize::MAX;
11002            }
11003
11004            for (old_range, new_text) in
11005                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11006            {
11007                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11008                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11009                edits.push((edit_start..edit_end, new_text));
11010            }
11011
11012            rewrapped_row_ranges.push(start_row..=end_row);
11013        }
11014
11015        self.buffer
11016            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11017    }
11018
11019    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11020        let mut text = String::new();
11021        let buffer = self.buffer.read(cx).snapshot(cx);
11022        let mut selections = self.selections.all::<Point>(cx);
11023        let mut clipboard_selections = Vec::with_capacity(selections.len());
11024        {
11025            let max_point = buffer.max_point();
11026            let mut is_first = true;
11027            for selection in &mut selections {
11028                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11029                if is_entire_line {
11030                    selection.start = Point::new(selection.start.row, 0);
11031                    if !selection.is_empty() && selection.end.column == 0 {
11032                        selection.end = cmp::min(max_point, selection.end);
11033                    } else {
11034                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11035                    }
11036                    selection.goal = SelectionGoal::None;
11037                }
11038                if is_first {
11039                    is_first = false;
11040                } else {
11041                    text += "\n";
11042                }
11043                let mut len = 0;
11044                for chunk in buffer.text_for_range(selection.start..selection.end) {
11045                    text.push_str(chunk);
11046                    len += chunk.len();
11047                }
11048                clipboard_selections.push(ClipboardSelection {
11049                    len,
11050                    is_entire_line,
11051                    first_line_indent: buffer
11052                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11053                        .len,
11054                });
11055            }
11056        }
11057
11058        self.transact(window, cx, |this, window, cx| {
11059            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11060                s.select(selections);
11061            });
11062            this.insert("", window, cx);
11063        });
11064        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11065    }
11066
11067    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11068        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11069        let item = self.cut_common(window, cx);
11070        cx.write_to_clipboard(item);
11071    }
11072
11073    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11074        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11075        self.change_selections(None, window, cx, |s| {
11076            s.move_with(|snapshot, sel| {
11077                if sel.is_empty() {
11078                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11079                }
11080            });
11081        });
11082        let item = self.cut_common(window, cx);
11083        cx.set_global(KillRing(item))
11084    }
11085
11086    pub fn kill_ring_yank(
11087        &mut self,
11088        _: &KillRingYank,
11089        window: &mut Window,
11090        cx: &mut Context<Self>,
11091    ) {
11092        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11093        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11094            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11095                (kill_ring.text().to_string(), kill_ring.metadata_json())
11096            } else {
11097                return;
11098            }
11099        } else {
11100            return;
11101        };
11102        self.do_paste(&text, metadata, false, window, cx);
11103    }
11104
11105    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11106        self.do_copy(true, cx);
11107    }
11108
11109    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11110        self.do_copy(false, cx);
11111    }
11112
11113    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11114        let selections = self.selections.all::<Point>(cx);
11115        let buffer = self.buffer.read(cx).read(cx);
11116        let mut text = String::new();
11117
11118        let mut clipboard_selections = Vec::with_capacity(selections.len());
11119        {
11120            let max_point = buffer.max_point();
11121            let mut is_first = true;
11122            for selection in &selections {
11123                let mut start = selection.start;
11124                let mut end = selection.end;
11125                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11126                if is_entire_line {
11127                    start = Point::new(start.row, 0);
11128                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11129                }
11130
11131                let mut trimmed_selections = Vec::new();
11132                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11133                    let row = MultiBufferRow(start.row);
11134                    let first_indent = buffer.indent_size_for_line(row);
11135                    if first_indent.len == 0 || start.column > first_indent.len {
11136                        trimmed_selections.push(start..end);
11137                    } else {
11138                        trimmed_selections.push(
11139                            Point::new(row.0, first_indent.len)
11140                                ..Point::new(row.0, buffer.line_len(row)),
11141                        );
11142                        for row in start.row + 1..=end.row {
11143                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11144                            if row == end.row {
11145                                line_len = end.column;
11146                            }
11147                            if line_len == 0 {
11148                                trimmed_selections
11149                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11150                                continue;
11151                            }
11152                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11153                            if row_indent_size.len >= first_indent.len {
11154                                trimmed_selections.push(
11155                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11156                                );
11157                            } else {
11158                                trimmed_selections.clear();
11159                                trimmed_selections.push(start..end);
11160                                break;
11161                            }
11162                        }
11163                    }
11164                } else {
11165                    trimmed_selections.push(start..end);
11166                }
11167
11168                for trimmed_range in trimmed_selections {
11169                    if is_first {
11170                        is_first = false;
11171                    } else {
11172                        text += "\n";
11173                    }
11174                    let mut len = 0;
11175                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11176                        text.push_str(chunk);
11177                        len += chunk.len();
11178                    }
11179                    clipboard_selections.push(ClipboardSelection {
11180                        len,
11181                        is_entire_line,
11182                        first_line_indent: buffer
11183                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11184                            .len,
11185                    });
11186                }
11187            }
11188        }
11189
11190        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11191            text,
11192            clipboard_selections,
11193        ));
11194    }
11195
11196    pub fn do_paste(
11197        &mut self,
11198        text: &String,
11199        clipboard_selections: Option<Vec<ClipboardSelection>>,
11200        handle_entire_lines: bool,
11201        window: &mut Window,
11202        cx: &mut Context<Self>,
11203    ) {
11204        if self.read_only(cx) {
11205            return;
11206        }
11207
11208        let clipboard_text = Cow::Borrowed(text);
11209
11210        self.transact(window, cx, |this, window, cx| {
11211            if let Some(mut clipboard_selections) = clipboard_selections {
11212                let old_selections = this.selections.all::<usize>(cx);
11213                let all_selections_were_entire_line =
11214                    clipboard_selections.iter().all(|s| s.is_entire_line);
11215                let first_selection_indent_column =
11216                    clipboard_selections.first().map(|s| s.first_line_indent);
11217                if clipboard_selections.len() != old_selections.len() {
11218                    clipboard_selections.drain(..);
11219                }
11220                let cursor_offset = this.selections.last::<usize>(cx).head();
11221                let mut auto_indent_on_paste = true;
11222
11223                this.buffer.update(cx, |buffer, cx| {
11224                    let snapshot = buffer.read(cx);
11225                    auto_indent_on_paste = snapshot
11226                        .language_settings_at(cursor_offset, cx)
11227                        .auto_indent_on_paste;
11228
11229                    let mut start_offset = 0;
11230                    let mut edits = Vec::new();
11231                    let mut original_indent_columns = Vec::new();
11232                    for (ix, selection) in old_selections.iter().enumerate() {
11233                        let to_insert;
11234                        let entire_line;
11235                        let original_indent_column;
11236                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11237                            let end_offset = start_offset + clipboard_selection.len;
11238                            to_insert = &clipboard_text[start_offset..end_offset];
11239                            entire_line = clipboard_selection.is_entire_line;
11240                            start_offset = end_offset + 1;
11241                            original_indent_column = Some(clipboard_selection.first_line_indent);
11242                        } else {
11243                            to_insert = clipboard_text.as_str();
11244                            entire_line = all_selections_were_entire_line;
11245                            original_indent_column = first_selection_indent_column
11246                        }
11247
11248                        // If the corresponding selection was empty when this slice of the
11249                        // clipboard text was written, then the entire line containing the
11250                        // selection was copied. If this selection is also currently empty,
11251                        // then paste the line before the current line of the buffer.
11252                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11253                            let column = selection.start.to_point(&snapshot).column as usize;
11254                            let line_start = selection.start - column;
11255                            line_start..line_start
11256                        } else {
11257                            selection.range()
11258                        };
11259
11260                        edits.push((range, to_insert));
11261                        original_indent_columns.push(original_indent_column);
11262                    }
11263                    drop(snapshot);
11264
11265                    buffer.edit(
11266                        edits,
11267                        if auto_indent_on_paste {
11268                            Some(AutoindentMode::Block {
11269                                original_indent_columns,
11270                            })
11271                        } else {
11272                            None
11273                        },
11274                        cx,
11275                    );
11276                });
11277
11278                let selections = this.selections.all::<usize>(cx);
11279                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11280                    s.select(selections)
11281                });
11282            } else {
11283                this.insert(&clipboard_text, window, cx);
11284            }
11285        });
11286    }
11287
11288    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11289        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11290        if let Some(item) = cx.read_from_clipboard() {
11291            let entries = item.entries();
11292
11293            match entries.first() {
11294                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11295                // of all the pasted entries.
11296                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11297                    .do_paste(
11298                        clipboard_string.text(),
11299                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11300                        true,
11301                        window,
11302                        cx,
11303                    ),
11304                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11305            }
11306        }
11307    }
11308
11309    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11310        if self.read_only(cx) {
11311            return;
11312        }
11313
11314        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11315
11316        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11317            if let Some((selections, _)) =
11318                self.selection_history.transaction(transaction_id).cloned()
11319            {
11320                self.change_selections(None, window, cx, |s| {
11321                    s.select_anchors(selections.to_vec());
11322                });
11323            } else {
11324                log::error!(
11325                    "No entry in selection_history found for undo. \
11326                     This may correspond to a bug where undo does not update the selection. \
11327                     If this is occurring, please add details to \
11328                     https://github.com/zed-industries/zed/issues/22692"
11329                );
11330            }
11331            self.request_autoscroll(Autoscroll::fit(), cx);
11332            self.unmark_text(window, cx);
11333            self.refresh_inline_completion(true, false, window, cx);
11334            cx.emit(EditorEvent::Edited { transaction_id });
11335            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11336        }
11337    }
11338
11339    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11340        if self.read_only(cx) {
11341            return;
11342        }
11343
11344        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11345
11346        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11347            if let Some((_, Some(selections))) =
11348                self.selection_history.transaction(transaction_id).cloned()
11349            {
11350                self.change_selections(None, window, cx, |s| {
11351                    s.select_anchors(selections.to_vec());
11352                });
11353            } else {
11354                log::error!(
11355                    "No entry in selection_history found for redo. \
11356                     This may correspond to a bug where undo does not update the selection. \
11357                     If this is occurring, please add details to \
11358                     https://github.com/zed-industries/zed/issues/22692"
11359                );
11360            }
11361            self.request_autoscroll(Autoscroll::fit(), cx);
11362            self.unmark_text(window, cx);
11363            self.refresh_inline_completion(true, false, window, cx);
11364            cx.emit(EditorEvent::Edited { transaction_id });
11365        }
11366    }
11367
11368    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11369        self.buffer
11370            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11371    }
11372
11373    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11374        self.buffer
11375            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11376    }
11377
11378    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11379        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11380        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11381            s.move_with(|map, selection| {
11382                let cursor = if selection.is_empty() {
11383                    movement::left(map, selection.start)
11384                } else {
11385                    selection.start
11386                };
11387                selection.collapse_to(cursor, SelectionGoal::None);
11388            });
11389        })
11390    }
11391
11392    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11393        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11394        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11395            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11396        })
11397    }
11398
11399    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11400        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11401        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11402            s.move_with(|map, selection| {
11403                let cursor = if selection.is_empty() {
11404                    movement::right(map, selection.end)
11405                } else {
11406                    selection.end
11407                };
11408                selection.collapse_to(cursor, SelectionGoal::None)
11409            });
11410        })
11411    }
11412
11413    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11414        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11415        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11416            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11417        })
11418    }
11419
11420    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11421        if self.take_rename(true, window, cx).is_some() {
11422            return;
11423        }
11424
11425        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11426            cx.propagate();
11427            return;
11428        }
11429
11430        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11431
11432        let text_layout_details = &self.text_layout_details(window);
11433        let selection_count = self.selections.count();
11434        let first_selection = self.selections.first_anchor();
11435
11436        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11437            s.move_with(|map, selection| {
11438                if !selection.is_empty() {
11439                    selection.goal = SelectionGoal::None;
11440                }
11441                let (cursor, goal) = movement::up(
11442                    map,
11443                    selection.start,
11444                    selection.goal,
11445                    false,
11446                    text_layout_details,
11447                );
11448                selection.collapse_to(cursor, goal);
11449            });
11450        });
11451
11452        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11453        {
11454            cx.propagate();
11455        }
11456    }
11457
11458    pub fn move_up_by_lines(
11459        &mut self,
11460        action: &MoveUpByLines,
11461        window: &mut Window,
11462        cx: &mut Context<Self>,
11463    ) {
11464        if self.take_rename(true, window, cx).is_some() {
11465            return;
11466        }
11467
11468        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11469            cx.propagate();
11470            return;
11471        }
11472
11473        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11474
11475        let text_layout_details = &self.text_layout_details(window);
11476
11477        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11478            s.move_with(|map, selection| {
11479                if !selection.is_empty() {
11480                    selection.goal = SelectionGoal::None;
11481                }
11482                let (cursor, goal) = movement::up_by_rows(
11483                    map,
11484                    selection.start,
11485                    action.lines,
11486                    selection.goal,
11487                    false,
11488                    text_layout_details,
11489                );
11490                selection.collapse_to(cursor, goal);
11491            });
11492        })
11493    }
11494
11495    pub fn move_down_by_lines(
11496        &mut self,
11497        action: &MoveDownByLines,
11498        window: &mut Window,
11499        cx: &mut Context<Self>,
11500    ) {
11501        if self.take_rename(true, window, cx).is_some() {
11502            return;
11503        }
11504
11505        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11506            cx.propagate();
11507            return;
11508        }
11509
11510        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11511
11512        let text_layout_details = &self.text_layout_details(window);
11513
11514        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11515            s.move_with(|map, selection| {
11516                if !selection.is_empty() {
11517                    selection.goal = SelectionGoal::None;
11518                }
11519                let (cursor, goal) = movement::down_by_rows(
11520                    map,
11521                    selection.start,
11522                    action.lines,
11523                    selection.goal,
11524                    false,
11525                    text_layout_details,
11526                );
11527                selection.collapse_to(cursor, goal);
11528            });
11529        })
11530    }
11531
11532    pub fn select_down_by_lines(
11533        &mut self,
11534        action: &SelectDownByLines,
11535        window: &mut Window,
11536        cx: &mut Context<Self>,
11537    ) {
11538        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11539        let text_layout_details = &self.text_layout_details(window);
11540        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11541            s.move_heads_with(|map, head, goal| {
11542                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11543            })
11544        })
11545    }
11546
11547    pub fn select_up_by_lines(
11548        &mut self,
11549        action: &SelectUpByLines,
11550        window: &mut Window,
11551        cx: &mut Context<Self>,
11552    ) {
11553        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11554        let text_layout_details = &self.text_layout_details(window);
11555        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11556            s.move_heads_with(|map, head, goal| {
11557                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11558            })
11559        })
11560    }
11561
11562    pub fn select_page_up(
11563        &mut self,
11564        _: &SelectPageUp,
11565        window: &mut Window,
11566        cx: &mut Context<Self>,
11567    ) {
11568        let Some(row_count) = self.visible_row_count() else {
11569            return;
11570        };
11571
11572        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11573
11574        let text_layout_details = &self.text_layout_details(window);
11575
11576        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11577            s.move_heads_with(|map, head, goal| {
11578                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11579            })
11580        })
11581    }
11582
11583    pub fn move_page_up(
11584        &mut self,
11585        action: &MovePageUp,
11586        window: &mut Window,
11587        cx: &mut Context<Self>,
11588    ) {
11589        if self.take_rename(true, window, cx).is_some() {
11590            return;
11591        }
11592
11593        if self
11594            .context_menu
11595            .borrow_mut()
11596            .as_mut()
11597            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11598            .unwrap_or(false)
11599        {
11600            return;
11601        }
11602
11603        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11604            cx.propagate();
11605            return;
11606        }
11607
11608        let Some(row_count) = self.visible_row_count() else {
11609            return;
11610        };
11611
11612        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11613
11614        let autoscroll = if action.center_cursor {
11615            Autoscroll::center()
11616        } else {
11617            Autoscroll::fit()
11618        };
11619
11620        let text_layout_details = &self.text_layout_details(window);
11621
11622        self.change_selections(Some(autoscroll), window, cx, |s| {
11623            s.move_with(|map, selection| {
11624                if !selection.is_empty() {
11625                    selection.goal = SelectionGoal::None;
11626                }
11627                let (cursor, goal) = movement::up_by_rows(
11628                    map,
11629                    selection.end,
11630                    row_count,
11631                    selection.goal,
11632                    false,
11633                    text_layout_details,
11634                );
11635                selection.collapse_to(cursor, goal);
11636            });
11637        });
11638    }
11639
11640    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11641        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11642        let text_layout_details = &self.text_layout_details(window);
11643        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11644            s.move_heads_with(|map, head, goal| {
11645                movement::up(map, head, goal, false, text_layout_details)
11646            })
11647        })
11648    }
11649
11650    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11651        self.take_rename(true, window, cx);
11652
11653        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11654            cx.propagate();
11655            return;
11656        }
11657
11658        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11659
11660        let text_layout_details = &self.text_layout_details(window);
11661        let selection_count = self.selections.count();
11662        let first_selection = self.selections.first_anchor();
11663
11664        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11665            s.move_with(|map, selection| {
11666                if !selection.is_empty() {
11667                    selection.goal = SelectionGoal::None;
11668                }
11669                let (cursor, goal) = movement::down(
11670                    map,
11671                    selection.end,
11672                    selection.goal,
11673                    false,
11674                    text_layout_details,
11675                );
11676                selection.collapse_to(cursor, goal);
11677            });
11678        });
11679
11680        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11681        {
11682            cx.propagate();
11683        }
11684    }
11685
11686    pub fn select_page_down(
11687        &mut self,
11688        _: &SelectPageDown,
11689        window: &mut Window,
11690        cx: &mut Context<Self>,
11691    ) {
11692        let Some(row_count) = self.visible_row_count() else {
11693            return;
11694        };
11695
11696        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11697
11698        let text_layout_details = &self.text_layout_details(window);
11699
11700        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11701            s.move_heads_with(|map, head, goal| {
11702                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11703            })
11704        })
11705    }
11706
11707    pub fn move_page_down(
11708        &mut self,
11709        action: &MovePageDown,
11710        window: &mut Window,
11711        cx: &mut Context<Self>,
11712    ) {
11713        if self.take_rename(true, window, cx).is_some() {
11714            return;
11715        }
11716
11717        if self
11718            .context_menu
11719            .borrow_mut()
11720            .as_mut()
11721            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11722            .unwrap_or(false)
11723        {
11724            return;
11725        }
11726
11727        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11728            cx.propagate();
11729            return;
11730        }
11731
11732        let Some(row_count) = self.visible_row_count() else {
11733            return;
11734        };
11735
11736        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11737
11738        let autoscroll = if action.center_cursor {
11739            Autoscroll::center()
11740        } else {
11741            Autoscroll::fit()
11742        };
11743
11744        let text_layout_details = &self.text_layout_details(window);
11745        self.change_selections(Some(autoscroll), window, cx, |s| {
11746            s.move_with(|map, selection| {
11747                if !selection.is_empty() {
11748                    selection.goal = SelectionGoal::None;
11749                }
11750                let (cursor, goal) = movement::down_by_rows(
11751                    map,
11752                    selection.end,
11753                    row_count,
11754                    selection.goal,
11755                    false,
11756                    text_layout_details,
11757                );
11758                selection.collapse_to(cursor, goal);
11759            });
11760        });
11761    }
11762
11763    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11764        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11765        let text_layout_details = &self.text_layout_details(window);
11766        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11767            s.move_heads_with(|map, head, goal| {
11768                movement::down(map, head, goal, false, text_layout_details)
11769            })
11770        });
11771    }
11772
11773    pub fn context_menu_first(
11774        &mut self,
11775        _: &ContextMenuFirst,
11776        window: &mut Window,
11777        cx: &mut Context<Self>,
11778    ) {
11779        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11780            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11781        }
11782    }
11783
11784    pub fn context_menu_prev(
11785        &mut self,
11786        _: &ContextMenuPrevious,
11787        window: &mut Window,
11788        cx: &mut Context<Self>,
11789    ) {
11790        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11791            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11792        }
11793    }
11794
11795    pub fn context_menu_next(
11796        &mut self,
11797        _: &ContextMenuNext,
11798        window: &mut Window,
11799        cx: &mut Context<Self>,
11800    ) {
11801        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11802            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11803        }
11804    }
11805
11806    pub fn context_menu_last(
11807        &mut self,
11808        _: &ContextMenuLast,
11809        window: &mut Window,
11810        cx: &mut Context<Self>,
11811    ) {
11812        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11813            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11814        }
11815    }
11816
11817    pub fn move_to_previous_word_start(
11818        &mut self,
11819        _: &MoveToPreviousWordStart,
11820        window: &mut Window,
11821        cx: &mut Context<Self>,
11822    ) {
11823        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11824        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11825            s.move_cursors_with(|map, head, _| {
11826                (
11827                    movement::previous_word_start(map, head),
11828                    SelectionGoal::None,
11829                )
11830            });
11831        })
11832    }
11833
11834    pub fn move_to_previous_subword_start(
11835        &mut self,
11836        _: &MoveToPreviousSubwordStart,
11837        window: &mut Window,
11838        cx: &mut Context<Self>,
11839    ) {
11840        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11841        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11842            s.move_cursors_with(|map, head, _| {
11843                (
11844                    movement::previous_subword_start(map, head),
11845                    SelectionGoal::None,
11846                )
11847            });
11848        })
11849    }
11850
11851    pub fn select_to_previous_word_start(
11852        &mut self,
11853        _: &SelectToPreviousWordStart,
11854        window: &mut Window,
11855        cx: &mut Context<Self>,
11856    ) {
11857        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11858        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11859            s.move_heads_with(|map, head, _| {
11860                (
11861                    movement::previous_word_start(map, head),
11862                    SelectionGoal::None,
11863                )
11864            });
11865        })
11866    }
11867
11868    pub fn select_to_previous_subword_start(
11869        &mut self,
11870        _: &SelectToPreviousSubwordStart,
11871        window: &mut Window,
11872        cx: &mut Context<Self>,
11873    ) {
11874        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11875        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11876            s.move_heads_with(|map, head, _| {
11877                (
11878                    movement::previous_subword_start(map, head),
11879                    SelectionGoal::None,
11880                )
11881            });
11882        })
11883    }
11884
11885    pub fn delete_to_previous_word_start(
11886        &mut self,
11887        action: &DeleteToPreviousWordStart,
11888        window: &mut Window,
11889        cx: &mut Context<Self>,
11890    ) {
11891        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11892        self.transact(window, cx, |this, window, cx| {
11893            this.select_autoclose_pair(window, cx);
11894            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11895                s.move_with(|map, selection| {
11896                    if selection.is_empty() {
11897                        let cursor = if action.ignore_newlines {
11898                            movement::previous_word_start(map, selection.head())
11899                        } else {
11900                            movement::previous_word_start_or_newline(map, selection.head())
11901                        };
11902                        selection.set_head(cursor, SelectionGoal::None);
11903                    }
11904                });
11905            });
11906            this.insert("", window, cx);
11907        });
11908    }
11909
11910    pub fn delete_to_previous_subword_start(
11911        &mut self,
11912        _: &DeleteToPreviousSubwordStart,
11913        window: &mut Window,
11914        cx: &mut Context<Self>,
11915    ) {
11916        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11917        self.transact(window, cx, |this, window, cx| {
11918            this.select_autoclose_pair(window, cx);
11919            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11920                s.move_with(|map, selection| {
11921                    if selection.is_empty() {
11922                        let cursor = movement::previous_subword_start(map, selection.head());
11923                        selection.set_head(cursor, SelectionGoal::None);
11924                    }
11925                });
11926            });
11927            this.insert("", window, cx);
11928        });
11929    }
11930
11931    pub fn move_to_next_word_end(
11932        &mut self,
11933        _: &MoveToNextWordEnd,
11934        window: &mut Window,
11935        cx: &mut Context<Self>,
11936    ) {
11937        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11938        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11939            s.move_cursors_with(|map, head, _| {
11940                (movement::next_word_end(map, head), SelectionGoal::None)
11941            });
11942        })
11943    }
11944
11945    pub fn move_to_next_subword_end(
11946        &mut self,
11947        _: &MoveToNextSubwordEnd,
11948        window: &mut Window,
11949        cx: &mut Context<Self>,
11950    ) {
11951        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11952        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11953            s.move_cursors_with(|map, head, _| {
11954                (movement::next_subword_end(map, head), SelectionGoal::None)
11955            });
11956        })
11957    }
11958
11959    pub fn select_to_next_word_end(
11960        &mut self,
11961        _: &SelectToNextWordEnd,
11962        window: &mut Window,
11963        cx: &mut Context<Self>,
11964    ) {
11965        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11966        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11967            s.move_heads_with(|map, head, _| {
11968                (movement::next_word_end(map, head), SelectionGoal::None)
11969            });
11970        })
11971    }
11972
11973    pub fn select_to_next_subword_end(
11974        &mut self,
11975        _: &SelectToNextSubwordEnd,
11976        window: &mut Window,
11977        cx: &mut Context<Self>,
11978    ) {
11979        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11980        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11981            s.move_heads_with(|map, head, _| {
11982                (movement::next_subword_end(map, head), SelectionGoal::None)
11983            });
11984        })
11985    }
11986
11987    pub fn delete_to_next_word_end(
11988        &mut self,
11989        action: &DeleteToNextWordEnd,
11990        window: &mut Window,
11991        cx: &mut Context<Self>,
11992    ) {
11993        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11994        self.transact(window, cx, |this, window, cx| {
11995            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11996                s.move_with(|map, selection| {
11997                    if selection.is_empty() {
11998                        let cursor = if action.ignore_newlines {
11999                            movement::next_word_end(map, selection.head())
12000                        } else {
12001                            movement::next_word_end_or_newline(map, selection.head())
12002                        };
12003                        selection.set_head(cursor, SelectionGoal::None);
12004                    }
12005                });
12006            });
12007            this.insert("", window, cx);
12008        });
12009    }
12010
12011    pub fn delete_to_next_subword_end(
12012        &mut self,
12013        _: &DeleteToNextSubwordEnd,
12014        window: &mut Window,
12015        cx: &mut Context<Self>,
12016    ) {
12017        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12018        self.transact(window, cx, |this, window, cx| {
12019            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12020                s.move_with(|map, selection| {
12021                    if selection.is_empty() {
12022                        let cursor = movement::next_subword_end(map, selection.head());
12023                        selection.set_head(cursor, SelectionGoal::None);
12024                    }
12025                });
12026            });
12027            this.insert("", window, cx);
12028        });
12029    }
12030
12031    pub fn move_to_beginning_of_line(
12032        &mut self,
12033        action: &MoveToBeginningOfLine,
12034        window: &mut Window,
12035        cx: &mut Context<Self>,
12036    ) {
12037        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12038        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12039            s.move_cursors_with(|map, head, _| {
12040                (
12041                    movement::indented_line_beginning(
12042                        map,
12043                        head,
12044                        action.stop_at_soft_wraps,
12045                        action.stop_at_indent,
12046                    ),
12047                    SelectionGoal::None,
12048                )
12049            });
12050        })
12051    }
12052
12053    pub fn select_to_beginning_of_line(
12054        &mut self,
12055        action: &SelectToBeginningOfLine,
12056        window: &mut Window,
12057        cx: &mut Context<Self>,
12058    ) {
12059        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12060        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12061            s.move_heads_with(|map, head, _| {
12062                (
12063                    movement::indented_line_beginning(
12064                        map,
12065                        head,
12066                        action.stop_at_soft_wraps,
12067                        action.stop_at_indent,
12068                    ),
12069                    SelectionGoal::None,
12070                )
12071            });
12072        });
12073    }
12074
12075    pub fn delete_to_beginning_of_line(
12076        &mut self,
12077        action: &DeleteToBeginningOfLine,
12078        window: &mut Window,
12079        cx: &mut Context<Self>,
12080    ) {
12081        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12082        self.transact(window, cx, |this, window, cx| {
12083            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12084                s.move_with(|_, selection| {
12085                    selection.reversed = true;
12086                });
12087            });
12088
12089            this.select_to_beginning_of_line(
12090                &SelectToBeginningOfLine {
12091                    stop_at_soft_wraps: false,
12092                    stop_at_indent: action.stop_at_indent,
12093                },
12094                window,
12095                cx,
12096            );
12097            this.backspace(&Backspace, window, cx);
12098        });
12099    }
12100
12101    pub fn move_to_end_of_line(
12102        &mut self,
12103        action: &MoveToEndOfLine,
12104        window: &mut Window,
12105        cx: &mut Context<Self>,
12106    ) {
12107        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12108        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12109            s.move_cursors_with(|map, head, _| {
12110                (
12111                    movement::line_end(map, head, action.stop_at_soft_wraps),
12112                    SelectionGoal::None,
12113                )
12114            });
12115        })
12116    }
12117
12118    pub fn select_to_end_of_line(
12119        &mut self,
12120        action: &SelectToEndOfLine,
12121        window: &mut Window,
12122        cx: &mut Context<Self>,
12123    ) {
12124        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12125        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12126            s.move_heads_with(|map, head, _| {
12127                (
12128                    movement::line_end(map, head, action.stop_at_soft_wraps),
12129                    SelectionGoal::None,
12130                )
12131            });
12132        })
12133    }
12134
12135    pub fn delete_to_end_of_line(
12136        &mut self,
12137        _: &DeleteToEndOfLine,
12138        window: &mut Window,
12139        cx: &mut Context<Self>,
12140    ) {
12141        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12142        self.transact(window, cx, |this, window, cx| {
12143            this.select_to_end_of_line(
12144                &SelectToEndOfLine {
12145                    stop_at_soft_wraps: false,
12146                },
12147                window,
12148                cx,
12149            );
12150            this.delete(&Delete, window, cx);
12151        });
12152    }
12153
12154    pub fn cut_to_end_of_line(
12155        &mut self,
12156        _: &CutToEndOfLine,
12157        window: &mut Window,
12158        cx: &mut Context<Self>,
12159    ) {
12160        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12161        self.transact(window, cx, |this, window, cx| {
12162            this.select_to_end_of_line(
12163                &SelectToEndOfLine {
12164                    stop_at_soft_wraps: false,
12165                },
12166                window,
12167                cx,
12168            );
12169            this.cut(&Cut, window, cx);
12170        });
12171    }
12172
12173    pub fn move_to_start_of_paragraph(
12174        &mut self,
12175        _: &MoveToStartOfParagraph,
12176        window: &mut Window,
12177        cx: &mut Context<Self>,
12178    ) {
12179        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12180            cx.propagate();
12181            return;
12182        }
12183        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12184        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12185            s.move_with(|map, selection| {
12186                selection.collapse_to(
12187                    movement::start_of_paragraph(map, selection.head(), 1),
12188                    SelectionGoal::None,
12189                )
12190            });
12191        })
12192    }
12193
12194    pub fn move_to_end_of_paragraph(
12195        &mut self,
12196        _: &MoveToEndOfParagraph,
12197        window: &mut Window,
12198        cx: &mut Context<Self>,
12199    ) {
12200        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12201            cx.propagate();
12202            return;
12203        }
12204        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12205        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12206            s.move_with(|map, selection| {
12207                selection.collapse_to(
12208                    movement::end_of_paragraph(map, selection.head(), 1),
12209                    SelectionGoal::None,
12210                )
12211            });
12212        })
12213    }
12214
12215    pub fn select_to_start_of_paragraph(
12216        &mut self,
12217        _: &SelectToStartOfParagraph,
12218        window: &mut Window,
12219        cx: &mut Context<Self>,
12220    ) {
12221        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12222            cx.propagate();
12223            return;
12224        }
12225        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12226        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12227            s.move_heads_with(|map, head, _| {
12228                (
12229                    movement::start_of_paragraph(map, head, 1),
12230                    SelectionGoal::None,
12231                )
12232            });
12233        })
12234    }
12235
12236    pub fn select_to_end_of_paragraph(
12237        &mut self,
12238        _: &SelectToEndOfParagraph,
12239        window: &mut Window,
12240        cx: &mut Context<Self>,
12241    ) {
12242        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12243            cx.propagate();
12244            return;
12245        }
12246        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12247        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12248            s.move_heads_with(|map, head, _| {
12249                (
12250                    movement::end_of_paragraph(map, head, 1),
12251                    SelectionGoal::None,
12252                )
12253            });
12254        })
12255    }
12256
12257    pub fn move_to_start_of_excerpt(
12258        &mut self,
12259        _: &MoveToStartOfExcerpt,
12260        window: &mut Window,
12261        cx: &mut Context<Self>,
12262    ) {
12263        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12264            cx.propagate();
12265            return;
12266        }
12267        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12268        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12269            s.move_with(|map, selection| {
12270                selection.collapse_to(
12271                    movement::start_of_excerpt(
12272                        map,
12273                        selection.head(),
12274                        workspace::searchable::Direction::Prev,
12275                    ),
12276                    SelectionGoal::None,
12277                )
12278            });
12279        })
12280    }
12281
12282    pub fn move_to_start_of_next_excerpt(
12283        &mut self,
12284        _: &MoveToStartOfNextExcerpt,
12285        window: &mut Window,
12286        cx: &mut Context<Self>,
12287    ) {
12288        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12289            cx.propagate();
12290            return;
12291        }
12292
12293        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12294            s.move_with(|map, selection| {
12295                selection.collapse_to(
12296                    movement::start_of_excerpt(
12297                        map,
12298                        selection.head(),
12299                        workspace::searchable::Direction::Next,
12300                    ),
12301                    SelectionGoal::None,
12302                )
12303            });
12304        })
12305    }
12306
12307    pub fn move_to_end_of_excerpt(
12308        &mut self,
12309        _: &MoveToEndOfExcerpt,
12310        window: &mut Window,
12311        cx: &mut Context<Self>,
12312    ) {
12313        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12314            cx.propagate();
12315            return;
12316        }
12317        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12318        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12319            s.move_with(|map, selection| {
12320                selection.collapse_to(
12321                    movement::end_of_excerpt(
12322                        map,
12323                        selection.head(),
12324                        workspace::searchable::Direction::Next,
12325                    ),
12326                    SelectionGoal::None,
12327                )
12328            });
12329        })
12330    }
12331
12332    pub fn move_to_end_of_previous_excerpt(
12333        &mut self,
12334        _: &MoveToEndOfPreviousExcerpt,
12335        window: &mut Window,
12336        cx: &mut Context<Self>,
12337    ) {
12338        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12339            cx.propagate();
12340            return;
12341        }
12342        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12343        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12344            s.move_with(|map, selection| {
12345                selection.collapse_to(
12346                    movement::end_of_excerpt(
12347                        map,
12348                        selection.head(),
12349                        workspace::searchable::Direction::Prev,
12350                    ),
12351                    SelectionGoal::None,
12352                )
12353            });
12354        })
12355    }
12356
12357    pub fn select_to_start_of_excerpt(
12358        &mut self,
12359        _: &SelectToStartOfExcerpt,
12360        window: &mut Window,
12361        cx: &mut Context<Self>,
12362    ) {
12363        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12364            cx.propagate();
12365            return;
12366        }
12367        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12368        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12369            s.move_heads_with(|map, head, _| {
12370                (
12371                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12372                    SelectionGoal::None,
12373                )
12374            });
12375        })
12376    }
12377
12378    pub fn select_to_start_of_next_excerpt(
12379        &mut self,
12380        _: &SelectToStartOfNextExcerpt,
12381        window: &mut Window,
12382        cx: &mut Context<Self>,
12383    ) {
12384        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12385            cx.propagate();
12386            return;
12387        }
12388        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12389        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12390            s.move_heads_with(|map, head, _| {
12391                (
12392                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12393                    SelectionGoal::None,
12394                )
12395            });
12396        })
12397    }
12398
12399    pub fn select_to_end_of_excerpt(
12400        &mut self,
12401        _: &SelectToEndOfExcerpt,
12402        window: &mut Window,
12403        cx: &mut Context<Self>,
12404    ) {
12405        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12406            cx.propagate();
12407            return;
12408        }
12409        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12410        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12411            s.move_heads_with(|map, head, _| {
12412                (
12413                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12414                    SelectionGoal::None,
12415                )
12416            });
12417        })
12418    }
12419
12420    pub fn select_to_end_of_previous_excerpt(
12421        &mut self,
12422        _: &SelectToEndOfPreviousExcerpt,
12423        window: &mut Window,
12424        cx: &mut Context<Self>,
12425    ) {
12426        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12427            cx.propagate();
12428            return;
12429        }
12430        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12431        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12432            s.move_heads_with(|map, head, _| {
12433                (
12434                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12435                    SelectionGoal::None,
12436                )
12437            });
12438        })
12439    }
12440
12441    pub fn move_to_beginning(
12442        &mut self,
12443        _: &MoveToBeginning,
12444        window: &mut Window,
12445        cx: &mut Context<Self>,
12446    ) {
12447        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12448            cx.propagate();
12449            return;
12450        }
12451        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12452        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12453            s.select_ranges(vec![0..0]);
12454        });
12455    }
12456
12457    pub fn select_to_beginning(
12458        &mut self,
12459        _: &SelectToBeginning,
12460        window: &mut Window,
12461        cx: &mut Context<Self>,
12462    ) {
12463        let mut selection = self.selections.last::<Point>(cx);
12464        selection.set_head(Point::zero(), SelectionGoal::None);
12465        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12466        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12467            s.select(vec![selection]);
12468        });
12469    }
12470
12471    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12472        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12473            cx.propagate();
12474            return;
12475        }
12476        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12477        let cursor = self.buffer.read(cx).read(cx).len();
12478        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12479            s.select_ranges(vec![cursor..cursor])
12480        });
12481    }
12482
12483    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12484        self.nav_history = nav_history;
12485    }
12486
12487    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12488        self.nav_history.as_ref()
12489    }
12490
12491    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12492        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12493    }
12494
12495    fn push_to_nav_history(
12496        &mut self,
12497        cursor_anchor: Anchor,
12498        new_position: Option<Point>,
12499        is_deactivate: bool,
12500        cx: &mut Context<Self>,
12501    ) {
12502        if let Some(nav_history) = self.nav_history.as_mut() {
12503            let buffer = self.buffer.read(cx).read(cx);
12504            let cursor_position = cursor_anchor.to_point(&buffer);
12505            let scroll_state = self.scroll_manager.anchor();
12506            let scroll_top_row = scroll_state.top_row(&buffer);
12507            drop(buffer);
12508
12509            if let Some(new_position) = new_position {
12510                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12511                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12512                    return;
12513                }
12514            }
12515
12516            nav_history.push(
12517                Some(NavigationData {
12518                    cursor_anchor,
12519                    cursor_position,
12520                    scroll_anchor: scroll_state,
12521                    scroll_top_row,
12522                }),
12523                cx,
12524            );
12525            cx.emit(EditorEvent::PushedToNavHistory {
12526                anchor: cursor_anchor,
12527                is_deactivate,
12528            })
12529        }
12530    }
12531
12532    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12533        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12534        let buffer = self.buffer.read(cx).snapshot(cx);
12535        let mut selection = self.selections.first::<usize>(cx);
12536        selection.set_head(buffer.len(), SelectionGoal::None);
12537        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12538            s.select(vec![selection]);
12539        });
12540    }
12541
12542    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12543        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12544        let end = self.buffer.read(cx).read(cx).len();
12545        self.change_selections(None, window, cx, |s| {
12546            s.select_ranges(vec![0..end]);
12547        });
12548    }
12549
12550    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12551        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12552        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12553        let mut selections = self.selections.all::<Point>(cx);
12554        let max_point = display_map.buffer_snapshot.max_point();
12555        for selection in &mut selections {
12556            let rows = selection.spanned_rows(true, &display_map);
12557            selection.start = Point::new(rows.start.0, 0);
12558            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12559            selection.reversed = false;
12560        }
12561        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12562            s.select(selections);
12563        });
12564    }
12565
12566    pub fn split_selection_into_lines(
12567        &mut self,
12568        _: &SplitSelectionIntoLines,
12569        window: &mut Window,
12570        cx: &mut Context<Self>,
12571    ) {
12572        let selections = self
12573            .selections
12574            .all::<Point>(cx)
12575            .into_iter()
12576            .map(|selection| selection.start..selection.end)
12577            .collect::<Vec<_>>();
12578        self.unfold_ranges(&selections, true, true, cx);
12579
12580        let mut new_selection_ranges = Vec::new();
12581        {
12582            let buffer = self.buffer.read(cx).read(cx);
12583            for selection in selections {
12584                for row in selection.start.row..selection.end.row {
12585                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12586                    new_selection_ranges.push(cursor..cursor);
12587                }
12588
12589                let is_multiline_selection = selection.start.row != selection.end.row;
12590                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12591                // so this action feels more ergonomic when paired with other selection operations
12592                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12593                if !should_skip_last {
12594                    new_selection_ranges.push(selection.end..selection.end);
12595                }
12596            }
12597        }
12598        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12599            s.select_ranges(new_selection_ranges);
12600        });
12601    }
12602
12603    pub fn add_selection_above(
12604        &mut self,
12605        _: &AddSelectionAbove,
12606        window: &mut Window,
12607        cx: &mut Context<Self>,
12608    ) {
12609        self.add_selection(true, window, cx);
12610    }
12611
12612    pub fn add_selection_below(
12613        &mut self,
12614        _: &AddSelectionBelow,
12615        window: &mut Window,
12616        cx: &mut Context<Self>,
12617    ) {
12618        self.add_selection(false, window, cx);
12619    }
12620
12621    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12622        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12623
12624        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12625        let mut selections = self.selections.all::<Point>(cx);
12626        let text_layout_details = self.text_layout_details(window);
12627        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12628            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12629            let range = oldest_selection.display_range(&display_map).sorted();
12630
12631            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12632            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12633            let positions = start_x.min(end_x)..start_x.max(end_x);
12634
12635            selections.clear();
12636            let mut stack = Vec::new();
12637            for row in range.start.row().0..=range.end.row().0 {
12638                if let Some(selection) = self.selections.build_columnar_selection(
12639                    &display_map,
12640                    DisplayRow(row),
12641                    &positions,
12642                    oldest_selection.reversed,
12643                    &text_layout_details,
12644                ) {
12645                    stack.push(selection.id);
12646                    selections.push(selection);
12647                }
12648            }
12649
12650            if above {
12651                stack.reverse();
12652            }
12653
12654            AddSelectionsState { above, stack }
12655        });
12656
12657        let last_added_selection = *state.stack.last().unwrap();
12658        let mut new_selections = Vec::new();
12659        if above == state.above {
12660            let end_row = if above {
12661                DisplayRow(0)
12662            } else {
12663                display_map.max_point().row()
12664            };
12665
12666            'outer: for selection in selections {
12667                if selection.id == last_added_selection {
12668                    let range = selection.display_range(&display_map).sorted();
12669                    debug_assert_eq!(range.start.row(), range.end.row());
12670                    let mut row = range.start.row();
12671                    let positions =
12672                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12673                            px(start)..px(end)
12674                        } else {
12675                            let start_x =
12676                                display_map.x_for_display_point(range.start, &text_layout_details);
12677                            let end_x =
12678                                display_map.x_for_display_point(range.end, &text_layout_details);
12679                            start_x.min(end_x)..start_x.max(end_x)
12680                        };
12681
12682                    while row != end_row {
12683                        if above {
12684                            row.0 -= 1;
12685                        } else {
12686                            row.0 += 1;
12687                        }
12688
12689                        if let Some(new_selection) = self.selections.build_columnar_selection(
12690                            &display_map,
12691                            row,
12692                            &positions,
12693                            selection.reversed,
12694                            &text_layout_details,
12695                        ) {
12696                            state.stack.push(new_selection.id);
12697                            if above {
12698                                new_selections.push(new_selection);
12699                                new_selections.push(selection);
12700                            } else {
12701                                new_selections.push(selection);
12702                                new_selections.push(new_selection);
12703                            }
12704
12705                            continue 'outer;
12706                        }
12707                    }
12708                }
12709
12710                new_selections.push(selection);
12711            }
12712        } else {
12713            new_selections = selections;
12714            new_selections.retain(|s| s.id != last_added_selection);
12715            state.stack.pop();
12716        }
12717
12718        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12719            s.select(new_selections);
12720        });
12721        if state.stack.len() > 1 {
12722            self.add_selections_state = Some(state);
12723        }
12724    }
12725
12726    fn select_match_ranges(
12727        &mut self,
12728        range: Range<usize>,
12729        reversed: bool,
12730        replace_newest: bool,
12731        auto_scroll: Option<Autoscroll>,
12732        window: &mut Window,
12733        cx: &mut Context<Editor>,
12734    ) {
12735        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12736        self.change_selections(auto_scroll, window, cx, |s| {
12737            if replace_newest {
12738                s.delete(s.newest_anchor().id);
12739            }
12740            if reversed {
12741                s.insert_range(range.end..range.start);
12742            } else {
12743                s.insert_range(range);
12744            }
12745        });
12746    }
12747
12748    pub fn select_next_match_internal(
12749        &mut self,
12750        display_map: &DisplaySnapshot,
12751        replace_newest: bool,
12752        autoscroll: Option<Autoscroll>,
12753        window: &mut Window,
12754        cx: &mut Context<Self>,
12755    ) -> Result<()> {
12756        let buffer = &display_map.buffer_snapshot;
12757        let mut selections = self.selections.all::<usize>(cx);
12758        if let Some(mut select_next_state) = self.select_next_state.take() {
12759            let query = &select_next_state.query;
12760            if !select_next_state.done {
12761                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12762                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12763                let mut next_selected_range = None;
12764
12765                let bytes_after_last_selection =
12766                    buffer.bytes_in_range(last_selection.end..buffer.len());
12767                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12768                let query_matches = query
12769                    .stream_find_iter(bytes_after_last_selection)
12770                    .map(|result| (last_selection.end, result))
12771                    .chain(
12772                        query
12773                            .stream_find_iter(bytes_before_first_selection)
12774                            .map(|result| (0, result)),
12775                    );
12776
12777                for (start_offset, query_match) in query_matches {
12778                    let query_match = query_match.unwrap(); // can only fail due to I/O
12779                    let offset_range =
12780                        start_offset + query_match.start()..start_offset + query_match.end();
12781                    let display_range = offset_range.start.to_display_point(display_map)
12782                        ..offset_range.end.to_display_point(display_map);
12783
12784                    if !select_next_state.wordwise
12785                        || (!movement::is_inside_word(display_map, display_range.start)
12786                            && !movement::is_inside_word(display_map, display_range.end))
12787                    {
12788                        // TODO: This is n^2, because we might check all the selections
12789                        if !selections
12790                            .iter()
12791                            .any(|selection| selection.range().overlaps(&offset_range))
12792                        {
12793                            next_selected_range = Some(offset_range);
12794                            break;
12795                        }
12796                    }
12797                }
12798
12799                if let Some(next_selected_range) = next_selected_range {
12800                    self.select_match_ranges(
12801                        next_selected_range,
12802                        last_selection.reversed,
12803                        replace_newest,
12804                        autoscroll,
12805                        window,
12806                        cx,
12807                    );
12808                } else {
12809                    select_next_state.done = true;
12810                }
12811            }
12812
12813            self.select_next_state = Some(select_next_state);
12814        } else {
12815            let mut only_carets = true;
12816            let mut same_text_selected = true;
12817            let mut selected_text = None;
12818
12819            let mut selections_iter = selections.iter().peekable();
12820            while let Some(selection) = selections_iter.next() {
12821                if selection.start != selection.end {
12822                    only_carets = false;
12823                }
12824
12825                if same_text_selected {
12826                    if selected_text.is_none() {
12827                        selected_text =
12828                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12829                    }
12830
12831                    if let Some(next_selection) = selections_iter.peek() {
12832                        if next_selection.range().len() == selection.range().len() {
12833                            let next_selected_text = buffer
12834                                .text_for_range(next_selection.range())
12835                                .collect::<String>();
12836                            if Some(next_selected_text) != selected_text {
12837                                same_text_selected = false;
12838                                selected_text = None;
12839                            }
12840                        } else {
12841                            same_text_selected = false;
12842                            selected_text = None;
12843                        }
12844                    }
12845                }
12846            }
12847
12848            if only_carets {
12849                for selection in &mut selections {
12850                    let word_range = movement::surrounding_word(
12851                        display_map,
12852                        selection.start.to_display_point(display_map),
12853                    );
12854                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12855                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12856                    selection.goal = SelectionGoal::None;
12857                    selection.reversed = false;
12858                    self.select_match_ranges(
12859                        selection.start..selection.end,
12860                        selection.reversed,
12861                        replace_newest,
12862                        autoscroll,
12863                        window,
12864                        cx,
12865                    );
12866                }
12867
12868                if selections.len() == 1 {
12869                    let selection = selections
12870                        .last()
12871                        .expect("ensured that there's only one selection");
12872                    let query = buffer
12873                        .text_for_range(selection.start..selection.end)
12874                        .collect::<String>();
12875                    let is_empty = query.is_empty();
12876                    let select_state = SelectNextState {
12877                        query: AhoCorasick::new(&[query])?,
12878                        wordwise: true,
12879                        done: is_empty,
12880                    };
12881                    self.select_next_state = Some(select_state);
12882                } else {
12883                    self.select_next_state = None;
12884                }
12885            } else if let Some(selected_text) = selected_text {
12886                self.select_next_state = Some(SelectNextState {
12887                    query: AhoCorasick::new(&[selected_text])?,
12888                    wordwise: false,
12889                    done: false,
12890                });
12891                self.select_next_match_internal(
12892                    display_map,
12893                    replace_newest,
12894                    autoscroll,
12895                    window,
12896                    cx,
12897                )?;
12898            }
12899        }
12900        Ok(())
12901    }
12902
12903    pub fn select_all_matches(
12904        &mut self,
12905        _action: &SelectAllMatches,
12906        window: &mut Window,
12907        cx: &mut Context<Self>,
12908    ) -> Result<()> {
12909        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12910
12911        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12912
12913        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12914        let Some(select_next_state) = self.select_next_state.as_mut() else {
12915            return Ok(());
12916        };
12917        if select_next_state.done {
12918            return Ok(());
12919        }
12920
12921        let mut new_selections = Vec::new();
12922
12923        let reversed = self.selections.oldest::<usize>(cx).reversed;
12924        let buffer = &display_map.buffer_snapshot;
12925        let query_matches = select_next_state
12926            .query
12927            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12928
12929        for query_match in query_matches.into_iter() {
12930            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12931            let offset_range = if reversed {
12932                query_match.end()..query_match.start()
12933            } else {
12934                query_match.start()..query_match.end()
12935            };
12936            let display_range = offset_range.start.to_display_point(&display_map)
12937                ..offset_range.end.to_display_point(&display_map);
12938
12939            if !select_next_state.wordwise
12940                || (!movement::is_inside_word(&display_map, display_range.start)
12941                    && !movement::is_inside_word(&display_map, display_range.end))
12942            {
12943                new_selections.push(offset_range.start..offset_range.end);
12944            }
12945        }
12946
12947        select_next_state.done = true;
12948        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12949        self.change_selections(None, window, cx, |selections| {
12950            selections.select_ranges(new_selections)
12951        });
12952
12953        Ok(())
12954    }
12955
12956    pub fn select_next(
12957        &mut self,
12958        action: &SelectNext,
12959        window: &mut Window,
12960        cx: &mut Context<Self>,
12961    ) -> Result<()> {
12962        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12963        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12964        self.select_next_match_internal(
12965            &display_map,
12966            action.replace_newest,
12967            Some(Autoscroll::newest()),
12968            window,
12969            cx,
12970        )?;
12971        Ok(())
12972    }
12973
12974    pub fn select_previous(
12975        &mut self,
12976        action: &SelectPrevious,
12977        window: &mut Window,
12978        cx: &mut Context<Self>,
12979    ) -> Result<()> {
12980        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12981        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12982        let buffer = &display_map.buffer_snapshot;
12983        let mut selections = self.selections.all::<usize>(cx);
12984        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12985            let query = &select_prev_state.query;
12986            if !select_prev_state.done {
12987                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12988                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12989                let mut next_selected_range = None;
12990                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12991                let bytes_before_last_selection =
12992                    buffer.reversed_bytes_in_range(0..last_selection.start);
12993                let bytes_after_first_selection =
12994                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12995                let query_matches = query
12996                    .stream_find_iter(bytes_before_last_selection)
12997                    .map(|result| (last_selection.start, result))
12998                    .chain(
12999                        query
13000                            .stream_find_iter(bytes_after_first_selection)
13001                            .map(|result| (buffer.len(), result)),
13002                    );
13003                for (end_offset, query_match) in query_matches {
13004                    let query_match = query_match.unwrap(); // can only fail due to I/O
13005                    let offset_range =
13006                        end_offset - query_match.end()..end_offset - query_match.start();
13007                    let display_range = offset_range.start.to_display_point(&display_map)
13008                        ..offset_range.end.to_display_point(&display_map);
13009
13010                    if !select_prev_state.wordwise
13011                        || (!movement::is_inside_word(&display_map, display_range.start)
13012                            && !movement::is_inside_word(&display_map, display_range.end))
13013                    {
13014                        next_selected_range = Some(offset_range);
13015                        break;
13016                    }
13017                }
13018
13019                if let Some(next_selected_range) = next_selected_range {
13020                    self.select_match_ranges(
13021                        next_selected_range,
13022                        last_selection.reversed,
13023                        action.replace_newest,
13024                        Some(Autoscroll::newest()),
13025                        window,
13026                        cx,
13027                    );
13028                } else {
13029                    select_prev_state.done = true;
13030                }
13031            }
13032
13033            self.select_prev_state = Some(select_prev_state);
13034        } else {
13035            let mut only_carets = true;
13036            let mut same_text_selected = true;
13037            let mut selected_text = None;
13038
13039            let mut selections_iter = selections.iter().peekable();
13040            while let Some(selection) = selections_iter.next() {
13041                if selection.start != selection.end {
13042                    only_carets = false;
13043                }
13044
13045                if same_text_selected {
13046                    if selected_text.is_none() {
13047                        selected_text =
13048                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13049                    }
13050
13051                    if let Some(next_selection) = selections_iter.peek() {
13052                        if next_selection.range().len() == selection.range().len() {
13053                            let next_selected_text = buffer
13054                                .text_for_range(next_selection.range())
13055                                .collect::<String>();
13056                            if Some(next_selected_text) != selected_text {
13057                                same_text_selected = false;
13058                                selected_text = None;
13059                            }
13060                        } else {
13061                            same_text_selected = false;
13062                            selected_text = None;
13063                        }
13064                    }
13065                }
13066            }
13067
13068            if only_carets {
13069                for selection in &mut selections {
13070                    let word_range = movement::surrounding_word(
13071                        &display_map,
13072                        selection.start.to_display_point(&display_map),
13073                    );
13074                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13075                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13076                    selection.goal = SelectionGoal::None;
13077                    selection.reversed = false;
13078                    self.select_match_ranges(
13079                        selection.start..selection.end,
13080                        selection.reversed,
13081                        action.replace_newest,
13082                        Some(Autoscroll::newest()),
13083                        window,
13084                        cx,
13085                    );
13086                }
13087                if selections.len() == 1 {
13088                    let selection = selections
13089                        .last()
13090                        .expect("ensured that there's only one selection");
13091                    let query = buffer
13092                        .text_for_range(selection.start..selection.end)
13093                        .collect::<String>();
13094                    let is_empty = query.is_empty();
13095                    let select_state = SelectNextState {
13096                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13097                        wordwise: true,
13098                        done: is_empty,
13099                    };
13100                    self.select_prev_state = Some(select_state);
13101                } else {
13102                    self.select_prev_state = None;
13103                }
13104            } else if let Some(selected_text) = selected_text {
13105                self.select_prev_state = Some(SelectNextState {
13106                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13107                    wordwise: false,
13108                    done: false,
13109                });
13110                self.select_previous(action, window, cx)?;
13111            }
13112        }
13113        Ok(())
13114    }
13115
13116    pub fn find_next_match(
13117        &mut self,
13118        _: &FindNextMatch,
13119        window: &mut Window,
13120        cx: &mut Context<Self>,
13121    ) -> Result<()> {
13122        let selections = self.selections.disjoint_anchors();
13123        match selections.first() {
13124            Some(first) if selections.len() >= 2 => {
13125                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13126                    s.select_ranges([first.range()]);
13127                });
13128            }
13129            _ => self.select_next(
13130                &SelectNext {
13131                    replace_newest: true,
13132                },
13133                window,
13134                cx,
13135            )?,
13136        }
13137        Ok(())
13138    }
13139
13140    pub fn find_previous_match(
13141        &mut self,
13142        _: &FindPreviousMatch,
13143        window: &mut Window,
13144        cx: &mut Context<Self>,
13145    ) -> Result<()> {
13146        let selections = self.selections.disjoint_anchors();
13147        match selections.last() {
13148            Some(last) if selections.len() >= 2 => {
13149                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13150                    s.select_ranges([last.range()]);
13151                });
13152            }
13153            _ => self.select_previous(
13154                &SelectPrevious {
13155                    replace_newest: true,
13156                },
13157                window,
13158                cx,
13159            )?,
13160        }
13161        Ok(())
13162    }
13163
13164    pub fn toggle_comments(
13165        &mut self,
13166        action: &ToggleComments,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        if self.read_only(cx) {
13171            return;
13172        }
13173        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13174        let text_layout_details = &self.text_layout_details(window);
13175        self.transact(window, cx, |this, window, cx| {
13176            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13177            let mut edits = Vec::new();
13178            let mut selection_edit_ranges = Vec::new();
13179            let mut last_toggled_row = None;
13180            let snapshot = this.buffer.read(cx).read(cx);
13181            let empty_str: Arc<str> = Arc::default();
13182            let mut suffixes_inserted = Vec::new();
13183            let ignore_indent = action.ignore_indent;
13184
13185            fn comment_prefix_range(
13186                snapshot: &MultiBufferSnapshot,
13187                row: MultiBufferRow,
13188                comment_prefix: &str,
13189                comment_prefix_whitespace: &str,
13190                ignore_indent: bool,
13191            ) -> Range<Point> {
13192                let indent_size = if ignore_indent {
13193                    0
13194                } else {
13195                    snapshot.indent_size_for_line(row).len
13196                };
13197
13198                let start = Point::new(row.0, indent_size);
13199
13200                let mut line_bytes = snapshot
13201                    .bytes_in_range(start..snapshot.max_point())
13202                    .flatten()
13203                    .copied();
13204
13205                // If this line currently begins with the line comment prefix, then record
13206                // the range containing the prefix.
13207                if line_bytes
13208                    .by_ref()
13209                    .take(comment_prefix.len())
13210                    .eq(comment_prefix.bytes())
13211                {
13212                    // Include any whitespace that matches the comment prefix.
13213                    let matching_whitespace_len = line_bytes
13214                        .zip(comment_prefix_whitespace.bytes())
13215                        .take_while(|(a, b)| a == b)
13216                        .count() as u32;
13217                    let end = Point::new(
13218                        start.row,
13219                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13220                    );
13221                    start..end
13222                } else {
13223                    start..start
13224                }
13225            }
13226
13227            fn comment_suffix_range(
13228                snapshot: &MultiBufferSnapshot,
13229                row: MultiBufferRow,
13230                comment_suffix: &str,
13231                comment_suffix_has_leading_space: bool,
13232            ) -> Range<Point> {
13233                let end = Point::new(row.0, snapshot.line_len(row));
13234                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13235
13236                let mut line_end_bytes = snapshot
13237                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13238                    .flatten()
13239                    .copied();
13240
13241                let leading_space_len = if suffix_start_column > 0
13242                    && line_end_bytes.next() == Some(b' ')
13243                    && comment_suffix_has_leading_space
13244                {
13245                    1
13246                } else {
13247                    0
13248                };
13249
13250                // If this line currently begins with the line comment prefix, then record
13251                // the range containing the prefix.
13252                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13253                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13254                    start..end
13255                } else {
13256                    end..end
13257                }
13258            }
13259
13260            // TODO: Handle selections that cross excerpts
13261            for selection in &mut selections {
13262                let start_column = snapshot
13263                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13264                    .len;
13265                let language = if let Some(language) =
13266                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13267                {
13268                    language
13269                } else {
13270                    continue;
13271                };
13272
13273                selection_edit_ranges.clear();
13274
13275                // If multiple selections contain a given row, avoid processing that
13276                // row more than once.
13277                let mut start_row = MultiBufferRow(selection.start.row);
13278                if last_toggled_row == Some(start_row) {
13279                    start_row = start_row.next_row();
13280                }
13281                let end_row =
13282                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13283                        MultiBufferRow(selection.end.row - 1)
13284                    } else {
13285                        MultiBufferRow(selection.end.row)
13286                    };
13287                last_toggled_row = Some(end_row);
13288
13289                if start_row > end_row {
13290                    continue;
13291                }
13292
13293                // If the language has line comments, toggle those.
13294                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13295
13296                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13297                if ignore_indent {
13298                    full_comment_prefixes = full_comment_prefixes
13299                        .into_iter()
13300                        .map(|s| Arc::from(s.trim_end()))
13301                        .collect();
13302                }
13303
13304                if !full_comment_prefixes.is_empty() {
13305                    let first_prefix = full_comment_prefixes
13306                        .first()
13307                        .expect("prefixes is non-empty");
13308                    let prefix_trimmed_lengths = full_comment_prefixes
13309                        .iter()
13310                        .map(|p| p.trim_end_matches(' ').len())
13311                        .collect::<SmallVec<[usize; 4]>>();
13312
13313                    let mut all_selection_lines_are_comments = true;
13314
13315                    for row in start_row.0..=end_row.0 {
13316                        let row = MultiBufferRow(row);
13317                        if start_row < end_row && snapshot.is_line_blank(row) {
13318                            continue;
13319                        }
13320
13321                        let prefix_range = full_comment_prefixes
13322                            .iter()
13323                            .zip(prefix_trimmed_lengths.iter().copied())
13324                            .map(|(prefix, trimmed_prefix_len)| {
13325                                comment_prefix_range(
13326                                    snapshot.deref(),
13327                                    row,
13328                                    &prefix[..trimmed_prefix_len],
13329                                    &prefix[trimmed_prefix_len..],
13330                                    ignore_indent,
13331                                )
13332                            })
13333                            .max_by_key(|range| range.end.column - range.start.column)
13334                            .expect("prefixes is non-empty");
13335
13336                        if prefix_range.is_empty() {
13337                            all_selection_lines_are_comments = false;
13338                        }
13339
13340                        selection_edit_ranges.push(prefix_range);
13341                    }
13342
13343                    if all_selection_lines_are_comments {
13344                        edits.extend(
13345                            selection_edit_ranges
13346                                .iter()
13347                                .cloned()
13348                                .map(|range| (range, empty_str.clone())),
13349                        );
13350                    } else {
13351                        let min_column = selection_edit_ranges
13352                            .iter()
13353                            .map(|range| range.start.column)
13354                            .min()
13355                            .unwrap_or(0);
13356                        edits.extend(selection_edit_ranges.iter().map(|range| {
13357                            let position = Point::new(range.start.row, min_column);
13358                            (position..position, first_prefix.clone())
13359                        }));
13360                    }
13361                } else if let Some((full_comment_prefix, comment_suffix)) =
13362                    language.block_comment_delimiters()
13363                {
13364                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13365                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13366                    let prefix_range = comment_prefix_range(
13367                        snapshot.deref(),
13368                        start_row,
13369                        comment_prefix,
13370                        comment_prefix_whitespace,
13371                        ignore_indent,
13372                    );
13373                    let suffix_range = comment_suffix_range(
13374                        snapshot.deref(),
13375                        end_row,
13376                        comment_suffix.trim_start_matches(' '),
13377                        comment_suffix.starts_with(' '),
13378                    );
13379
13380                    if prefix_range.is_empty() || suffix_range.is_empty() {
13381                        edits.push((
13382                            prefix_range.start..prefix_range.start,
13383                            full_comment_prefix.clone(),
13384                        ));
13385                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13386                        suffixes_inserted.push((end_row, comment_suffix.len()));
13387                    } else {
13388                        edits.push((prefix_range, empty_str.clone()));
13389                        edits.push((suffix_range, empty_str.clone()));
13390                    }
13391                } else {
13392                    continue;
13393                }
13394            }
13395
13396            drop(snapshot);
13397            this.buffer.update(cx, |buffer, cx| {
13398                buffer.edit(edits, None, cx);
13399            });
13400
13401            // Adjust selections so that they end before any comment suffixes that
13402            // were inserted.
13403            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13404            let mut selections = this.selections.all::<Point>(cx);
13405            let snapshot = this.buffer.read(cx).read(cx);
13406            for selection in &mut selections {
13407                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13408                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13409                        Ordering::Less => {
13410                            suffixes_inserted.next();
13411                            continue;
13412                        }
13413                        Ordering::Greater => break,
13414                        Ordering::Equal => {
13415                            if selection.end.column == snapshot.line_len(row) {
13416                                if selection.is_empty() {
13417                                    selection.start.column -= suffix_len as u32;
13418                                }
13419                                selection.end.column -= suffix_len as u32;
13420                            }
13421                            break;
13422                        }
13423                    }
13424                }
13425            }
13426
13427            drop(snapshot);
13428            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13429                s.select(selections)
13430            });
13431
13432            let selections = this.selections.all::<Point>(cx);
13433            let selections_on_single_row = selections.windows(2).all(|selections| {
13434                selections[0].start.row == selections[1].start.row
13435                    && selections[0].end.row == selections[1].end.row
13436                    && selections[0].start.row == selections[0].end.row
13437            });
13438            let selections_selecting = selections
13439                .iter()
13440                .any(|selection| selection.start != selection.end);
13441            let advance_downwards = action.advance_downwards
13442                && selections_on_single_row
13443                && !selections_selecting
13444                && !matches!(this.mode, EditorMode::SingleLine { .. });
13445
13446            if advance_downwards {
13447                let snapshot = this.buffer.read(cx).snapshot(cx);
13448
13449                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13450                    s.move_cursors_with(|display_snapshot, display_point, _| {
13451                        let mut point = display_point.to_point(display_snapshot);
13452                        point.row += 1;
13453                        point = snapshot.clip_point(point, Bias::Left);
13454                        let display_point = point.to_display_point(display_snapshot);
13455                        let goal = SelectionGoal::HorizontalPosition(
13456                            display_snapshot
13457                                .x_for_display_point(display_point, text_layout_details)
13458                                .into(),
13459                        );
13460                        (display_point, goal)
13461                    })
13462                });
13463            }
13464        });
13465    }
13466
13467    pub fn select_enclosing_symbol(
13468        &mut self,
13469        _: &SelectEnclosingSymbol,
13470        window: &mut Window,
13471        cx: &mut Context<Self>,
13472    ) {
13473        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13474
13475        let buffer = self.buffer.read(cx).snapshot(cx);
13476        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13477
13478        fn update_selection(
13479            selection: &Selection<usize>,
13480            buffer_snap: &MultiBufferSnapshot,
13481        ) -> Option<Selection<usize>> {
13482            let cursor = selection.head();
13483            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13484            for symbol in symbols.iter().rev() {
13485                let start = symbol.range.start.to_offset(buffer_snap);
13486                let end = symbol.range.end.to_offset(buffer_snap);
13487                let new_range = start..end;
13488                if start < selection.start || end > selection.end {
13489                    return Some(Selection {
13490                        id: selection.id,
13491                        start: new_range.start,
13492                        end: new_range.end,
13493                        goal: SelectionGoal::None,
13494                        reversed: selection.reversed,
13495                    });
13496                }
13497            }
13498            None
13499        }
13500
13501        let mut selected_larger_symbol = false;
13502        let new_selections = old_selections
13503            .iter()
13504            .map(|selection| match update_selection(selection, &buffer) {
13505                Some(new_selection) => {
13506                    if new_selection.range() != selection.range() {
13507                        selected_larger_symbol = true;
13508                    }
13509                    new_selection
13510                }
13511                None => selection.clone(),
13512            })
13513            .collect::<Vec<_>>();
13514
13515        if selected_larger_symbol {
13516            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13517                s.select(new_selections);
13518            });
13519        }
13520    }
13521
13522    pub fn select_larger_syntax_node(
13523        &mut self,
13524        _: &SelectLargerSyntaxNode,
13525        window: &mut Window,
13526        cx: &mut Context<Self>,
13527    ) {
13528        let Some(visible_row_count) = self.visible_row_count() else {
13529            return;
13530        };
13531        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13532        if old_selections.is_empty() {
13533            return;
13534        }
13535
13536        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13537
13538        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13539        let buffer = self.buffer.read(cx).snapshot(cx);
13540
13541        let mut selected_larger_node = false;
13542        let mut new_selections = old_selections
13543            .iter()
13544            .map(|selection| {
13545                let old_range = selection.start..selection.end;
13546
13547                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13548                    // manually select word at selection
13549                    if ["string_content", "inline"].contains(&node.kind()) {
13550                        let word_range = {
13551                            let display_point = buffer
13552                                .offset_to_point(old_range.start)
13553                                .to_display_point(&display_map);
13554                            let Range { start, end } =
13555                                movement::surrounding_word(&display_map, display_point);
13556                            start.to_point(&display_map).to_offset(&buffer)
13557                                ..end.to_point(&display_map).to_offset(&buffer)
13558                        };
13559                        // ignore if word is already selected
13560                        if !word_range.is_empty() && old_range != word_range {
13561                            let last_word_range = {
13562                                let display_point = buffer
13563                                    .offset_to_point(old_range.end)
13564                                    .to_display_point(&display_map);
13565                                let Range { start, end } =
13566                                    movement::surrounding_word(&display_map, display_point);
13567                                start.to_point(&display_map).to_offset(&buffer)
13568                                    ..end.to_point(&display_map).to_offset(&buffer)
13569                            };
13570                            // only select word if start and end point belongs to same word
13571                            if word_range == last_word_range {
13572                                selected_larger_node = true;
13573                                return Selection {
13574                                    id: selection.id,
13575                                    start: word_range.start,
13576                                    end: word_range.end,
13577                                    goal: SelectionGoal::None,
13578                                    reversed: selection.reversed,
13579                                };
13580                            }
13581                        }
13582                    }
13583                }
13584
13585                let mut new_range = old_range.clone();
13586                while let Some((_node, containing_range)) =
13587                    buffer.syntax_ancestor(new_range.clone())
13588                {
13589                    new_range = match containing_range {
13590                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13591                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13592                    };
13593                    if !display_map.intersects_fold(new_range.start)
13594                        && !display_map.intersects_fold(new_range.end)
13595                    {
13596                        break;
13597                    }
13598                }
13599
13600                selected_larger_node |= new_range != old_range;
13601                Selection {
13602                    id: selection.id,
13603                    start: new_range.start,
13604                    end: new_range.end,
13605                    goal: SelectionGoal::None,
13606                    reversed: selection.reversed,
13607                }
13608            })
13609            .collect::<Vec<_>>();
13610
13611        if !selected_larger_node {
13612            return; // don't put this call in the history
13613        }
13614
13615        // scroll based on transformation done to the last selection created by the user
13616        let (last_old, last_new) = old_selections
13617            .last()
13618            .zip(new_selections.last().cloned())
13619            .expect("old_selections isn't empty");
13620
13621        // revert selection
13622        let is_selection_reversed = {
13623            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13624            new_selections.last_mut().expect("checked above").reversed =
13625                should_newest_selection_be_reversed;
13626            should_newest_selection_be_reversed
13627        };
13628
13629        if selected_larger_node {
13630            self.select_syntax_node_history.disable_clearing = true;
13631            self.change_selections(None, window, cx, |s| {
13632                s.select(new_selections.clone());
13633            });
13634            self.select_syntax_node_history.disable_clearing = false;
13635        }
13636
13637        let start_row = last_new.start.to_display_point(&display_map).row().0;
13638        let end_row = last_new.end.to_display_point(&display_map).row().0;
13639        let selection_height = end_row - start_row + 1;
13640        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13641
13642        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13643        let scroll_behavior = if fits_on_the_screen {
13644            self.request_autoscroll(Autoscroll::fit(), cx);
13645            SelectSyntaxNodeScrollBehavior::FitSelection
13646        } else if is_selection_reversed {
13647            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13648            SelectSyntaxNodeScrollBehavior::CursorTop
13649        } else {
13650            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13651            SelectSyntaxNodeScrollBehavior::CursorBottom
13652        };
13653
13654        self.select_syntax_node_history.push((
13655            old_selections,
13656            scroll_behavior,
13657            is_selection_reversed,
13658        ));
13659    }
13660
13661    pub fn select_smaller_syntax_node(
13662        &mut self,
13663        _: &SelectSmallerSyntaxNode,
13664        window: &mut Window,
13665        cx: &mut Context<Self>,
13666    ) {
13667        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13668
13669        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13670            self.select_syntax_node_history.pop()
13671        {
13672            if let Some(selection) = selections.last_mut() {
13673                selection.reversed = is_selection_reversed;
13674            }
13675
13676            self.select_syntax_node_history.disable_clearing = true;
13677            self.change_selections(None, window, cx, |s| {
13678                s.select(selections.to_vec());
13679            });
13680            self.select_syntax_node_history.disable_clearing = false;
13681
13682            match scroll_behavior {
13683                SelectSyntaxNodeScrollBehavior::CursorTop => {
13684                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13685                }
13686                SelectSyntaxNodeScrollBehavior::FitSelection => {
13687                    self.request_autoscroll(Autoscroll::fit(), cx);
13688                }
13689                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13690                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13691                }
13692            }
13693        }
13694    }
13695
13696    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13697        if !EditorSettings::get_global(cx).gutter.runnables {
13698            self.clear_tasks();
13699            return Task::ready(());
13700        }
13701        let project = self.project.as_ref().map(Entity::downgrade);
13702        let task_sources = self.lsp_task_sources(cx);
13703        let multi_buffer = self.buffer.downgrade();
13704        cx.spawn_in(window, async move |editor, cx| {
13705            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13706            let Some(project) = project.and_then(|p| p.upgrade()) else {
13707                return;
13708            };
13709            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13710                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13711            }) else {
13712                return;
13713            };
13714
13715            let hide_runnables = project
13716                .update(cx, |project, cx| {
13717                    // Do not display any test indicators in non-dev server remote projects.
13718                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13719                })
13720                .unwrap_or(true);
13721            if hide_runnables {
13722                return;
13723            }
13724            let new_rows =
13725                cx.background_spawn({
13726                    let snapshot = display_snapshot.clone();
13727                    async move {
13728                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13729                    }
13730                })
13731                    .await;
13732            let Ok(lsp_tasks) =
13733                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13734            else {
13735                return;
13736            };
13737            let lsp_tasks = lsp_tasks.await;
13738
13739            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13740                lsp_tasks
13741                    .into_iter()
13742                    .flat_map(|(kind, tasks)| {
13743                        tasks.into_iter().filter_map(move |(location, task)| {
13744                            Some((kind.clone(), location?, task))
13745                        })
13746                    })
13747                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13748                        let buffer = location.target.buffer;
13749                        let buffer_snapshot = buffer.read(cx).snapshot();
13750                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13751                            |(excerpt_id, snapshot, _)| {
13752                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13753                                    display_snapshot
13754                                        .buffer_snapshot
13755                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13756                                } else {
13757                                    None
13758                                }
13759                            },
13760                        );
13761                        if let Some(offset) = offset {
13762                            let task_buffer_range =
13763                                location.target.range.to_point(&buffer_snapshot);
13764                            let context_buffer_range =
13765                                task_buffer_range.to_offset(&buffer_snapshot);
13766                            let context_range = BufferOffset(context_buffer_range.start)
13767                                ..BufferOffset(context_buffer_range.end);
13768
13769                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13770                                .or_insert_with(|| RunnableTasks {
13771                                    templates: Vec::new(),
13772                                    offset,
13773                                    column: task_buffer_range.start.column,
13774                                    extra_variables: HashMap::default(),
13775                                    context_range,
13776                                })
13777                                .templates
13778                                .push((kind, task.original_task().clone()));
13779                        }
13780
13781                        acc
13782                    })
13783            }) else {
13784                return;
13785            };
13786
13787            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
13788                buffer.language_settings(cx).tasks.prefer_lsp
13789            }) else {
13790                return;
13791            };
13792
13793            let rows = Self::runnable_rows(
13794                project,
13795                display_snapshot,
13796                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
13797                new_rows,
13798                cx.clone(),
13799            );
13800            editor
13801                .update(cx, |editor, _| {
13802                    editor.clear_tasks();
13803                    for (key, mut value) in rows {
13804                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13805                            value.templates.extend(lsp_tasks.templates);
13806                        }
13807
13808                        editor.insert_tasks(key, value);
13809                    }
13810                    for (key, value) in lsp_tasks_by_rows {
13811                        editor.insert_tasks(key, value);
13812                    }
13813                })
13814                .ok();
13815        })
13816    }
13817    fn fetch_runnable_ranges(
13818        snapshot: &DisplaySnapshot,
13819        range: Range<Anchor>,
13820    ) -> Vec<language::RunnableRange> {
13821        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13822    }
13823
13824    fn runnable_rows(
13825        project: Entity<Project>,
13826        snapshot: DisplaySnapshot,
13827        prefer_lsp: bool,
13828        runnable_ranges: Vec<RunnableRange>,
13829        mut cx: AsyncWindowContext,
13830    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13831        runnable_ranges
13832            .into_iter()
13833            .filter_map(|mut runnable| {
13834                let mut tasks = cx
13835                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13836                    .ok()?;
13837                if prefer_lsp {
13838                    tasks.retain(|(task_kind, _)| {
13839                        !matches!(task_kind, TaskSourceKind::Language { .. })
13840                    });
13841                }
13842                if tasks.is_empty() {
13843                    return None;
13844                }
13845
13846                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13847
13848                let row = snapshot
13849                    .buffer_snapshot
13850                    .buffer_line_for_row(MultiBufferRow(point.row))?
13851                    .1
13852                    .start
13853                    .row;
13854
13855                let context_range =
13856                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13857                Some((
13858                    (runnable.buffer_id, row),
13859                    RunnableTasks {
13860                        templates: tasks,
13861                        offset: snapshot
13862                            .buffer_snapshot
13863                            .anchor_before(runnable.run_range.start),
13864                        context_range,
13865                        column: point.column,
13866                        extra_variables: runnable.extra_captures,
13867                    },
13868                ))
13869            })
13870            .collect()
13871    }
13872
13873    fn templates_with_tags(
13874        project: &Entity<Project>,
13875        runnable: &mut Runnable,
13876        cx: &mut App,
13877    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13878        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13879            let (worktree_id, file) = project
13880                .buffer_for_id(runnable.buffer, cx)
13881                .and_then(|buffer| buffer.read(cx).file())
13882                .map(|file| (file.worktree_id(cx), file.clone()))
13883                .unzip();
13884
13885            (
13886                project.task_store().read(cx).task_inventory().cloned(),
13887                worktree_id,
13888                file,
13889            )
13890        });
13891
13892        let mut templates_with_tags = mem::take(&mut runnable.tags)
13893            .into_iter()
13894            .flat_map(|RunnableTag(tag)| {
13895                inventory
13896                    .as_ref()
13897                    .into_iter()
13898                    .flat_map(|inventory| {
13899                        inventory.read(cx).list_tasks(
13900                            file.clone(),
13901                            Some(runnable.language.clone()),
13902                            worktree_id,
13903                            cx,
13904                        )
13905                    })
13906                    .filter(move |(_, template)| {
13907                        template.tags.iter().any(|source_tag| source_tag == &tag)
13908                    })
13909            })
13910            .sorted_by_key(|(kind, _)| kind.to_owned())
13911            .collect::<Vec<_>>();
13912        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13913            // Strongest source wins; if we have worktree tag binding, prefer that to
13914            // global and language bindings;
13915            // if we have a global binding, prefer that to language binding.
13916            let first_mismatch = templates_with_tags
13917                .iter()
13918                .position(|(tag_source, _)| tag_source != leading_tag_source);
13919            if let Some(index) = first_mismatch {
13920                templates_with_tags.truncate(index);
13921            }
13922        }
13923
13924        templates_with_tags
13925    }
13926
13927    pub fn move_to_enclosing_bracket(
13928        &mut self,
13929        _: &MoveToEnclosingBracket,
13930        window: &mut Window,
13931        cx: &mut Context<Self>,
13932    ) {
13933        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13934        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13935            s.move_offsets_with(|snapshot, selection| {
13936                let Some(enclosing_bracket_ranges) =
13937                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13938                else {
13939                    return;
13940                };
13941
13942                let mut best_length = usize::MAX;
13943                let mut best_inside = false;
13944                let mut best_in_bracket_range = false;
13945                let mut best_destination = None;
13946                for (open, close) in enclosing_bracket_ranges {
13947                    let close = close.to_inclusive();
13948                    let length = close.end() - open.start;
13949                    let inside = selection.start >= open.end && selection.end <= *close.start();
13950                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13951                        || close.contains(&selection.head());
13952
13953                    // If best is next to a bracket and current isn't, skip
13954                    if !in_bracket_range && best_in_bracket_range {
13955                        continue;
13956                    }
13957
13958                    // Prefer smaller lengths unless best is inside and current isn't
13959                    if length > best_length && (best_inside || !inside) {
13960                        continue;
13961                    }
13962
13963                    best_length = length;
13964                    best_inside = inside;
13965                    best_in_bracket_range = in_bracket_range;
13966                    best_destination = Some(
13967                        if close.contains(&selection.start) && close.contains(&selection.end) {
13968                            if inside { open.end } else { open.start }
13969                        } else if inside {
13970                            *close.start()
13971                        } else {
13972                            *close.end()
13973                        },
13974                    );
13975                }
13976
13977                if let Some(destination) = best_destination {
13978                    selection.collapse_to(destination, SelectionGoal::None);
13979                }
13980            })
13981        });
13982    }
13983
13984    pub fn undo_selection(
13985        &mut self,
13986        _: &UndoSelection,
13987        window: &mut Window,
13988        cx: &mut Context<Self>,
13989    ) {
13990        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13991        self.end_selection(window, cx);
13992        self.selection_history.mode = SelectionHistoryMode::Undoing;
13993        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13994            self.change_selections(None, window, cx, |s| {
13995                s.select_anchors(entry.selections.to_vec())
13996            });
13997            self.select_next_state = entry.select_next_state;
13998            self.select_prev_state = entry.select_prev_state;
13999            self.add_selections_state = entry.add_selections_state;
14000            self.request_autoscroll(Autoscroll::newest(), cx);
14001        }
14002        self.selection_history.mode = SelectionHistoryMode::Normal;
14003    }
14004
14005    pub fn redo_selection(
14006        &mut self,
14007        _: &RedoSelection,
14008        window: &mut Window,
14009        cx: &mut Context<Self>,
14010    ) {
14011        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14012        self.end_selection(window, cx);
14013        self.selection_history.mode = SelectionHistoryMode::Redoing;
14014        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14015            self.change_selections(None, window, cx, |s| {
14016                s.select_anchors(entry.selections.to_vec())
14017            });
14018            self.select_next_state = entry.select_next_state;
14019            self.select_prev_state = entry.select_prev_state;
14020            self.add_selections_state = entry.add_selections_state;
14021            self.request_autoscroll(Autoscroll::newest(), cx);
14022        }
14023        self.selection_history.mode = SelectionHistoryMode::Normal;
14024    }
14025
14026    pub fn expand_excerpts(
14027        &mut self,
14028        action: &ExpandExcerpts,
14029        _: &mut Window,
14030        cx: &mut Context<Self>,
14031    ) {
14032        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14033    }
14034
14035    pub fn expand_excerpts_down(
14036        &mut self,
14037        action: &ExpandExcerptsDown,
14038        _: &mut Window,
14039        cx: &mut Context<Self>,
14040    ) {
14041        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14042    }
14043
14044    pub fn expand_excerpts_up(
14045        &mut self,
14046        action: &ExpandExcerptsUp,
14047        _: &mut Window,
14048        cx: &mut Context<Self>,
14049    ) {
14050        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14051    }
14052
14053    pub fn expand_excerpts_for_direction(
14054        &mut self,
14055        lines: u32,
14056        direction: ExpandExcerptDirection,
14057
14058        cx: &mut Context<Self>,
14059    ) {
14060        let selections = self.selections.disjoint_anchors();
14061
14062        let lines = if lines == 0 {
14063            EditorSettings::get_global(cx).expand_excerpt_lines
14064        } else {
14065            lines
14066        };
14067
14068        self.buffer.update(cx, |buffer, cx| {
14069            let snapshot = buffer.snapshot(cx);
14070            let mut excerpt_ids = selections
14071                .iter()
14072                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14073                .collect::<Vec<_>>();
14074            excerpt_ids.sort();
14075            excerpt_ids.dedup();
14076            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14077        })
14078    }
14079
14080    pub fn expand_excerpt(
14081        &mut self,
14082        excerpt: ExcerptId,
14083        direction: ExpandExcerptDirection,
14084        window: &mut Window,
14085        cx: &mut Context<Self>,
14086    ) {
14087        let current_scroll_position = self.scroll_position(cx);
14088        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14089        let mut should_scroll_up = false;
14090
14091        if direction == ExpandExcerptDirection::Down {
14092            let multi_buffer = self.buffer.read(cx);
14093            let snapshot = multi_buffer.snapshot(cx);
14094            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14095                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14096                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14097                        let buffer_snapshot = buffer.read(cx).snapshot();
14098                        let excerpt_end_row =
14099                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14100                        let last_row = buffer_snapshot.max_point().row;
14101                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14102                        should_scroll_up = lines_below >= lines_to_expand;
14103                    }
14104                }
14105            }
14106        }
14107
14108        self.buffer.update(cx, |buffer, cx| {
14109            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14110        });
14111
14112        if should_scroll_up {
14113            let new_scroll_position =
14114                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14115            self.set_scroll_position(new_scroll_position, window, cx);
14116        }
14117    }
14118
14119    pub fn go_to_singleton_buffer_point(
14120        &mut self,
14121        point: Point,
14122        window: &mut Window,
14123        cx: &mut Context<Self>,
14124    ) {
14125        self.go_to_singleton_buffer_range(point..point, window, cx);
14126    }
14127
14128    pub fn go_to_singleton_buffer_range(
14129        &mut self,
14130        range: Range<Point>,
14131        window: &mut Window,
14132        cx: &mut Context<Self>,
14133    ) {
14134        let multibuffer = self.buffer().read(cx);
14135        let Some(buffer) = multibuffer.as_singleton() else {
14136            return;
14137        };
14138        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14139            return;
14140        };
14141        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14142            return;
14143        };
14144        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14145            s.select_anchor_ranges([start..end])
14146        });
14147    }
14148
14149    pub fn go_to_diagnostic(
14150        &mut self,
14151        _: &GoToDiagnostic,
14152        window: &mut Window,
14153        cx: &mut Context<Self>,
14154    ) {
14155        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14156        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14157    }
14158
14159    pub fn go_to_prev_diagnostic(
14160        &mut self,
14161        _: &GoToPreviousDiagnostic,
14162        window: &mut Window,
14163        cx: &mut Context<Self>,
14164    ) {
14165        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14166        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14167    }
14168
14169    pub fn go_to_diagnostic_impl(
14170        &mut self,
14171        direction: Direction,
14172        window: &mut Window,
14173        cx: &mut Context<Self>,
14174    ) {
14175        let buffer = self.buffer.read(cx).snapshot(cx);
14176        let selection = self.selections.newest::<usize>(cx);
14177
14178        let mut active_group_id = None;
14179        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14180            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14181                active_group_id = Some(active_group.group_id);
14182            }
14183        }
14184
14185        fn filtered(
14186            snapshot: EditorSnapshot,
14187            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14188        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14189            diagnostics
14190                .filter(|entry| entry.range.start != entry.range.end)
14191                .filter(|entry| !entry.diagnostic.is_unnecessary)
14192                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14193        }
14194
14195        let snapshot = self.snapshot(window, cx);
14196        let before = filtered(
14197            snapshot.clone(),
14198            buffer
14199                .diagnostics_in_range(0..selection.start)
14200                .filter(|entry| entry.range.start <= selection.start),
14201        );
14202        let after = filtered(
14203            snapshot,
14204            buffer
14205                .diagnostics_in_range(selection.start..buffer.len())
14206                .filter(|entry| entry.range.start >= selection.start),
14207        );
14208
14209        let mut found: Option<DiagnosticEntry<usize>> = None;
14210        if direction == Direction::Prev {
14211            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14212            {
14213                for diagnostic in prev_diagnostics.into_iter().rev() {
14214                    if diagnostic.range.start != selection.start
14215                        || active_group_id
14216                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14217                    {
14218                        found = Some(diagnostic);
14219                        break 'outer;
14220                    }
14221                }
14222            }
14223        } else {
14224            for diagnostic in after.chain(before) {
14225                if diagnostic.range.start != selection.start
14226                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14227                {
14228                    found = Some(diagnostic);
14229                    break;
14230                }
14231            }
14232        }
14233        let Some(next_diagnostic) = found else {
14234            return;
14235        };
14236
14237        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14238            return;
14239        };
14240        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14241            s.select_ranges(vec![
14242                next_diagnostic.range.start..next_diagnostic.range.start,
14243            ])
14244        });
14245        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14246        self.refresh_inline_completion(false, true, window, cx);
14247    }
14248
14249    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14250        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14251        let snapshot = self.snapshot(window, cx);
14252        let selection = self.selections.newest::<Point>(cx);
14253        self.go_to_hunk_before_or_after_position(
14254            &snapshot,
14255            selection.head(),
14256            Direction::Next,
14257            window,
14258            cx,
14259        );
14260    }
14261
14262    pub fn go_to_hunk_before_or_after_position(
14263        &mut self,
14264        snapshot: &EditorSnapshot,
14265        position: Point,
14266        direction: Direction,
14267        window: &mut Window,
14268        cx: &mut Context<Editor>,
14269    ) {
14270        let row = if direction == Direction::Next {
14271            self.hunk_after_position(snapshot, position)
14272                .map(|hunk| hunk.row_range.start)
14273        } else {
14274            self.hunk_before_position(snapshot, position)
14275        };
14276
14277        if let Some(row) = row {
14278            let destination = Point::new(row.0, 0);
14279            let autoscroll = Autoscroll::center();
14280
14281            self.unfold_ranges(&[destination..destination], false, false, cx);
14282            self.change_selections(Some(autoscroll), window, cx, |s| {
14283                s.select_ranges([destination..destination]);
14284            });
14285        }
14286    }
14287
14288    fn hunk_after_position(
14289        &mut self,
14290        snapshot: &EditorSnapshot,
14291        position: Point,
14292    ) -> Option<MultiBufferDiffHunk> {
14293        snapshot
14294            .buffer_snapshot
14295            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14296            .find(|hunk| hunk.row_range.start.0 > position.row)
14297            .or_else(|| {
14298                snapshot
14299                    .buffer_snapshot
14300                    .diff_hunks_in_range(Point::zero()..position)
14301                    .find(|hunk| hunk.row_range.end.0 < position.row)
14302            })
14303    }
14304
14305    fn go_to_prev_hunk(
14306        &mut self,
14307        _: &GoToPreviousHunk,
14308        window: &mut Window,
14309        cx: &mut Context<Self>,
14310    ) {
14311        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14312        let snapshot = self.snapshot(window, cx);
14313        let selection = self.selections.newest::<Point>(cx);
14314        self.go_to_hunk_before_or_after_position(
14315            &snapshot,
14316            selection.head(),
14317            Direction::Prev,
14318            window,
14319            cx,
14320        );
14321    }
14322
14323    fn hunk_before_position(
14324        &mut self,
14325        snapshot: &EditorSnapshot,
14326        position: Point,
14327    ) -> Option<MultiBufferRow> {
14328        snapshot
14329            .buffer_snapshot
14330            .diff_hunk_before(position)
14331            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14332    }
14333
14334    fn go_to_next_change(
14335        &mut self,
14336        _: &GoToNextChange,
14337        window: &mut Window,
14338        cx: &mut Context<Self>,
14339    ) {
14340        if let Some(selections) = self
14341            .change_list
14342            .next_change(1, Direction::Next)
14343            .map(|s| s.to_vec())
14344        {
14345            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14346                let map = s.display_map();
14347                s.select_display_ranges(selections.iter().map(|a| {
14348                    let point = a.to_display_point(&map);
14349                    point..point
14350                }))
14351            })
14352        }
14353    }
14354
14355    fn go_to_previous_change(
14356        &mut self,
14357        _: &GoToPreviousChange,
14358        window: &mut Window,
14359        cx: &mut Context<Self>,
14360    ) {
14361        if let Some(selections) = self
14362            .change_list
14363            .next_change(1, Direction::Prev)
14364            .map(|s| s.to_vec())
14365        {
14366            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14367                let map = s.display_map();
14368                s.select_display_ranges(selections.iter().map(|a| {
14369                    let point = a.to_display_point(&map);
14370                    point..point
14371                }))
14372            })
14373        }
14374    }
14375
14376    fn go_to_line<T: 'static>(
14377        &mut self,
14378        position: Anchor,
14379        highlight_color: Option<Hsla>,
14380        window: &mut Window,
14381        cx: &mut Context<Self>,
14382    ) {
14383        let snapshot = self.snapshot(window, cx).display_snapshot;
14384        let position = position.to_point(&snapshot.buffer_snapshot);
14385        let start = snapshot
14386            .buffer_snapshot
14387            .clip_point(Point::new(position.row, 0), Bias::Left);
14388        let end = start + Point::new(1, 0);
14389        let start = snapshot.buffer_snapshot.anchor_before(start);
14390        let end = snapshot.buffer_snapshot.anchor_before(end);
14391
14392        self.highlight_rows::<T>(
14393            start..end,
14394            highlight_color
14395                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14396            Default::default(),
14397            cx,
14398        );
14399
14400        if self.buffer.read(cx).is_singleton() {
14401            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14402        }
14403    }
14404
14405    pub fn go_to_definition(
14406        &mut self,
14407        _: &GoToDefinition,
14408        window: &mut Window,
14409        cx: &mut Context<Self>,
14410    ) -> Task<Result<Navigated>> {
14411        let definition =
14412            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14413        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14414        cx.spawn_in(window, async move |editor, cx| {
14415            if definition.await? == Navigated::Yes {
14416                return Ok(Navigated::Yes);
14417            }
14418            match fallback_strategy {
14419                GoToDefinitionFallback::None => Ok(Navigated::No),
14420                GoToDefinitionFallback::FindAllReferences => {
14421                    match editor.update_in(cx, |editor, window, cx| {
14422                        editor.find_all_references(&FindAllReferences, window, cx)
14423                    })? {
14424                        Some(references) => references.await,
14425                        None => Ok(Navigated::No),
14426                    }
14427                }
14428            }
14429        })
14430    }
14431
14432    pub fn go_to_declaration(
14433        &mut self,
14434        _: &GoToDeclaration,
14435        window: &mut Window,
14436        cx: &mut Context<Self>,
14437    ) -> Task<Result<Navigated>> {
14438        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14439    }
14440
14441    pub fn go_to_declaration_split(
14442        &mut self,
14443        _: &GoToDeclaration,
14444        window: &mut Window,
14445        cx: &mut Context<Self>,
14446    ) -> Task<Result<Navigated>> {
14447        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14448    }
14449
14450    pub fn go_to_implementation(
14451        &mut self,
14452        _: &GoToImplementation,
14453        window: &mut Window,
14454        cx: &mut Context<Self>,
14455    ) -> Task<Result<Navigated>> {
14456        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14457    }
14458
14459    pub fn go_to_implementation_split(
14460        &mut self,
14461        _: &GoToImplementationSplit,
14462        window: &mut Window,
14463        cx: &mut Context<Self>,
14464    ) -> Task<Result<Navigated>> {
14465        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14466    }
14467
14468    pub fn go_to_type_definition(
14469        &mut self,
14470        _: &GoToTypeDefinition,
14471        window: &mut Window,
14472        cx: &mut Context<Self>,
14473    ) -> Task<Result<Navigated>> {
14474        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14475    }
14476
14477    pub fn go_to_definition_split(
14478        &mut self,
14479        _: &GoToDefinitionSplit,
14480        window: &mut Window,
14481        cx: &mut Context<Self>,
14482    ) -> Task<Result<Navigated>> {
14483        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14484    }
14485
14486    pub fn go_to_type_definition_split(
14487        &mut self,
14488        _: &GoToTypeDefinitionSplit,
14489        window: &mut Window,
14490        cx: &mut Context<Self>,
14491    ) -> Task<Result<Navigated>> {
14492        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14493    }
14494
14495    fn go_to_definition_of_kind(
14496        &mut self,
14497        kind: GotoDefinitionKind,
14498        split: bool,
14499        window: &mut Window,
14500        cx: &mut Context<Self>,
14501    ) -> Task<Result<Navigated>> {
14502        let Some(provider) = self.semantics_provider.clone() else {
14503            return Task::ready(Ok(Navigated::No));
14504        };
14505        let head = self.selections.newest::<usize>(cx).head();
14506        let buffer = self.buffer.read(cx);
14507        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14508            text_anchor
14509        } else {
14510            return Task::ready(Ok(Navigated::No));
14511        };
14512
14513        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14514            return Task::ready(Ok(Navigated::No));
14515        };
14516
14517        cx.spawn_in(window, async move |editor, cx| {
14518            let definitions = definitions.await?;
14519            let navigated = editor
14520                .update_in(cx, |editor, window, cx| {
14521                    editor.navigate_to_hover_links(
14522                        Some(kind),
14523                        definitions
14524                            .into_iter()
14525                            .filter(|location| {
14526                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14527                            })
14528                            .map(HoverLink::Text)
14529                            .collect::<Vec<_>>(),
14530                        split,
14531                        window,
14532                        cx,
14533                    )
14534                })?
14535                .await?;
14536            anyhow::Ok(navigated)
14537        })
14538    }
14539
14540    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14541        let selection = self.selections.newest_anchor();
14542        let head = selection.head();
14543        let tail = selection.tail();
14544
14545        let Some((buffer, start_position)) =
14546            self.buffer.read(cx).text_anchor_for_position(head, cx)
14547        else {
14548            return;
14549        };
14550
14551        let end_position = if head != tail {
14552            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14553                return;
14554            };
14555            Some(pos)
14556        } else {
14557            None
14558        };
14559
14560        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14561            let url = if let Some(end_pos) = end_position {
14562                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14563            } else {
14564                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14565            };
14566
14567            if let Some(url) = url {
14568                editor.update(cx, |_, cx| {
14569                    cx.open_url(&url);
14570                })
14571            } else {
14572                Ok(())
14573            }
14574        });
14575
14576        url_finder.detach();
14577    }
14578
14579    pub fn open_selected_filename(
14580        &mut self,
14581        _: &OpenSelectedFilename,
14582        window: &mut Window,
14583        cx: &mut Context<Self>,
14584    ) {
14585        let Some(workspace) = self.workspace() else {
14586            return;
14587        };
14588
14589        let position = self.selections.newest_anchor().head();
14590
14591        let Some((buffer, buffer_position)) =
14592            self.buffer.read(cx).text_anchor_for_position(position, cx)
14593        else {
14594            return;
14595        };
14596
14597        let project = self.project.clone();
14598
14599        cx.spawn_in(window, async move |_, cx| {
14600            let result = find_file(&buffer, project, buffer_position, cx).await;
14601
14602            if let Some((_, path)) = result {
14603                workspace
14604                    .update_in(cx, |workspace, window, cx| {
14605                        workspace.open_resolved_path(path, window, cx)
14606                    })?
14607                    .await?;
14608            }
14609            anyhow::Ok(())
14610        })
14611        .detach();
14612    }
14613
14614    pub(crate) fn navigate_to_hover_links(
14615        &mut self,
14616        kind: Option<GotoDefinitionKind>,
14617        mut definitions: Vec<HoverLink>,
14618        split: bool,
14619        window: &mut Window,
14620        cx: &mut Context<Editor>,
14621    ) -> Task<Result<Navigated>> {
14622        // If there is one definition, just open it directly
14623        if definitions.len() == 1 {
14624            let definition = definitions.pop().unwrap();
14625
14626            enum TargetTaskResult {
14627                Location(Option<Location>),
14628                AlreadyNavigated,
14629            }
14630
14631            let target_task = match definition {
14632                HoverLink::Text(link) => {
14633                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14634                }
14635                HoverLink::InlayHint(lsp_location, server_id) => {
14636                    let computation =
14637                        self.compute_target_location(lsp_location, server_id, window, cx);
14638                    cx.background_spawn(async move {
14639                        let location = computation.await?;
14640                        Ok(TargetTaskResult::Location(location))
14641                    })
14642                }
14643                HoverLink::Url(url) => {
14644                    cx.open_url(&url);
14645                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14646                }
14647                HoverLink::File(path) => {
14648                    if let Some(workspace) = self.workspace() {
14649                        cx.spawn_in(window, async move |_, cx| {
14650                            workspace
14651                                .update_in(cx, |workspace, window, cx| {
14652                                    workspace.open_resolved_path(path, window, cx)
14653                                })?
14654                                .await
14655                                .map(|_| TargetTaskResult::AlreadyNavigated)
14656                        })
14657                    } else {
14658                        Task::ready(Ok(TargetTaskResult::Location(None)))
14659                    }
14660                }
14661            };
14662            cx.spawn_in(window, async move |editor, cx| {
14663                let target = match target_task.await.context("target resolution task")? {
14664                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14665                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14666                    TargetTaskResult::Location(Some(target)) => target,
14667                };
14668
14669                editor.update_in(cx, |editor, window, cx| {
14670                    let Some(workspace) = editor.workspace() else {
14671                        return Navigated::No;
14672                    };
14673                    let pane = workspace.read(cx).active_pane().clone();
14674
14675                    let range = target.range.to_point(target.buffer.read(cx));
14676                    let range = editor.range_for_match(&range);
14677                    let range = collapse_multiline_range(range);
14678
14679                    if !split
14680                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14681                    {
14682                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14683                    } else {
14684                        window.defer(cx, move |window, cx| {
14685                            let target_editor: Entity<Self> =
14686                                workspace.update(cx, |workspace, cx| {
14687                                    let pane = if split {
14688                                        workspace.adjacent_pane(window, cx)
14689                                    } else {
14690                                        workspace.active_pane().clone()
14691                                    };
14692
14693                                    workspace.open_project_item(
14694                                        pane,
14695                                        target.buffer.clone(),
14696                                        true,
14697                                        true,
14698                                        window,
14699                                        cx,
14700                                    )
14701                                });
14702                            target_editor.update(cx, |target_editor, cx| {
14703                                // When selecting a definition in a different buffer, disable the nav history
14704                                // to avoid creating a history entry at the previous cursor location.
14705                                pane.update(cx, |pane, _| pane.disable_history());
14706                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14707                                pane.update(cx, |pane, _| pane.enable_history());
14708                            });
14709                        });
14710                    }
14711                    Navigated::Yes
14712                })
14713            })
14714        } else if !definitions.is_empty() {
14715            cx.spawn_in(window, async move |editor, cx| {
14716                let (title, location_tasks, workspace) = editor
14717                    .update_in(cx, |editor, window, cx| {
14718                        let tab_kind = match kind {
14719                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14720                            _ => "Definitions",
14721                        };
14722                        let title = definitions
14723                            .iter()
14724                            .find_map(|definition| match definition {
14725                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14726                                    let buffer = origin.buffer.read(cx);
14727                                    format!(
14728                                        "{} for {}",
14729                                        tab_kind,
14730                                        buffer
14731                                            .text_for_range(origin.range.clone())
14732                                            .collect::<String>()
14733                                    )
14734                                }),
14735                                HoverLink::InlayHint(_, _) => None,
14736                                HoverLink::Url(_) => None,
14737                                HoverLink::File(_) => None,
14738                            })
14739                            .unwrap_or(tab_kind.to_string());
14740                        let location_tasks = definitions
14741                            .into_iter()
14742                            .map(|definition| match definition {
14743                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14744                                HoverLink::InlayHint(lsp_location, server_id) => editor
14745                                    .compute_target_location(lsp_location, server_id, window, cx),
14746                                HoverLink::Url(_) => Task::ready(Ok(None)),
14747                                HoverLink::File(_) => Task::ready(Ok(None)),
14748                            })
14749                            .collect::<Vec<_>>();
14750                        (title, location_tasks, editor.workspace().clone())
14751                    })
14752                    .context("location tasks preparation")?;
14753
14754                let locations = future::join_all(location_tasks)
14755                    .await
14756                    .into_iter()
14757                    .filter_map(|location| location.transpose())
14758                    .collect::<Result<_>>()
14759                    .context("location tasks")?;
14760
14761                let Some(workspace) = workspace else {
14762                    return Ok(Navigated::No);
14763                };
14764                let opened = workspace
14765                    .update_in(cx, |workspace, window, cx| {
14766                        Self::open_locations_in_multibuffer(
14767                            workspace,
14768                            locations,
14769                            title,
14770                            split,
14771                            MultibufferSelectionMode::First,
14772                            window,
14773                            cx,
14774                        )
14775                    })
14776                    .ok();
14777
14778                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14779            })
14780        } else {
14781            Task::ready(Ok(Navigated::No))
14782        }
14783    }
14784
14785    fn compute_target_location(
14786        &self,
14787        lsp_location: lsp::Location,
14788        server_id: LanguageServerId,
14789        window: &mut Window,
14790        cx: &mut Context<Self>,
14791    ) -> Task<anyhow::Result<Option<Location>>> {
14792        let Some(project) = self.project.clone() else {
14793            return Task::ready(Ok(None));
14794        };
14795
14796        cx.spawn_in(window, async move |editor, cx| {
14797            let location_task = editor.update(cx, |_, cx| {
14798                project.update(cx, |project, cx| {
14799                    let language_server_name = project
14800                        .language_server_statuses(cx)
14801                        .find(|(id, _)| server_id == *id)
14802                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14803                    language_server_name.map(|language_server_name| {
14804                        project.open_local_buffer_via_lsp(
14805                            lsp_location.uri.clone(),
14806                            server_id,
14807                            language_server_name,
14808                            cx,
14809                        )
14810                    })
14811                })
14812            })?;
14813            let location = match location_task {
14814                Some(task) => Some({
14815                    let target_buffer_handle = task.await.context("open local buffer")?;
14816                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
14817                        let target_start = target_buffer
14818                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14819                        let target_end = target_buffer
14820                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14821                        target_buffer.anchor_after(target_start)
14822                            ..target_buffer.anchor_before(target_end)
14823                    })?;
14824                    Location {
14825                        buffer: target_buffer_handle,
14826                        range,
14827                    }
14828                }),
14829                None => None,
14830            };
14831            Ok(location)
14832        })
14833    }
14834
14835    pub fn find_all_references(
14836        &mut self,
14837        _: &FindAllReferences,
14838        window: &mut Window,
14839        cx: &mut Context<Self>,
14840    ) -> Option<Task<Result<Navigated>>> {
14841        let selection = self.selections.newest::<usize>(cx);
14842        let multi_buffer = self.buffer.read(cx);
14843        let head = selection.head();
14844
14845        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14846        let head_anchor = multi_buffer_snapshot.anchor_at(
14847            head,
14848            if head < selection.tail() {
14849                Bias::Right
14850            } else {
14851                Bias::Left
14852            },
14853        );
14854
14855        match self
14856            .find_all_references_task_sources
14857            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14858        {
14859            Ok(_) => {
14860                log::info!(
14861                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14862                );
14863                return None;
14864            }
14865            Err(i) => {
14866                self.find_all_references_task_sources.insert(i, head_anchor);
14867            }
14868        }
14869
14870        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14871        let workspace = self.workspace()?;
14872        let project = workspace.read(cx).project().clone();
14873        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14874        Some(cx.spawn_in(window, async move |editor, cx| {
14875            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14876                if let Ok(i) = editor
14877                    .find_all_references_task_sources
14878                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14879                {
14880                    editor.find_all_references_task_sources.remove(i);
14881                }
14882            });
14883
14884            let locations = references.await?;
14885            if locations.is_empty() {
14886                return anyhow::Ok(Navigated::No);
14887            }
14888
14889            workspace.update_in(cx, |workspace, window, cx| {
14890                let title = locations
14891                    .first()
14892                    .as_ref()
14893                    .map(|location| {
14894                        let buffer = location.buffer.read(cx);
14895                        format!(
14896                            "References to `{}`",
14897                            buffer
14898                                .text_for_range(location.range.clone())
14899                                .collect::<String>()
14900                        )
14901                    })
14902                    .unwrap();
14903                Self::open_locations_in_multibuffer(
14904                    workspace,
14905                    locations,
14906                    title,
14907                    false,
14908                    MultibufferSelectionMode::First,
14909                    window,
14910                    cx,
14911                );
14912                Navigated::Yes
14913            })
14914        }))
14915    }
14916
14917    /// Opens a multibuffer with the given project locations in it
14918    pub fn open_locations_in_multibuffer(
14919        workspace: &mut Workspace,
14920        mut locations: Vec<Location>,
14921        title: String,
14922        split: bool,
14923        multibuffer_selection_mode: MultibufferSelectionMode,
14924        window: &mut Window,
14925        cx: &mut Context<Workspace>,
14926    ) {
14927        // If there are multiple definitions, open them in a multibuffer
14928        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14929        let mut locations = locations.into_iter().peekable();
14930        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14931        let capability = workspace.project().read(cx).capability();
14932
14933        let excerpt_buffer = cx.new(|cx| {
14934            let mut multibuffer = MultiBuffer::new(capability);
14935            while let Some(location) = locations.next() {
14936                let buffer = location.buffer.read(cx);
14937                let mut ranges_for_buffer = Vec::new();
14938                let range = location.range.to_point(buffer);
14939                ranges_for_buffer.push(range.clone());
14940
14941                while let Some(next_location) = locations.peek() {
14942                    if next_location.buffer == location.buffer {
14943                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14944                        locations.next();
14945                    } else {
14946                        break;
14947                    }
14948                }
14949
14950                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14951                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14952                    PathKey::for_buffer(&location.buffer, cx),
14953                    location.buffer.clone(),
14954                    ranges_for_buffer,
14955                    DEFAULT_MULTIBUFFER_CONTEXT,
14956                    cx,
14957                );
14958                ranges.extend(new_ranges)
14959            }
14960
14961            multibuffer.with_title(title)
14962        });
14963
14964        let editor = cx.new(|cx| {
14965            Editor::for_multibuffer(
14966                excerpt_buffer,
14967                Some(workspace.project().clone()),
14968                window,
14969                cx,
14970            )
14971        });
14972        editor.update(cx, |editor, cx| {
14973            match multibuffer_selection_mode {
14974                MultibufferSelectionMode::First => {
14975                    if let Some(first_range) = ranges.first() {
14976                        editor.change_selections(None, window, cx, |selections| {
14977                            selections.clear_disjoint();
14978                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14979                        });
14980                    }
14981                    editor.highlight_background::<Self>(
14982                        &ranges,
14983                        |theme| theme.editor_highlighted_line_background,
14984                        cx,
14985                    );
14986                }
14987                MultibufferSelectionMode::All => {
14988                    editor.change_selections(None, window, cx, |selections| {
14989                        selections.clear_disjoint();
14990                        selections.select_anchor_ranges(ranges);
14991                    });
14992                }
14993            }
14994            editor.register_buffers_with_language_servers(cx);
14995        });
14996
14997        let item = Box::new(editor);
14998        let item_id = item.item_id();
14999
15000        if split {
15001            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15002        } else {
15003            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15004                let (preview_item_id, preview_item_idx) =
15005                    workspace.active_pane().read_with(cx, |pane, _| {
15006                        (pane.preview_item_id(), pane.preview_item_idx())
15007                    });
15008
15009                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15010
15011                if let Some(preview_item_id) = preview_item_id {
15012                    workspace.active_pane().update(cx, |pane, cx| {
15013                        pane.remove_item(preview_item_id, false, false, window, cx);
15014                    });
15015                }
15016            } else {
15017                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15018            }
15019        }
15020        workspace.active_pane().update(cx, |pane, cx| {
15021            pane.set_preview_item_id(Some(item_id), cx);
15022        });
15023    }
15024
15025    pub fn rename(
15026        &mut self,
15027        _: &Rename,
15028        window: &mut Window,
15029        cx: &mut Context<Self>,
15030    ) -> Option<Task<Result<()>>> {
15031        use language::ToOffset as _;
15032
15033        let provider = self.semantics_provider.clone()?;
15034        let selection = self.selections.newest_anchor().clone();
15035        let (cursor_buffer, cursor_buffer_position) = self
15036            .buffer
15037            .read(cx)
15038            .text_anchor_for_position(selection.head(), cx)?;
15039        let (tail_buffer, cursor_buffer_position_end) = self
15040            .buffer
15041            .read(cx)
15042            .text_anchor_for_position(selection.tail(), cx)?;
15043        if tail_buffer != cursor_buffer {
15044            return None;
15045        }
15046
15047        let snapshot = cursor_buffer.read(cx).snapshot();
15048        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15049        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15050        let prepare_rename = provider
15051            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15052            .unwrap_or_else(|| Task::ready(Ok(None)));
15053        drop(snapshot);
15054
15055        Some(cx.spawn_in(window, async move |this, cx| {
15056            let rename_range = if let Some(range) = prepare_rename.await? {
15057                Some(range)
15058            } else {
15059                this.update(cx, |this, cx| {
15060                    let buffer = this.buffer.read(cx).snapshot(cx);
15061                    let mut buffer_highlights = this
15062                        .document_highlights_for_position(selection.head(), &buffer)
15063                        .filter(|highlight| {
15064                            highlight.start.excerpt_id == selection.head().excerpt_id
15065                                && highlight.end.excerpt_id == selection.head().excerpt_id
15066                        });
15067                    buffer_highlights
15068                        .next()
15069                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15070                })?
15071            };
15072            if let Some(rename_range) = rename_range {
15073                this.update_in(cx, |this, window, cx| {
15074                    let snapshot = cursor_buffer.read(cx).snapshot();
15075                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15076                    let cursor_offset_in_rename_range =
15077                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15078                    let cursor_offset_in_rename_range_end =
15079                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15080
15081                    this.take_rename(false, window, cx);
15082                    let buffer = this.buffer.read(cx).read(cx);
15083                    let cursor_offset = selection.head().to_offset(&buffer);
15084                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15085                    let rename_end = rename_start + rename_buffer_range.len();
15086                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15087                    let mut old_highlight_id = None;
15088                    let old_name: Arc<str> = buffer
15089                        .chunks(rename_start..rename_end, true)
15090                        .map(|chunk| {
15091                            if old_highlight_id.is_none() {
15092                                old_highlight_id = chunk.syntax_highlight_id;
15093                            }
15094                            chunk.text
15095                        })
15096                        .collect::<String>()
15097                        .into();
15098
15099                    drop(buffer);
15100
15101                    // Position the selection in the rename editor so that it matches the current selection.
15102                    this.show_local_selections = false;
15103                    let rename_editor = cx.new(|cx| {
15104                        let mut editor = Editor::single_line(window, cx);
15105                        editor.buffer.update(cx, |buffer, cx| {
15106                            buffer.edit([(0..0, old_name.clone())], None, cx)
15107                        });
15108                        let rename_selection_range = match cursor_offset_in_rename_range
15109                            .cmp(&cursor_offset_in_rename_range_end)
15110                        {
15111                            Ordering::Equal => {
15112                                editor.select_all(&SelectAll, window, cx);
15113                                return editor;
15114                            }
15115                            Ordering::Less => {
15116                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15117                            }
15118                            Ordering::Greater => {
15119                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15120                            }
15121                        };
15122                        if rename_selection_range.end > old_name.len() {
15123                            editor.select_all(&SelectAll, window, cx);
15124                        } else {
15125                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15126                                s.select_ranges([rename_selection_range]);
15127                            });
15128                        }
15129                        editor
15130                    });
15131                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15132                        if e == &EditorEvent::Focused {
15133                            cx.emit(EditorEvent::FocusedIn)
15134                        }
15135                    })
15136                    .detach();
15137
15138                    let write_highlights =
15139                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15140                    let read_highlights =
15141                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15142                    let ranges = write_highlights
15143                        .iter()
15144                        .flat_map(|(_, ranges)| ranges.iter())
15145                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15146                        .cloned()
15147                        .collect();
15148
15149                    this.highlight_text::<Rename>(
15150                        ranges,
15151                        HighlightStyle {
15152                            fade_out: Some(0.6),
15153                            ..Default::default()
15154                        },
15155                        cx,
15156                    );
15157                    let rename_focus_handle = rename_editor.focus_handle(cx);
15158                    window.focus(&rename_focus_handle);
15159                    let block_id = this.insert_blocks(
15160                        [BlockProperties {
15161                            style: BlockStyle::Flex,
15162                            placement: BlockPlacement::Below(range.start),
15163                            height: Some(1),
15164                            render: Arc::new({
15165                                let rename_editor = rename_editor.clone();
15166                                move |cx: &mut BlockContext| {
15167                                    let mut text_style = cx.editor_style.text.clone();
15168                                    if let Some(highlight_style) = old_highlight_id
15169                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15170                                    {
15171                                        text_style = text_style.highlight(highlight_style);
15172                                    }
15173                                    div()
15174                                        .block_mouse_except_scroll()
15175                                        .pl(cx.anchor_x)
15176                                        .child(EditorElement::new(
15177                                            &rename_editor,
15178                                            EditorStyle {
15179                                                background: cx.theme().system().transparent,
15180                                                local_player: cx.editor_style.local_player,
15181                                                text: text_style,
15182                                                scrollbar_width: cx.editor_style.scrollbar_width,
15183                                                syntax: cx.editor_style.syntax.clone(),
15184                                                status: cx.editor_style.status.clone(),
15185                                                inlay_hints_style: HighlightStyle {
15186                                                    font_weight: Some(FontWeight::BOLD),
15187                                                    ..make_inlay_hints_style(cx.app)
15188                                                },
15189                                                inline_completion_styles: make_suggestion_styles(
15190                                                    cx.app,
15191                                                ),
15192                                                ..EditorStyle::default()
15193                                            },
15194                                        ))
15195                                        .into_any_element()
15196                                }
15197                            }),
15198                            priority: 0,
15199                            render_in_minimap: true,
15200                        }],
15201                        Some(Autoscroll::fit()),
15202                        cx,
15203                    )[0];
15204                    this.pending_rename = Some(RenameState {
15205                        range,
15206                        old_name,
15207                        editor: rename_editor,
15208                        block_id,
15209                    });
15210                })?;
15211            }
15212
15213            Ok(())
15214        }))
15215    }
15216
15217    pub fn confirm_rename(
15218        &mut self,
15219        _: &ConfirmRename,
15220        window: &mut Window,
15221        cx: &mut Context<Self>,
15222    ) -> Option<Task<Result<()>>> {
15223        let rename = self.take_rename(false, window, cx)?;
15224        let workspace = self.workspace()?.downgrade();
15225        let (buffer, start) = self
15226            .buffer
15227            .read(cx)
15228            .text_anchor_for_position(rename.range.start, cx)?;
15229        let (end_buffer, _) = self
15230            .buffer
15231            .read(cx)
15232            .text_anchor_for_position(rename.range.end, cx)?;
15233        if buffer != end_buffer {
15234            return None;
15235        }
15236
15237        let old_name = rename.old_name;
15238        let new_name = rename.editor.read(cx).text(cx);
15239
15240        let rename = self.semantics_provider.as_ref()?.perform_rename(
15241            &buffer,
15242            start,
15243            new_name.clone(),
15244            cx,
15245        )?;
15246
15247        Some(cx.spawn_in(window, async move |editor, cx| {
15248            let project_transaction = rename.await?;
15249            Self::open_project_transaction(
15250                &editor,
15251                workspace,
15252                project_transaction,
15253                format!("Rename: {}{}", old_name, new_name),
15254                cx,
15255            )
15256            .await?;
15257
15258            editor.update(cx, |editor, cx| {
15259                editor.refresh_document_highlights(cx);
15260            })?;
15261            Ok(())
15262        }))
15263    }
15264
15265    fn take_rename(
15266        &mut self,
15267        moving_cursor: bool,
15268        window: &mut Window,
15269        cx: &mut Context<Self>,
15270    ) -> Option<RenameState> {
15271        let rename = self.pending_rename.take()?;
15272        if rename.editor.focus_handle(cx).is_focused(window) {
15273            window.focus(&self.focus_handle);
15274        }
15275
15276        self.remove_blocks(
15277            [rename.block_id].into_iter().collect(),
15278            Some(Autoscroll::fit()),
15279            cx,
15280        );
15281        self.clear_highlights::<Rename>(cx);
15282        self.show_local_selections = true;
15283
15284        if moving_cursor {
15285            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15286                editor.selections.newest::<usize>(cx).head()
15287            });
15288
15289            // Update the selection to match the position of the selection inside
15290            // the rename editor.
15291            let snapshot = self.buffer.read(cx).read(cx);
15292            let rename_range = rename.range.to_offset(&snapshot);
15293            let cursor_in_editor = snapshot
15294                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15295                .min(rename_range.end);
15296            drop(snapshot);
15297
15298            self.change_selections(None, window, cx, |s| {
15299                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15300            });
15301        } else {
15302            self.refresh_document_highlights(cx);
15303        }
15304
15305        Some(rename)
15306    }
15307
15308    pub fn pending_rename(&self) -> Option<&RenameState> {
15309        self.pending_rename.as_ref()
15310    }
15311
15312    fn format(
15313        &mut self,
15314        _: &Format,
15315        window: &mut Window,
15316        cx: &mut Context<Self>,
15317    ) -> Option<Task<Result<()>>> {
15318        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15319
15320        let project = match &self.project {
15321            Some(project) => project.clone(),
15322            None => return None,
15323        };
15324
15325        Some(self.perform_format(
15326            project,
15327            FormatTrigger::Manual,
15328            FormatTarget::Buffers,
15329            window,
15330            cx,
15331        ))
15332    }
15333
15334    fn format_selections(
15335        &mut self,
15336        _: &FormatSelections,
15337        window: &mut Window,
15338        cx: &mut Context<Self>,
15339    ) -> Option<Task<Result<()>>> {
15340        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15341
15342        let project = match &self.project {
15343            Some(project) => project.clone(),
15344            None => return None,
15345        };
15346
15347        let ranges = self
15348            .selections
15349            .all_adjusted(cx)
15350            .into_iter()
15351            .map(|selection| selection.range())
15352            .collect_vec();
15353
15354        Some(self.perform_format(
15355            project,
15356            FormatTrigger::Manual,
15357            FormatTarget::Ranges(ranges),
15358            window,
15359            cx,
15360        ))
15361    }
15362
15363    fn perform_format(
15364        &mut self,
15365        project: Entity<Project>,
15366        trigger: FormatTrigger,
15367        target: FormatTarget,
15368        window: &mut Window,
15369        cx: &mut Context<Self>,
15370    ) -> Task<Result<()>> {
15371        let buffer = self.buffer.clone();
15372        let (buffers, target) = match target {
15373            FormatTarget::Buffers => {
15374                let mut buffers = buffer.read(cx).all_buffers();
15375                if trigger == FormatTrigger::Save {
15376                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15377                }
15378                (buffers, LspFormatTarget::Buffers)
15379            }
15380            FormatTarget::Ranges(selection_ranges) => {
15381                let multi_buffer = buffer.read(cx);
15382                let snapshot = multi_buffer.read(cx);
15383                let mut buffers = HashSet::default();
15384                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15385                    BTreeMap::new();
15386                for selection_range in selection_ranges {
15387                    for (buffer, buffer_range, _) in
15388                        snapshot.range_to_buffer_ranges(selection_range)
15389                    {
15390                        let buffer_id = buffer.remote_id();
15391                        let start = buffer.anchor_before(buffer_range.start);
15392                        let end = buffer.anchor_after(buffer_range.end);
15393                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15394                        buffer_id_to_ranges
15395                            .entry(buffer_id)
15396                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15397                            .or_insert_with(|| vec![start..end]);
15398                    }
15399                }
15400                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15401            }
15402        };
15403
15404        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15405        let selections_prev = transaction_id_prev
15406            .and_then(|transaction_id_prev| {
15407                // default to selections as they were after the last edit, if we have them,
15408                // instead of how they are now.
15409                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15410                // will take you back to where you made the last edit, instead of staying where you scrolled
15411                self.selection_history
15412                    .transaction(transaction_id_prev)
15413                    .map(|t| t.0.clone())
15414            })
15415            .unwrap_or_else(|| {
15416                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15417                self.selections.disjoint_anchors()
15418            });
15419
15420        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15421        let format = project.update(cx, |project, cx| {
15422            project.format(buffers, target, true, trigger, cx)
15423        });
15424
15425        cx.spawn_in(window, async move |editor, cx| {
15426            let transaction = futures::select_biased! {
15427                transaction = format.log_err().fuse() => transaction,
15428                () = timeout => {
15429                    log::warn!("timed out waiting for formatting");
15430                    None
15431                }
15432            };
15433
15434            buffer
15435                .update(cx, |buffer, cx| {
15436                    if let Some(transaction) = transaction {
15437                        if !buffer.is_singleton() {
15438                            buffer.push_transaction(&transaction.0, cx);
15439                        }
15440                    }
15441                    cx.notify();
15442                })
15443                .ok();
15444
15445            if let Some(transaction_id_now) =
15446                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15447            {
15448                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15449                if has_new_transaction {
15450                    _ = editor.update(cx, |editor, _| {
15451                        editor
15452                            .selection_history
15453                            .insert_transaction(transaction_id_now, selections_prev);
15454                    });
15455                }
15456            }
15457
15458            Ok(())
15459        })
15460    }
15461
15462    fn organize_imports(
15463        &mut self,
15464        _: &OrganizeImports,
15465        window: &mut Window,
15466        cx: &mut Context<Self>,
15467    ) -> Option<Task<Result<()>>> {
15468        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15469        let project = match &self.project {
15470            Some(project) => project.clone(),
15471            None => return None,
15472        };
15473        Some(self.perform_code_action_kind(
15474            project,
15475            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15476            window,
15477            cx,
15478        ))
15479    }
15480
15481    fn perform_code_action_kind(
15482        &mut self,
15483        project: Entity<Project>,
15484        kind: CodeActionKind,
15485        window: &mut Window,
15486        cx: &mut Context<Self>,
15487    ) -> Task<Result<()>> {
15488        let buffer = self.buffer.clone();
15489        let buffers = buffer.read(cx).all_buffers();
15490        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15491        let apply_action = project.update(cx, |project, cx| {
15492            project.apply_code_action_kind(buffers, kind, true, cx)
15493        });
15494        cx.spawn_in(window, async move |_, cx| {
15495            let transaction = futures::select_biased! {
15496                () = timeout => {
15497                    log::warn!("timed out waiting for executing code action");
15498                    None
15499                }
15500                transaction = apply_action.log_err().fuse() => transaction,
15501            };
15502            buffer
15503                .update(cx, |buffer, cx| {
15504                    // check if we need this
15505                    if let Some(transaction) = transaction {
15506                        if !buffer.is_singleton() {
15507                            buffer.push_transaction(&transaction.0, cx);
15508                        }
15509                    }
15510                    cx.notify();
15511                })
15512                .ok();
15513            Ok(())
15514        })
15515    }
15516
15517    fn restart_language_server(
15518        &mut self,
15519        _: &RestartLanguageServer,
15520        _: &mut Window,
15521        cx: &mut Context<Self>,
15522    ) {
15523        if let Some(project) = self.project.clone() {
15524            self.buffer.update(cx, |multi_buffer, cx| {
15525                project.update(cx, |project, cx| {
15526                    project.restart_language_servers_for_buffers(
15527                        multi_buffer.all_buffers().into_iter().collect(),
15528                        cx,
15529                    );
15530                });
15531            })
15532        }
15533    }
15534
15535    fn stop_language_server(
15536        &mut self,
15537        _: &StopLanguageServer,
15538        _: &mut Window,
15539        cx: &mut Context<Self>,
15540    ) {
15541        if let Some(project) = self.project.clone() {
15542            self.buffer.update(cx, |multi_buffer, cx| {
15543                project.update(cx, |project, cx| {
15544                    project.stop_language_servers_for_buffers(
15545                        multi_buffer.all_buffers().into_iter().collect(),
15546                        cx,
15547                    );
15548                    cx.emit(project::Event::RefreshInlayHints);
15549                });
15550            });
15551        }
15552    }
15553
15554    fn cancel_language_server_work(
15555        workspace: &mut Workspace,
15556        _: &actions::CancelLanguageServerWork,
15557        _: &mut Window,
15558        cx: &mut Context<Workspace>,
15559    ) {
15560        let project = workspace.project();
15561        let buffers = workspace
15562            .active_item(cx)
15563            .and_then(|item| item.act_as::<Editor>(cx))
15564            .map_or(HashSet::default(), |editor| {
15565                editor.read(cx).buffer.read(cx).all_buffers()
15566            });
15567        project.update(cx, |project, cx| {
15568            project.cancel_language_server_work_for_buffers(buffers, cx);
15569        });
15570    }
15571
15572    fn show_character_palette(
15573        &mut self,
15574        _: &ShowCharacterPalette,
15575        window: &mut Window,
15576        _: &mut Context<Self>,
15577    ) {
15578        window.show_character_palette();
15579    }
15580
15581    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15582        if self.mode.is_minimap() {
15583            return;
15584        }
15585
15586        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15587            let buffer = self.buffer.read(cx).snapshot(cx);
15588            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15589            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15590            let is_valid = buffer
15591                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15592                .any(|entry| {
15593                    entry.diagnostic.is_primary
15594                        && !entry.range.is_empty()
15595                        && entry.range.start == primary_range_start
15596                        && entry.diagnostic.message == active_diagnostics.active_message
15597                });
15598
15599            if !is_valid {
15600                self.dismiss_diagnostics(cx);
15601            }
15602        }
15603    }
15604
15605    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15606        match &self.active_diagnostics {
15607            ActiveDiagnostic::Group(group) => Some(group),
15608            _ => None,
15609        }
15610    }
15611
15612    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15613        self.dismiss_diagnostics(cx);
15614        self.active_diagnostics = ActiveDiagnostic::All;
15615    }
15616
15617    fn activate_diagnostics(
15618        &mut self,
15619        buffer_id: BufferId,
15620        diagnostic: DiagnosticEntry<usize>,
15621        window: &mut Window,
15622        cx: &mut Context<Self>,
15623    ) {
15624        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15625            return;
15626        }
15627        self.dismiss_diagnostics(cx);
15628        let snapshot = self.snapshot(window, cx);
15629        let buffer = self.buffer.read(cx).snapshot(cx);
15630        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15631            return;
15632        };
15633
15634        let diagnostic_group = buffer
15635            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15636            .collect::<Vec<_>>();
15637
15638        let blocks =
15639            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15640
15641        let blocks = self.display_map.update(cx, |display_map, cx| {
15642            display_map.insert_blocks(blocks, cx).into_iter().collect()
15643        });
15644        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15645            active_range: buffer.anchor_before(diagnostic.range.start)
15646                ..buffer.anchor_after(diagnostic.range.end),
15647            active_message: diagnostic.diagnostic.message.clone(),
15648            group_id: diagnostic.diagnostic.group_id,
15649            blocks,
15650        });
15651        cx.notify();
15652    }
15653
15654    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15655        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15656            return;
15657        };
15658
15659        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15660        if let ActiveDiagnostic::Group(group) = prev {
15661            self.display_map.update(cx, |display_map, cx| {
15662                display_map.remove_blocks(group.blocks, cx);
15663            });
15664            cx.notify();
15665        }
15666    }
15667
15668    /// Disable inline diagnostics rendering for this editor.
15669    pub fn disable_inline_diagnostics(&mut self) {
15670        self.inline_diagnostics_enabled = false;
15671        self.inline_diagnostics_update = Task::ready(());
15672        self.inline_diagnostics.clear();
15673    }
15674
15675    pub fn diagnostics_enabled(&self) -> bool {
15676        self.mode.is_full()
15677    }
15678
15679    pub fn inline_diagnostics_enabled(&self) -> bool {
15680        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15681    }
15682
15683    pub fn show_inline_diagnostics(&self) -> bool {
15684        self.show_inline_diagnostics
15685    }
15686
15687    pub fn toggle_inline_diagnostics(
15688        &mut self,
15689        _: &ToggleInlineDiagnostics,
15690        window: &mut Window,
15691        cx: &mut Context<Editor>,
15692    ) {
15693        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15694        self.refresh_inline_diagnostics(false, window, cx);
15695    }
15696
15697    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15698        self.diagnostics_max_severity = severity;
15699        self.display_map.update(cx, |display_map, _| {
15700            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15701        });
15702    }
15703
15704    pub fn toggle_diagnostics(
15705        &mut self,
15706        _: &ToggleDiagnostics,
15707        window: &mut Window,
15708        cx: &mut Context<Editor>,
15709    ) {
15710        if !self.diagnostics_enabled() {
15711            return;
15712        }
15713
15714        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15715            EditorSettings::get_global(cx)
15716                .diagnostics_max_severity
15717                .filter(|severity| severity != &DiagnosticSeverity::Off)
15718                .unwrap_or(DiagnosticSeverity::Hint)
15719        } else {
15720            DiagnosticSeverity::Off
15721        };
15722        self.set_max_diagnostics_severity(new_severity, cx);
15723        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15724            self.active_diagnostics = ActiveDiagnostic::None;
15725            self.inline_diagnostics_update = Task::ready(());
15726            self.inline_diagnostics.clear();
15727        } else {
15728            self.refresh_inline_diagnostics(false, window, cx);
15729        }
15730
15731        cx.notify();
15732    }
15733
15734    pub fn toggle_minimap(
15735        &mut self,
15736        _: &ToggleMinimap,
15737        window: &mut Window,
15738        cx: &mut Context<Editor>,
15739    ) {
15740        if self.supports_minimap(cx) {
15741            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15742        }
15743    }
15744
15745    fn refresh_inline_diagnostics(
15746        &mut self,
15747        debounce: bool,
15748        window: &mut Window,
15749        cx: &mut Context<Self>,
15750    ) {
15751        let max_severity = ProjectSettings::get_global(cx)
15752            .diagnostics
15753            .inline
15754            .max_severity
15755            .unwrap_or(self.diagnostics_max_severity);
15756
15757        if !self.inline_diagnostics_enabled()
15758            || !self.show_inline_diagnostics
15759            || max_severity == DiagnosticSeverity::Off
15760        {
15761            self.inline_diagnostics_update = Task::ready(());
15762            self.inline_diagnostics.clear();
15763            return;
15764        }
15765
15766        let debounce_ms = ProjectSettings::get_global(cx)
15767            .diagnostics
15768            .inline
15769            .update_debounce_ms;
15770        let debounce = if debounce && debounce_ms > 0 {
15771            Some(Duration::from_millis(debounce_ms))
15772        } else {
15773            None
15774        };
15775        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15776            if let Some(debounce) = debounce {
15777                cx.background_executor().timer(debounce).await;
15778            }
15779            let Some(snapshot) = editor.upgrade().and_then(|editor| {
15780                editor
15781                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15782                    .ok()
15783            }) else {
15784                return;
15785            };
15786
15787            let new_inline_diagnostics = cx
15788                .background_spawn(async move {
15789                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15790                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15791                        let message = diagnostic_entry
15792                            .diagnostic
15793                            .message
15794                            .split_once('\n')
15795                            .map(|(line, _)| line)
15796                            .map(SharedString::new)
15797                            .unwrap_or_else(|| {
15798                                SharedString::from(diagnostic_entry.diagnostic.message)
15799                            });
15800                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15801                        let (Ok(i) | Err(i)) = inline_diagnostics
15802                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15803                        inline_diagnostics.insert(
15804                            i,
15805                            (
15806                                start_anchor,
15807                                InlineDiagnostic {
15808                                    message,
15809                                    group_id: diagnostic_entry.diagnostic.group_id,
15810                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15811                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15812                                    severity: diagnostic_entry.diagnostic.severity,
15813                                },
15814                            ),
15815                        );
15816                    }
15817                    inline_diagnostics
15818                })
15819                .await;
15820
15821            editor
15822                .update(cx, |editor, cx| {
15823                    editor.inline_diagnostics = new_inline_diagnostics;
15824                    cx.notify();
15825                })
15826                .ok();
15827        });
15828    }
15829
15830    pub fn set_selections_from_remote(
15831        &mut self,
15832        selections: Vec<Selection<Anchor>>,
15833        pending_selection: Option<Selection<Anchor>>,
15834        window: &mut Window,
15835        cx: &mut Context<Self>,
15836    ) {
15837        let old_cursor_position = self.selections.newest_anchor().head();
15838        self.selections.change_with(cx, |s| {
15839            s.select_anchors(selections);
15840            if let Some(pending_selection) = pending_selection {
15841                s.set_pending(pending_selection, SelectMode::Character);
15842            } else {
15843                s.clear_pending();
15844            }
15845        });
15846        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15847    }
15848
15849    pub fn transact(
15850        &mut self,
15851        window: &mut Window,
15852        cx: &mut Context<Self>,
15853        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15854    ) -> Option<TransactionId> {
15855        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15856            this.start_transaction_at(Instant::now(), window, cx);
15857            update(this, window, cx);
15858            this.end_transaction_at(Instant::now(), cx)
15859        })
15860    }
15861
15862    pub fn start_transaction_at(
15863        &mut self,
15864        now: Instant,
15865        window: &mut Window,
15866        cx: &mut Context<Self>,
15867    ) {
15868        self.end_selection(window, cx);
15869        if let Some(tx_id) = self
15870            .buffer
15871            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15872        {
15873            self.selection_history
15874                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15875            cx.emit(EditorEvent::TransactionBegun {
15876                transaction_id: tx_id,
15877            })
15878        }
15879    }
15880
15881    pub fn end_transaction_at(
15882        &mut self,
15883        now: Instant,
15884        cx: &mut Context<Self>,
15885    ) -> Option<TransactionId> {
15886        if let Some(transaction_id) = self
15887            .buffer
15888            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15889        {
15890            if let Some((_, end_selections)) =
15891                self.selection_history.transaction_mut(transaction_id)
15892            {
15893                *end_selections = Some(self.selections.disjoint_anchors());
15894            } else {
15895                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15896            }
15897
15898            cx.emit(EditorEvent::Edited { transaction_id });
15899            Some(transaction_id)
15900        } else {
15901            None
15902        }
15903    }
15904
15905    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15906        if self.selection_mark_mode {
15907            self.change_selections(None, window, cx, |s| {
15908                s.move_with(|_, sel| {
15909                    sel.collapse_to(sel.head(), SelectionGoal::None);
15910                });
15911            })
15912        }
15913        self.selection_mark_mode = true;
15914        cx.notify();
15915    }
15916
15917    pub fn swap_selection_ends(
15918        &mut self,
15919        _: &actions::SwapSelectionEnds,
15920        window: &mut Window,
15921        cx: &mut Context<Self>,
15922    ) {
15923        self.change_selections(None, window, cx, |s| {
15924            s.move_with(|_, sel| {
15925                if sel.start != sel.end {
15926                    sel.reversed = !sel.reversed
15927                }
15928            });
15929        });
15930        self.request_autoscroll(Autoscroll::newest(), cx);
15931        cx.notify();
15932    }
15933
15934    pub fn toggle_fold(
15935        &mut self,
15936        _: &actions::ToggleFold,
15937        window: &mut Window,
15938        cx: &mut Context<Self>,
15939    ) {
15940        if self.is_singleton(cx) {
15941            let selection = self.selections.newest::<Point>(cx);
15942
15943            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15944            let range = if selection.is_empty() {
15945                let point = selection.head().to_display_point(&display_map);
15946                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15947                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15948                    .to_point(&display_map);
15949                start..end
15950            } else {
15951                selection.range()
15952            };
15953            if display_map.folds_in_range(range).next().is_some() {
15954                self.unfold_lines(&Default::default(), window, cx)
15955            } else {
15956                self.fold(&Default::default(), window, cx)
15957            }
15958        } else {
15959            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15960            let buffer_ids: HashSet<_> = self
15961                .selections
15962                .disjoint_anchor_ranges()
15963                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15964                .collect();
15965
15966            let should_unfold = buffer_ids
15967                .iter()
15968                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15969
15970            for buffer_id in buffer_ids {
15971                if should_unfold {
15972                    self.unfold_buffer(buffer_id, cx);
15973                } else {
15974                    self.fold_buffer(buffer_id, cx);
15975                }
15976            }
15977        }
15978    }
15979
15980    pub fn toggle_fold_recursive(
15981        &mut self,
15982        _: &actions::ToggleFoldRecursive,
15983        window: &mut Window,
15984        cx: &mut Context<Self>,
15985    ) {
15986        let selection = self.selections.newest::<Point>(cx);
15987
15988        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15989        let range = if selection.is_empty() {
15990            let point = selection.head().to_display_point(&display_map);
15991            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15992            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15993                .to_point(&display_map);
15994            start..end
15995        } else {
15996            selection.range()
15997        };
15998        if display_map.folds_in_range(range).next().is_some() {
15999            self.unfold_recursive(&Default::default(), window, cx)
16000        } else {
16001            self.fold_recursive(&Default::default(), window, cx)
16002        }
16003    }
16004
16005    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16006        if self.is_singleton(cx) {
16007            let mut to_fold = Vec::new();
16008            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16009            let selections = self.selections.all_adjusted(cx);
16010
16011            for selection in selections {
16012                let range = selection.range().sorted();
16013                let buffer_start_row = range.start.row;
16014
16015                if range.start.row != range.end.row {
16016                    let mut found = false;
16017                    let mut row = range.start.row;
16018                    while row <= range.end.row {
16019                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16020                        {
16021                            found = true;
16022                            row = crease.range().end.row + 1;
16023                            to_fold.push(crease);
16024                        } else {
16025                            row += 1
16026                        }
16027                    }
16028                    if found {
16029                        continue;
16030                    }
16031                }
16032
16033                for row in (0..=range.start.row).rev() {
16034                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16035                        if crease.range().end.row >= buffer_start_row {
16036                            to_fold.push(crease);
16037                            if row <= range.start.row {
16038                                break;
16039                            }
16040                        }
16041                    }
16042                }
16043            }
16044
16045            self.fold_creases(to_fold, true, window, cx);
16046        } else {
16047            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16048            let buffer_ids = self
16049                .selections
16050                .disjoint_anchor_ranges()
16051                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16052                .collect::<HashSet<_>>();
16053            for buffer_id in buffer_ids {
16054                self.fold_buffer(buffer_id, cx);
16055            }
16056        }
16057    }
16058
16059    fn fold_at_level(
16060        &mut self,
16061        fold_at: &FoldAtLevel,
16062        window: &mut Window,
16063        cx: &mut Context<Self>,
16064    ) {
16065        if !self.buffer.read(cx).is_singleton() {
16066            return;
16067        }
16068
16069        let fold_at_level = fold_at.0;
16070        let snapshot = self.buffer.read(cx).snapshot(cx);
16071        let mut to_fold = Vec::new();
16072        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16073
16074        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16075            while start_row < end_row {
16076                match self
16077                    .snapshot(window, cx)
16078                    .crease_for_buffer_row(MultiBufferRow(start_row))
16079                {
16080                    Some(crease) => {
16081                        let nested_start_row = crease.range().start.row + 1;
16082                        let nested_end_row = crease.range().end.row;
16083
16084                        if current_level < fold_at_level {
16085                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16086                        } else if current_level == fold_at_level {
16087                            to_fold.push(crease);
16088                        }
16089
16090                        start_row = nested_end_row + 1;
16091                    }
16092                    None => start_row += 1,
16093                }
16094            }
16095        }
16096
16097        self.fold_creases(to_fold, true, window, cx);
16098    }
16099
16100    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16101        if self.buffer.read(cx).is_singleton() {
16102            let mut fold_ranges = Vec::new();
16103            let snapshot = self.buffer.read(cx).snapshot(cx);
16104
16105            for row in 0..snapshot.max_row().0 {
16106                if let Some(foldable_range) = self
16107                    .snapshot(window, cx)
16108                    .crease_for_buffer_row(MultiBufferRow(row))
16109                {
16110                    fold_ranges.push(foldable_range);
16111                }
16112            }
16113
16114            self.fold_creases(fold_ranges, true, window, cx);
16115        } else {
16116            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16117                editor
16118                    .update_in(cx, |editor, _, cx| {
16119                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16120                            editor.fold_buffer(buffer_id, cx);
16121                        }
16122                    })
16123                    .ok();
16124            });
16125        }
16126    }
16127
16128    pub fn fold_function_bodies(
16129        &mut self,
16130        _: &actions::FoldFunctionBodies,
16131        window: &mut Window,
16132        cx: &mut Context<Self>,
16133    ) {
16134        let snapshot = self.buffer.read(cx).snapshot(cx);
16135
16136        let ranges = snapshot
16137            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16138            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16139            .collect::<Vec<_>>();
16140
16141        let creases = ranges
16142            .into_iter()
16143            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16144            .collect();
16145
16146        self.fold_creases(creases, true, window, cx);
16147    }
16148
16149    pub fn fold_recursive(
16150        &mut self,
16151        _: &actions::FoldRecursive,
16152        window: &mut Window,
16153        cx: &mut Context<Self>,
16154    ) {
16155        let mut to_fold = Vec::new();
16156        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16157        let selections = self.selections.all_adjusted(cx);
16158
16159        for selection in selections {
16160            let range = selection.range().sorted();
16161            let buffer_start_row = range.start.row;
16162
16163            if range.start.row != range.end.row {
16164                let mut found = false;
16165                for row in range.start.row..=range.end.row {
16166                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16167                        found = true;
16168                        to_fold.push(crease);
16169                    }
16170                }
16171                if found {
16172                    continue;
16173                }
16174            }
16175
16176            for row in (0..=range.start.row).rev() {
16177                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16178                    if crease.range().end.row >= buffer_start_row {
16179                        to_fold.push(crease);
16180                    } else {
16181                        break;
16182                    }
16183                }
16184            }
16185        }
16186
16187        self.fold_creases(to_fold, true, window, cx);
16188    }
16189
16190    pub fn fold_at(
16191        &mut self,
16192        buffer_row: MultiBufferRow,
16193        window: &mut Window,
16194        cx: &mut Context<Self>,
16195    ) {
16196        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16197
16198        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16199            let autoscroll = self
16200                .selections
16201                .all::<Point>(cx)
16202                .iter()
16203                .any(|selection| crease.range().overlaps(&selection.range()));
16204
16205            self.fold_creases(vec![crease], autoscroll, window, cx);
16206        }
16207    }
16208
16209    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16210        if self.is_singleton(cx) {
16211            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16212            let buffer = &display_map.buffer_snapshot;
16213            let selections = self.selections.all::<Point>(cx);
16214            let ranges = selections
16215                .iter()
16216                .map(|s| {
16217                    let range = s.display_range(&display_map).sorted();
16218                    let mut start = range.start.to_point(&display_map);
16219                    let mut end = range.end.to_point(&display_map);
16220                    start.column = 0;
16221                    end.column = buffer.line_len(MultiBufferRow(end.row));
16222                    start..end
16223                })
16224                .collect::<Vec<_>>();
16225
16226            self.unfold_ranges(&ranges, true, true, cx);
16227        } else {
16228            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16229            let buffer_ids = self
16230                .selections
16231                .disjoint_anchor_ranges()
16232                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16233                .collect::<HashSet<_>>();
16234            for buffer_id in buffer_ids {
16235                self.unfold_buffer(buffer_id, cx);
16236            }
16237        }
16238    }
16239
16240    pub fn unfold_recursive(
16241        &mut self,
16242        _: &UnfoldRecursive,
16243        _window: &mut Window,
16244        cx: &mut Context<Self>,
16245    ) {
16246        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16247        let selections = self.selections.all::<Point>(cx);
16248        let ranges = selections
16249            .iter()
16250            .map(|s| {
16251                let mut range = s.display_range(&display_map).sorted();
16252                *range.start.column_mut() = 0;
16253                *range.end.column_mut() = display_map.line_len(range.end.row());
16254                let start = range.start.to_point(&display_map);
16255                let end = range.end.to_point(&display_map);
16256                start..end
16257            })
16258            .collect::<Vec<_>>();
16259
16260        self.unfold_ranges(&ranges, true, true, cx);
16261    }
16262
16263    pub fn unfold_at(
16264        &mut self,
16265        buffer_row: MultiBufferRow,
16266        _window: &mut Window,
16267        cx: &mut Context<Self>,
16268    ) {
16269        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16270
16271        let intersection_range = Point::new(buffer_row.0, 0)
16272            ..Point::new(
16273                buffer_row.0,
16274                display_map.buffer_snapshot.line_len(buffer_row),
16275            );
16276
16277        let autoscroll = self
16278            .selections
16279            .all::<Point>(cx)
16280            .iter()
16281            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16282
16283        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16284    }
16285
16286    pub fn unfold_all(
16287        &mut self,
16288        _: &actions::UnfoldAll,
16289        _window: &mut Window,
16290        cx: &mut Context<Self>,
16291    ) {
16292        if self.buffer.read(cx).is_singleton() {
16293            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16294            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16295        } else {
16296            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16297                editor
16298                    .update(cx, |editor, cx| {
16299                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16300                            editor.unfold_buffer(buffer_id, cx);
16301                        }
16302                    })
16303                    .ok();
16304            });
16305        }
16306    }
16307
16308    pub fn fold_selected_ranges(
16309        &mut self,
16310        _: &FoldSelectedRanges,
16311        window: &mut Window,
16312        cx: &mut Context<Self>,
16313    ) {
16314        let selections = self.selections.all_adjusted(cx);
16315        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16316        let ranges = selections
16317            .into_iter()
16318            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16319            .collect::<Vec<_>>();
16320        self.fold_creases(ranges, true, window, cx);
16321    }
16322
16323    pub fn fold_ranges<T: ToOffset + Clone>(
16324        &mut self,
16325        ranges: Vec<Range<T>>,
16326        auto_scroll: bool,
16327        window: &mut Window,
16328        cx: &mut Context<Self>,
16329    ) {
16330        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16331        let ranges = ranges
16332            .into_iter()
16333            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16334            .collect::<Vec<_>>();
16335        self.fold_creases(ranges, auto_scroll, window, cx);
16336    }
16337
16338    pub fn fold_creases<T: ToOffset + Clone>(
16339        &mut self,
16340        creases: Vec<Crease<T>>,
16341        auto_scroll: bool,
16342        _window: &mut Window,
16343        cx: &mut Context<Self>,
16344    ) {
16345        if creases.is_empty() {
16346            return;
16347        }
16348
16349        let mut buffers_affected = HashSet::default();
16350        let multi_buffer = self.buffer().read(cx);
16351        for crease in &creases {
16352            if let Some((_, buffer, _)) =
16353                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16354            {
16355                buffers_affected.insert(buffer.read(cx).remote_id());
16356            };
16357        }
16358
16359        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16360
16361        if auto_scroll {
16362            self.request_autoscroll(Autoscroll::fit(), cx);
16363        }
16364
16365        cx.notify();
16366
16367        self.scrollbar_marker_state.dirty = true;
16368        self.folds_did_change(cx);
16369    }
16370
16371    /// Removes any folds whose ranges intersect any of the given ranges.
16372    pub fn unfold_ranges<T: ToOffset + Clone>(
16373        &mut self,
16374        ranges: &[Range<T>],
16375        inclusive: bool,
16376        auto_scroll: bool,
16377        cx: &mut Context<Self>,
16378    ) {
16379        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16380            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16381        });
16382        self.folds_did_change(cx);
16383    }
16384
16385    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16386        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16387            return;
16388        }
16389        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16390        self.display_map.update(cx, |display_map, cx| {
16391            display_map.fold_buffers([buffer_id], cx)
16392        });
16393        cx.emit(EditorEvent::BufferFoldToggled {
16394            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16395            folded: true,
16396        });
16397        cx.notify();
16398    }
16399
16400    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16401        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16402            return;
16403        }
16404        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16405        self.display_map.update(cx, |display_map, cx| {
16406            display_map.unfold_buffers([buffer_id], cx);
16407        });
16408        cx.emit(EditorEvent::BufferFoldToggled {
16409            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16410            folded: false,
16411        });
16412        cx.notify();
16413    }
16414
16415    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16416        self.display_map.read(cx).is_buffer_folded(buffer)
16417    }
16418
16419    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16420        self.display_map.read(cx).folded_buffers()
16421    }
16422
16423    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16424        self.display_map.update(cx, |display_map, cx| {
16425            display_map.disable_header_for_buffer(buffer_id, cx);
16426        });
16427        cx.notify();
16428    }
16429
16430    /// Removes any folds with the given ranges.
16431    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16432        &mut self,
16433        ranges: &[Range<T>],
16434        type_id: TypeId,
16435        auto_scroll: bool,
16436        cx: &mut Context<Self>,
16437    ) {
16438        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16439            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16440        });
16441        self.folds_did_change(cx);
16442    }
16443
16444    fn remove_folds_with<T: ToOffset + Clone>(
16445        &mut self,
16446        ranges: &[Range<T>],
16447        auto_scroll: bool,
16448        cx: &mut Context<Self>,
16449        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16450    ) {
16451        if ranges.is_empty() {
16452            return;
16453        }
16454
16455        let mut buffers_affected = HashSet::default();
16456        let multi_buffer = self.buffer().read(cx);
16457        for range in ranges {
16458            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16459                buffers_affected.insert(buffer.read(cx).remote_id());
16460            };
16461        }
16462
16463        self.display_map.update(cx, update);
16464
16465        if auto_scroll {
16466            self.request_autoscroll(Autoscroll::fit(), cx);
16467        }
16468
16469        cx.notify();
16470        self.scrollbar_marker_state.dirty = true;
16471        self.active_indent_guides_state.dirty = true;
16472    }
16473
16474    pub fn update_fold_widths(
16475        &mut self,
16476        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16477        cx: &mut Context<Self>,
16478    ) -> bool {
16479        self.display_map
16480            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16481    }
16482
16483    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16484        self.display_map.read(cx).fold_placeholder.clone()
16485    }
16486
16487    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16488        self.buffer.update(cx, |buffer, cx| {
16489            buffer.set_all_diff_hunks_expanded(cx);
16490        });
16491    }
16492
16493    pub fn expand_all_diff_hunks(
16494        &mut self,
16495        _: &ExpandAllDiffHunks,
16496        _window: &mut Window,
16497        cx: &mut Context<Self>,
16498    ) {
16499        self.buffer.update(cx, |buffer, cx| {
16500            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16501        });
16502    }
16503
16504    pub fn toggle_selected_diff_hunks(
16505        &mut self,
16506        _: &ToggleSelectedDiffHunks,
16507        _window: &mut Window,
16508        cx: &mut Context<Self>,
16509    ) {
16510        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16511        self.toggle_diff_hunks_in_ranges(ranges, cx);
16512    }
16513
16514    pub fn diff_hunks_in_ranges<'a>(
16515        &'a self,
16516        ranges: &'a [Range<Anchor>],
16517        buffer: &'a MultiBufferSnapshot,
16518    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16519        ranges.iter().flat_map(move |range| {
16520            let end_excerpt_id = range.end.excerpt_id;
16521            let range = range.to_point(buffer);
16522            let mut peek_end = range.end;
16523            if range.end.row < buffer.max_row().0 {
16524                peek_end = Point::new(range.end.row + 1, 0);
16525            }
16526            buffer
16527                .diff_hunks_in_range(range.start..peek_end)
16528                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16529        })
16530    }
16531
16532    pub fn has_stageable_diff_hunks_in_ranges(
16533        &self,
16534        ranges: &[Range<Anchor>],
16535        snapshot: &MultiBufferSnapshot,
16536    ) -> bool {
16537        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16538        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16539    }
16540
16541    pub fn toggle_staged_selected_diff_hunks(
16542        &mut self,
16543        _: &::git::ToggleStaged,
16544        _: &mut Window,
16545        cx: &mut Context<Self>,
16546    ) {
16547        let snapshot = self.buffer.read(cx).snapshot(cx);
16548        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16549        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16550        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16551    }
16552
16553    pub fn set_render_diff_hunk_controls(
16554        &mut self,
16555        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16556        cx: &mut Context<Self>,
16557    ) {
16558        self.render_diff_hunk_controls = render_diff_hunk_controls;
16559        cx.notify();
16560    }
16561
16562    pub fn stage_and_next(
16563        &mut self,
16564        _: &::git::StageAndNext,
16565        window: &mut Window,
16566        cx: &mut Context<Self>,
16567    ) {
16568        self.do_stage_or_unstage_and_next(true, window, cx);
16569    }
16570
16571    pub fn unstage_and_next(
16572        &mut self,
16573        _: &::git::UnstageAndNext,
16574        window: &mut Window,
16575        cx: &mut Context<Self>,
16576    ) {
16577        self.do_stage_or_unstage_and_next(false, window, cx);
16578    }
16579
16580    pub fn stage_or_unstage_diff_hunks(
16581        &mut self,
16582        stage: bool,
16583        ranges: Vec<Range<Anchor>>,
16584        cx: &mut Context<Self>,
16585    ) {
16586        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16587        cx.spawn(async move |this, cx| {
16588            task.await?;
16589            this.update(cx, |this, cx| {
16590                let snapshot = this.buffer.read(cx).snapshot(cx);
16591                let chunk_by = this
16592                    .diff_hunks_in_ranges(&ranges, &snapshot)
16593                    .chunk_by(|hunk| hunk.buffer_id);
16594                for (buffer_id, hunks) in &chunk_by {
16595                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16596                }
16597            })
16598        })
16599        .detach_and_log_err(cx);
16600    }
16601
16602    fn save_buffers_for_ranges_if_needed(
16603        &mut self,
16604        ranges: &[Range<Anchor>],
16605        cx: &mut Context<Editor>,
16606    ) -> Task<Result<()>> {
16607        let multibuffer = self.buffer.read(cx);
16608        let snapshot = multibuffer.read(cx);
16609        let buffer_ids: HashSet<_> = ranges
16610            .iter()
16611            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16612            .collect();
16613        drop(snapshot);
16614
16615        let mut buffers = HashSet::default();
16616        for buffer_id in buffer_ids {
16617            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16618                let buffer = buffer_entity.read(cx);
16619                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16620                {
16621                    buffers.insert(buffer_entity);
16622                }
16623            }
16624        }
16625
16626        if let Some(project) = &self.project {
16627            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16628        } else {
16629            Task::ready(Ok(()))
16630        }
16631    }
16632
16633    fn do_stage_or_unstage_and_next(
16634        &mut self,
16635        stage: bool,
16636        window: &mut Window,
16637        cx: &mut Context<Self>,
16638    ) {
16639        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16640
16641        if ranges.iter().any(|range| range.start != range.end) {
16642            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16643            return;
16644        }
16645
16646        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16647        let snapshot = self.snapshot(window, cx);
16648        let position = self.selections.newest::<Point>(cx).head();
16649        let mut row = snapshot
16650            .buffer_snapshot
16651            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16652            .find(|hunk| hunk.row_range.start.0 > position.row)
16653            .map(|hunk| hunk.row_range.start);
16654
16655        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16656        // Outside of the project diff editor, wrap around to the beginning.
16657        if !all_diff_hunks_expanded {
16658            row = row.or_else(|| {
16659                snapshot
16660                    .buffer_snapshot
16661                    .diff_hunks_in_range(Point::zero()..position)
16662                    .find(|hunk| hunk.row_range.end.0 < position.row)
16663                    .map(|hunk| hunk.row_range.start)
16664            });
16665        }
16666
16667        if let Some(row) = row {
16668            let destination = Point::new(row.0, 0);
16669            let autoscroll = Autoscroll::center();
16670
16671            self.unfold_ranges(&[destination..destination], false, false, cx);
16672            self.change_selections(Some(autoscroll), window, cx, |s| {
16673                s.select_ranges([destination..destination]);
16674            });
16675        }
16676    }
16677
16678    fn do_stage_or_unstage(
16679        &self,
16680        stage: bool,
16681        buffer_id: BufferId,
16682        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16683        cx: &mut App,
16684    ) -> Option<()> {
16685        let project = self.project.as_ref()?;
16686        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16687        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16688        let buffer_snapshot = buffer.read(cx).snapshot();
16689        let file_exists = buffer_snapshot
16690            .file()
16691            .is_some_and(|file| file.disk_state().exists());
16692        diff.update(cx, |diff, cx| {
16693            diff.stage_or_unstage_hunks(
16694                stage,
16695                &hunks
16696                    .map(|hunk| buffer_diff::DiffHunk {
16697                        buffer_range: hunk.buffer_range,
16698                        diff_base_byte_range: hunk.diff_base_byte_range,
16699                        secondary_status: hunk.secondary_status,
16700                        range: Point::zero()..Point::zero(), // unused
16701                    })
16702                    .collect::<Vec<_>>(),
16703                &buffer_snapshot,
16704                file_exists,
16705                cx,
16706            )
16707        });
16708        None
16709    }
16710
16711    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16712        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16713        self.buffer
16714            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16715    }
16716
16717    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16718        self.buffer.update(cx, |buffer, cx| {
16719            let ranges = vec![Anchor::min()..Anchor::max()];
16720            if !buffer.all_diff_hunks_expanded()
16721                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16722            {
16723                buffer.collapse_diff_hunks(ranges, cx);
16724                true
16725            } else {
16726                false
16727            }
16728        })
16729    }
16730
16731    fn toggle_diff_hunks_in_ranges(
16732        &mut self,
16733        ranges: Vec<Range<Anchor>>,
16734        cx: &mut Context<Editor>,
16735    ) {
16736        self.buffer.update(cx, |buffer, cx| {
16737            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16738            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16739        })
16740    }
16741
16742    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16743        self.buffer.update(cx, |buffer, cx| {
16744            let snapshot = buffer.snapshot(cx);
16745            let excerpt_id = range.end.excerpt_id;
16746            let point_range = range.to_point(&snapshot);
16747            let expand = !buffer.single_hunk_is_expanded(range, cx);
16748            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16749        })
16750    }
16751
16752    pub(crate) fn apply_all_diff_hunks(
16753        &mut self,
16754        _: &ApplyAllDiffHunks,
16755        window: &mut Window,
16756        cx: &mut Context<Self>,
16757    ) {
16758        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16759
16760        let buffers = self.buffer.read(cx).all_buffers();
16761        for branch_buffer in buffers {
16762            branch_buffer.update(cx, |branch_buffer, cx| {
16763                branch_buffer.merge_into_base(Vec::new(), cx);
16764            });
16765        }
16766
16767        if let Some(project) = self.project.clone() {
16768            self.save(true, project, window, cx).detach_and_log_err(cx);
16769        }
16770    }
16771
16772    pub(crate) fn apply_selected_diff_hunks(
16773        &mut self,
16774        _: &ApplyDiffHunk,
16775        window: &mut Window,
16776        cx: &mut Context<Self>,
16777    ) {
16778        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16779        let snapshot = self.snapshot(window, cx);
16780        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16781        let mut ranges_by_buffer = HashMap::default();
16782        self.transact(window, cx, |editor, _window, cx| {
16783            for hunk in hunks {
16784                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16785                    ranges_by_buffer
16786                        .entry(buffer.clone())
16787                        .or_insert_with(Vec::new)
16788                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16789                }
16790            }
16791
16792            for (buffer, ranges) in ranges_by_buffer {
16793                buffer.update(cx, |buffer, cx| {
16794                    buffer.merge_into_base(ranges, cx);
16795                });
16796            }
16797        });
16798
16799        if let Some(project) = self.project.clone() {
16800            self.save(true, project, window, cx).detach_and_log_err(cx);
16801        }
16802    }
16803
16804    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16805        if hovered != self.gutter_hovered {
16806            self.gutter_hovered = hovered;
16807            cx.notify();
16808        }
16809    }
16810
16811    pub fn insert_blocks(
16812        &mut self,
16813        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16814        autoscroll: Option<Autoscroll>,
16815        cx: &mut Context<Self>,
16816    ) -> Vec<CustomBlockId> {
16817        let blocks = self
16818            .display_map
16819            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16820        if let Some(autoscroll) = autoscroll {
16821            self.request_autoscroll(autoscroll, cx);
16822        }
16823        cx.notify();
16824        blocks
16825    }
16826
16827    pub fn resize_blocks(
16828        &mut self,
16829        heights: HashMap<CustomBlockId, u32>,
16830        autoscroll: Option<Autoscroll>,
16831        cx: &mut Context<Self>,
16832    ) {
16833        self.display_map
16834            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16835        if let Some(autoscroll) = autoscroll {
16836            self.request_autoscroll(autoscroll, cx);
16837        }
16838        cx.notify();
16839    }
16840
16841    pub fn replace_blocks(
16842        &mut self,
16843        renderers: HashMap<CustomBlockId, RenderBlock>,
16844        autoscroll: Option<Autoscroll>,
16845        cx: &mut Context<Self>,
16846    ) {
16847        self.display_map
16848            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16849        if let Some(autoscroll) = autoscroll {
16850            self.request_autoscroll(autoscroll, cx);
16851        }
16852        cx.notify();
16853    }
16854
16855    pub fn remove_blocks(
16856        &mut self,
16857        block_ids: HashSet<CustomBlockId>,
16858        autoscroll: Option<Autoscroll>,
16859        cx: &mut Context<Self>,
16860    ) {
16861        self.display_map.update(cx, |display_map, cx| {
16862            display_map.remove_blocks(block_ids, cx)
16863        });
16864        if let Some(autoscroll) = autoscroll {
16865            self.request_autoscroll(autoscroll, cx);
16866        }
16867        cx.notify();
16868    }
16869
16870    pub fn row_for_block(
16871        &self,
16872        block_id: CustomBlockId,
16873        cx: &mut Context<Self>,
16874    ) -> Option<DisplayRow> {
16875        self.display_map
16876            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16877    }
16878
16879    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16880        self.focused_block = Some(focused_block);
16881    }
16882
16883    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16884        self.focused_block.take()
16885    }
16886
16887    pub fn insert_creases(
16888        &mut self,
16889        creases: impl IntoIterator<Item = Crease<Anchor>>,
16890        cx: &mut Context<Self>,
16891    ) -> Vec<CreaseId> {
16892        self.display_map
16893            .update(cx, |map, cx| map.insert_creases(creases, cx))
16894    }
16895
16896    pub fn remove_creases(
16897        &mut self,
16898        ids: impl IntoIterator<Item = CreaseId>,
16899        cx: &mut Context<Self>,
16900    ) -> Vec<(CreaseId, Range<Anchor>)> {
16901        self.display_map
16902            .update(cx, |map, cx| map.remove_creases(ids, cx))
16903    }
16904
16905    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16906        self.display_map
16907            .update(cx, |map, cx| map.snapshot(cx))
16908            .longest_row()
16909    }
16910
16911    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16912        self.display_map
16913            .update(cx, |map, cx| map.snapshot(cx))
16914            .max_point()
16915    }
16916
16917    pub fn text(&self, cx: &App) -> String {
16918        self.buffer.read(cx).read(cx).text()
16919    }
16920
16921    pub fn is_empty(&self, cx: &App) -> bool {
16922        self.buffer.read(cx).read(cx).is_empty()
16923    }
16924
16925    pub fn text_option(&self, cx: &App) -> Option<String> {
16926        let text = self.text(cx);
16927        let text = text.trim();
16928
16929        if text.is_empty() {
16930            return None;
16931        }
16932
16933        Some(text.to_string())
16934    }
16935
16936    pub fn set_text(
16937        &mut self,
16938        text: impl Into<Arc<str>>,
16939        window: &mut Window,
16940        cx: &mut Context<Self>,
16941    ) {
16942        self.transact(window, cx, |this, _, cx| {
16943            this.buffer
16944                .read(cx)
16945                .as_singleton()
16946                .expect("you can only call set_text on editors for singleton buffers")
16947                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16948        });
16949    }
16950
16951    pub fn display_text(&self, cx: &mut App) -> String {
16952        self.display_map
16953            .update(cx, |map, cx| map.snapshot(cx))
16954            .text()
16955    }
16956
16957    fn create_minimap(
16958        &self,
16959        minimap_settings: MinimapSettings,
16960        window: &mut Window,
16961        cx: &mut Context<Self>,
16962    ) -> Option<Entity<Self>> {
16963        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16964            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16965    }
16966
16967    fn initialize_new_minimap(
16968        &self,
16969        minimap_settings: MinimapSettings,
16970        window: &mut Window,
16971        cx: &mut Context<Self>,
16972    ) -> Entity<Self> {
16973        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16974
16975        let mut minimap = Editor::new_internal(
16976            EditorMode::Minimap {
16977                parent: cx.weak_entity(),
16978            },
16979            self.buffer.clone(),
16980            self.project.clone(),
16981            Some(self.display_map.clone()),
16982            window,
16983            cx,
16984        );
16985        minimap.scroll_manager.clone_state(&self.scroll_manager);
16986        minimap.set_text_style_refinement(TextStyleRefinement {
16987            font_size: Some(MINIMAP_FONT_SIZE),
16988            font_weight: Some(MINIMAP_FONT_WEIGHT),
16989            ..Default::default()
16990        });
16991        minimap.update_minimap_configuration(minimap_settings, cx);
16992        cx.new(|_| minimap)
16993    }
16994
16995    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16996        let current_line_highlight = minimap_settings
16997            .current_line_highlight
16998            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16999        self.set_current_line_highlight(Some(current_line_highlight));
17000    }
17001
17002    pub fn minimap(&self) -> Option<&Entity<Self>> {
17003        self.minimap
17004            .as_ref()
17005            .filter(|_| self.minimap_visibility.visible())
17006    }
17007
17008    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17009        let mut wrap_guides = smallvec![];
17010
17011        if self.show_wrap_guides == Some(false) {
17012            return wrap_guides;
17013        }
17014
17015        let settings = self.buffer.read(cx).language_settings(cx);
17016        if settings.show_wrap_guides {
17017            match self.soft_wrap_mode(cx) {
17018                SoftWrap::Column(soft_wrap) => {
17019                    wrap_guides.push((soft_wrap as usize, true));
17020                }
17021                SoftWrap::Bounded(soft_wrap) => {
17022                    wrap_guides.push((soft_wrap as usize, true));
17023                }
17024                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17025            }
17026            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17027        }
17028
17029        wrap_guides
17030    }
17031
17032    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17033        let settings = self.buffer.read(cx).language_settings(cx);
17034        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17035        match mode {
17036            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17037                SoftWrap::None
17038            }
17039            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17040            language_settings::SoftWrap::PreferredLineLength => {
17041                SoftWrap::Column(settings.preferred_line_length)
17042            }
17043            language_settings::SoftWrap::Bounded => {
17044                SoftWrap::Bounded(settings.preferred_line_length)
17045            }
17046        }
17047    }
17048
17049    pub fn set_soft_wrap_mode(
17050        &mut self,
17051        mode: language_settings::SoftWrap,
17052
17053        cx: &mut Context<Self>,
17054    ) {
17055        self.soft_wrap_mode_override = Some(mode);
17056        cx.notify();
17057    }
17058
17059    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17060        self.hard_wrap = hard_wrap;
17061        cx.notify();
17062    }
17063
17064    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17065        self.text_style_refinement = Some(style);
17066    }
17067
17068    /// called by the Element so we know what style we were most recently rendered with.
17069    pub(crate) fn set_style(
17070        &mut self,
17071        style: EditorStyle,
17072        window: &mut Window,
17073        cx: &mut Context<Self>,
17074    ) {
17075        // We intentionally do not inform the display map about the minimap style
17076        // so that wrapping is not recalculated and stays consistent for the editor
17077        // and its linked minimap.
17078        if !self.mode.is_minimap() {
17079            let rem_size = window.rem_size();
17080            self.display_map.update(cx, |map, cx| {
17081                map.set_font(
17082                    style.text.font(),
17083                    style.text.font_size.to_pixels(rem_size),
17084                    cx,
17085                )
17086            });
17087        }
17088        self.style = Some(style);
17089    }
17090
17091    pub fn style(&self) -> Option<&EditorStyle> {
17092        self.style.as_ref()
17093    }
17094
17095    // Called by the element. This method is not designed to be called outside of the editor
17096    // element's layout code because it does not notify when rewrapping is computed synchronously.
17097    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17098        self.display_map
17099            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17100    }
17101
17102    pub fn set_soft_wrap(&mut self) {
17103        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17104    }
17105
17106    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17107        if self.soft_wrap_mode_override.is_some() {
17108            self.soft_wrap_mode_override.take();
17109        } else {
17110            let soft_wrap = match self.soft_wrap_mode(cx) {
17111                SoftWrap::GitDiff => return,
17112                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17113                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17114                    language_settings::SoftWrap::None
17115                }
17116            };
17117            self.soft_wrap_mode_override = Some(soft_wrap);
17118        }
17119        cx.notify();
17120    }
17121
17122    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17123        let Some(workspace) = self.workspace() else {
17124            return;
17125        };
17126        let fs = workspace.read(cx).app_state().fs.clone();
17127        let current_show = TabBarSettings::get_global(cx).show;
17128        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17129            setting.show = Some(!current_show);
17130        });
17131    }
17132
17133    pub fn toggle_indent_guides(
17134        &mut self,
17135        _: &ToggleIndentGuides,
17136        _: &mut Window,
17137        cx: &mut Context<Self>,
17138    ) {
17139        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17140            self.buffer
17141                .read(cx)
17142                .language_settings(cx)
17143                .indent_guides
17144                .enabled
17145        });
17146        self.show_indent_guides = Some(!currently_enabled);
17147        cx.notify();
17148    }
17149
17150    fn should_show_indent_guides(&self) -> Option<bool> {
17151        self.show_indent_guides
17152    }
17153
17154    pub fn toggle_line_numbers(
17155        &mut self,
17156        _: &ToggleLineNumbers,
17157        _: &mut Window,
17158        cx: &mut Context<Self>,
17159    ) {
17160        let mut editor_settings = EditorSettings::get_global(cx).clone();
17161        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17162        EditorSettings::override_global(editor_settings, cx);
17163    }
17164
17165    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17166        if let Some(show_line_numbers) = self.show_line_numbers {
17167            return show_line_numbers;
17168        }
17169        EditorSettings::get_global(cx).gutter.line_numbers
17170    }
17171
17172    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17173        self.use_relative_line_numbers
17174            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17175    }
17176
17177    pub fn toggle_relative_line_numbers(
17178        &mut self,
17179        _: &ToggleRelativeLineNumbers,
17180        _: &mut Window,
17181        cx: &mut Context<Self>,
17182    ) {
17183        let is_relative = self.should_use_relative_line_numbers(cx);
17184        self.set_relative_line_number(Some(!is_relative), cx)
17185    }
17186
17187    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17188        self.use_relative_line_numbers = is_relative;
17189        cx.notify();
17190    }
17191
17192    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17193        self.show_gutter = show_gutter;
17194        cx.notify();
17195    }
17196
17197    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17198        self.show_scrollbars = ScrollbarAxes {
17199            horizontal: show,
17200            vertical: show,
17201        };
17202        cx.notify();
17203    }
17204
17205    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17206        self.show_scrollbars.vertical = show;
17207        cx.notify();
17208    }
17209
17210    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17211        self.show_scrollbars.horizontal = show;
17212        cx.notify();
17213    }
17214
17215    pub fn set_minimap_visibility(
17216        &mut self,
17217        minimap_visibility: MinimapVisibility,
17218        window: &mut Window,
17219        cx: &mut Context<Self>,
17220    ) {
17221        if self.minimap_visibility != minimap_visibility {
17222            if minimap_visibility.visible() && self.minimap.is_none() {
17223                let minimap_settings = EditorSettings::get_global(cx).minimap;
17224                self.minimap =
17225                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17226            }
17227            self.minimap_visibility = minimap_visibility;
17228            cx.notify();
17229        }
17230    }
17231
17232    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17233        self.set_show_scrollbars(false, cx);
17234        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17235    }
17236
17237    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17238        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17239    }
17240
17241    /// Normally the text in full mode and auto height editors is padded on the
17242    /// left side by roughly half a character width for improved hit testing.
17243    ///
17244    /// Use this method to disable this for cases where this is not wanted (e.g.
17245    /// if you want to align the editor text with some other text above or below)
17246    /// or if you want to add this padding to single-line editors.
17247    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17248        self.offset_content = offset_content;
17249        cx.notify();
17250    }
17251
17252    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17253        self.show_line_numbers = Some(show_line_numbers);
17254        cx.notify();
17255    }
17256
17257    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17258        self.disable_expand_excerpt_buttons = true;
17259        cx.notify();
17260    }
17261
17262    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17263        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17264        cx.notify();
17265    }
17266
17267    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17268        self.show_code_actions = Some(show_code_actions);
17269        cx.notify();
17270    }
17271
17272    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17273        self.show_runnables = Some(show_runnables);
17274        cx.notify();
17275    }
17276
17277    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17278        self.show_breakpoints = Some(show_breakpoints);
17279        cx.notify();
17280    }
17281
17282    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17283        if self.display_map.read(cx).masked != masked {
17284            self.display_map.update(cx, |map, _| map.masked = masked);
17285        }
17286        cx.notify()
17287    }
17288
17289    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17290        self.show_wrap_guides = Some(show_wrap_guides);
17291        cx.notify();
17292    }
17293
17294    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17295        self.show_indent_guides = Some(show_indent_guides);
17296        cx.notify();
17297    }
17298
17299    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17300        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17301            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17302                if let Some(dir) = file.abs_path(cx).parent() {
17303                    return Some(dir.to_owned());
17304                }
17305            }
17306
17307            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17308                return Some(project_path.path.to_path_buf());
17309            }
17310        }
17311
17312        None
17313    }
17314
17315    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17316        self.active_excerpt(cx)?
17317            .1
17318            .read(cx)
17319            .file()
17320            .and_then(|f| f.as_local())
17321    }
17322
17323    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17324        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17325            let buffer = buffer.read(cx);
17326            if let Some(project_path) = buffer.project_path(cx) {
17327                let project = self.project.as_ref()?.read(cx);
17328                project.absolute_path(&project_path, cx)
17329            } else {
17330                buffer
17331                    .file()
17332                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17333            }
17334        })
17335    }
17336
17337    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17338        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17339            let project_path = buffer.read(cx).project_path(cx)?;
17340            let project = self.project.as_ref()?.read(cx);
17341            let entry = project.entry_for_path(&project_path, cx)?;
17342            let path = entry.path.to_path_buf();
17343            Some(path)
17344        })
17345    }
17346
17347    pub fn reveal_in_finder(
17348        &mut self,
17349        _: &RevealInFileManager,
17350        _window: &mut Window,
17351        cx: &mut Context<Self>,
17352    ) {
17353        if let Some(target) = self.target_file(cx) {
17354            cx.reveal_path(&target.abs_path(cx));
17355        }
17356    }
17357
17358    pub fn copy_path(
17359        &mut self,
17360        _: &zed_actions::workspace::CopyPath,
17361        _window: &mut Window,
17362        cx: &mut Context<Self>,
17363    ) {
17364        if let Some(path) = self.target_file_abs_path(cx) {
17365            if let Some(path) = path.to_str() {
17366                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17367            }
17368        }
17369    }
17370
17371    pub fn copy_relative_path(
17372        &mut self,
17373        _: &zed_actions::workspace::CopyRelativePath,
17374        _window: &mut Window,
17375        cx: &mut Context<Self>,
17376    ) {
17377        if let Some(path) = self.target_file_path(cx) {
17378            if let Some(path) = path.to_str() {
17379                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17380            }
17381        }
17382    }
17383
17384    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17385        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17386            buffer.read(cx).project_path(cx)
17387        } else {
17388            None
17389        }
17390    }
17391
17392    // Returns true if the editor handled a go-to-line request
17393    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17394        maybe!({
17395            let breakpoint_store = self.breakpoint_store.as_ref()?;
17396
17397            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17398            else {
17399                self.clear_row_highlights::<ActiveDebugLine>();
17400                return None;
17401            };
17402
17403            let position = active_stack_frame.position;
17404            let buffer_id = position.buffer_id?;
17405            let snapshot = self
17406                .project
17407                .as_ref()?
17408                .read(cx)
17409                .buffer_for_id(buffer_id, cx)?
17410                .read(cx)
17411                .snapshot();
17412
17413            let mut handled = false;
17414            for (id, ExcerptRange { context, .. }) in
17415                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17416            {
17417                if context.start.cmp(&position, &snapshot).is_ge()
17418                    || context.end.cmp(&position, &snapshot).is_lt()
17419                {
17420                    continue;
17421                }
17422                let snapshot = self.buffer.read(cx).snapshot(cx);
17423                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17424
17425                handled = true;
17426                self.clear_row_highlights::<ActiveDebugLine>();
17427
17428                self.go_to_line::<ActiveDebugLine>(
17429                    multibuffer_anchor,
17430                    Some(cx.theme().colors().editor_debugger_active_line_background),
17431                    window,
17432                    cx,
17433                );
17434
17435                cx.notify();
17436            }
17437
17438            handled.then_some(())
17439        })
17440        .is_some()
17441    }
17442
17443    pub fn copy_file_name_without_extension(
17444        &mut self,
17445        _: &CopyFileNameWithoutExtension,
17446        _: &mut Window,
17447        cx: &mut Context<Self>,
17448    ) {
17449        if let Some(file) = self.target_file(cx) {
17450            if let Some(file_stem) = file.path().file_stem() {
17451                if let Some(name) = file_stem.to_str() {
17452                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17453                }
17454            }
17455        }
17456    }
17457
17458    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17459        if let Some(file) = self.target_file(cx) {
17460            if let Some(file_name) = file.path().file_name() {
17461                if let Some(name) = file_name.to_str() {
17462                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17463                }
17464            }
17465        }
17466    }
17467
17468    pub fn toggle_git_blame(
17469        &mut self,
17470        _: &::git::Blame,
17471        window: &mut Window,
17472        cx: &mut Context<Self>,
17473    ) {
17474        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17475
17476        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17477            self.start_git_blame(true, window, cx);
17478        }
17479
17480        cx.notify();
17481    }
17482
17483    pub fn toggle_git_blame_inline(
17484        &mut self,
17485        _: &ToggleGitBlameInline,
17486        window: &mut Window,
17487        cx: &mut Context<Self>,
17488    ) {
17489        self.toggle_git_blame_inline_internal(true, window, cx);
17490        cx.notify();
17491    }
17492
17493    pub fn open_git_blame_commit(
17494        &mut self,
17495        _: &OpenGitBlameCommit,
17496        window: &mut Window,
17497        cx: &mut Context<Self>,
17498    ) {
17499        self.open_git_blame_commit_internal(window, cx);
17500    }
17501
17502    fn open_git_blame_commit_internal(
17503        &mut self,
17504        window: &mut Window,
17505        cx: &mut Context<Self>,
17506    ) -> Option<()> {
17507        let blame = self.blame.as_ref()?;
17508        let snapshot = self.snapshot(window, cx);
17509        let cursor = self.selections.newest::<Point>(cx).head();
17510        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17511        let blame_entry = blame
17512            .update(cx, |blame, cx| {
17513                blame
17514                    .blame_for_rows(
17515                        &[RowInfo {
17516                            buffer_id: Some(buffer.remote_id()),
17517                            buffer_row: Some(point.row),
17518                            ..Default::default()
17519                        }],
17520                        cx,
17521                    )
17522                    .next()
17523            })
17524            .flatten()?;
17525        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17526        let repo = blame.read(cx).repository(cx)?;
17527        let workspace = self.workspace()?.downgrade();
17528        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17529        None
17530    }
17531
17532    pub fn git_blame_inline_enabled(&self) -> bool {
17533        self.git_blame_inline_enabled
17534    }
17535
17536    pub fn toggle_selection_menu(
17537        &mut self,
17538        _: &ToggleSelectionMenu,
17539        _: &mut Window,
17540        cx: &mut Context<Self>,
17541    ) {
17542        self.show_selection_menu = self
17543            .show_selection_menu
17544            .map(|show_selections_menu| !show_selections_menu)
17545            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17546
17547        cx.notify();
17548    }
17549
17550    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17551        self.show_selection_menu
17552            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17553    }
17554
17555    fn start_git_blame(
17556        &mut self,
17557        user_triggered: bool,
17558        window: &mut Window,
17559        cx: &mut Context<Self>,
17560    ) {
17561        if let Some(project) = self.project.as_ref() {
17562            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17563                return;
17564            };
17565
17566            if buffer.read(cx).file().is_none() {
17567                return;
17568            }
17569
17570            let focused = self.focus_handle(cx).contains_focused(window, cx);
17571
17572            let project = project.clone();
17573            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17574            self.blame_subscription =
17575                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17576            self.blame = Some(blame);
17577        }
17578    }
17579
17580    fn toggle_git_blame_inline_internal(
17581        &mut self,
17582        user_triggered: bool,
17583        window: &mut Window,
17584        cx: &mut Context<Self>,
17585    ) {
17586        if self.git_blame_inline_enabled {
17587            self.git_blame_inline_enabled = false;
17588            self.show_git_blame_inline = false;
17589            self.show_git_blame_inline_delay_task.take();
17590        } else {
17591            self.git_blame_inline_enabled = true;
17592            self.start_git_blame_inline(user_triggered, window, cx);
17593        }
17594
17595        cx.notify();
17596    }
17597
17598    fn start_git_blame_inline(
17599        &mut self,
17600        user_triggered: bool,
17601        window: &mut Window,
17602        cx: &mut Context<Self>,
17603    ) {
17604        self.start_git_blame(user_triggered, window, cx);
17605
17606        if ProjectSettings::get_global(cx)
17607            .git
17608            .inline_blame_delay()
17609            .is_some()
17610        {
17611            self.start_inline_blame_timer(window, cx);
17612        } else {
17613            self.show_git_blame_inline = true
17614        }
17615    }
17616
17617    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17618        self.blame.as_ref()
17619    }
17620
17621    pub fn show_git_blame_gutter(&self) -> bool {
17622        self.show_git_blame_gutter
17623    }
17624
17625    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17626        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17627    }
17628
17629    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17630        self.show_git_blame_inline
17631            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17632            && !self.newest_selection_head_on_empty_line(cx)
17633            && self.has_blame_entries(cx)
17634    }
17635
17636    fn has_blame_entries(&self, cx: &App) -> bool {
17637        self.blame()
17638            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17639    }
17640
17641    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17642        let cursor_anchor = self.selections.newest_anchor().head();
17643
17644        let snapshot = self.buffer.read(cx).snapshot(cx);
17645        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17646
17647        snapshot.line_len(buffer_row) == 0
17648    }
17649
17650    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17651        let buffer_and_selection = maybe!({
17652            let selection = self.selections.newest::<Point>(cx);
17653            let selection_range = selection.range();
17654
17655            let multi_buffer = self.buffer().read(cx);
17656            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17657            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17658
17659            let (buffer, range, _) = if selection.reversed {
17660                buffer_ranges.first()
17661            } else {
17662                buffer_ranges.last()
17663            }?;
17664
17665            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17666                ..text::ToPoint::to_point(&range.end, &buffer).row;
17667            Some((
17668                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17669                selection,
17670            ))
17671        });
17672
17673        let Some((buffer, selection)) = buffer_and_selection else {
17674            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17675        };
17676
17677        let Some(project) = self.project.as_ref() else {
17678            return Task::ready(Err(anyhow!("editor does not have project")));
17679        };
17680
17681        project.update(cx, |project, cx| {
17682            project.get_permalink_to_line(&buffer, selection, cx)
17683        })
17684    }
17685
17686    pub fn copy_permalink_to_line(
17687        &mut self,
17688        _: &CopyPermalinkToLine,
17689        window: &mut Window,
17690        cx: &mut Context<Self>,
17691    ) {
17692        let permalink_task = self.get_permalink_to_line(cx);
17693        let workspace = self.workspace();
17694
17695        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17696            Ok(permalink) => {
17697                cx.update(|_, cx| {
17698                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17699                })
17700                .ok();
17701            }
17702            Err(err) => {
17703                let message = format!("Failed to copy permalink: {err}");
17704
17705                anyhow::Result::<()>::Err(err).log_err();
17706
17707                if let Some(workspace) = workspace {
17708                    workspace
17709                        .update_in(cx, |workspace, _, cx| {
17710                            struct CopyPermalinkToLine;
17711
17712                            workspace.show_toast(
17713                                Toast::new(
17714                                    NotificationId::unique::<CopyPermalinkToLine>(),
17715                                    message,
17716                                ),
17717                                cx,
17718                            )
17719                        })
17720                        .ok();
17721                }
17722            }
17723        })
17724        .detach();
17725    }
17726
17727    pub fn copy_file_location(
17728        &mut self,
17729        _: &CopyFileLocation,
17730        _: &mut Window,
17731        cx: &mut Context<Self>,
17732    ) {
17733        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17734        if let Some(file) = self.target_file(cx) {
17735            if let Some(path) = file.path().to_str() {
17736                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17737            }
17738        }
17739    }
17740
17741    pub fn open_permalink_to_line(
17742        &mut self,
17743        _: &OpenPermalinkToLine,
17744        window: &mut Window,
17745        cx: &mut Context<Self>,
17746    ) {
17747        let permalink_task = self.get_permalink_to_line(cx);
17748        let workspace = self.workspace();
17749
17750        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17751            Ok(permalink) => {
17752                cx.update(|_, cx| {
17753                    cx.open_url(permalink.as_ref());
17754                })
17755                .ok();
17756            }
17757            Err(err) => {
17758                let message = format!("Failed to open permalink: {err}");
17759
17760                anyhow::Result::<()>::Err(err).log_err();
17761
17762                if let Some(workspace) = workspace {
17763                    workspace
17764                        .update(cx, |workspace, cx| {
17765                            struct OpenPermalinkToLine;
17766
17767                            workspace.show_toast(
17768                                Toast::new(
17769                                    NotificationId::unique::<OpenPermalinkToLine>(),
17770                                    message,
17771                                ),
17772                                cx,
17773                            )
17774                        })
17775                        .ok();
17776                }
17777            }
17778        })
17779        .detach();
17780    }
17781
17782    pub fn insert_uuid_v4(
17783        &mut self,
17784        _: &InsertUuidV4,
17785        window: &mut Window,
17786        cx: &mut Context<Self>,
17787    ) {
17788        self.insert_uuid(UuidVersion::V4, window, cx);
17789    }
17790
17791    pub fn insert_uuid_v7(
17792        &mut self,
17793        _: &InsertUuidV7,
17794        window: &mut Window,
17795        cx: &mut Context<Self>,
17796    ) {
17797        self.insert_uuid(UuidVersion::V7, window, cx);
17798    }
17799
17800    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17801        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17802        self.transact(window, cx, |this, window, cx| {
17803            let edits = this
17804                .selections
17805                .all::<Point>(cx)
17806                .into_iter()
17807                .map(|selection| {
17808                    let uuid = match version {
17809                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17810                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17811                    };
17812
17813                    (selection.range(), uuid.to_string())
17814                });
17815            this.edit(edits, cx);
17816            this.refresh_inline_completion(true, false, window, cx);
17817        });
17818    }
17819
17820    pub fn open_selections_in_multibuffer(
17821        &mut self,
17822        _: &OpenSelectionsInMultibuffer,
17823        window: &mut Window,
17824        cx: &mut Context<Self>,
17825    ) {
17826        let multibuffer = self.buffer.read(cx);
17827
17828        let Some(buffer) = multibuffer.as_singleton() else {
17829            return;
17830        };
17831
17832        let Some(workspace) = self.workspace() else {
17833            return;
17834        };
17835
17836        let locations = self
17837            .selections
17838            .disjoint_anchors()
17839            .iter()
17840            .map(|selection| {
17841                let range = if selection.reversed {
17842                    selection.end.text_anchor..selection.start.text_anchor
17843                } else {
17844                    selection.start.text_anchor..selection.end.text_anchor
17845                };
17846                Location {
17847                    buffer: buffer.clone(),
17848                    range,
17849                }
17850            })
17851            .collect::<Vec<_>>();
17852
17853        let title = multibuffer.title(cx).to_string();
17854
17855        cx.spawn_in(window, async move |_, cx| {
17856            workspace.update_in(cx, |workspace, window, cx| {
17857                Self::open_locations_in_multibuffer(
17858                    workspace,
17859                    locations,
17860                    format!("Selections for '{title}'"),
17861                    false,
17862                    MultibufferSelectionMode::All,
17863                    window,
17864                    cx,
17865                );
17866            })
17867        })
17868        .detach();
17869    }
17870
17871    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17872    /// last highlight added will be used.
17873    ///
17874    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17875    pub fn highlight_rows<T: 'static>(
17876        &mut self,
17877        range: Range<Anchor>,
17878        color: Hsla,
17879        options: RowHighlightOptions,
17880        cx: &mut Context<Self>,
17881    ) {
17882        let snapshot = self.buffer().read(cx).snapshot(cx);
17883        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17884        let ix = row_highlights.binary_search_by(|highlight| {
17885            Ordering::Equal
17886                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17887                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17888        });
17889
17890        if let Err(mut ix) = ix {
17891            let index = post_inc(&mut self.highlight_order);
17892
17893            // If this range intersects with the preceding highlight, then merge it with
17894            // the preceding highlight. Otherwise insert a new highlight.
17895            let mut merged = false;
17896            if ix > 0 {
17897                let prev_highlight = &mut row_highlights[ix - 1];
17898                if prev_highlight
17899                    .range
17900                    .end
17901                    .cmp(&range.start, &snapshot)
17902                    .is_ge()
17903                {
17904                    ix -= 1;
17905                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17906                        prev_highlight.range.end = range.end;
17907                    }
17908                    merged = true;
17909                    prev_highlight.index = index;
17910                    prev_highlight.color = color;
17911                    prev_highlight.options = options;
17912                }
17913            }
17914
17915            if !merged {
17916                row_highlights.insert(
17917                    ix,
17918                    RowHighlight {
17919                        range: range.clone(),
17920                        index,
17921                        color,
17922                        options,
17923                        type_id: TypeId::of::<T>(),
17924                    },
17925                );
17926            }
17927
17928            // If any of the following highlights intersect with this one, merge them.
17929            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17930                let highlight = &row_highlights[ix];
17931                if next_highlight
17932                    .range
17933                    .start
17934                    .cmp(&highlight.range.end, &snapshot)
17935                    .is_le()
17936                {
17937                    if next_highlight
17938                        .range
17939                        .end
17940                        .cmp(&highlight.range.end, &snapshot)
17941                        .is_gt()
17942                    {
17943                        row_highlights[ix].range.end = next_highlight.range.end;
17944                    }
17945                    row_highlights.remove(ix + 1);
17946                } else {
17947                    break;
17948                }
17949            }
17950        }
17951    }
17952
17953    /// Remove any highlighted row ranges of the given type that intersect the
17954    /// given ranges.
17955    pub fn remove_highlighted_rows<T: 'static>(
17956        &mut self,
17957        ranges_to_remove: Vec<Range<Anchor>>,
17958        cx: &mut Context<Self>,
17959    ) {
17960        let snapshot = self.buffer().read(cx).snapshot(cx);
17961        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17962        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17963        row_highlights.retain(|highlight| {
17964            while let Some(range_to_remove) = ranges_to_remove.peek() {
17965                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17966                    Ordering::Less | Ordering::Equal => {
17967                        ranges_to_remove.next();
17968                    }
17969                    Ordering::Greater => {
17970                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17971                            Ordering::Less | Ordering::Equal => {
17972                                return false;
17973                            }
17974                            Ordering::Greater => break,
17975                        }
17976                    }
17977                }
17978            }
17979
17980            true
17981        })
17982    }
17983
17984    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17985    pub fn clear_row_highlights<T: 'static>(&mut self) {
17986        self.highlighted_rows.remove(&TypeId::of::<T>());
17987    }
17988
17989    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17990    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17991        self.highlighted_rows
17992            .get(&TypeId::of::<T>())
17993            .map_or(&[] as &[_], |vec| vec.as_slice())
17994            .iter()
17995            .map(|highlight| (highlight.range.clone(), highlight.color))
17996    }
17997
17998    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17999    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18000    /// Allows to ignore certain kinds of highlights.
18001    pub fn highlighted_display_rows(
18002        &self,
18003        window: &mut Window,
18004        cx: &mut App,
18005    ) -> BTreeMap<DisplayRow, LineHighlight> {
18006        let snapshot = self.snapshot(window, cx);
18007        let mut used_highlight_orders = HashMap::default();
18008        self.highlighted_rows
18009            .iter()
18010            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18011            .fold(
18012                BTreeMap::<DisplayRow, LineHighlight>::new(),
18013                |mut unique_rows, highlight| {
18014                    let start = highlight.range.start.to_display_point(&snapshot);
18015                    let end = highlight.range.end.to_display_point(&snapshot);
18016                    let start_row = start.row().0;
18017                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18018                        && end.column() == 0
18019                    {
18020                        end.row().0.saturating_sub(1)
18021                    } else {
18022                        end.row().0
18023                    };
18024                    for row in start_row..=end_row {
18025                        let used_index =
18026                            used_highlight_orders.entry(row).or_insert(highlight.index);
18027                        if highlight.index >= *used_index {
18028                            *used_index = highlight.index;
18029                            unique_rows.insert(
18030                                DisplayRow(row),
18031                                LineHighlight {
18032                                    include_gutter: highlight.options.include_gutter,
18033                                    border: None,
18034                                    background: highlight.color.into(),
18035                                    type_id: Some(highlight.type_id),
18036                                },
18037                            );
18038                        }
18039                    }
18040                    unique_rows
18041                },
18042            )
18043    }
18044
18045    pub fn highlighted_display_row_for_autoscroll(
18046        &self,
18047        snapshot: &DisplaySnapshot,
18048    ) -> Option<DisplayRow> {
18049        self.highlighted_rows
18050            .values()
18051            .flat_map(|highlighted_rows| highlighted_rows.iter())
18052            .filter_map(|highlight| {
18053                if highlight.options.autoscroll {
18054                    Some(highlight.range.start.to_display_point(snapshot).row())
18055                } else {
18056                    None
18057                }
18058            })
18059            .min()
18060    }
18061
18062    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18063        self.highlight_background::<SearchWithinRange>(
18064            ranges,
18065            |colors| colors.editor_document_highlight_read_background,
18066            cx,
18067        )
18068    }
18069
18070    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18071        self.breadcrumb_header = Some(new_header);
18072    }
18073
18074    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18075        self.clear_background_highlights::<SearchWithinRange>(cx);
18076    }
18077
18078    pub fn highlight_background<T: 'static>(
18079        &mut self,
18080        ranges: &[Range<Anchor>],
18081        color_fetcher: fn(&ThemeColors) -> Hsla,
18082        cx: &mut Context<Self>,
18083    ) {
18084        self.background_highlights
18085            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18086        self.scrollbar_marker_state.dirty = true;
18087        cx.notify();
18088    }
18089
18090    pub fn clear_background_highlights<T: 'static>(
18091        &mut self,
18092        cx: &mut Context<Self>,
18093    ) -> Option<BackgroundHighlight> {
18094        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18095        if !text_highlights.1.is_empty() {
18096            self.scrollbar_marker_state.dirty = true;
18097            cx.notify();
18098        }
18099        Some(text_highlights)
18100    }
18101
18102    pub fn highlight_gutter<T: 'static>(
18103        &mut self,
18104        ranges: &[Range<Anchor>],
18105        color_fetcher: fn(&App) -> Hsla,
18106        cx: &mut Context<Self>,
18107    ) {
18108        self.gutter_highlights
18109            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18110        cx.notify();
18111    }
18112
18113    pub fn clear_gutter_highlights<T: 'static>(
18114        &mut self,
18115        cx: &mut Context<Self>,
18116    ) -> Option<GutterHighlight> {
18117        cx.notify();
18118        self.gutter_highlights.remove(&TypeId::of::<T>())
18119    }
18120
18121    #[cfg(feature = "test-support")]
18122    pub fn all_text_background_highlights(
18123        &self,
18124        window: &mut Window,
18125        cx: &mut Context<Self>,
18126    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18127        let snapshot = self.snapshot(window, cx);
18128        let buffer = &snapshot.buffer_snapshot;
18129        let start = buffer.anchor_before(0);
18130        let end = buffer.anchor_after(buffer.len());
18131        let theme = cx.theme().colors();
18132        self.background_highlights_in_range(start..end, &snapshot, theme)
18133    }
18134
18135    #[cfg(feature = "test-support")]
18136    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18137        let snapshot = self.buffer().read(cx).snapshot(cx);
18138
18139        let highlights = self
18140            .background_highlights
18141            .get(&TypeId::of::<items::BufferSearchHighlights>());
18142
18143        if let Some((_color, ranges)) = highlights {
18144            ranges
18145                .iter()
18146                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18147                .collect_vec()
18148        } else {
18149            vec![]
18150        }
18151    }
18152
18153    fn document_highlights_for_position<'a>(
18154        &'a self,
18155        position: Anchor,
18156        buffer: &'a MultiBufferSnapshot,
18157    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18158        let read_highlights = self
18159            .background_highlights
18160            .get(&TypeId::of::<DocumentHighlightRead>())
18161            .map(|h| &h.1);
18162        let write_highlights = self
18163            .background_highlights
18164            .get(&TypeId::of::<DocumentHighlightWrite>())
18165            .map(|h| &h.1);
18166        let left_position = position.bias_left(buffer);
18167        let right_position = position.bias_right(buffer);
18168        read_highlights
18169            .into_iter()
18170            .chain(write_highlights)
18171            .flat_map(move |ranges| {
18172                let start_ix = match ranges.binary_search_by(|probe| {
18173                    let cmp = probe.end.cmp(&left_position, buffer);
18174                    if cmp.is_ge() {
18175                        Ordering::Greater
18176                    } else {
18177                        Ordering::Less
18178                    }
18179                }) {
18180                    Ok(i) | Err(i) => i,
18181                };
18182
18183                ranges[start_ix..]
18184                    .iter()
18185                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18186            })
18187    }
18188
18189    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18190        self.background_highlights
18191            .get(&TypeId::of::<T>())
18192            .map_or(false, |(_, highlights)| !highlights.is_empty())
18193    }
18194
18195    pub fn background_highlights_in_range(
18196        &self,
18197        search_range: Range<Anchor>,
18198        display_snapshot: &DisplaySnapshot,
18199        theme: &ThemeColors,
18200    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18201        let mut results = Vec::new();
18202        for (color_fetcher, ranges) in self.background_highlights.values() {
18203            let color = color_fetcher(theme);
18204            let start_ix = match ranges.binary_search_by(|probe| {
18205                let cmp = probe
18206                    .end
18207                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18208                if cmp.is_gt() {
18209                    Ordering::Greater
18210                } else {
18211                    Ordering::Less
18212                }
18213            }) {
18214                Ok(i) | Err(i) => i,
18215            };
18216            for range in &ranges[start_ix..] {
18217                if range
18218                    .start
18219                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18220                    .is_ge()
18221                {
18222                    break;
18223                }
18224
18225                let start = range.start.to_display_point(display_snapshot);
18226                let end = range.end.to_display_point(display_snapshot);
18227                results.push((start..end, color))
18228            }
18229        }
18230        results
18231    }
18232
18233    pub fn background_highlight_row_ranges<T: 'static>(
18234        &self,
18235        search_range: Range<Anchor>,
18236        display_snapshot: &DisplaySnapshot,
18237        count: usize,
18238    ) -> Vec<RangeInclusive<DisplayPoint>> {
18239        let mut results = Vec::new();
18240        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18241            return vec![];
18242        };
18243
18244        let start_ix = match ranges.binary_search_by(|probe| {
18245            let cmp = probe
18246                .end
18247                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18248            if cmp.is_gt() {
18249                Ordering::Greater
18250            } else {
18251                Ordering::Less
18252            }
18253        }) {
18254            Ok(i) | Err(i) => i,
18255        };
18256        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18257            if let (Some(start_display), Some(end_display)) = (start, end) {
18258                results.push(
18259                    start_display.to_display_point(display_snapshot)
18260                        ..=end_display.to_display_point(display_snapshot),
18261                );
18262            }
18263        };
18264        let mut start_row: Option<Point> = None;
18265        let mut end_row: Option<Point> = None;
18266        if ranges.len() > count {
18267            return Vec::new();
18268        }
18269        for range in &ranges[start_ix..] {
18270            if range
18271                .start
18272                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18273                .is_ge()
18274            {
18275                break;
18276            }
18277            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18278            if let Some(current_row) = &end_row {
18279                if end.row == current_row.row {
18280                    continue;
18281                }
18282            }
18283            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18284            if start_row.is_none() {
18285                assert_eq!(end_row, None);
18286                start_row = Some(start);
18287                end_row = Some(end);
18288                continue;
18289            }
18290            if let Some(current_end) = end_row.as_mut() {
18291                if start.row > current_end.row + 1 {
18292                    push_region(start_row, end_row);
18293                    start_row = Some(start);
18294                    end_row = Some(end);
18295                } else {
18296                    // Merge two hunks.
18297                    *current_end = end;
18298                }
18299            } else {
18300                unreachable!();
18301            }
18302        }
18303        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18304        push_region(start_row, end_row);
18305        results
18306    }
18307
18308    pub fn gutter_highlights_in_range(
18309        &self,
18310        search_range: Range<Anchor>,
18311        display_snapshot: &DisplaySnapshot,
18312        cx: &App,
18313    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18314        let mut results = Vec::new();
18315        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18316            let color = color_fetcher(cx);
18317            let start_ix = match ranges.binary_search_by(|probe| {
18318                let cmp = probe
18319                    .end
18320                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18321                if cmp.is_gt() {
18322                    Ordering::Greater
18323                } else {
18324                    Ordering::Less
18325                }
18326            }) {
18327                Ok(i) | Err(i) => i,
18328            };
18329            for range in &ranges[start_ix..] {
18330                if range
18331                    .start
18332                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18333                    .is_ge()
18334                {
18335                    break;
18336                }
18337
18338                let start = range.start.to_display_point(display_snapshot);
18339                let end = range.end.to_display_point(display_snapshot);
18340                results.push((start..end, color))
18341            }
18342        }
18343        results
18344    }
18345
18346    /// Get the text ranges corresponding to the redaction query
18347    pub fn redacted_ranges(
18348        &self,
18349        search_range: Range<Anchor>,
18350        display_snapshot: &DisplaySnapshot,
18351        cx: &App,
18352    ) -> Vec<Range<DisplayPoint>> {
18353        display_snapshot
18354            .buffer_snapshot
18355            .redacted_ranges(search_range, |file| {
18356                if let Some(file) = file {
18357                    file.is_private()
18358                        && EditorSettings::get(
18359                            Some(SettingsLocation {
18360                                worktree_id: file.worktree_id(cx),
18361                                path: file.path().as_ref(),
18362                            }),
18363                            cx,
18364                        )
18365                        .redact_private_values
18366                } else {
18367                    false
18368                }
18369            })
18370            .map(|range| {
18371                range.start.to_display_point(display_snapshot)
18372                    ..range.end.to_display_point(display_snapshot)
18373            })
18374            .collect()
18375    }
18376
18377    pub fn highlight_text<T: 'static>(
18378        &mut self,
18379        ranges: Vec<Range<Anchor>>,
18380        style: HighlightStyle,
18381        cx: &mut Context<Self>,
18382    ) {
18383        self.display_map.update(cx, |map, _| {
18384            map.highlight_text(TypeId::of::<T>(), ranges, style)
18385        });
18386        cx.notify();
18387    }
18388
18389    pub(crate) fn highlight_inlays<T: 'static>(
18390        &mut self,
18391        highlights: Vec<InlayHighlight>,
18392        style: HighlightStyle,
18393        cx: &mut Context<Self>,
18394    ) {
18395        self.display_map.update(cx, |map, _| {
18396            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18397        });
18398        cx.notify();
18399    }
18400
18401    pub fn text_highlights<'a, T: 'static>(
18402        &'a self,
18403        cx: &'a App,
18404    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18405        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18406    }
18407
18408    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18409        let cleared = self
18410            .display_map
18411            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18412        if cleared {
18413            cx.notify();
18414        }
18415    }
18416
18417    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18418        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18419            && self.focus_handle.is_focused(window)
18420    }
18421
18422    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18423        self.show_cursor_when_unfocused = is_enabled;
18424        cx.notify();
18425    }
18426
18427    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18428        cx.notify();
18429    }
18430
18431    fn on_debug_session_event(
18432        &mut self,
18433        _session: Entity<Session>,
18434        event: &SessionEvent,
18435        cx: &mut Context<Self>,
18436    ) {
18437        match event {
18438            SessionEvent::InvalidateInlineValue => {
18439                self.refresh_inline_values(cx);
18440            }
18441            _ => {}
18442        }
18443    }
18444
18445    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18446        let Some(project) = self.project.clone() else {
18447            return;
18448        };
18449
18450        if !self.inline_value_cache.enabled {
18451            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18452            self.splice_inlays(&inlays, Vec::new(), cx);
18453            return;
18454        }
18455
18456        let current_execution_position = self
18457            .highlighted_rows
18458            .get(&TypeId::of::<ActiveDebugLine>())
18459            .and_then(|lines| lines.last().map(|line| line.range.start));
18460
18461        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18462            let inline_values = editor
18463                .update(cx, |editor, cx| {
18464                    let Some(current_execution_position) = current_execution_position else {
18465                        return Some(Task::ready(Ok(Vec::new())));
18466                    };
18467
18468                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18469                        let snapshot = buffer.snapshot(cx);
18470
18471                        let excerpt = snapshot.excerpt_containing(
18472                            current_execution_position..current_execution_position,
18473                        )?;
18474
18475                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18476                    })?;
18477
18478                    let range =
18479                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18480
18481                    project.inline_values(buffer, range, cx)
18482                })
18483                .ok()
18484                .flatten()?
18485                .await
18486                .context("refreshing debugger inlays")
18487                .log_err()?;
18488
18489            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18490
18491            for (buffer_id, inline_value) in inline_values
18492                .into_iter()
18493                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18494            {
18495                buffer_inline_values
18496                    .entry(buffer_id)
18497                    .or_default()
18498                    .push(inline_value);
18499            }
18500
18501            editor
18502                .update(cx, |editor, cx| {
18503                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18504                    let mut new_inlays = Vec::default();
18505
18506                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18507                        let buffer_id = buffer_snapshot.remote_id();
18508                        buffer_inline_values
18509                            .get(&buffer_id)
18510                            .into_iter()
18511                            .flatten()
18512                            .for_each(|hint| {
18513                                let inlay = Inlay::debugger_hint(
18514                                    post_inc(&mut editor.next_inlay_id),
18515                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18516                                    hint.text(),
18517                                );
18518
18519                                new_inlays.push(inlay);
18520                            });
18521                    }
18522
18523                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18524                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18525
18526                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18527                })
18528                .ok()?;
18529            Some(())
18530        });
18531    }
18532
18533    fn on_buffer_event(
18534        &mut self,
18535        multibuffer: &Entity<MultiBuffer>,
18536        event: &multi_buffer::Event,
18537        window: &mut Window,
18538        cx: &mut Context<Self>,
18539    ) {
18540        match event {
18541            multi_buffer::Event::Edited {
18542                singleton_buffer_edited,
18543                edited_buffer: buffer_edited,
18544            } => {
18545                self.scrollbar_marker_state.dirty = true;
18546                self.active_indent_guides_state.dirty = true;
18547                self.refresh_active_diagnostics(cx);
18548                self.refresh_code_actions(window, cx);
18549                self.refresh_selected_text_highlights(true, window, cx);
18550                refresh_matching_bracket_highlights(self, window, cx);
18551                if self.has_active_inline_completion() {
18552                    self.update_visible_inline_completion(window, cx);
18553                }
18554                if let Some(buffer) = buffer_edited {
18555                    let buffer_id = buffer.read(cx).remote_id();
18556                    if !self.registered_buffers.contains_key(&buffer_id) {
18557                        if let Some(project) = self.project.as_ref() {
18558                            project.update(cx, |project, cx| {
18559                                self.registered_buffers.insert(
18560                                    buffer_id,
18561                                    project.register_buffer_with_language_servers(&buffer, cx),
18562                                );
18563                            })
18564                        }
18565                    }
18566                }
18567                cx.emit(EditorEvent::BufferEdited);
18568                cx.emit(SearchEvent::MatchesInvalidated);
18569                if *singleton_buffer_edited {
18570                    if let Some(project) = &self.project {
18571                        #[allow(clippy::mutable_key_type)]
18572                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18573                            multibuffer
18574                                .all_buffers()
18575                                .into_iter()
18576                                .filter_map(|buffer| {
18577                                    buffer.update(cx, |buffer, cx| {
18578                                        let language = buffer.language()?;
18579                                        let should_discard = project.update(cx, |project, cx| {
18580                                            project.is_local()
18581                                                && !project.has_language_servers_for(buffer, cx)
18582                                        });
18583                                        should_discard.not().then_some(language.clone())
18584                                    })
18585                                })
18586                                .collect::<HashSet<_>>()
18587                        });
18588                        if !languages_affected.is_empty() {
18589                            self.refresh_inlay_hints(
18590                                InlayHintRefreshReason::BufferEdited(languages_affected),
18591                                cx,
18592                            );
18593                        }
18594                    }
18595                }
18596
18597                let Some(project) = &self.project else { return };
18598                let (telemetry, is_via_ssh) = {
18599                    let project = project.read(cx);
18600                    let telemetry = project.client().telemetry().clone();
18601                    let is_via_ssh = project.is_via_ssh();
18602                    (telemetry, is_via_ssh)
18603                };
18604                refresh_linked_ranges(self, window, cx);
18605                telemetry.log_edit_event("editor", is_via_ssh);
18606            }
18607            multi_buffer::Event::ExcerptsAdded {
18608                buffer,
18609                predecessor,
18610                excerpts,
18611            } => {
18612                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18613                let buffer_id = buffer.read(cx).remote_id();
18614                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18615                    if let Some(project) = &self.project {
18616                        update_uncommitted_diff_for_buffer(
18617                            cx.entity(),
18618                            project,
18619                            [buffer.clone()],
18620                            self.buffer.clone(),
18621                            cx,
18622                        )
18623                        .detach();
18624                    }
18625                }
18626                cx.emit(EditorEvent::ExcerptsAdded {
18627                    buffer: buffer.clone(),
18628                    predecessor: *predecessor,
18629                    excerpts: excerpts.clone(),
18630                });
18631                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18632            }
18633            multi_buffer::Event::ExcerptsRemoved {
18634                ids,
18635                removed_buffer_ids,
18636            } => {
18637                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18638                let buffer = self.buffer.read(cx);
18639                self.registered_buffers
18640                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18641                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18642                cx.emit(EditorEvent::ExcerptsRemoved {
18643                    ids: ids.clone(),
18644                    removed_buffer_ids: removed_buffer_ids.clone(),
18645                })
18646            }
18647            multi_buffer::Event::ExcerptsEdited {
18648                excerpt_ids,
18649                buffer_ids,
18650            } => {
18651                self.display_map.update(cx, |map, cx| {
18652                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18653                });
18654                cx.emit(EditorEvent::ExcerptsEdited {
18655                    ids: excerpt_ids.clone(),
18656                })
18657            }
18658            multi_buffer::Event::ExcerptsExpanded { ids } => {
18659                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18660                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18661            }
18662            multi_buffer::Event::Reparsed(buffer_id) => {
18663                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18664                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18665
18666                cx.emit(EditorEvent::Reparsed(*buffer_id));
18667            }
18668            multi_buffer::Event::DiffHunksToggled => {
18669                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18670            }
18671            multi_buffer::Event::LanguageChanged(buffer_id) => {
18672                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18673                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18674                cx.emit(EditorEvent::Reparsed(*buffer_id));
18675                cx.notify();
18676            }
18677            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18678            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18679            multi_buffer::Event::FileHandleChanged
18680            | multi_buffer::Event::Reloaded
18681            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18682            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18683            multi_buffer::Event::DiagnosticsUpdated => {
18684                self.refresh_active_diagnostics(cx);
18685                self.refresh_inline_diagnostics(true, window, cx);
18686                self.scrollbar_marker_state.dirty = true;
18687                cx.notify();
18688            }
18689            _ => {}
18690        };
18691    }
18692
18693    pub fn start_temporary_diff_override(&mut self) {
18694        self.load_diff_task.take();
18695        self.temporary_diff_override = true;
18696    }
18697
18698    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18699        self.temporary_diff_override = false;
18700        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18701        self.buffer.update(cx, |buffer, cx| {
18702            buffer.set_all_diff_hunks_collapsed(cx);
18703        });
18704
18705        if let Some(project) = self.project.clone() {
18706            self.load_diff_task = Some(
18707                update_uncommitted_diff_for_buffer(
18708                    cx.entity(),
18709                    &project,
18710                    self.buffer.read(cx).all_buffers(),
18711                    self.buffer.clone(),
18712                    cx,
18713                )
18714                .shared(),
18715            );
18716        }
18717    }
18718
18719    fn on_display_map_changed(
18720        &mut self,
18721        _: Entity<DisplayMap>,
18722        _: &mut Window,
18723        cx: &mut Context<Self>,
18724    ) {
18725        cx.notify();
18726    }
18727
18728    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18729        let new_severity = if self.diagnostics_enabled() {
18730            EditorSettings::get_global(cx)
18731                .diagnostics_max_severity
18732                .unwrap_or(DiagnosticSeverity::Hint)
18733        } else {
18734            DiagnosticSeverity::Off
18735        };
18736        self.set_max_diagnostics_severity(new_severity, cx);
18737        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18738        self.update_edit_prediction_settings(cx);
18739        self.refresh_inline_completion(true, false, window, cx);
18740        self.refresh_inlay_hints(
18741            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18742                self.selections.newest_anchor().head(),
18743                &self.buffer.read(cx).snapshot(cx),
18744                cx,
18745            )),
18746            cx,
18747        );
18748
18749        let old_cursor_shape = self.cursor_shape;
18750
18751        {
18752            let editor_settings = EditorSettings::get_global(cx);
18753            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18754            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18755            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18756            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18757        }
18758
18759        if old_cursor_shape != self.cursor_shape {
18760            cx.emit(EditorEvent::CursorShapeChanged);
18761        }
18762
18763        let project_settings = ProjectSettings::get_global(cx);
18764        self.serialize_dirty_buffers =
18765            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18766
18767        if self.mode.is_full() {
18768            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18769            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18770            if self.show_inline_diagnostics != show_inline_diagnostics {
18771                self.show_inline_diagnostics = show_inline_diagnostics;
18772                self.refresh_inline_diagnostics(false, window, cx);
18773            }
18774
18775            if self.git_blame_inline_enabled != inline_blame_enabled {
18776                self.toggle_git_blame_inline_internal(false, window, cx);
18777            }
18778
18779            let minimap_settings = EditorSettings::get_global(cx).minimap;
18780            if self.minimap_visibility != MinimapVisibility::Disabled {
18781                if self.minimap_visibility.settings_visibility()
18782                    != minimap_settings.minimap_enabled()
18783                {
18784                    self.set_minimap_visibility(
18785                        MinimapVisibility::for_mode(self.mode(), cx),
18786                        window,
18787                        cx,
18788                    );
18789                } else if let Some(minimap_entity) = self.minimap.as_ref() {
18790                    minimap_entity.update(cx, |minimap_editor, cx| {
18791                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
18792                    })
18793                }
18794            }
18795        }
18796
18797        cx.notify();
18798    }
18799
18800    pub fn set_searchable(&mut self, searchable: bool) {
18801        self.searchable = searchable;
18802    }
18803
18804    pub fn searchable(&self) -> bool {
18805        self.searchable
18806    }
18807
18808    fn open_proposed_changes_editor(
18809        &mut self,
18810        _: &OpenProposedChangesEditor,
18811        window: &mut Window,
18812        cx: &mut Context<Self>,
18813    ) {
18814        let Some(workspace) = self.workspace() else {
18815            cx.propagate();
18816            return;
18817        };
18818
18819        let selections = self.selections.all::<usize>(cx);
18820        let multi_buffer = self.buffer.read(cx);
18821        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18822        let mut new_selections_by_buffer = HashMap::default();
18823        for selection in selections {
18824            for (buffer, range, _) in
18825                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18826            {
18827                let mut range = range.to_point(buffer);
18828                range.start.column = 0;
18829                range.end.column = buffer.line_len(range.end.row);
18830                new_selections_by_buffer
18831                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18832                    .or_insert(Vec::new())
18833                    .push(range)
18834            }
18835        }
18836
18837        let proposed_changes_buffers = new_selections_by_buffer
18838            .into_iter()
18839            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18840            .collect::<Vec<_>>();
18841        let proposed_changes_editor = cx.new(|cx| {
18842            ProposedChangesEditor::new(
18843                "Proposed changes",
18844                proposed_changes_buffers,
18845                self.project.clone(),
18846                window,
18847                cx,
18848            )
18849        });
18850
18851        window.defer(cx, move |window, cx| {
18852            workspace.update(cx, |workspace, cx| {
18853                workspace.active_pane().update(cx, |pane, cx| {
18854                    pane.add_item(
18855                        Box::new(proposed_changes_editor),
18856                        true,
18857                        true,
18858                        None,
18859                        window,
18860                        cx,
18861                    );
18862                });
18863            });
18864        });
18865    }
18866
18867    pub fn open_excerpts_in_split(
18868        &mut self,
18869        _: &OpenExcerptsSplit,
18870        window: &mut Window,
18871        cx: &mut Context<Self>,
18872    ) {
18873        self.open_excerpts_common(None, true, window, cx)
18874    }
18875
18876    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18877        self.open_excerpts_common(None, false, window, cx)
18878    }
18879
18880    fn open_excerpts_common(
18881        &mut self,
18882        jump_data: Option<JumpData>,
18883        split: bool,
18884        window: &mut Window,
18885        cx: &mut Context<Self>,
18886    ) {
18887        let Some(workspace) = self.workspace() else {
18888            cx.propagate();
18889            return;
18890        };
18891
18892        if self.buffer.read(cx).is_singleton() {
18893            cx.propagate();
18894            return;
18895        }
18896
18897        let mut new_selections_by_buffer = HashMap::default();
18898        match &jump_data {
18899            Some(JumpData::MultiBufferPoint {
18900                excerpt_id,
18901                position,
18902                anchor,
18903                line_offset_from_top,
18904            }) => {
18905                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18906                if let Some(buffer) = multi_buffer_snapshot
18907                    .buffer_id_for_excerpt(*excerpt_id)
18908                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18909                {
18910                    let buffer_snapshot = buffer.read(cx).snapshot();
18911                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18912                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18913                    } else {
18914                        buffer_snapshot.clip_point(*position, Bias::Left)
18915                    };
18916                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18917                    new_selections_by_buffer.insert(
18918                        buffer,
18919                        (
18920                            vec![jump_to_offset..jump_to_offset],
18921                            Some(*line_offset_from_top),
18922                        ),
18923                    );
18924                }
18925            }
18926            Some(JumpData::MultiBufferRow {
18927                row,
18928                line_offset_from_top,
18929            }) => {
18930                let point = MultiBufferPoint::new(row.0, 0);
18931                if let Some((buffer, buffer_point, _)) =
18932                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18933                {
18934                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18935                    new_selections_by_buffer
18936                        .entry(buffer)
18937                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18938                        .0
18939                        .push(buffer_offset..buffer_offset)
18940                }
18941            }
18942            None => {
18943                let selections = self.selections.all::<usize>(cx);
18944                let multi_buffer = self.buffer.read(cx);
18945                for selection in selections {
18946                    for (snapshot, range, _, anchor) in multi_buffer
18947                        .snapshot(cx)
18948                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18949                    {
18950                        if let Some(anchor) = anchor {
18951                            // selection is in a deleted hunk
18952                            let Some(buffer_id) = anchor.buffer_id else {
18953                                continue;
18954                            };
18955                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18956                                continue;
18957                            };
18958                            let offset = text::ToOffset::to_offset(
18959                                &anchor.text_anchor,
18960                                &buffer_handle.read(cx).snapshot(),
18961                            );
18962                            let range = offset..offset;
18963                            new_selections_by_buffer
18964                                .entry(buffer_handle)
18965                                .or_insert((Vec::new(), None))
18966                                .0
18967                                .push(range)
18968                        } else {
18969                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18970                            else {
18971                                continue;
18972                            };
18973                            new_selections_by_buffer
18974                                .entry(buffer_handle)
18975                                .or_insert((Vec::new(), None))
18976                                .0
18977                                .push(range)
18978                        }
18979                    }
18980                }
18981            }
18982        }
18983
18984        new_selections_by_buffer
18985            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18986
18987        if new_selections_by_buffer.is_empty() {
18988            return;
18989        }
18990
18991        // We defer the pane interaction because we ourselves are a workspace item
18992        // and activating a new item causes the pane to call a method on us reentrantly,
18993        // which panics if we're on the stack.
18994        window.defer(cx, move |window, cx| {
18995            workspace.update(cx, |workspace, cx| {
18996                let pane = if split {
18997                    workspace.adjacent_pane(window, cx)
18998                } else {
18999                    workspace.active_pane().clone()
19000                };
19001
19002                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19003                    let editor = buffer
19004                        .read(cx)
19005                        .file()
19006                        .is_none()
19007                        .then(|| {
19008                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19009                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19010                            // Instead, we try to activate the existing editor in the pane first.
19011                            let (editor, pane_item_index) =
19012                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19013                                    let editor = item.downcast::<Editor>()?;
19014                                    let singleton_buffer =
19015                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19016                                    if singleton_buffer == buffer {
19017                                        Some((editor, i))
19018                                    } else {
19019                                        None
19020                                    }
19021                                })?;
19022                            pane.update(cx, |pane, cx| {
19023                                pane.activate_item(pane_item_index, true, true, window, cx)
19024                            });
19025                            Some(editor)
19026                        })
19027                        .flatten()
19028                        .unwrap_or_else(|| {
19029                            workspace.open_project_item::<Self>(
19030                                pane.clone(),
19031                                buffer,
19032                                true,
19033                                true,
19034                                window,
19035                                cx,
19036                            )
19037                        });
19038
19039                    editor.update(cx, |editor, cx| {
19040                        let autoscroll = match scroll_offset {
19041                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19042                            None => Autoscroll::newest(),
19043                        };
19044                        let nav_history = editor.nav_history.take();
19045                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19046                            s.select_ranges(ranges);
19047                        });
19048                        editor.nav_history = nav_history;
19049                    });
19050                }
19051            })
19052        });
19053    }
19054
19055    // For now, don't allow opening excerpts in buffers that aren't backed by
19056    // regular project files.
19057    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19058        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19059    }
19060
19061    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19062        let snapshot = self.buffer.read(cx).read(cx);
19063        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19064        Some(
19065            ranges
19066                .iter()
19067                .map(move |range| {
19068                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19069                })
19070                .collect(),
19071        )
19072    }
19073
19074    fn selection_replacement_ranges(
19075        &self,
19076        range: Range<OffsetUtf16>,
19077        cx: &mut App,
19078    ) -> Vec<Range<OffsetUtf16>> {
19079        let selections = self.selections.all::<OffsetUtf16>(cx);
19080        let newest_selection = selections
19081            .iter()
19082            .max_by_key(|selection| selection.id)
19083            .unwrap();
19084        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19085        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19086        let snapshot = self.buffer.read(cx).read(cx);
19087        selections
19088            .into_iter()
19089            .map(|mut selection| {
19090                selection.start.0 =
19091                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19092                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19093                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19094                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19095            })
19096            .collect()
19097    }
19098
19099    fn report_editor_event(
19100        &self,
19101        event_type: &'static str,
19102        file_extension: Option<String>,
19103        cx: &App,
19104    ) {
19105        if cfg!(any(test, feature = "test-support")) {
19106            return;
19107        }
19108
19109        let Some(project) = &self.project else { return };
19110
19111        // If None, we are in a file without an extension
19112        let file = self
19113            .buffer
19114            .read(cx)
19115            .as_singleton()
19116            .and_then(|b| b.read(cx).file());
19117        let file_extension = file_extension.or(file
19118            .as_ref()
19119            .and_then(|file| Path::new(file.file_name(cx)).extension())
19120            .and_then(|e| e.to_str())
19121            .map(|a| a.to_string()));
19122
19123        let vim_mode = vim_enabled(cx);
19124
19125        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19126        let copilot_enabled = edit_predictions_provider
19127            == language::language_settings::EditPredictionProvider::Copilot;
19128        let copilot_enabled_for_language = self
19129            .buffer
19130            .read(cx)
19131            .language_settings(cx)
19132            .show_edit_predictions;
19133
19134        let project = project.read(cx);
19135        telemetry::event!(
19136            event_type,
19137            file_extension,
19138            vim_mode,
19139            copilot_enabled,
19140            copilot_enabled_for_language,
19141            edit_predictions_provider,
19142            is_via_ssh = project.is_via_ssh(),
19143        );
19144    }
19145
19146    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19147    /// with each line being an array of {text, highlight} objects.
19148    fn copy_highlight_json(
19149        &mut self,
19150        _: &CopyHighlightJson,
19151        window: &mut Window,
19152        cx: &mut Context<Self>,
19153    ) {
19154        #[derive(Serialize)]
19155        struct Chunk<'a> {
19156            text: String,
19157            highlight: Option<&'a str>,
19158        }
19159
19160        let snapshot = self.buffer.read(cx).snapshot(cx);
19161        let range = self
19162            .selected_text_range(false, window, cx)
19163            .and_then(|selection| {
19164                if selection.range.is_empty() {
19165                    None
19166                } else {
19167                    Some(selection.range)
19168                }
19169            })
19170            .unwrap_or_else(|| 0..snapshot.len());
19171
19172        let chunks = snapshot.chunks(range, true);
19173        let mut lines = Vec::new();
19174        let mut line: VecDeque<Chunk> = VecDeque::new();
19175
19176        let Some(style) = self.style.as_ref() else {
19177            return;
19178        };
19179
19180        for chunk in chunks {
19181            let highlight = chunk
19182                .syntax_highlight_id
19183                .and_then(|id| id.name(&style.syntax));
19184            let mut chunk_lines = chunk.text.split('\n').peekable();
19185            while let Some(text) = chunk_lines.next() {
19186                let mut merged_with_last_token = false;
19187                if let Some(last_token) = line.back_mut() {
19188                    if last_token.highlight == highlight {
19189                        last_token.text.push_str(text);
19190                        merged_with_last_token = true;
19191                    }
19192                }
19193
19194                if !merged_with_last_token {
19195                    line.push_back(Chunk {
19196                        text: text.into(),
19197                        highlight,
19198                    });
19199                }
19200
19201                if chunk_lines.peek().is_some() {
19202                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19203                        line.pop_front();
19204                    }
19205                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19206                        line.pop_back();
19207                    }
19208
19209                    lines.push(mem::take(&mut line));
19210                }
19211            }
19212        }
19213
19214        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19215            return;
19216        };
19217        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19218    }
19219
19220    pub fn open_context_menu(
19221        &mut self,
19222        _: &OpenContextMenu,
19223        window: &mut Window,
19224        cx: &mut Context<Self>,
19225    ) {
19226        self.request_autoscroll(Autoscroll::newest(), cx);
19227        let position = self.selections.newest_display(cx).start;
19228        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19229    }
19230
19231    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19232        &self.inlay_hint_cache
19233    }
19234
19235    pub fn replay_insert_event(
19236        &mut self,
19237        text: &str,
19238        relative_utf16_range: Option<Range<isize>>,
19239        window: &mut Window,
19240        cx: &mut Context<Self>,
19241    ) {
19242        if !self.input_enabled {
19243            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19244            return;
19245        }
19246        if let Some(relative_utf16_range) = relative_utf16_range {
19247            let selections = self.selections.all::<OffsetUtf16>(cx);
19248            self.change_selections(None, window, cx, |s| {
19249                let new_ranges = selections.into_iter().map(|range| {
19250                    let start = OffsetUtf16(
19251                        range
19252                            .head()
19253                            .0
19254                            .saturating_add_signed(relative_utf16_range.start),
19255                    );
19256                    let end = OffsetUtf16(
19257                        range
19258                            .head()
19259                            .0
19260                            .saturating_add_signed(relative_utf16_range.end),
19261                    );
19262                    start..end
19263                });
19264                s.select_ranges(new_ranges);
19265            });
19266        }
19267
19268        self.handle_input(text, window, cx);
19269    }
19270
19271    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19272        let Some(provider) = self.semantics_provider.as_ref() else {
19273            return false;
19274        };
19275
19276        let mut supports = false;
19277        self.buffer().update(cx, |this, cx| {
19278            this.for_each_buffer(|buffer| {
19279                supports |= provider.supports_inlay_hints(buffer, cx);
19280            });
19281        });
19282
19283        supports
19284    }
19285
19286    pub fn is_focused(&self, window: &Window) -> bool {
19287        self.focus_handle.is_focused(window)
19288    }
19289
19290    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19291        cx.emit(EditorEvent::Focused);
19292
19293        if let Some(descendant) = self
19294            .last_focused_descendant
19295            .take()
19296            .and_then(|descendant| descendant.upgrade())
19297        {
19298            window.focus(&descendant);
19299        } else {
19300            if let Some(blame) = self.blame.as_ref() {
19301                blame.update(cx, GitBlame::focus)
19302            }
19303
19304            self.blink_manager.update(cx, BlinkManager::enable);
19305            self.show_cursor_names(window, cx);
19306            self.buffer.update(cx, |buffer, cx| {
19307                buffer.finalize_last_transaction(cx);
19308                if self.leader_id.is_none() {
19309                    buffer.set_active_selections(
19310                        &self.selections.disjoint_anchors(),
19311                        self.selections.line_mode,
19312                        self.cursor_shape,
19313                        cx,
19314                    );
19315                }
19316            });
19317        }
19318    }
19319
19320    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19321        cx.emit(EditorEvent::FocusedIn)
19322    }
19323
19324    fn handle_focus_out(
19325        &mut self,
19326        event: FocusOutEvent,
19327        _window: &mut Window,
19328        cx: &mut Context<Self>,
19329    ) {
19330        if event.blurred != self.focus_handle {
19331            self.last_focused_descendant = Some(event.blurred);
19332        }
19333        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19334    }
19335
19336    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19337        self.blink_manager.update(cx, BlinkManager::disable);
19338        self.buffer
19339            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19340
19341        if let Some(blame) = self.blame.as_ref() {
19342            blame.update(cx, GitBlame::blur)
19343        }
19344        if !self.hover_state.focused(window, cx) {
19345            hide_hover(self, cx);
19346        }
19347        if !self
19348            .context_menu
19349            .borrow()
19350            .as_ref()
19351            .is_some_and(|context_menu| context_menu.focused(window, cx))
19352        {
19353            self.hide_context_menu(window, cx);
19354        }
19355        self.discard_inline_completion(false, cx);
19356        cx.emit(EditorEvent::Blurred);
19357        cx.notify();
19358    }
19359
19360    pub fn register_action<A: Action>(
19361        &mut self,
19362        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19363    ) -> Subscription {
19364        let id = self.next_editor_action_id.post_inc();
19365        let listener = Arc::new(listener);
19366        self.editor_actions.borrow_mut().insert(
19367            id,
19368            Box::new(move |window, _| {
19369                let listener = listener.clone();
19370                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19371                    let action = action.downcast_ref().unwrap();
19372                    if phase == DispatchPhase::Bubble {
19373                        listener(action, window, cx)
19374                    }
19375                })
19376            }),
19377        );
19378
19379        let editor_actions = self.editor_actions.clone();
19380        Subscription::new(move || {
19381            editor_actions.borrow_mut().remove(&id);
19382        })
19383    }
19384
19385    pub fn file_header_size(&self) -> u32 {
19386        FILE_HEADER_HEIGHT
19387    }
19388
19389    pub fn restore(
19390        &mut self,
19391        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19392        window: &mut Window,
19393        cx: &mut Context<Self>,
19394    ) {
19395        let workspace = self.workspace();
19396        let project = self.project.as_ref();
19397        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19398            let mut tasks = Vec::new();
19399            for (buffer_id, changes) in revert_changes {
19400                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19401                    buffer.update(cx, |buffer, cx| {
19402                        buffer.edit(
19403                            changes
19404                                .into_iter()
19405                                .map(|(range, text)| (range, text.to_string())),
19406                            None,
19407                            cx,
19408                        );
19409                    });
19410
19411                    if let Some(project) =
19412                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19413                    {
19414                        project.update(cx, |project, cx| {
19415                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19416                        })
19417                    }
19418                }
19419            }
19420            tasks
19421        });
19422        cx.spawn_in(window, async move |_, cx| {
19423            for (buffer, task) in save_tasks {
19424                let result = task.await;
19425                if result.is_err() {
19426                    let Some(path) = buffer
19427                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19428                        .ok()
19429                    else {
19430                        continue;
19431                    };
19432                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19433                        let Some(task) = cx
19434                            .update_window_entity(&workspace, |workspace, window, cx| {
19435                                workspace
19436                                    .open_path_preview(path, None, false, false, false, window, cx)
19437                            })
19438                            .ok()
19439                        else {
19440                            continue;
19441                        };
19442                        task.await.log_err();
19443                    }
19444                }
19445            }
19446        })
19447        .detach();
19448        self.change_selections(None, window, cx, |selections| selections.refresh());
19449    }
19450
19451    pub fn to_pixel_point(
19452        &self,
19453        source: multi_buffer::Anchor,
19454        editor_snapshot: &EditorSnapshot,
19455        window: &mut Window,
19456    ) -> Option<gpui::Point<Pixels>> {
19457        let source_point = source.to_display_point(editor_snapshot);
19458        self.display_to_pixel_point(source_point, editor_snapshot, window)
19459    }
19460
19461    pub fn display_to_pixel_point(
19462        &self,
19463        source: DisplayPoint,
19464        editor_snapshot: &EditorSnapshot,
19465        window: &mut Window,
19466    ) -> Option<gpui::Point<Pixels>> {
19467        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19468        let text_layout_details = self.text_layout_details(window);
19469        let scroll_top = text_layout_details
19470            .scroll_anchor
19471            .scroll_position(editor_snapshot)
19472            .y;
19473
19474        if source.row().as_f32() < scroll_top.floor() {
19475            return None;
19476        }
19477        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19478        let source_y = line_height * (source.row().as_f32() - scroll_top);
19479        Some(gpui::Point::new(source_x, source_y))
19480    }
19481
19482    pub fn has_visible_completions_menu(&self) -> bool {
19483        !self.edit_prediction_preview_is_active()
19484            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19485                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19486            })
19487    }
19488
19489    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19490        if self.mode.is_minimap() {
19491            return;
19492        }
19493        self.addons
19494            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19495    }
19496
19497    pub fn unregister_addon<T: Addon>(&mut self) {
19498        self.addons.remove(&std::any::TypeId::of::<T>());
19499    }
19500
19501    pub fn addon<T: Addon>(&self) -> Option<&T> {
19502        let type_id = std::any::TypeId::of::<T>();
19503        self.addons
19504            .get(&type_id)
19505            .and_then(|item| item.to_any().downcast_ref::<T>())
19506    }
19507
19508    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19509        let type_id = std::any::TypeId::of::<T>();
19510        self.addons
19511            .get_mut(&type_id)
19512            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19513    }
19514
19515    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19516        let text_layout_details = self.text_layout_details(window);
19517        let style = &text_layout_details.editor_style;
19518        let font_id = window.text_system().resolve_font(&style.text.font());
19519        let font_size = style.text.font_size.to_pixels(window.rem_size());
19520        let line_height = style.text.line_height_in_pixels(window.rem_size());
19521        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19522
19523        gpui::Size::new(em_width, line_height)
19524    }
19525
19526    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19527        self.load_diff_task.clone()
19528    }
19529
19530    fn read_metadata_from_db(
19531        &mut self,
19532        item_id: u64,
19533        workspace_id: WorkspaceId,
19534        window: &mut Window,
19535        cx: &mut Context<Editor>,
19536    ) {
19537        if self.is_singleton(cx)
19538            && !self.mode.is_minimap()
19539            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19540        {
19541            let buffer_snapshot = OnceCell::new();
19542
19543            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19544                if !folds.is_empty() {
19545                    let snapshot =
19546                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19547                    self.fold_ranges(
19548                        folds
19549                            .into_iter()
19550                            .map(|(start, end)| {
19551                                snapshot.clip_offset(start, Bias::Left)
19552                                    ..snapshot.clip_offset(end, Bias::Right)
19553                            })
19554                            .collect(),
19555                        false,
19556                        window,
19557                        cx,
19558                    );
19559                }
19560            }
19561
19562            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19563                if !selections.is_empty() {
19564                    let snapshot =
19565                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19566                    self.change_selections(None, window, cx, |s| {
19567                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19568                            snapshot.clip_offset(start, Bias::Left)
19569                                ..snapshot.clip_offset(end, Bias::Right)
19570                        }));
19571                    });
19572                }
19573            };
19574        }
19575
19576        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19577    }
19578}
19579
19580fn vim_enabled(cx: &App) -> bool {
19581    cx.global::<SettingsStore>()
19582        .raw_user_settings()
19583        .get("vim_mode")
19584        == Some(&serde_json::Value::Bool(true))
19585}
19586
19587fn process_completion_for_edit(
19588    completion: &Completion,
19589    intent: CompletionIntent,
19590    buffer: &Entity<Buffer>,
19591    cursor_position: &text::Anchor,
19592    cx: &mut Context<Editor>,
19593) -> CompletionEdit {
19594    let buffer = buffer.read(cx);
19595    let buffer_snapshot = buffer.snapshot();
19596    let (snippet, new_text) = if completion.is_snippet() {
19597        let mut snippet_source = completion.new_text.clone();
19598        if let Some(scope) = buffer_snapshot.language_scope_at(cursor_position) {
19599            if scope.prefers_label_for_snippet_in_completion() {
19600                if let Some(label) = completion.label() {
19601                    if matches!(
19602                        completion.kind(),
19603                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
19604                    ) {
19605                        snippet_source = label;
19606                    }
19607                }
19608            }
19609        }
19610        match Snippet::parse(&snippet_source).log_err() {
19611            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
19612            None => (None, completion.new_text.clone()),
19613        }
19614    } else {
19615        (None, completion.new_text.clone())
19616    };
19617
19618    let mut range_to_replace = {
19619        let replace_range = &completion.replace_range;
19620        if let CompletionSource::Lsp {
19621            insert_range: Some(insert_range),
19622            ..
19623        } = &completion.source
19624        {
19625            debug_assert_eq!(
19626                insert_range.start, replace_range.start,
19627                "insert_range and replace_range should start at the same position"
19628            );
19629            debug_assert!(
19630                insert_range
19631                    .start
19632                    .cmp(&cursor_position, &buffer_snapshot)
19633                    .is_le(),
19634                "insert_range should start before or at cursor position"
19635            );
19636            debug_assert!(
19637                replace_range
19638                    .start
19639                    .cmp(&cursor_position, &buffer_snapshot)
19640                    .is_le(),
19641                "replace_range should start before or at cursor position"
19642            );
19643            debug_assert!(
19644                insert_range
19645                    .end
19646                    .cmp(&cursor_position, &buffer_snapshot)
19647                    .is_le(),
19648                "insert_range should end before or at cursor position"
19649            );
19650
19651            let should_replace = match intent {
19652                CompletionIntent::CompleteWithInsert => false,
19653                CompletionIntent::CompleteWithReplace => true,
19654                CompletionIntent::Complete | CompletionIntent::Compose => {
19655                    let insert_mode =
19656                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19657                            .completions
19658                            .lsp_insert_mode;
19659                    match insert_mode {
19660                        LspInsertMode::Insert => false,
19661                        LspInsertMode::Replace => true,
19662                        LspInsertMode::ReplaceSubsequence => {
19663                            let mut text_to_replace = buffer.chars_for_range(
19664                                buffer.anchor_before(replace_range.start)
19665                                    ..buffer.anchor_after(replace_range.end),
19666                            );
19667                            let mut current_needle = text_to_replace.next();
19668                            for haystack_ch in completion.label.text.chars() {
19669                                if let Some(needle_ch) = current_needle {
19670                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
19671                                        current_needle = text_to_replace.next();
19672                                    }
19673                                }
19674                            }
19675                            current_needle.is_none()
19676                        }
19677                        LspInsertMode::ReplaceSuffix => {
19678                            if replace_range
19679                                .end
19680                                .cmp(&cursor_position, &buffer_snapshot)
19681                                .is_gt()
19682                            {
19683                                let range_after_cursor = *cursor_position..replace_range.end;
19684                                let text_after_cursor = buffer
19685                                    .text_for_range(
19686                                        buffer.anchor_before(range_after_cursor.start)
19687                                            ..buffer.anchor_after(range_after_cursor.end),
19688                                    )
19689                                    .collect::<String>()
19690                                    .to_ascii_lowercase();
19691                                completion
19692                                    .label
19693                                    .text
19694                                    .to_ascii_lowercase()
19695                                    .ends_with(&text_after_cursor)
19696                            } else {
19697                                true
19698                            }
19699                        }
19700                    }
19701                }
19702            };
19703
19704            if should_replace {
19705                replace_range.clone()
19706            } else {
19707                insert_range.clone()
19708            }
19709        } else {
19710            replace_range.clone()
19711        }
19712    };
19713
19714    if range_to_replace
19715        .end
19716        .cmp(&cursor_position, &buffer_snapshot)
19717        .is_lt()
19718    {
19719        range_to_replace.end = *cursor_position;
19720    }
19721
19722    CompletionEdit {
19723        new_text,
19724        replace_range: range_to_replace.to_offset(&buffer),
19725        snippet,
19726    }
19727}
19728
19729struct CompletionEdit {
19730    new_text: String,
19731    replace_range: Range<usize>,
19732    snippet: Option<Snippet>,
19733}
19734
19735fn insert_extra_newline_brackets(
19736    buffer: &MultiBufferSnapshot,
19737    range: Range<usize>,
19738    language: &language::LanguageScope,
19739) -> bool {
19740    let leading_whitespace_len = buffer
19741        .reversed_chars_at(range.start)
19742        .take_while(|c| c.is_whitespace() && *c != '\n')
19743        .map(|c| c.len_utf8())
19744        .sum::<usize>();
19745    let trailing_whitespace_len = buffer
19746        .chars_at(range.end)
19747        .take_while(|c| c.is_whitespace() && *c != '\n')
19748        .map(|c| c.len_utf8())
19749        .sum::<usize>();
19750    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19751
19752    language.brackets().any(|(pair, enabled)| {
19753        let pair_start = pair.start.trim_end();
19754        let pair_end = pair.end.trim_start();
19755
19756        enabled
19757            && pair.newline
19758            && buffer.contains_str_at(range.end, pair_end)
19759            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19760    })
19761}
19762
19763fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19764    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19765        [(buffer, range, _)] => (*buffer, range.clone()),
19766        _ => return false,
19767    };
19768    let pair = {
19769        let mut result: Option<BracketMatch> = None;
19770
19771        for pair in buffer
19772            .all_bracket_ranges(range.clone())
19773            .filter(move |pair| {
19774                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19775            })
19776        {
19777            let len = pair.close_range.end - pair.open_range.start;
19778
19779            if let Some(existing) = &result {
19780                let existing_len = existing.close_range.end - existing.open_range.start;
19781                if len > existing_len {
19782                    continue;
19783                }
19784            }
19785
19786            result = Some(pair);
19787        }
19788
19789        result
19790    };
19791    let Some(pair) = pair else {
19792        return false;
19793    };
19794    pair.newline_only
19795        && buffer
19796            .chars_for_range(pair.open_range.end..range.start)
19797            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19798            .all(|c| c.is_whitespace() && c != '\n')
19799}
19800
19801fn update_uncommitted_diff_for_buffer(
19802    editor: Entity<Editor>,
19803    project: &Entity<Project>,
19804    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19805    buffer: Entity<MultiBuffer>,
19806    cx: &mut App,
19807) -> Task<()> {
19808    let mut tasks = Vec::new();
19809    project.update(cx, |project, cx| {
19810        for buffer in buffers {
19811            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19812                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19813            }
19814        }
19815    });
19816    cx.spawn(async move |cx| {
19817        let diffs = future::join_all(tasks).await;
19818        if editor
19819            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19820            .unwrap_or(false)
19821        {
19822            return;
19823        }
19824
19825        buffer
19826            .update(cx, |buffer, cx| {
19827                for diff in diffs.into_iter().flatten() {
19828                    buffer.add_diff(diff, cx);
19829                }
19830            })
19831            .ok();
19832    })
19833}
19834
19835fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19836    let tab_size = tab_size.get() as usize;
19837    let mut width = offset;
19838
19839    for ch in text.chars() {
19840        width += if ch == '\t' {
19841            tab_size - (width % tab_size)
19842        } else {
19843            1
19844        };
19845    }
19846
19847    width - offset
19848}
19849
19850#[cfg(test)]
19851mod tests {
19852    use super::*;
19853
19854    #[test]
19855    fn test_string_size_with_expanded_tabs() {
19856        let nz = |val| NonZeroU32::new(val).unwrap();
19857        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19858        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19859        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19860        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19861        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19862        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19863        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19864        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19865    }
19866}
19867
19868/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19869struct WordBreakingTokenizer<'a> {
19870    input: &'a str,
19871}
19872
19873impl<'a> WordBreakingTokenizer<'a> {
19874    fn new(input: &'a str) -> Self {
19875        Self { input }
19876    }
19877}
19878
19879fn is_char_ideographic(ch: char) -> bool {
19880    use unicode_script::Script::*;
19881    use unicode_script::UnicodeScript;
19882    matches!(ch.script(), Han | Tangut | Yi)
19883}
19884
19885fn is_grapheme_ideographic(text: &str) -> bool {
19886    text.chars().any(is_char_ideographic)
19887}
19888
19889fn is_grapheme_whitespace(text: &str) -> bool {
19890    text.chars().any(|x| x.is_whitespace())
19891}
19892
19893fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19894    text.chars().next().map_or(false, |ch| {
19895        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19896    })
19897}
19898
19899#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19900enum WordBreakToken<'a> {
19901    Word { token: &'a str, grapheme_len: usize },
19902    InlineWhitespace { token: &'a str, grapheme_len: usize },
19903    Newline,
19904}
19905
19906impl<'a> Iterator for WordBreakingTokenizer<'a> {
19907    /// Yields a span, the count of graphemes in the token, and whether it was
19908    /// whitespace. Note that it also breaks at word boundaries.
19909    type Item = WordBreakToken<'a>;
19910
19911    fn next(&mut self) -> Option<Self::Item> {
19912        use unicode_segmentation::UnicodeSegmentation;
19913        if self.input.is_empty() {
19914            return None;
19915        }
19916
19917        let mut iter = self.input.graphemes(true).peekable();
19918        let mut offset = 0;
19919        let mut grapheme_len = 0;
19920        if let Some(first_grapheme) = iter.next() {
19921            let is_newline = first_grapheme == "\n";
19922            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19923            offset += first_grapheme.len();
19924            grapheme_len += 1;
19925            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19926                if let Some(grapheme) = iter.peek().copied() {
19927                    if should_stay_with_preceding_ideograph(grapheme) {
19928                        offset += grapheme.len();
19929                        grapheme_len += 1;
19930                    }
19931                }
19932            } else {
19933                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19934                let mut next_word_bound = words.peek().copied();
19935                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19936                    next_word_bound = words.next();
19937                }
19938                while let Some(grapheme) = iter.peek().copied() {
19939                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19940                        break;
19941                    };
19942                    if is_grapheme_whitespace(grapheme) != is_whitespace
19943                        || (grapheme == "\n") != is_newline
19944                    {
19945                        break;
19946                    };
19947                    offset += grapheme.len();
19948                    grapheme_len += 1;
19949                    iter.next();
19950                }
19951            }
19952            let token = &self.input[..offset];
19953            self.input = &self.input[offset..];
19954            if token == "\n" {
19955                Some(WordBreakToken::Newline)
19956            } else if is_whitespace {
19957                Some(WordBreakToken::InlineWhitespace {
19958                    token,
19959                    grapheme_len,
19960                })
19961            } else {
19962                Some(WordBreakToken::Word {
19963                    token,
19964                    grapheme_len,
19965                })
19966            }
19967        } else {
19968            None
19969        }
19970    }
19971}
19972
19973#[test]
19974fn test_word_breaking_tokenizer() {
19975    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19976        ("", &[]),
19977        ("  ", &[whitespace("  ", 2)]),
19978        ("Ʒ", &[word("Ʒ", 1)]),
19979        ("Ǽ", &[word("Ǽ", 1)]),
19980        ("", &[word("", 1)]),
19981        ("⋑⋑", &[word("⋑⋑", 2)]),
19982        (
19983            "原理,进而",
19984            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19985        ),
19986        (
19987            "hello world",
19988            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19989        ),
19990        (
19991            "hello, world",
19992            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19993        ),
19994        (
19995            "  hello world",
19996            &[
19997                whitespace("  ", 2),
19998                word("hello", 5),
19999                whitespace(" ", 1),
20000                word("world", 5),
20001            ],
20002        ),
20003        (
20004            "这是什么 \n 钢笔",
20005            &[
20006                word("", 1),
20007                word("", 1),
20008                word("", 1),
20009                word("", 1),
20010                whitespace(" ", 1),
20011                newline(),
20012                whitespace(" ", 1),
20013                word("", 1),
20014                word("", 1),
20015            ],
20016        ),
20017        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20018    ];
20019
20020    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20021        WordBreakToken::Word {
20022            token,
20023            grapheme_len,
20024        }
20025    }
20026
20027    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20028        WordBreakToken::InlineWhitespace {
20029            token,
20030            grapheme_len,
20031        }
20032    }
20033
20034    fn newline() -> WordBreakToken<'static> {
20035        WordBreakToken::Newline
20036    }
20037
20038    for (input, result) in tests {
20039        assert_eq!(
20040            WordBreakingTokenizer::new(input)
20041                .collect::<Vec<_>>()
20042                .as_slice(),
20043            *result,
20044        );
20045    }
20046}
20047
20048fn wrap_with_prefix(
20049    line_prefix: String,
20050    unwrapped_text: String,
20051    wrap_column: usize,
20052    tab_size: NonZeroU32,
20053    preserve_existing_whitespace: bool,
20054) -> String {
20055    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20056    let mut wrapped_text = String::new();
20057    let mut current_line = line_prefix.clone();
20058
20059    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20060    let mut current_line_len = line_prefix_len;
20061    let mut in_whitespace = false;
20062    for token in tokenizer {
20063        let have_preceding_whitespace = in_whitespace;
20064        match token {
20065            WordBreakToken::Word {
20066                token,
20067                grapheme_len,
20068            } => {
20069                in_whitespace = false;
20070                if current_line_len + grapheme_len > wrap_column
20071                    && current_line_len != line_prefix_len
20072                {
20073                    wrapped_text.push_str(current_line.trim_end());
20074                    wrapped_text.push('\n');
20075                    current_line.truncate(line_prefix.len());
20076                    current_line_len = line_prefix_len;
20077                }
20078                current_line.push_str(token);
20079                current_line_len += grapheme_len;
20080            }
20081            WordBreakToken::InlineWhitespace {
20082                mut token,
20083                mut grapheme_len,
20084            } => {
20085                in_whitespace = true;
20086                if have_preceding_whitespace && !preserve_existing_whitespace {
20087                    continue;
20088                }
20089                if !preserve_existing_whitespace {
20090                    token = " ";
20091                    grapheme_len = 1;
20092                }
20093                if current_line_len + grapheme_len > wrap_column {
20094                    wrapped_text.push_str(current_line.trim_end());
20095                    wrapped_text.push('\n');
20096                    current_line.truncate(line_prefix.len());
20097                    current_line_len = line_prefix_len;
20098                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20099                    current_line.push_str(token);
20100                    current_line_len += grapheme_len;
20101                }
20102            }
20103            WordBreakToken::Newline => {
20104                in_whitespace = true;
20105                if preserve_existing_whitespace {
20106                    wrapped_text.push_str(current_line.trim_end());
20107                    wrapped_text.push('\n');
20108                    current_line.truncate(line_prefix.len());
20109                    current_line_len = line_prefix_len;
20110                } else if have_preceding_whitespace {
20111                    continue;
20112                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20113                {
20114                    wrapped_text.push_str(current_line.trim_end());
20115                    wrapped_text.push('\n');
20116                    current_line.truncate(line_prefix.len());
20117                    current_line_len = line_prefix_len;
20118                } else if current_line_len != line_prefix_len {
20119                    current_line.push(' ');
20120                    current_line_len += 1;
20121                }
20122            }
20123        }
20124    }
20125
20126    if !current_line.is_empty() {
20127        wrapped_text.push_str(&current_line);
20128    }
20129    wrapped_text
20130}
20131
20132#[test]
20133fn test_wrap_with_prefix() {
20134    assert_eq!(
20135        wrap_with_prefix(
20136            "# ".to_string(),
20137            "abcdefg".to_string(),
20138            4,
20139            NonZeroU32::new(4).unwrap(),
20140            false,
20141        ),
20142        "# abcdefg"
20143    );
20144    assert_eq!(
20145        wrap_with_prefix(
20146            "".to_string(),
20147            "\thello world".to_string(),
20148            8,
20149            NonZeroU32::new(4).unwrap(),
20150            false,
20151        ),
20152        "hello\nworld"
20153    );
20154    assert_eq!(
20155        wrap_with_prefix(
20156            "// ".to_string(),
20157            "xx \nyy zz aa bb cc".to_string(),
20158            12,
20159            NonZeroU32::new(4).unwrap(),
20160            false,
20161        ),
20162        "// xx yy zz\n// aa bb cc"
20163    );
20164    assert_eq!(
20165        wrap_with_prefix(
20166            String::new(),
20167            "这是什么 \n 钢笔".to_string(),
20168            3,
20169            NonZeroU32::new(4).unwrap(),
20170            false,
20171        ),
20172        "这是什\n么 钢\n"
20173    );
20174}
20175
20176pub trait CollaborationHub {
20177    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20178    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20179    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20180}
20181
20182impl CollaborationHub for Entity<Project> {
20183    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20184        self.read(cx).collaborators()
20185    }
20186
20187    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20188        self.read(cx).user_store().read(cx).participant_indices()
20189    }
20190
20191    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20192        let this = self.read(cx);
20193        let user_ids = this.collaborators().values().map(|c| c.user_id);
20194        this.user_store().read(cx).participant_names(user_ids, cx)
20195    }
20196}
20197
20198pub trait SemanticsProvider {
20199    fn hover(
20200        &self,
20201        buffer: &Entity<Buffer>,
20202        position: text::Anchor,
20203        cx: &mut App,
20204    ) -> Option<Task<Vec<project::Hover>>>;
20205
20206    fn inline_values(
20207        &self,
20208        buffer_handle: Entity<Buffer>,
20209        range: Range<text::Anchor>,
20210        cx: &mut App,
20211    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20212
20213    fn inlay_hints(
20214        &self,
20215        buffer_handle: Entity<Buffer>,
20216        range: Range<text::Anchor>,
20217        cx: &mut App,
20218    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20219
20220    fn resolve_inlay_hint(
20221        &self,
20222        hint: InlayHint,
20223        buffer_handle: Entity<Buffer>,
20224        server_id: LanguageServerId,
20225        cx: &mut App,
20226    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20227
20228    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20229
20230    fn document_highlights(
20231        &self,
20232        buffer: &Entity<Buffer>,
20233        position: text::Anchor,
20234        cx: &mut App,
20235    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20236
20237    fn definitions(
20238        &self,
20239        buffer: &Entity<Buffer>,
20240        position: text::Anchor,
20241        kind: GotoDefinitionKind,
20242        cx: &mut App,
20243    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20244
20245    fn range_for_rename(
20246        &self,
20247        buffer: &Entity<Buffer>,
20248        position: text::Anchor,
20249        cx: &mut App,
20250    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20251
20252    fn perform_rename(
20253        &self,
20254        buffer: &Entity<Buffer>,
20255        position: text::Anchor,
20256        new_name: String,
20257        cx: &mut App,
20258    ) -> Option<Task<Result<ProjectTransaction>>>;
20259}
20260
20261pub trait CompletionProvider {
20262    fn completions(
20263        &self,
20264        excerpt_id: ExcerptId,
20265        buffer: &Entity<Buffer>,
20266        buffer_position: text::Anchor,
20267        trigger: CompletionContext,
20268        window: &mut Window,
20269        cx: &mut Context<Editor>,
20270    ) -> Task<Result<Vec<CompletionResponse>>>;
20271
20272    fn resolve_completions(
20273        &self,
20274        buffer: Entity<Buffer>,
20275        completion_indices: Vec<usize>,
20276        completions: Rc<RefCell<Box<[Completion]>>>,
20277        cx: &mut Context<Editor>,
20278    ) -> Task<Result<bool>>;
20279
20280    fn apply_additional_edits_for_completion(
20281        &self,
20282        _buffer: Entity<Buffer>,
20283        _completions: Rc<RefCell<Box<[Completion]>>>,
20284        _completion_index: usize,
20285        _push_to_history: bool,
20286        _cx: &mut Context<Editor>,
20287    ) -> Task<Result<Option<language::Transaction>>> {
20288        Task::ready(Ok(None))
20289    }
20290
20291    fn is_completion_trigger(
20292        &self,
20293        buffer: &Entity<Buffer>,
20294        position: language::Anchor,
20295        text: &str,
20296        trigger_in_words: bool,
20297        cx: &mut Context<Editor>,
20298    ) -> bool;
20299
20300    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20301
20302    fn sort_completions(&self) -> bool {
20303        true
20304    }
20305
20306    fn filter_completions(&self) -> bool {
20307        true
20308    }
20309}
20310
20311pub trait CodeActionProvider {
20312    fn id(&self) -> Arc<str>;
20313
20314    fn code_actions(
20315        &self,
20316        buffer: &Entity<Buffer>,
20317        range: Range<text::Anchor>,
20318        window: &mut Window,
20319        cx: &mut App,
20320    ) -> Task<Result<Vec<CodeAction>>>;
20321
20322    fn apply_code_action(
20323        &self,
20324        buffer_handle: Entity<Buffer>,
20325        action: CodeAction,
20326        excerpt_id: ExcerptId,
20327        push_to_history: bool,
20328        window: &mut Window,
20329        cx: &mut App,
20330    ) -> Task<Result<ProjectTransaction>>;
20331}
20332
20333impl CodeActionProvider for Entity<Project> {
20334    fn id(&self) -> Arc<str> {
20335        "project".into()
20336    }
20337
20338    fn code_actions(
20339        &self,
20340        buffer: &Entity<Buffer>,
20341        range: Range<text::Anchor>,
20342        _window: &mut Window,
20343        cx: &mut App,
20344    ) -> Task<Result<Vec<CodeAction>>> {
20345        self.update(cx, |project, cx| {
20346            let code_lens = project.code_lens(buffer, range.clone(), cx);
20347            let code_actions = project.code_actions(buffer, range, None, cx);
20348            cx.background_spawn(async move {
20349                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20350                Ok(code_lens
20351                    .context("code lens fetch")?
20352                    .into_iter()
20353                    .chain(code_actions.context("code action fetch")?)
20354                    .collect())
20355            })
20356        })
20357    }
20358
20359    fn apply_code_action(
20360        &self,
20361        buffer_handle: Entity<Buffer>,
20362        action: CodeAction,
20363        _excerpt_id: ExcerptId,
20364        push_to_history: bool,
20365        _window: &mut Window,
20366        cx: &mut App,
20367    ) -> Task<Result<ProjectTransaction>> {
20368        self.update(cx, |project, cx| {
20369            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20370        })
20371    }
20372}
20373
20374fn snippet_completions(
20375    project: &Project,
20376    buffer: &Entity<Buffer>,
20377    buffer_position: text::Anchor,
20378    cx: &mut App,
20379) -> Task<Result<CompletionResponse>> {
20380    let languages = buffer.read(cx).languages_at(buffer_position);
20381    let snippet_store = project.snippets().read(cx);
20382
20383    let scopes: Vec<_> = languages
20384        .iter()
20385        .filter_map(|language| {
20386            let language_name = language.lsp_id();
20387            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20388
20389            if snippets.is_empty() {
20390                None
20391            } else {
20392                Some((language.default_scope(), snippets))
20393            }
20394        })
20395        .collect();
20396
20397    if scopes.is_empty() {
20398        return Task::ready(Ok(CompletionResponse {
20399            completions: vec![],
20400            is_incomplete: false,
20401        }));
20402    }
20403
20404    let snapshot = buffer.read(cx).text_snapshot();
20405    let chars: String = snapshot
20406        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20407        .collect();
20408    let executor = cx.background_executor().clone();
20409
20410    cx.background_spawn(async move {
20411        let mut is_incomplete = false;
20412        let mut completions: Vec<Completion> = Vec::new();
20413        for (scope, snippets) in scopes.into_iter() {
20414            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20415            let mut last_word = chars
20416                .chars()
20417                .take_while(|c| classifier.is_word(*c))
20418                .collect::<String>();
20419            last_word = last_word.chars().rev().collect();
20420
20421            if last_word.is_empty() {
20422                return Ok(CompletionResponse {
20423                    completions: vec![],
20424                    is_incomplete: true,
20425                });
20426            }
20427
20428            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20429            let to_lsp = |point: &text::Anchor| {
20430                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20431                point_to_lsp(end)
20432            };
20433            let lsp_end = to_lsp(&buffer_position);
20434
20435            let candidates = snippets
20436                .iter()
20437                .enumerate()
20438                .flat_map(|(ix, snippet)| {
20439                    snippet
20440                        .prefix
20441                        .iter()
20442                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20443                })
20444                .collect::<Vec<StringMatchCandidate>>();
20445
20446            const MAX_RESULTS: usize = 100;
20447            let mut matches = fuzzy::match_strings(
20448                &candidates,
20449                &last_word,
20450                last_word.chars().any(|c| c.is_uppercase()),
20451                MAX_RESULTS,
20452                &Default::default(),
20453                executor.clone(),
20454            )
20455            .await;
20456
20457            if matches.len() >= MAX_RESULTS {
20458                is_incomplete = true;
20459            }
20460
20461            // Remove all candidates where the query's start does not match the start of any word in the candidate
20462            if let Some(query_start) = last_word.chars().next() {
20463                matches.retain(|string_match| {
20464                    split_words(&string_match.string).any(|word| {
20465                        // Check that the first codepoint of the word as lowercase matches the first
20466                        // codepoint of the query as lowercase
20467                        word.chars()
20468                            .flat_map(|codepoint| codepoint.to_lowercase())
20469                            .zip(query_start.to_lowercase())
20470                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20471                    })
20472                });
20473            }
20474
20475            let matched_strings = matches
20476                .into_iter()
20477                .map(|m| m.string)
20478                .collect::<HashSet<_>>();
20479
20480            completions.extend(snippets.iter().filter_map(|snippet| {
20481                let matching_prefix = snippet
20482                    .prefix
20483                    .iter()
20484                    .find(|prefix| matched_strings.contains(*prefix))?;
20485                let start = as_offset - last_word.len();
20486                let start = snapshot.anchor_before(start);
20487                let range = start..buffer_position;
20488                let lsp_start = to_lsp(&start);
20489                let lsp_range = lsp::Range {
20490                    start: lsp_start,
20491                    end: lsp_end,
20492                };
20493                Some(Completion {
20494                    replace_range: range,
20495                    new_text: snippet.body.clone(),
20496                    source: CompletionSource::Lsp {
20497                        insert_range: None,
20498                        server_id: LanguageServerId(usize::MAX),
20499                        resolved: true,
20500                        lsp_completion: Box::new(lsp::CompletionItem {
20501                            label: snippet.prefix.first().unwrap().clone(),
20502                            kind: Some(CompletionItemKind::SNIPPET),
20503                            label_details: snippet.description.as_ref().map(|description| {
20504                                lsp::CompletionItemLabelDetails {
20505                                    detail: Some(description.clone()),
20506                                    description: None,
20507                                }
20508                            }),
20509                            insert_text_format: Some(InsertTextFormat::SNIPPET),
20510                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20511                                lsp::InsertReplaceEdit {
20512                                    new_text: snippet.body.clone(),
20513                                    insert: lsp_range,
20514                                    replace: lsp_range,
20515                                },
20516                            )),
20517                            filter_text: Some(snippet.body.clone()),
20518                            sort_text: Some(char::MAX.to_string()),
20519                            ..lsp::CompletionItem::default()
20520                        }),
20521                        lsp_defaults: None,
20522                    },
20523                    label: CodeLabel {
20524                        text: matching_prefix.clone(),
20525                        runs: Vec::new(),
20526                        filter_range: 0..matching_prefix.len(),
20527                    },
20528                    icon_path: None,
20529                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
20530                        single_line: snippet.name.clone().into(),
20531                        plain_text: snippet
20532                            .description
20533                            .clone()
20534                            .map(|description| description.into()),
20535                    }),
20536                    insert_text_mode: None,
20537                    confirm: None,
20538                })
20539            }))
20540        }
20541
20542        Ok(CompletionResponse {
20543            completions,
20544            is_incomplete,
20545        })
20546    })
20547}
20548
20549impl CompletionProvider for Entity<Project> {
20550    fn completions(
20551        &self,
20552        _excerpt_id: ExcerptId,
20553        buffer: &Entity<Buffer>,
20554        buffer_position: text::Anchor,
20555        options: CompletionContext,
20556        _window: &mut Window,
20557        cx: &mut Context<Editor>,
20558    ) -> Task<Result<Vec<CompletionResponse>>> {
20559        self.update(cx, |project, cx| {
20560            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20561            let project_completions = project.completions(buffer, buffer_position, options, cx);
20562            cx.background_spawn(async move {
20563                let mut responses = project_completions.await?;
20564                let snippets = snippets.await?;
20565                if !snippets.completions.is_empty() {
20566                    responses.push(snippets);
20567                }
20568                Ok(responses)
20569            })
20570        })
20571    }
20572
20573    fn resolve_completions(
20574        &self,
20575        buffer: Entity<Buffer>,
20576        completion_indices: Vec<usize>,
20577        completions: Rc<RefCell<Box<[Completion]>>>,
20578        cx: &mut Context<Editor>,
20579    ) -> Task<Result<bool>> {
20580        self.update(cx, |project, cx| {
20581            project.lsp_store().update(cx, |lsp_store, cx| {
20582                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20583            })
20584        })
20585    }
20586
20587    fn apply_additional_edits_for_completion(
20588        &self,
20589        buffer: Entity<Buffer>,
20590        completions: Rc<RefCell<Box<[Completion]>>>,
20591        completion_index: usize,
20592        push_to_history: bool,
20593        cx: &mut Context<Editor>,
20594    ) -> Task<Result<Option<language::Transaction>>> {
20595        self.update(cx, |project, cx| {
20596            project.lsp_store().update(cx, |lsp_store, cx| {
20597                lsp_store.apply_additional_edits_for_completion(
20598                    buffer,
20599                    completions,
20600                    completion_index,
20601                    push_to_history,
20602                    cx,
20603                )
20604            })
20605        })
20606    }
20607
20608    fn is_completion_trigger(
20609        &self,
20610        buffer: &Entity<Buffer>,
20611        position: language::Anchor,
20612        text: &str,
20613        trigger_in_words: bool,
20614        cx: &mut Context<Editor>,
20615    ) -> bool {
20616        let mut chars = text.chars();
20617        let char = if let Some(char) = chars.next() {
20618            char
20619        } else {
20620            return false;
20621        };
20622        if chars.next().is_some() {
20623            return false;
20624        }
20625
20626        let buffer = buffer.read(cx);
20627        let snapshot = buffer.snapshot();
20628        if !snapshot.settings_at(position, cx).show_completions_on_input {
20629            return false;
20630        }
20631        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20632        if trigger_in_words && classifier.is_word(char) {
20633            return true;
20634        }
20635
20636        buffer.completion_triggers().contains(text)
20637    }
20638}
20639
20640impl SemanticsProvider for Entity<Project> {
20641    fn hover(
20642        &self,
20643        buffer: &Entity<Buffer>,
20644        position: text::Anchor,
20645        cx: &mut App,
20646    ) -> Option<Task<Vec<project::Hover>>> {
20647        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20648    }
20649
20650    fn document_highlights(
20651        &self,
20652        buffer: &Entity<Buffer>,
20653        position: text::Anchor,
20654        cx: &mut App,
20655    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20656        Some(self.update(cx, |project, cx| {
20657            project.document_highlights(buffer, position, cx)
20658        }))
20659    }
20660
20661    fn definitions(
20662        &self,
20663        buffer: &Entity<Buffer>,
20664        position: text::Anchor,
20665        kind: GotoDefinitionKind,
20666        cx: &mut App,
20667    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20668        Some(self.update(cx, |project, cx| match kind {
20669            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20670            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20671            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20672            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20673        }))
20674    }
20675
20676    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20677        // TODO: make this work for remote projects
20678        self.update(cx, |project, cx| {
20679            if project
20680                .active_debug_session(cx)
20681                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20682            {
20683                return true;
20684            }
20685
20686            buffer.update(cx, |buffer, cx| {
20687                project.any_language_server_supports_inlay_hints(buffer, cx)
20688            })
20689        })
20690    }
20691
20692    fn inline_values(
20693        &self,
20694        buffer_handle: Entity<Buffer>,
20695
20696        range: Range<text::Anchor>,
20697        cx: &mut App,
20698    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20699        self.update(cx, |project, cx| {
20700            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20701
20702            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20703        })
20704    }
20705
20706    fn inlay_hints(
20707        &self,
20708        buffer_handle: Entity<Buffer>,
20709        range: Range<text::Anchor>,
20710        cx: &mut App,
20711    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20712        Some(self.update(cx, |project, cx| {
20713            project.inlay_hints(buffer_handle, range, cx)
20714        }))
20715    }
20716
20717    fn resolve_inlay_hint(
20718        &self,
20719        hint: InlayHint,
20720        buffer_handle: Entity<Buffer>,
20721        server_id: LanguageServerId,
20722        cx: &mut App,
20723    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20724        Some(self.update(cx, |project, cx| {
20725            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20726        }))
20727    }
20728
20729    fn range_for_rename(
20730        &self,
20731        buffer: &Entity<Buffer>,
20732        position: text::Anchor,
20733        cx: &mut App,
20734    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20735        Some(self.update(cx, |project, cx| {
20736            let buffer = buffer.clone();
20737            let task = project.prepare_rename(buffer.clone(), position, cx);
20738            cx.spawn(async move |_, cx| {
20739                Ok(match task.await? {
20740                    PrepareRenameResponse::Success(range) => Some(range),
20741                    PrepareRenameResponse::InvalidPosition => None,
20742                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20743                        // Fallback on using TreeSitter info to determine identifier range
20744                        buffer.read_with(cx, |buffer, _| {
20745                            let snapshot = buffer.snapshot();
20746                            let (range, kind) = snapshot.surrounding_word(position);
20747                            if kind != Some(CharKind::Word) {
20748                                return None;
20749                            }
20750                            Some(
20751                                snapshot.anchor_before(range.start)
20752                                    ..snapshot.anchor_after(range.end),
20753                            )
20754                        })?
20755                    }
20756                })
20757            })
20758        }))
20759    }
20760
20761    fn perform_rename(
20762        &self,
20763        buffer: &Entity<Buffer>,
20764        position: text::Anchor,
20765        new_name: String,
20766        cx: &mut App,
20767    ) -> Option<Task<Result<ProjectTransaction>>> {
20768        Some(self.update(cx, |project, cx| {
20769            project.perform_rename(buffer.clone(), position, new_name, cx)
20770        }))
20771    }
20772}
20773
20774fn inlay_hint_settings(
20775    location: Anchor,
20776    snapshot: &MultiBufferSnapshot,
20777    cx: &mut Context<Editor>,
20778) -> InlayHintSettings {
20779    let file = snapshot.file_at(location);
20780    let language = snapshot.language_at(location).map(|l| l.name());
20781    language_settings(language, file, cx).inlay_hints
20782}
20783
20784fn consume_contiguous_rows(
20785    contiguous_row_selections: &mut Vec<Selection<Point>>,
20786    selection: &Selection<Point>,
20787    display_map: &DisplaySnapshot,
20788    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20789) -> (MultiBufferRow, MultiBufferRow) {
20790    contiguous_row_selections.push(selection.clone());
20791    let start_row = MultiBufferRow(selection.start.row);
20792    let mut end_row = ending_row(selection, display_map);
20793
20794    while let Some(next_selection) = selections.peek() {
20795        if next_selection.start.row <= end_row.0 {
20796            end_row = ending_row(next_selection, display_map);
20797            contiguous_row_selections.push(selections.next().unwrap().clone());
20798        } else {
20799            break;
20800        }
20801    }
20802    (start_row, end_row)
20803}
20804
20805fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20806    if next_selection.end.column > 0 || next_selection.is_empty() {
20807        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20808    } else {
20809        MultiBufferRow(next_selection.end.row)
20810    }
20811}
20812
20813impl EditorSnapshot {
20814    pub fn remote_selections_in_range<'a>(
20815        &'a self,
20816        range: &'a Range<Anchor>,
20817        collaboration_hub: &dyn CollaborationHub,
20818        cx: &'a App,
20819    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20820        let participant_names = collaboration_hub.user_names(cx);
20821        let participant_indices = collaboration_hub.user_participant_indices(cx);
20822        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20823        let collaborators_by_replica_id = collaborators_by_peer_id
20824            .values()
20825            .map(|collaborator| (collaborator.replica_id, collaborator))
20826            .collect::<HashMap<_, _>>();
20827        self.buffer_snapshot
20828            .selections_in_range(range, false)
20829            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20830                if replica_id == AGENT_REPLICA_ID {
20831                    Some(RemoteSelection {
20832                        replica_id,
20833                        selection,
20834                        cursor_shape,
20835                        line_mode,
20836                        collaborator_id: CollaboratorId::Agent,
20837                        user_name: Some("Agent".into()),
20838                        color: cx.theme().players().agent(),
20839                    })
20840                } else {
20841                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20842                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20843                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20844                    Some(RemoteSelection {
20845                        replica_id,
20846                        selection,
20847                        cursor_shape,
20848                        line_mode,
20849                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20850                        user_name,
20851                        color: if let Some(index) = participant_index {
20852                            cx.theme().players().color_for_participant(index.0)
20853                        } else {
20854                            cx.theme().players().absent()
20855                        },
20856                    })
20857                }
20858            })
20859    }
20860
20861    pub fn hunks_for_ranges(
20862        &self,
20863        ranges: impl IntoIterator<Item = Range<Point>>,
20864    ) -> Vec<MultiBufferDiffHunk> {
20865        let mut hunks = Vec::new();
20866        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20867            HashMap::default();
20868        for query_range in ranges {
20869            let query_rows =
20870                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20871            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20872                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20873            ) {
20874                // Include deleted hunks that are adjacent to the query range, because
20875                // otherwise they would be missed.
20876                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20877                if hunk.status().is_deleted() {
20878                    intersects_range |= hunk.row_range.start == query_rows.end;
20879                    intersects_range |= hunk.row_range.end == query_rows.start;
20880                }
20881                if intersects_range {
20882                    if !processed_buffer_rows
20883                        .entry(hunk.buffer_id)
20884                        .or_default()
20885                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20886                    {
20887                        continue;
20888                    }
20889                    hunks.push(hunk);
20890                }
20891            }
20892        }
20893
20894        hunks
20895    }
20896
20897    fn display_diff_hunks_for_rows<'a>(
20898        &'a self,
20899        display_rows: Range<DisplayRow>,
20900        folded_buffers: &'a HashSet<BufferId>,
20901    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20902        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20903        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20904
20905        self.buffer_snapshot
20906            .diff_hunks_in_range(buffer_start..buffer_end)
20907            .filter_map(|hunk| {
20908                if folded_buffers.contains(&hunk.buffer_id) {
20909                    return None;
20910                }
20911
20912                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20913                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20914
20915                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20916                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20917
20918                let display_hunk = if hunk_display_start.column() != 0 {
20919                    DisplayDiffHunk::Folded {
20920                        display_row: hunk_display_start.row(),
20921                    }
20922                } else {
20923                    let mut end_row = hunk_display_end.row();
20924                    if hunk_display_end.column() > 0 {
20925                        end_row.0 += 1;
20926                    }
20927                    let is_created_file = hunk.is_created_file();
20928                    DisplayDiffHunk::Unfolded {
20929                        status: hunk.status(),
20930                        diff_base_byte_range: hunk.diff_base_byte_range,
20931                        display_row_range: hunk_display_start.row()..end_row,
20932                        multi_buffer_range: Anchor::range_in_buffer(
20933                            hunk.excerpt_id,
20934                            hunk.buffer_id,
20935                            hunk.buffer_range,
20936                        ),
20937                        is_created_file,
20938                    }
20939                };
20940
20941                Some(display_hunk)
20942            })
20943    }
20944
20945    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20946        self.display_snapshot.buffer_snapshot.language_at(position)
20947    }
20948
20949    pub fn is_focused(&self) -> bool {
20950        self.is_focused
20951    }
20952
20953    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20954        self.placeholder_text.as_ref()
20955    }
20956
20957    pub fn scroll_position(&self) -> gpui::Point<f32> {
20958        self.scroll_anchor.scroll_position(&self.display_snapshot)
20959    }
20960
20961    fn gutter_dimensions(
20962        &self,
20963        font_id: FontId,
20964        font_size: Pixels,
20965        max_line_number_width: Pixels,
20966        cx: &App,
20967    ) -> Option<GutterDimensions> {
20968        if !self.show_gutter {
20969            return None;
20970        }
20971
20972        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20973        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20974
20975        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20976            matches!(
20977                ProjectSettings::get_global(cx).git.git_gutter,
20978                Some(GitGutterSetting::TrackedFiles)
20979            )
20980        });
20981        let gutter_settings = EditorSettings::get_global(cx).gutter;
20982        let show_line_numbers = self
20983            .show_line_numbers
20984            .unwrap_or(gutter_settings.line_numbers);
20985        let line_gutter_width = if show_line_numbers {
20986            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20987            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20988            max_line_number_width.max(min_width_for_number_on_gutter)
20989        } else {
20990            0.0.into()
20991        };
20992
20993        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20994        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20995
20996        let git_blame_entries_width =
20997            self.git_blame_gutter_max_author_length
20998                .map(|max_author_length| {
20999                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21000                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21001
21002                    /// The number of characters to dedicate to gaps and margins.
21003                    const SPACING_WIDTH: usize = 4;
21004
21005                    let max_char_count = max_author_length.min(renderer.max_author_length())
21006                        + ::git::SHORT_SHA_LENGTH
21007                        + MAX_RELATIVE_TIMESTAMP.len()
21008                        + SPACING_WIDTH;
21009
21010                    em_advance * max_char_count
21011                });
21012
21013        let is_singleton = self.buffer_snapshot.is_singleton();
21014
21015        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21016        left_padding += if !is_singleton {
21017            em_width * 4.0
21018        } else if show_runnables || show_breakpoints {
21019            em_width * 3.0
21020        } else if show_git_gutter && show_line_numbers {
21021            em_width * 2.0
21022        } else if show_git_gutter || show_line_numbers {
21023            em_width
21024        } else {
21025            px(0.)
21026        };
21027
21028        let shows_folds = is_singleton && gutter_settings.folds;
21029
21030        let right_padding = if shows_folds && show_line_numbers {
21031            em_width * 4.0
21032        } else if shows_folds || (!is_singleton && show_line_numbers) {
21033            em_width * 3.0
21034        } else if show_line_numbers {
21035            em_width
21036        } else {
21037            px(0.)
21038        };
21039
21040        Some(GutterDimensions {
21041            left_padding,
21042            right_padding,
21043            width: line_gutter_width + left_padding + right_padding,
21044            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21045            git_blame_entries_width,
21046        })
21047    }
21048
21049    pub fn render_crease_toggle(
21050        &self,
21051        buffer_row: MultiBufferRow,
21052        row_contains_cursor: bool,
21053        editor: Entity<Editor>,
21054        window: &mut Window,
21055        cx: &mut App,
21056    ) -> Option<AnyElement> {
21057        let folded = self.is_line_folded(buffer_row);
21058        let mut is_foldable = false;
21059
21060        if let Some(crease) = self
21061            .crease_snapshot
21062            .query_row(buffer_row, &self.buffer_snapshot)
21063        {
21064            is_foldable = true;
21065            match crease {
21066                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21067                    if let Some(render_toggle) = render_toggle {
21068                        let toggle_callback =
21069                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21070                                if folded {
21071                                    editor.update(cx, |editor, cx| {
21072                                        editor.fold_at(buffer_row, window, cx)
21073                                    });
21074                                } else {
21075                                    editor.update(cx, |editor, cx| {
21076                                        editor.unfold_at(buffer_row, window, cx)
21077                                    });
21078                                }
21079                            });
21080                        return Some((render_toggle)(
21081                            buffer_row,
21082                            folded,
21083                            toggle_callback,
21084                            window,
21085                            cx,
21086                        ));
21087                    }
21088                }
21089            }
21090        }
21091
21092        is_foldable |= self.starts_indent(buffer_row);
21093
21094        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21095            Some(
21096                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21097                    .toggle_state(folded)
21098                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21099                        if folded {
21100                            this.unfold_at(buffer_row, window, cx);
21101                        } else {
21102                            this.fold_at(buffer_row, window, cx);
21103                        }
21104                    }))
21105                    .into_any_element(),
21106            )
21107        } else {
21108            None
21109        }
21110    }
21111
21112    pub fn render_crease_trailer(
21113        &self,
21114        buffer_row: MultiBufferRow,
21115        window: &mut Window,
21116        cx: &mut App,
21117    ) -> Option<AnyElement> {
21118        let folded = self.is_line_folded(buffer_row);
21119        if let Crease::Inline { render_trailer, .. } = self
21120            .crease_snapshot
21121            .query_row(buffer_row, &self.buffer_snapshot)?
21122        {
21123            let render_trailer = render_trailer.as_ref()?;
21124            Some(render_trailer(buffer_row, folded, window, cx))
21125        } else {
21126            None
21127        }
21128    }
21129}
21130
21131impl Deref for EditorSnapshot {
21132    type Target = DisplaySnapshot;
21133
21134    fn deref(&self) -> &Self::Target {
21135        &self.display_snapshot
21136    }
21137}
21138
21139#[derive(Clone, Debug, PartialEq, Eq)]
21140pub enum EditorEvent {
21141    InputIgnored {
21142        text: Arc<str>,
21143    },
21144    InputHandled {
21145        utf16_range_to_replace: Option<Range<isize>>,
21146        text: Arc<str>,
21147    },
21148    ExcerptsAdded {
21149        buffer: Entity<Buffer>,
21150        predecessor: ExcerptId,
21151        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21152    },
21153    ExcerptsRemoved {
21154        ids: Vec<ExcerptId>,
21155        removed_buffer_ids: Vec<BufferId>,
21156    },
21157    BufferFoldToggled {
21158        ids: Vec<ExcerptId>,
21159        folded: bool,
21160    },
21161    ExcerptsEdited {
21162        ids: Vec<ExcerptId>,
21163    },
21164    ExcerptsExpanded {
21165        ids: Vec<ExcerptId>,
21166    },
21167    BufferEdited,
21168    Edited {
21169        transaction_id: clock::Lamport,
21170    },
21171    Reparsed(BufferId),
21172    Focused,
21173    FocusedIn,
21174    Blurred,
21175    DirtyChanged,
21176    Saved,
21177    TitleChanged,
21178    DiffBaseChanged,
21179    SelectionsChanged {
21180        local: bool,
21181    },
21182    ScrollPositionChanged {
21183        local: bool,
21184        autoscroll: bool,
21185    },
21186    Closed,
21187    TransactionUndone {
21188        transaction_id: clock::Lamport,
21189    },
21190    TransactionBegun {
21191        transaction_id: clock::Lamport,
21192    },
21193    Reloaded,
21194    CursorShapeChanged,
21195    PushedToNavHistory {
21196        anchor: Anchor,
21197        is_deactivate: bool,
21198    },
21199}
21200
21201impl EventEmitter<EditorEvent> for Editor {}
21202
21203impl Focusable for Editor {
21204    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21205        self.focus_handle.clone()
21206    }
21207}
21208
21209impl Render for Editor {
21210    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21211        let settings = ThemeSettings::get_global(cx);
21212
21213        let mut text_style = match self.mode {
21214            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21215                color: cx.theme().colors().editor_foreground,
21216                font_family: settings.ui_font.family.clone(),
21217                font_features: settings.ui_font.features.clone(),
21218                font_fallbacks: settings.ui_font.fallbacks.clone(),
21219                font_size: rems(0.875).into(),
21220                font_weight: settings.ui_font.weight,
21221                line_height: relative(settings.buffer_line_height.value()),
21222                ..Default::default()
21223            },
21224            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21225                color: cx.theme().colors().editor_foreground,
21226                font_family: settings.buffer_font.family.clone(),
21227                font_features: settings.buffer_font.features.clone(),
21228                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21229                font_size: settings.buffer_font_size(cx).into(),
21230                font_weight: settings.buffer_font.weight,
21231                line_height: relative(settings.buffer_line_height.value()),
21232                ..Default::default()
21233            },
21234        };
21235        if let Some(text_style_refinement) = &self.text_style_refinement {
21236            text_style.refine(text_style_refinement)
21237        }
21238
21239        let background = match self.mode {
21240            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21241            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21242            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21243            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21244        };
21245
21246        EditorElement::new(
21247            &cx.entity(),
21248            EditorStyle {
21249                background,
21250                local_player: cx.theme().players().local(),
21251                text: text_style,
21252                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21253                syntax: cx.theme().syntax().clone(),
21254                status: cx.theme().status().clone(),
21255                inlay_hints_style: make_inlay_hints_style(cx),
21256                inline_completion_styles: make_suggestion_styles(cx),
21257                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21258                show_underlines: !self.mode.is_minimap(),
21259            },
21260        )
21261    }
21262}
21263
21264impl EntityInputHandler for Editor {
21265    fn text_for_range(
21266        &mut self,
21267        range_utf16: Range<usize>,
21268        adjusted_range: &mut Option<Range<usize>>,
21269        _: &mut Window,
21270        cx: &mut Context<Self>,
21271    ) -> Option<String> {
21272        let snapshot = self.buffer.read(cx).read(cx);
21273        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21274        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21275        if (start.0..end.0) != range_utf16 {
21276            adjusted_range.replace(start.0..end.0);
21277        }
21278        Some(snapshot.text_for_range(start..end).collect())
21279    }
21280
21281    fn selected_text_range(
21282        &mut self,
21283        ignore_disabled_input: bool,
21284        _: &mut Window,
21285        cx: &mut Context<Self>,
21286    ) -> Option<UTF16Selection> {
21287        // Prevent the IME menu from appearing when holding down an alphabetic key
21288        // while input is disabled.
21289        if !ignore_disabled_input && !self.input_enabled {
21290            return None;
21291        }
21292
21293        let selection = self.selections.newest::<OffsetUtf16>(cx);
21294        let range = selection.range();
21295
21296        Some(UTF16Selection {
21297            range: range.start.0..range.end.0,
21298            reversed: selection.reversed,
21299        })
21300    }
21301
21302    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21303        let snapshot = self.buffer.read(cx).read(cx);
21304        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21305        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21306    }
21307
21308    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21309        self.clear_highlights::<InputComposition>(cx);
21310        self.ime_transaction.take();
21311    }
21312
21313    fn replace_text_in_range(
21314        &mut self,
21315        range_utf16: Option<Range<usize>>,
21316        text: &str,
21317        window: &mut Window,
21318        cx: &mut Context<Self>,
21319    ) {
21320        if !self.input_enabled {
21321            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21322            return;
21323        }
21324
21325        self.transact(window, cx, |this, window, cx| {
21326            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21327                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21328                Some(this.selection_replacement_ranges(range_utf16, cx))
21329            } else {
21330                this.marked_text_ranges(cx)
21331            };
21332
21333            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21334                let newest_selection_id = this.selections.newest_anchor().id;
21335                this.selections
21336                    .all::<OffsetUtf16>(cx)
21337                    .iter()
21338                    .zip(ranges_to_replace.iter())
21339                    .find_map(|(selection, range)| {
21340                        if selection.id == newest_selection_id {
21341                            Some(
21342                                (range.start.0 as isize - selection.head().0 as isize)
21343                                    ..(range.end.0 as isize - selection.head().0 as isize),
21344                            )
21345                        } else {
21346                            None
21347                        }
21348                    })
21349            });
21350
21351            cx.emit(EditorEvent::InputHandled {
21352                utf16_range_to_replace: range_to_replace,
21353                text: text.into(),
21354            });
21355
21356            if let Some(new_selected_ranges) = new_selected_ranges {
21357                this.change_selections(None, window, cx, |selections| {
21358                    selections.select_ranges(new_selected_ranges)
21359                });
21360                this.backspace(&Default::default(), window, cx);
21361            }
21362
21363            this.handle_input(text, window, cx);
21364        });
21365
21366        if let Some(transaction) = self.ime_transaction {
21367            self.buffer.update(cx, |buffer, cx| {
21368                buffer.group_until_transaction(transaction, cx);
21369            });
21370        }
21371
21372        self.unmark_text(window, cx);
21373    }
21374
21375    fn replace_and_mark_text_in_range(
21376        &mut self,
21377        range_utf16: Option<Range<usize>>,
21378        text: &str,
21379        new_selected_range_utf16: Option<Range<usize>>,
21380        window: &mut Window,
21381        cx: &mut Context<Self>,
21382    ) {
21383        if !self.input_enabled {
21384            return;
21385        }
21386
21387        let transaction = self.transact(window, cx, |this, window, cx| {
21388            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21389                let snapshot = this.buffer.read(cx).read(cx);
21390                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21391                    for marked_range in &mut marked_ranges {
21392                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21393                        marked_range.start.0 += relative_range_utf16.start;
21394                        marked_range.start =
21395                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21396                        marked_range.end =
21397                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21398                    }
21399                }
21400                Some(marked_ranges)
21401            } else if let Some(range_utf16) = range_utf16 {
21402                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21403                Some(this.selection_replacement_ranges(range_utf16, cx))
21404            } else {
21405                None
21406            };
21407
21408            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21409                let newest_selection_id = this.selections.newest_anchor().id;
21410                this.selections
21411                    .all::<OffsetUtf16>(cx)
21412                    .iter()
21413                    .zip(ranges_to_replace.iter())
21414                    .find_map(|(selection, range)| {
21415                        if selection.id == newest_selection_id {
21416                            Some(
21417                                (range.start.0 as isize - selection.head().0 as isize)
21418                                    ..(range.end.0 as isize - selection.head().0 as isize),
21419                            )
21420                        } else {
21421                            None
21422                        }
21423                    })
21424            });
21425
21426            cx.emit(EditorEvent::InputHandled {
21427                utf16_range_to_replace: range_to_replace,
21428                text: text.into(),
21429            });
21430
21431            if let Some(ranges) = ranges_to_replace {
21432                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21433            }
21434
21435            let marked_ranges = {
21436                let snapshot = this.buffer.read(cx).read(cx);
21437                this.selections
21438                    .disjoint_anchors()
21439                    .iter()
21440                    .map(|selection| {
21441                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21442                    })
21443                    .collect::<Vec<_>>()
21444            };
21445
21446            if text.is_empty() {
21447                this.unmark_text(window, cx);
21448            } else {
21449                this.highlight_text::<InputComposition>(
21450                    marked_ranges.clone(),
21451                    HighlightStyle {
21452                        underline: Some(UnderlineStyle {
21453                            thickness: px(1.),
21454                            color: None,
21455                            wavy: false,
21456                        }),
21457                        ..Default::default()
21458                    },
21459                    cx,
21460                );
21461            }
21462
21463            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21464            let use_autoclose = this.use_autoclose;
21465            let use_auto_surround = this.use_auto_surround;
21466            this.set_use_autoclose(false);
21467            this.set_use_auto_surround(false);
21468            this.handle_input(text, window, cx);
21469            this.set_use_autoclose(use_autoclose);
21470            this.set_use_auto_surround(use_auto_surround);
21471
21472            if let Some(new_selected_range) = new_selected_range_utf16 {
21473                let snapshot = this.buffer.read(cx).read(cx);
21474                let new_selected_ranges = marked_ranges
21475                    .into_iter()
21476                    .map(|marked_range| {
21477                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21478                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21479                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21480                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21481                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21482                    })
21483                    .collect::<Vec<_>>();
21484
21485                drop(snapshot);
21486                this.change_selections(None, window, cx, |selections| {
21487                    selections.select_ranges(new_selected_ranges)
21488                });
21489            }
21490        });
21491
21492        self.ime_transaction = self.ime_transaction.or(transaction);
21493        if let Some(transaction) = self.ime_transaction {
21494            self.buffer.update(cx, |buffer, cx| {
21495                buffer.group_until_transaction(transaction, cx);
21496            });
21497        }
21498
21499        if self.text_highlights::<InputComposition>(cx).is_none() {
21500            self.ime_transaction.take();
21501        }
21502    }
21503
21504    fn bounds_for_range(
21505        &mut self,
21506        range_utf16: Range<usize>,
21507        element_bounds: gpui::Bounds<Pixels>,
21508        window: &mut Window,
21509        cx: &mut Context<Self>,
21510    ) -> Option<gpui::Bounds<Pixels>> {
21511        let text_layout_details = self.text_layout_details(window);
21512        let gpui::Size {
21513            width: em_width,
21514            height: line_height,
21515        } = self.character_size(window);
21516
21517        let snapshot = self.snapshot(window, cx);
21518        let scroll_position = snapshot.scroll_position();
21519        let scroll_left = scroll_position.x * em_width;
21520
21521        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21522        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21523            + self.gutter_dimensions.width
21524            + self.gutter_dimensions.margin;
21525        let y = line_height * (start.row().as_f32() - scroll_position.y);
21526
21527        Some(Bounds {
21528            origin: element_bounds.origin + point(x, y),
21529            size: size(em_width, line_height),
21530        })
21531    }
21532
21533    fn character_index_for_point(
21534        &mut self,
21535        point: gpui::Point<Pixels>,
21536        _window: &mut Window,
21537        _cx: &mut Context<Self>,
21538    ) -> Option<usize> {
21539        let position_map = self.last_position_map.as_ref()?;
21540        if !position_map.text_hitbox.contains(&point) {
21541            return None;
21542        }
21543        let display_point = position_map.point_for_position(point).previous_valid;
21544        let anchor = position_map
21545            .snapshot
21546            .display_point_to_anchor(display_point, Bias::Left);
21547        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21548        Some(utf16_offset.0)
21549    }
21550}
21551
21552trait SelectionExt {
21553    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21554    fn spanned_rows(
21555        &self,
21556        include_end_if_at_line_start: bool,
21557        map: &DisplaySnapshot,
21558    ) -> Range<MultiBufferRow>;
21559}
21560
21561impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21562    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21563        let start = self
21564            .start
21565            .to_point(&map.buffer_snapshot)
21566            .to_display_point(map);
21567        let end = self
21568            .end
21569            .to_point(&map.buffer_snapshot)
21570            .to_display_point(map);
21571        if self.reversed {
21572            end..start
21573        } else {
21574            start..end
21575        }
21576    }
21577
21578    fn spanned_rows(
21579        &self,
21580        include_end_if_at_line_start: bool,
21581        map: &DisplaySnapshot,
21582    ) -> Range<MultiBufferRow> {
21583        let start = self.start.to_point(&map.buffer_snapshot);
21584        let mut end = self.end.to_point(&map.buffer_snapshot);
21585        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21586            end.row -= 1;
21587        }
21588
21589        let buffer_start = map.prev_line_boundary(start).0;
21590        let buffer_end = map.next_line_boundary(end).0;
21591        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21592    }
21593}
21594
21595impl<T: InvalidationRegion> InvalidationStack<T> {
21596    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21597    where
21598        S: Clone + ToOffset,
21599    {
21600        while let Some(region) = self.last() {
21601            let all_selections_inside_invalidation_ranges =
21602                if selections.len() == region.ranges().len() {
21603                    selections
21604                        .iter()
21605                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21606                        .all(|(selection, invalidation_range)| {
21607                            let head = selection.head().to_offset(buffer);
21608                            invalidation_range.start <= head && invalidation_range.end >= head
21609                        })
21610                } else {
21611                    false
21612                };
21613
21614            if all_selections_inside_invalidation_ranges {
21615                break;
21616            } else {
21617                self.pop();
21618            }
21619        }
21620    }
21621}
21622
21623impl<T> Default for InvalidationStack<T> {
21624    fn default() -> Self {
21625        Self(Default::default())
21626    }
21627}
21628
21629impl<T> Deref for InvalidationStack<T> {
21630    type Target = Vec<T>;
21631
21632    fn deref(&self) -> &Self::Target {
21633        &self.0
21634    }
21635}
21636
21637impl<T> DerefMut for InvalidationStack<T> {
21638    fn deref_mut(&mut self) -> &mut Self::Target {
21639        &mut self.0
21640    }
21641}
21642
21643impl InvalidationRegion for SnippetState {
21644    fn ranges(&self) -> &[Range<Anchor>] {
21645        &self.ranges[self.active_index]
21646    }
21647}
21648
21649fn inline_completion_edit_text(
21650    current_snapshot: &BufferSnapshot,
21651    edits: &[(Range<Anchor>, String)],
21652    edit_preview: &EditPreview,
21653    include_deletions: bool,
21654    cx: &App,
21655) -> HighlightedText {
21656    let edits = edits
21657        .iter()
21658        .map(|(anchor, text)| {
21659            (
21660                anchor.start.text_anchor..anchor.end.text_anchor,
21661                text.clone(),
21662            )
21663        })
21664        .collect::<Vec<_>>();
21665
21666    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21667}
21668
21669pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21670    match severity {
21671        lsp::DiagnosticSeverity::ERROR => colors.error,
21672        lsp::DiagnosticSeverity::WARNING => colors.warning,
21673        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21674        lsp::DiagnosticSeverity::HINT => colors.info,
21675        _ => colors.ignored,
21676    }
21677}
21678
21679pub fn styled_runs_for_code_label<'a>(
21680    label: &'a CodeLabel,
21681    syntax_theme: &'a theme::SyntaxTheme,
21682) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21683    let fade_out = HighlightStyle {
21684        fade_out: Some(0.35),
21685        ..Default::default()
21686    };
21687
21688    let mut prev_end = label.filter_range.end;
21689    label
21690        .runs
21691        .iter()
21692        .enumerate()
21693        .flat_map(move |(ix, (range, highlight_id))| {
21694            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21695                style
21696            } else {
21697                return Default::default();
21698            };
21699            let mut muted_style = style;
21700            muted_style.highlight(fade_out);
21701
21702            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21703            if range.start >= label.filter_range.end {
21704                if range.start > prev_end {
21705                    runs.push((prev_end..range.start, fade_out));
21706                }
21707                runs.push((range.clone(), muted_style));
21708            } else if range.end <= label.filter_range.end {
21709                runs.push((range.clone(), style));
21710            } else {
21711                runs.push((range.start..label.filter_range.end, style));
21712                runs.push((label.filter_range.end..range.end, muted_style));
21713            }
21714            prev_end = cmp::max(prev_end, range.end);
21715
21716            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21717                runs.push((prev_end..label.text.len(), fade_out));
21718            }
21719
21720            runs
21721        })
21722}
21723
21724pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21725    let mut prev_index = 0;
21726    let mut prev_codepoint: Option<char> = None;
21727    text.char_indices()
21728        .chain([(text.len(), '\0')])
21729        .filter_map(move |(index, codepoint)| {
21730            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21731            let is_boundary = index == text.len()
21732                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21733                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21734            if is_boundary {
21735                let chunk = &text[prev_index..index];
21736                prev_index = index;
21737                Some(chunk)
21738            } else {
21739                None
21740            }
21741        })
21742}
21743
21744pub trait RangeToAnchorExt: Sized {
21745    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21746
21747    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21748        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21749        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21750    }
21751}
21752
21753impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21754    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21755        let start_offset = self.start.to_offset(snapshot);
21756        let end_offset = self.end.to_offset(snapshot);
21757        if start_offset == end_offset {
21758            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21759        } else {
21760            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21761        }
21762    }
21763}
21764
21765pub trait RowExt {
21766    fn as_f32(&self) -> f32;
21767
21768    fn next_row(&self) -> Self;
21769
21770    fn previous_row(&self) -> Self;
21771
21772    fn minus(&self, other: Self) -> u32;
21773}
21774
21775impl RowExt for DisplayRow {
21776    fn as_f32(&self) -> f32 {
21777        self.0 as f32
21778    }
21779
21780    fn next_row(&self) -> Self {
21781        Self(self.0 + 1)
21782    }
21783
21784    fn previous_row(&self) -> Self {
21785        Self(self.0.saturating_sub(1))
21786    }
21787
21788    fn minus(&self, other: Self) -> u32 {
21789        self.0 - other.0
21790    }
21791}
21792
21793impl RowExt for MultiBufferRow {
21794    fn as_f32(&self) -> f32 {
21795        self.0 as f32
21796    }
21797
21798    fn next_row(&self) -> Self {
21799        Self(self.0 + 1)
21800    }
21801
21802    fn previous_row(&self) -> Self {
21803        Self(self.0.saturating_sub(1))
21804    }
21805
21806    fn minus(&self, other: Self) -> u32 {
21807        self.0 - other.0
21808    }
21809}
21810
21811trait RowRangeExt {
21812    type Row;
21813
21814    fn len(&self) -> usize;
21815
21816    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21817}
21818
21819impl RowRangeExt for Range<MultiBufferRow> {
21820    type Row = MultiBufferRow;
21821
21822    fn len(&self) -> usize {
21823        (self.end.0 - self.start.0) as usize
21824    }
21825
21826    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21827        (self.start.0..self.end.0).map(MultiBufferRow)
21828    }
21829}
21830
21831impl RowRangeExt for Range<DisplayRow> {
21832    type Row = DisplayRow;
21833
21834    fn len(&self) -> usize {
21835        (self.end.0 - self.start.0) as usize
21836    }
21837
21838    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21839        (self.start.0..self.end.0).map(DisplayRow)
21840    }
21841}
21842
21843/// If select range has more than one line, we
21844/// just point the cursor to range.start.
21845fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21846    if range.start.row == range.end.row {
21847        range
21848    } else {
21849        range.start..range.start
21850    }
21851}
21852pub struct KillRing(ClipboardItem);
21853impl Global for KillRing {}
21854
21855const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21856
21857enum BreakpointPromptEditAction {
21858    Log,
21859    Condition,
21860    HitCondition,
21861}
21862
21863struct BreakpointPromptEditor {
21864    pub(crate) prompt: Entity<Editor>,
21865    editor: WeakEntity<Editor>,
21866    breakpoint_anchor: Anchor,
21867    breakpoint: Breakpoint,
21868    edit_action: BreakpointPromptEditAction,
21869    block_ids: HashSet<CustomBlockId>,
21870    editor_margins: Arc<Mutex<EditorMargins>>,
21871    _subscriptions: Vec<Subscription>,
21872}
21873
21874impl BreakpointPromptEditor {
21875    const MAX_LINES: u8 = 4;
21876
21877    fn new(
21878        editor: WeakEntity<Editor>,
21879        breakpoint_anchor: Anchor,
21880        breakpoint: Breakpoint,
21881        edit_action: BreakpointPromptEditAction,
21882        window: &mut Window,
21883        cx: &mut Context<Self>,
21884    ) -> Self {
21885        let base_text = match edit_action {
21886            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21887            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21888            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21889        }
21890        .map(|msg| msg.to_string())
21891        .unwrap_or_default();
21892
21893        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21894        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21895
21896        let prompt = cx.new(|cx| {
21897            let mut prompt = Editor::new(
21898                EditorMode::AutoHeight {
21899                    max_lines: Self::MAX_LINES as usize,
21900                },
21901                buffer,
21902                None,
21903                window,
21904                cx,
21905            );
21906            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21907            prompt.set_show_cursor_when_unfocused(false, cx);
21908            prompt.set_placeholder_text(
21909                match edit_action {
21910                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21911                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21912                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21913                },
21914                cx,
21915            );
21916
21917            prompt
21918        });
21919
21920        Self {
21921            prompt,
21922            editor,
21923            breakpoint_anchor,
21924            breakpoint,
21925            edit_action,
21926            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21927            block_ids: Default::default(),
21928            _subscriptions: vec![],
21929        }
21930    }
21931
21932    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21933        self.block_ids.extend(block_ids)
21934    }
21935
21936    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21937        if let Some(editor) = self.editor.upgrade() {
21938            let message = self
21939                .prompt
21940                .read(cx)
21941                .buffer
21942                .read(cx)
21943                .as_singleton()
21944                .expect("A multi buffer in breakpoint prompt isn't possible")
21945                .read(cx)
21946                .as_rope()
21947                .to_string();
21948
21949            editor.update(cx, |editor, cx| {
21950                editor.edit_breakpoint_at_anchor(
21951                    self.breakpoint_anchor,
21952                    self.breakpoint.clone(),
21953                    match self.edit_action {
21954                        BreakpointPromptEditAction::Log => {
21955                            BreakpointEditAction::EditLogMessage(message.into())
21956                        }
21957                        BreakpointPromptEditAction::Condition => {
21958                            BreakpointEditAction::EditCondition(message.into())
21959                        }
21960                        BreakpointPromptEditAction::HitCondition => {
21961                            BreakpointEditAction::EditHitCondition(message.into())
21962                        }
21963                    },
21964                    cx,
21965                );
21966
21967                editor.remove_blocks(self.block_ids.clone(), None, cx);
21968                cx.focus_self(window);
21969            });
21970        }
21971    }
21972
21973    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21974        self.editor
21975            .update(cx, |editor, cx| {
21976                editor.remove_blocks(self.block_ids.clone(), None, cx);
21977                window.focus(&editor.focus_handle);
21978            })
21979            .log_err();
21980    }
21981
21982    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21983        let settings = ThemeSettings::get_global(cx);
21984        let text_style = TextStyle {
21985            color: if self.prompt.read(cx).read_only(cx) {
21986                cx.theme().colors().text_disabled
21987            } else {
21988                cx.theme().colors().text
21989            },
21990            font_family: settings.buffer_font.family.clone(),
21991            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21992            font_size: settings.buffer_font_size(cx).into(),
21993            font_weight: settings.buffer_font.weight,
21994            line_height: relative(settings.buffer_line_height.value()),
21995            ..Default::default()
21996        };
21997        EditorElement::new(
21998            &self.prompt,
21999            EditorStyle {
22000                background: cx.theme().colors().editor_background,
22001                local_player: cx.theme().players().local(),
22002                text: text_style,
22003                ..Default::default()
22004            },
22005        )
22006    }
22007}
22008
22009impl Render for BreakpointPromptEditor {
22010    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22011        let editor_margins = *self.editor_margins.lock();
22012        let gutter_dimensions = editor_margins.gutter;
22013        h_flex()
22014            .key_context("Editor")
22015            .bg(cx.theme().colors().editor_background)
22016            .border_y_1()
22017            .border_color(cx.theme().status().info_border)
22018            .size_full()
22019            .py(window.line_height() / 2.5)
22020            .on_action(cx.listener(Self::confirm))
22021            .on_action(cx.listener(Self::cancel))
22022            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22023            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22024    }
22025}
22026
22027impl Focusable for BreakpointPromptEditor {
22028    fn focus_handle(&self, cx: &App) -> FocusHandle {
22029        self.prompt.focus_handle(cx)
22030    }
22031}
22032
22033fn all_edits_insertions_or_deletions(
22034    edits: &Vec<(Range<Anchor>, String)>,
22035    snapshot: &MultiBufferSnapshot,
22036) -> bool {
22037    let mut all_insertions = true;
22038    let mut all_deletions = true;
22039
22040    for (range, new_text) in edits.iter() {
22041        let range_is_empty = range.to_offset(&snapshot).is_empty();
22042        let text_is_empty = new_text.is_empty();
22043
22044        if range_is_empty != text_is_empty {
22045            if range_is_empty {
22046                all_deletions = false;
22047            } else {
22048                all_insertions = false;
22049            }
22050        } else {
22051            return false;
22052        }
22053
22054        if !all_insertions && !all_deletions {
22055            return false;
22056        }
22057    }
22058    all_insertions || all_deletions
22059}
22060
22061struct MissingEditPredictionKeybindingTooltip;
22062
22063impl Render for MissingEditPredictionKeybindingTooltip {
22064    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22065        ui::tooltip_container(window, cx, |container, _, cx| {
22066            container
22067                .flex_shrink_0()
22068                .max_w_80()
22069                .min_h(rems_from_px(124.))
22070                .justify_between()
22071                .child(
22072                    v_flex()
22073                        .flex_1()
22074                        .text_ui_sm(cx)
22075                        .child(Label::new("Conflict with Accept Keybinding"))
22076                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22077                )
22078                .child(
22079                    h_flex()
22080                        .pb_1()
22081                        .gap_1()
22082                        .items_end()
22083                        .w_full()
22084                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22085                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22086                        }))
22087                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22088                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22089                        })),
22090                )
22091        })
22092    }
22093}
22094
22095#[derive(Debug, Clone, Copy, PartialEq)]
22096pub struct LineHighlight {
22097    pub background: Background,
22098    pub border: Option<gpui::Hsla>,
22099    pub include_gutter: bool,
22100    pub type_id: Option<TypeId>,
22101}
22102
22103fn render_diff_hunk_controls(
22104    row: u32,
22105    status: &DiffHunkStatus,
22106    hunk_range: Range<Anchor>,
22107    is_created_file: bool,
22108    line_height: Pixels,
22109    editor: &Entity<Editor>,
22110    _window: &mut Window,
22111    cx: &mut App,
22112) -> AnyElement {
22113    h_flex()
22114        .h(line_height)
22115        .mr_1()
22116        .gap_1()
22117        .px_0p5()
22118        .pb_1()
22119        .border_x_1()
22120        .border_b_1()
22121        .border_color(cx.theme().colors().border_variant)
22122        .rounded_b_lg()
22123        .bg(cx.theme().colors().editor_background)
22124        .gap_1()
22125        .block_mouse_except_scroll()
22126        .shadow_md()
22127        .child(if status.has_secondary_hunk() {
22128            Button::new(("stage", row as u64), "Stage")
22129                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22130                .tooltip({
22131                    let focus_handle = editor.focus_handle(cx);
22132                    move |window, cx| {
22133                        Tooltip::for_action_in(
22134                            "Stage Hunk",
22135                            &::git::ToggleStaged,
22136                            &focus_handle,
22137                            window,
22138                            cx,
22139                        )
22140                    }
22141                })
22142                .on_click({
22143                    let editor = editor.clone();
22144                    move |_event, _window, cx| {
22145                        editor.update(cx, |editor, cx| {
22146                            editor.stage_or_unstage_diff_hunks(
22147                                true,
22148                                vec![hunk_range.start..hunk_range.start],
22149                                cx,
22150                            );
22151                        });
22152                    }
22153                })
22154        } else {
22155            Button::new(("unstage", row as u64), "Unstage")
22156                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22157                .tooltip({
22158                    let focus_handle = editor.focus_handle(cx);
22159                    move |window, cx| {
22160                        Tooltip::for_action_in(
22161                            "Unstage Hunk",
22162                            &::git::ToggleStaged,
22163                            &focus_handle,
22164                            window,
22165                            cx,
22166                        )
22167                    }
22168                })
22169                .on_click({
22170                    let editor = editor.clone();
22171                    move |_event, _window, cx| {
22172                        editor.update(cx, |editor, cx| {
22173                            editor.stage_or_unstage_diff_hunks(
22174                                false,
22175                                vec![hunk_range.start..hunk_range.start],
22176                                cx,
22177                            );
22178                        });
22179                    }
22180                })
22181        })
22182        .child(
22183            Button::new(("restore", row as u64), "Restore")
22184                .tooltip({
22185                    let focus_handle = editor.focus_handle(cx);
22186                    move |window, cx| {
22187                        Tooltip::for_action_in(
22188                            "Restore Hunk",
22189                            &::git::Restore,
22190                            &focus_handle,
22191                            window,
22192                            cx,
22193                        )
22194                    }
22195                })
22196                .on_click({
22197                    let editor = editor.clone();
22198                    move |_event, window, cx| {
22199                        editor.update(cx, |editor, cx| {
22200                            let snapshot = editor.snapshot(window, cx);
22201                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22202                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22203                        });
22204                    }
22205                })
22206                .disabled(is_created_file),
22207        )
22208        .when(
22209            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22210            |el| {
22211                el.child(
22212                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22213                        .shape(IconButtonShape::Square)
22214                        .icon_size(IconSize::Small)
22215                        // .disabled(!has_multiple_hunks)
22216                        .tooltip({
22217                            let focus_handle = editor.focus_handle(cx);
22218                            move |window, cx| {
22219                                Tooltip::for_action_in(
22220                                    "Next Hunk",
22221                                    &GoToHunk,
22222                                    &focus_handle,
22223                                    window,
22224                                    cx,
22225                                )
22226                            }
22227                        })
22228                        .on_click({
22229                            let editor = editor.clone();
22230                            move |_event, window, cx| {
22231                                editor.update(cx, |editor, cx| {
22232                                    let snapshot = editor.snapshot(window, cx);
22233                                    let position =
22234                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22235                                    editor.go_to_hunk_before_or_after_position(
22236                                        &snapshot,
22237                                        position,
22238                                        Direction::Next,
22239                                        window,
22240                                        cx,
22241                                    );
22242                                    editor.expand_selected_diff_hunks(cx);
22243                                });
22244                            }
22245                        }),
22246                )
22247                .child(
22248                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22249                        .shape(IconButtonShape::Square)
22250                        .icon_size(IconSize::Small)
22251                        // .disabled(!has_multiple_hunks)
22252                        .tooltip({
22253                            let focus_handle = editor.focus_handle(cx);
22254                            move |window, cx| {
22255                                Tooltip::for_action_in(
22256                                    "Previous Hunk",
22257                                    &GoToPreviousHunk,
22258                                    &focus_handle,
22259                                    window,
22260                                    cx,
22261                                )
22262                            }
22263                        })
22264                        .on_click({
22265                            let editor = editor.clone();
22266                            move |_event, window, cx| {
22267                                editor.update(cx, |editor, cx| {
22268                                    let snapshot = editor.snapshot(window, cx);
22269                                    let point =
22270                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22271                                    editor.go_to_hunk_before_or_after_position(
22272                                        &snapshot,
22273                                        point,
22274                                        Direction::Prev,
22275                                        window,
22276                                        cx,
22277                                    );
22278                                    editor.expand_selected_diff_hunks(cx);
22279                                });
22280                            }
22281                        }),
22282                )
22283            },
22284        )
22285        .into_any_element()
22286}