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;
   18mod 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::ReplicaId;
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use display_map::*;
   63pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   64use editor_settings::GoToDefinitionFallback;
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   67    ShowScrollbar,
   68};
   69pub use editor_settings_controls::*;
   70use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   71pub use element::{
   72    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   73};
   74use feature_flags::{Debugger, FeatureFlagAppExt};
   75use futures::{
   76    FutureExt,
   77    future::{self, Shared, join},
   78};
   79use fuzzy::StringMatchCandidate;
   80
   81use ::git::Restore;
   82use code_context_menus::{
   83    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   84    CompletionsMenu, ContextMenuOrigin,
   85};
   86use git::blame::{GitBlame, GlobalBlameRenderer};
   87use gpui::{
   88    Action, Animation, AnimationExt, AnyElement, AnyWeakEntity, App, AppContext,
   89    AsyncWindowContext, AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry,
   90    ClipboardItem, Context, DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter,
   91    FocusHandle, FocusOutEvent, Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla,
   92    KeyContext, Modifiers, MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render,
   93    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   94    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   95    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   96};
   97use highlight_matching_bracket::refresh_matching_bracket_highlights;
   98use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
   99pub use hover_popover::hover_markdown_style;
  100use hover_popover::{HoverState, hide_hover};
  101use indent_guides::ActiveIndentGuidesState;
  102use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  103pub use inline_completion::Direction;
  104use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  105pub use items::MAX_TAB_TITLE_LEN;
  106use itertools::Itertools;
  107use language::{
  108    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  109    CursorShape, DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText,
  110    IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection, SelectionGoal, TextObject,
  111    TransactionId, TreeSitterOptions, WordsQuery,
  112    language_settings::{
  113        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  114        all_language_settings, language_settings,
  115    },
  116    point_from_lsp, text_diff_with_options,
  117};
  118use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  119use linked_editing_ranges::refresh_linked_ranges;
  120use mouse_context_menu::MouseContextMenu;
  121use persistence::DB;
  122use project::{
  123    ProjectPath,
  124    debugger::{
  125        breakpoint_store::{
  126            BreakpointEditAction, BreakpointState, BreakpointStore, BreakpointStoreEvent,
  127        },
  128        session::{Session, SessionEvent},
  129    },
  130};
  131
  132pub use git::blame::BlameRenderer;
  133pub use proposed_changes_editor::{
  134    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  135};
  136use smallvec::smallvec;
  137use std::{cell::OnceCell, iter::Peekable};
  138use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  139
  140pub use lsp::CompletionContext;
  141use lsp::{
  142    CodeActionKind, CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity,
  143    InsertTextFormat, InsertTextMode, LanguageServerId, LanguageServerName,
  144};
  145
  146use language::BufferSnapshot;
  147pub use lsp_ext::lsp_tasks;
  148use movement::TextLayoutDetails;
  149pub use multi_buffer::{
  150    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  151    RowInfo, ToOffset, ToPoint,
  152};
  153use multi_buffer::{
  154    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  155    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  156};
  157use parking_lot::Mutex;
  158use project::{
  159    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  160    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  161    TaskSourceKind,
  162    debugger::breakpoint_store::Breakpoint,
  163    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  164    project_settings::{GitGutterSetting, ProjectSettings},
  165};
  166use rand::prelude::*;
  167use rpc::{ErrorExt, proto::*};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::SmallVec;
  175use snippet::Snippet;
  176use std::sync::Arc;
  177use std::{
  178    any::TypeId,
  179    borrow::Cow,
  180    cell::RefCell,
  181    cmp::{self, Ordering, Reverse},
  182    mem,
  183    num::NonZeroU32,
  184    ops::{ControlFlow, Deref, DerefMut, Not as _, Range, RangeInclusive},
  185    path::{Path, PathBuf},
  186    rc::Rc,
  187    time::{Duration, Instant},
  188};
  189pub use sum_tree::Bias;
  190use sum_tree::TreeMap;
  191use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  192use theme::{
  193    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  194    observe_buffer_font_size_adjustment,
  195};
  196use ui::{
  197    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  198    IconSize, Key, Tooltip, h_flex, prelude::*,
  199};
  200use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  201use workspace::{
  202    Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  203    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  204    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  205    item::{ItemHandle, PreviewTabsSettings},
  206    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  207    searchable::SearchEvent,
  208};
  209
  210use crate::hover_links::{find_url, find_url_from_range};
  211use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  212
  213pub const FILE_HEADER_HEIGHT: u32 = 2;
  214pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  215pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  216const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  217const MAX_LINE_LEN: usize = 1024;
  218const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  219const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  220pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  221#[doc(hidden)]
  222pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  223const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  224
  225pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  226pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  227pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  228
  229pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  230pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  231pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  232
  233pub type RenderDiffHunkControlsFn = Arc<
  234    dyn Fn(
  235        u32,
  236        &DiffHunkStatus,
  237        Range<Anchor>,
  238        bool,
  239        Pixels,
  240        &Entity<Editor>,
  241        &mut Window,
  242        &mut App,
  243    ) -> AnyElement,
  244>;
  245
  246const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  247    alt: true,
  248    shift: true,
  249    control: false,
  250    platform: false,
  251    function: false,
  252};
  253
  254struct InlineValueCache {
  255    enabled: bool,
  256    inlays: Vec<InlayId>,
  257    refresh_task: Task<Option<()>>,
  258}
  259
  260impl InlineValueCache {
  261    fn new(enabled: bool) -> Self {
  262        Self {
  263            enabled,
  264            inlays: Vec::new(),
  265            refresh_task: Task::ready(None),
  266        }
  267    }
  268}
  269
  270#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  271pub enum InlayId {
  272    InlineCompletion(usize),
  273    Hint(usize),
  274    DebuggerValue(usize),
  275}
  276
  277impl InlayId {
  278    fn id(&self) -> usize {
  279        match self {
  280            Self::InlineCompletion(id) => *id,
  281            Self::Hint(id) => *id,
  282            Self::DebuggerValue(id) => *id,
  283        }
  284    }
  285}
  286
  287pub enum DebugCurrentRowHighlight {}
  288enum DocumentHighlightRead {}
  289enum DocumentHighlightWrite {}
  290enum InputComposition {}
  291enum SelectedTextHighlight {}
  292
  293pub enum ConflictsOuter {}
  294pub enum ConflictsOurs {}
  295pub enum ConflictsTheirs {}
  296pub enum ConflictsOursMarker {}
  297pub enum ConflictsTheirsMarker {}
  298
  299#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  300pub enum Navigated {
  301    Yes,
  302    No,
  303}
  304
  305impl Navigated {
  306    pub fn from_bool(yes: bool) -> Navigated {
  307        if yes { Navigated::Yes } else { Navigated::No }
  308    }
  309}
  310
  311#[derive(Debug, Clone, PartialEq, Eq)]
  312enum DisplayDiffHunk {
  313    Folded {
  314        display_row: DisplayRow,
  315    },
  316    Unfolded {
  317        is_created_file: bool,
  318        diff_base_byte_range: Range<usize>,
  319        display_row_range: Range<DisplayRow>,
  320        multi_buffer_range: Range<Anchor>,
  321        status: DiffHunkStatus,
  322    },
  323}
  324
  325pub enum HideMouseCursorOrigin {
  326    TypingAction,
  327    MovementAction,
  328}
  329
  330pub fn init_settings(cx: &mut App) {
  331    EditorSettings::register(cx);
  332}
  333
  334pub fn init(cx: &mut App) {
  335    init_settings(cx);
  336
  337    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  338
  339    workspace::register_project_item::<Editor>(cx);
  340    workspace::FollowableViewRegistry::register::<Editor>(cx);
  341    workspace::register_serializable_item::<Editor>(cx);
  342
  343    cx.observe_new(
  344        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  345            workspace.register_action(Editor::new_file);
  346            workspace.register_action(Editor::new_file_vertical);
  347            workspace.register_action(Editor::new_file_horizontal);
  348            workspace.register_action(Editor::cancel_language_server_work);
  349        },
  350    )
  351    .detach();
  352
  353    cx.on_action(move |_: &workspace::NewFile, cx| {
  354        let app_state = workspace::AppState::global(cx);
  355        if let Some(app_state) = app_state.upgrade() {
  356            workspace::open_new(
  357                Default::default(),
  358                app_state,
  359                cx,
  360                |workspace, window, cx| {
  361                    Editor::new_file(workspace, &Default::default(), window, cx)
  362                },
  363            )
  364            .detach();
  365        }
  366    });
  367    cx.on_action(move |_: &workspace::NewWindow, cx| {
  368        let app_state = workspace::AppState::global(cx);
  369        if let Some(app_state) = app_state.upgrade() {
  370            workspace::open_new(
  371                Default::default(),
  372                app_state,
  373                cx,
  374                |workspace, window, cx| {
  375                    cx.activate(true);
  376                    Editor::new_file(workspace, &Default::default(), window, cx)
  377                },
  378            )
  379            .detach();
  380        }
  381    });
  382}
  383
  384pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  385    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  386}
  387
  388pub trait DiagnosticRenderer {
  389    fn render_group(
  390        &self,
  391        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  392        buffer_id: BufferId,
  393        snapshot: EditorSnapshot,
  394        editor: WeakEntity<Editor>,
  395        cx: &mut App,
  396    ) -> Vec<BlockProperties<Anchor>>;
  397
  398    fn render_hover(
  399        &self,
  400        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  401        range: Range<Point>,
  402        buffer_id: BufferId,
  403        cx: &mut App,
  404    ) -> Option<Entity<markdown::Markdown>>;
  405
  406    fn open_link(
  407        &self,
  408        editor: &mut Editor,
  409        link: SharedString,
  410        window: &mut Window,
  411        cx: &mut Context<Editor>,
  412    );
  413}
  414
  415pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  416
  417impl GlobalDiagnosticRenderer {
  418    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  419        cx.try_global::<Self>().map(|g| g.0.clone())
  420    }
  421}
  422
  423impl gpui::Global for GlobalDiagnosticRenderer {}
  424pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  425    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  426}
  427
  428pub struct SearchWithinRange;
  429
  430trait InvalidationRegion {
  431    fn ranges(&self) -> &[Range<Anchor>];
  432}
  433
  434#[derive(Clone, Debug, PartialEq)]
  435pub enum SelectPhase {
  436    Begin {
  437        position: DisplayPoint,
  438        add: bool,
  439        click_count: usize,
  440    },
  441    BeginColumnar {
  442        position: DisplayPoint,
  443        reset: bool,
  444        goal_column: u32,
  445    },
  446    Extend {
  447        position: DisplayPoint,
  448        click_count: usize,
  449    },
  450    Update {
  451        position: DisplayPoint,
  452        goal_column: u32,
  453        scroll_delta: gpui::Point<f32>,
  454    },
  455    End,
  456}
  457
  458#[derive(Clone, Debug)]
  459pub enum SelectMode {
  460    Character,
  461    Word(Range<Anchor>),
  462    Line(Range<Anchor>),
  463    All,
  464}
  465
  466#[derive(Copy, Clone, PartialEq, Eq, Debug)]
  467pub enum EditorMode {
  468    SingleLine {
  469        auto_width: bool,
  470    },
  471    AutoHeight {
  472        max_lines: usize,
  473    },
  474    Full {
  475        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  476        scale_ui_elements_with_buffer_font_size: bool,
  477        /// When set to `true`, the editor will render a background for the active line.
  478        show_active_line_background: bool,
  479        /// When set to `true`, the editor's height will be determined by its content.
  480        sized_by_content: bool,
  481    },
  482}
  483
  484impl EditorMode {
  485    pub fn full() -> Self {
  486        Self::Full {
  487            scale_ui_elements_with_buffer_font_size: true,
  488            show_active_line_background: true,
  489            sized_by_content: false,
  490        }
  491    }
  492
  493    pub fn is_full(&self) -> bool {
  494        matches!(self, Self::Full { .. })
  495    }
  496}
  497
  498#[derive(Copy, Clone, Debug)]
  499pub enum SoftWrap {
  500    /// Prefer not to wrap at all.
  501    ///
  502    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  503    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  504    GitDiff,
  505    /// Prefer a single line generally, unless an overly long line is encountered.
  506    None,
  507    /// Soft wrap lines that exceed the editor width.
  508    EditorWidth,
  509    /// Soft wrap lines at the preferred line length.
  510    Column(u32),
  511    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  512    Bounded(u32),
  513}
  514
  515#[derive(Clone)]
  516pub struct EditorStyle {
  517    pub background: Hsla,
  518    pub local_player: PlayerColor,
  519    pub text: TextStyle,
  520    pub scrollbar_width: Pixels,
  521    pub syntax: Arc<SyntaxTheme>,
  522    pub status: StatusColors,
  523    pub inlay_hints_style: HighlightStyle,
  524    pub inline_completion_styles: InlineCompletionStyles,
  525    pub unnecessary_code_fade: f32,
  526}
  527
  528impl Default for EditorStyle {
  529    fn default() -> Self {
  530        Self {
  531            background: Hsla::default(),
  532            local_player: PlayerColor::default(),
  533            text: TextStyle::default(),
  534            scrollbar_width: Pixels::default(),
  535            syntax: Default::default(),
  536            // HACK: Status colors don't have a real default.
  537            // We should look into removing the status colors from the editor
  538            // style and retrieve them directly from the theme.
  539            status: StatusColors::dark(),
  540            inlay_hints_style: HighlightStyle::default(),
  541            inline_completion_styles: InlineCompletionStyles {
  542                insertion: HighlightStyle::default(),
  543                whitespace: HighlightStyle::default(),
  544            },
  545            unnecessary_code_fade: Default::default(),
  546        }
  547    }
  548}
  549
  550pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  551    let show_background = language_settings::language_settings(None, None, cx)
  552        .inlay_hints
  553        .show_background;
  554
  555    HighlightStyle {
  556        color: Some(cx.theme().status().hint),
  557        background_color: show_background.then(|| cx.theme().status().hint_background),
  558        ..HighlightStyle::default()
  559    }
  560}
  561
  562pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  563    InlineCompletionStyles {
  564        insertion: HighlightStyle {
  565            color: Some(cx.theme().status().predictive),
  566            ..HighlightStyle::default()
  567        },
  568        whitespace: HighlightStyle {
  569            background_color: Some(cx.theme().status().created_background),
  570            ..HighlightStyle::default()
  571        },
  572    }
  573}
  574
  575type CompletionId = usize;
  576
  577pub(crate) enum EditDisplayMode {
  578    TabAccept,
  579    DiffPopover,
  580    Inline,
  581}
  582
  583enum InlineCompletion {
  584    Edit {
  585        edits: Vec<(Range<Anchor>, String)>,
  586        edit_preview: Option<EditPreview>,
  587        display_mode: EditDisplayMode,
  588        snapshot: BufferSnapshot,
  589    },
  590    Move {
  591        target: Anchor,
  592        snapshot: BufferSnapshot,
  593    },
  594}
  595
  596struct InlineCompletionState {
  597    inlay_ids: Vec<InlayId>,
  598    completion: InlineCompletion,
  599    completion_id: Option<SharedString>,
  600    invalidation_range: Range<Anchor>,
  601}
  602
  603enum EditPredictionSettings {
  604    Disabled,
  605    Enabled {
  606        show_in_menu: bool,
  607        preview_requires_modifier: bool,
  608    },
  609}
  610
  611enum InlineCompletionHighlight {}
  612
  613#[derive(Debug, Clone)]
  614struct InlineDiagnostic {
  615    message: SharedString,
  616    group_id: usize,
  617    is_primary: bool,
  618    start: Point,
  619    severity: DiagnosticSeverity,
  620}
  621
  622pub enum MenuInlineCompletionsPolicy {
  623    Never,
  624    ByProvider,
  625}
  626
  627pub enum EditPredictionPreview {
  628    /// Modifier is not pressed
  629    Inactive { released_too_fast: bool },
  630    /// Modifier pressed
  631    Active {
  632        since: Instant,
  633        previous_scroll_position: Option<ScrollAnchor>,
  634    },
  635}
  636
  637impl EditPredictionPreview {
  638    pub fn released_too_fast(&self) -> bool {
  639        match self {
  640            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  641            EditPredictionPreview::Active { .. } => false,
  642        }
  643    }
  644
  645    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  646        if let EditPredictionPreview::Active {
  647            previous_scroll_position,
  648            ..
  649        } = self
  650        {
  651            *previous_scroll_position = scroll_position;
  652        }
  653    }
  654}
  655
  656pub struct ContextMenuOptions {
  657    pub min_entries_visible: usize,
  658    pub max_entries_visible: usize,
  659    pub placement: Option<ContextMenuPlacement>,
  660}
  661
  662#[derive(Debug, Clone, PartialEq, Eq)]
  663pub enum ContextMenuPlacement {
  664    Above,
  665    Below,
  666}
  667
  668#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  669struct EditorActionId(usize);
  670
  671impl EditorActionId {
  672    pub fn post_inc(&mut self) -> Self {
  673        let answer = self.0;
  674
  675        *self = Self(answer + 1);
  676
  677        Self(answer)
  678    }
  679}
  680
  681// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  682// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  683
  684type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  685type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  686
  687#[derive(Default)]
  688struct ScrollbarMarkerState {
  689    scrollbar_size: Size<Pixels>,
  690    dirty: bool,
  691    markers: Arc<[PaintQuad]>,
  692    pending_refresh: Option<Task<Result<()>>>,
  693}
  694
  695impl ScrollbarMarkerState {
  696    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  697        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  698    }
  699}
  700
  701#[derive(Clone, Debug)]
  702struct RunnableTasks {
  703    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  704    offset: multi_buffer::Anchor,
  705    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  706    column: u32,
  707    // Values of all named captures, including those starting with '_'
  708    extra_variables: HashMap<String, String>,
  709    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  710    context_range: Range<BufferOffset>,
  711}
  712
  713impl RunnableTasks {
  714    fn resolve<'a>(
  715        &'a self,
  716        cx: &'a task::TaskContext,
  717    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  718        self.templates.iter().filter_map(|(kind, template)| {
  719            template
  720                .resolve_task(&kind.to_id_base(), cx)
  721                .map(|task| (kind.clone(), task))
  722        })
  723    }
  724}
  725
  726#[derive(Clone)]
  727struct ResolvedTasks {
  728    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  729    position: Anchor,
  730}
  731
  732#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  733struct BufferOffset(usize);
  734
  735// Addons allow storing per-editor state in other crates (e.g. Vim)
  736pub trait Addon: 'static {
  737    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  738
  739    fn render_buffer_header_controls(
  740        &self,
  741        _: &ExcerptInfo,
  742        _: &Window,
  743        _: &App,
  744    ) -> Option<AnyElement> {
  745        None
  746    }
  747
  748    fn to_any(&self) -> &dyn std::any::Any;
  749
  750    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  751        None
  752    }
  753}
  754
  755/// A set of caret positions, registered when the editor was edited.
  756pub struct ChangeList {
  757    changes: Vec<Vec<Anchor>>,
  758    /// Currently "selected" change.
  759    position: Option<usize>,
  760}
  761
  762impl ChangeList {
  763    pub fn new() -> Self {
  764        Self {
  765            changes: Vec::new(),
  766            position: None,
  767        }
  768    }
  769
  770    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  771    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  772    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  773        if self.changes.is_empty() {
  774            return None;
  775        }
  776
  777        let prev = self.position.unwrap_or(self.changes.len());
  778        let next = if direction == Direction::Prev {
  779            prev.saturating_sub(count)
  780        } else {
  781            (prev + count).min(self.changes.len() - 1)
  782        };
  783        self.position = Some(next);
  784        self.changes.get(next).map(|anchors| anchors.as_slice())
  785    }
  786
  787    /// Adds a new change to the list, resetting the change list position.
  788    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  789        self.position.take();
  790        if pop_state {
  791            self.changes.pop();
  792        }
  793        self.changes.push(new_positions.clone());
  794    }
  795
  796    pub fn last(&self) -> Option<&[Anchor]> {
  797        self.changes.last().map(|anchors| anchors.as_slice())
  798    }
  799}
  800
  801/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  802///
  803/// See the [module level documentation](self) for more information.
  804pub struct Editor {
  805    focus_handle: FocusHandle,
  806    last_focused_descendant: Option<WeakFocusHandle>,
  807    /// The text buffer being edited
  808    buffer: Entity<MultiBuffer>,
  809    /// Map of how text in the buffer should be displayed.
  810    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  811    pub display_map: Entity<DisplayMap>,
  812    pub selections: SelectionsCollection,
  813    pub scroll_manager: ScrollManager,
  814    /// When inline assist editors are linked, they all render cursors because
  815    /// typing enters text into each of them, even the ones that aren't focused.
  816    pub(crate) show_cursor_when_unfocused: bool,
  817    columnar_selection_tail: Option<Anchor>,
  818    add_selections_state: Option<AddSelectionsState>,
  819    select_next_state: Option<SelectNextState>,
  820    select_prev_state: Option<SelectNextState>,
  821    selection_history: SelectionHistory,
  822    autoclose_regions: Vec<AutocloseRegion>,
  823    snippet_stack: InvalidationStack<SnippetState>,
  824    select_syntax_node_history: SelectSyntaxNodeHistory,
  825    ime_transaction: Option<TransactionId>,
  826    active_diagnostics: ActiveDiagnostic,
  827    show_inline_diagnostics: bool,
  828    inline_diagnostics_update: Task<()>,
  829    inline_diagnostics_enabled: bool,
  830    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  831    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  832    hard_wrap: Option<usize>,
  833
  834    // TODO: make this a access method
  835    pub project: Option<Entity<Project>>,
  836    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  837    completion_provider: Option<Box<dyn CompletionProvider>>,
  838    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  839    blink_manager: Entity<BlinkManager>,
  840    show_cursor_names: bool,
  841    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  842    pub show_local_selections: bool,
  843    mode: EditorMode,
  844    show_breadcrumbs: bool,
  845    show_gutter: bool,
  846    show_scrollbars: bool,
  847    disable_scrolling: bool,
  848    disable_expand_excerpt_buttons: bool,
  849    show_line_numbers: Option<bool>,
  850    use_relative_line_numbers: Option<bool>,
  851    show_git_diff_gutter: Option<bool>,
  852    show_code_actions: Option<bool>,
  853    show_runnables: Option<bool>,
  854    show_breakpoints: Option<bool>,
  855    show_wrap_guides: Option<bool>,
  856    show_indent_guides: Option<bool>,
  857    placeholder_text: Option<Arc<str>>,
  858    highlight_order: usize,
  859    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  860    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  861    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  862    scrollbar_marker_state: ScrollbarMarkerState,
  863    active_indent_guides_state: ActiveIndentGuidesState,
  864    nav_history: Option<ItemNavHistory>,
  865    context_menu: RefCell<Option<CodeContextMenu>>,
  866    context_menu_options: Option<ContextMenuOptions>,
  867    mouse_context_menu: Option<MouseContextMenu>,
  868    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  869    signature_help_state: SignatureHelpState,
  870    auto_signature_help: Option<bool>,
  871    find_all_references_task_sources: Vec<Anchor>,
  872    next_completion_id: CompletionId,
  873    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  874    code_actions_task: Option<Task<Result<()>>>,
  875    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  876    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  877    document_highlights_task: Option<Task<()>>,
  878    linked_editing_range_task: Option<Task<Option<()>>>,
  879    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  880    pending_rename: Option<RenameState>,
  881    searchable: bool,
  882    cursor_shape: CursorShape,
  883    current_line_highlight: Option<CurrentLineHighlight>,
  884    collapse_matches: bool,
  885    autoindent_mode: Option<AutoindentMode>,
  886    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  887    input_enabled: bool,
  888    use_modal_editing: bool,
  889    read_only: bool,
  890    leader_peer_id: Option<PeerId>,
  891    remote_id: Option<ViewId>,
  892    pub hover_state: HoverState,
  893    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  894    gutter_hovered: bool,
  895    hovered_link_state: Option<HoveredLinkState>,
  896    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  897    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  898    active_inline_completion: Option<InlineCompletionState>,
  899    /// Used to prevent flickering as the user types while the menu is open
  900    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  901    edit_prediction_settings: EditPredictionSettings,
  902    inline_completions_hidden_for_vim_mode: bool,
  903    show_inline_completions_override: Option<bool>,
  904    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  905    edit_prediction_preview: EditPredictionPreview,
  906    edit_prediction_indent_conflict: bool,
  907    edit_prediction_requires_modifier_in_indent_conflict: bool,
  908    inlay_hint_cache: InlayHintCache,
  909    next_inlay_id: usize,
  910    _subscriptions: Vec<Subscription>,
  911    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  912    gutter_dimensions: GutterDimensions,
  913    style: Option<EditorStyle>,
  914    text_style_refinement: Option<TextStyleRefinement>,
  915    next_editor_action_id: EditorActionId,
  916    editor_actions:
  917        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  918    use_autoclose: bool,
  919    use_auto_surround: bool,
  920    auto_replace_emoji_shortcode: bool,
  921    jsx_tag_auto_close_enabled_in_any_buffer: bool,
  922    show_git_blame_gutter: bool,
  923    show_git_blame_inline: bool,
  924    show_git_blame_inline_delay_task: Option<Task<()>>,
  925    pub git_blame_inline_tooltip: Option<AnyWeakEntity>,
  926    git_blame_inline_enabled: bool,
  927    render_diff_hunk_controls: RenderDiffHunkControlsFn,
  928    serialize_dirty_buffers: bool,
  929    show_selection_menu: Option<bool>,
  930    blame: Option<Entity<GitBlame>>,
  931    blame_subscription: Option<Subscription>,
  932    custom_context_menu: Option<
  933        Box<
  934            dyn 'static
  935                + Fn(
  936                    &mut Self,
  937                    DisplayPoint,
  938                    &mut Window,
  939                    &mut Context<Self>,
  940                ) -> Option<Entity<ui::ContextMenu>>,
  941        >,
  942    >,
  943    last_bounds: Option<Bounds<Pixels>>,
  944    last_position_map: Option<Rc<PositionMap>>,
  945    expect_bounds_change: Option<Bounds<Pixels>>,
  946    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
  947    tasks_update_task: Option<Task<()>>,
  948    breakpoint_store: Option<Entity<BreakpointStore>>,
  949    /// Allow's a user to create a breakpoint by selecting this indicator
  950    /// It should be None while a user is not hovering over the gutter
  951    /// Otherwise it represents the point that the breakpoint will be shown
  952    gutter_breakpoint_indicator: (Option<(DisplayPoint, bool)>, Option<Task<()>>),
  953    in_project_search: bool,
  954    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
  955    breadcrumb_header: Option<String>,
  956    focused_block: Option<FocusedBlock>,
  957    next_scroll_position: NextScrollCursorCenterTopBottom,
  958    addons: HashMap<TypeId, Box<dyn Addon>>,
  959    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
  960    load_diff_task: Option<Shared<Task<()>>>,
  961    selection_mark_mode: bool,
  962    toggle_fold_multiple_buffers: Task<()>,
  963    _scroll_cursor_center_top_bottom_task: Task<()>,
  964    serialize_selections: Task<()>,
  965    serialize_folds: Task<()>,
  966    mouse_cursor_hidden: bool,
  967    hide_mouse_mode: HideMouseMode,
  968    pub change_list: ChangeList,
  969    inline_value_cache: InlineValueCache,
  970}
  971
  972#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
  973enum NextScrollCursorCenterTopBottom {
  974    #[default]
  975    Center,
  976    Top,
  977    Bottom,
  978}
  979
  980impl NextScrollCursorCenterTopBottom {
  981    fn next(&self) -> Self {
  982        match self {
  983            Self::Center => Self::Top,
  984            Self::Top => Self::Bottom,
  985            Self::Bottom => Self::Center,
  986        }
  987    }
  988}
  989
  990#[derive(Clone)]
  991pub struct EditorSnapshot {
  992    pub mode: EditorMode,
  993    show_gutter: bool,
  994    show_line_numbers: Option<bool>,
  995    show_git_diff_gutter: Option<bool>,
  996    show_code_actions: Option<bool>,
  997    show_runnables: Option<bool>,
  998    show_breakpoints: Option<bool>,
  999    git_blame_gutter_max_author_length: Option<usize>,
 1000    pub display_snapshot: DisplaySnapshot,
 1001    pub placeholder_text: Option<Arc<str>>,
 1002    is_focused: bool,
 1003    scroll_anchor: ScrollAnchor,
 1004    ongoing_scroll: OngoingScroll,
 1005    current_line_highlight: CurrentLineHighlight,
 1006    gutter_hovered: bool,
 1007}
 1008
 1009#[derive(Default, Debug, Clone, Copy)]
 1010pub struct GutterDimensions {
 1011    pub left_padding: Pixels,
 1012    pub right_padding: Pixels,
 1013    pub width: Pixels,
 1014    pub margin: Pixels,
 1015    pub git_blame_entries_width: Option<Pixels>,
 1016}
 1017
 1018impl GutterDimensions {
 1019    /// The full width of the space taken up by the gutter.
 1020    pub fn full_width(&self) -> Pixels {
 1021        self.margin + self.width
 1022    }
 1023
 1024    /// The width of the space reserved for the fold indicators,
 1025    /// use alongside 'justify_end' and `gutter_width` to
 1026    /// right align content with the line numbers
 1027    pub fn fold_area_width(&self) -> Pixels {
 1028        self.margin + self.right_padding
 1029    }
 1030}
 1031
 1032#[derive(Debug)]
 1033pub struct RemoteSelection {
 1034    pub replica_id: ReplicaId,
 1035    pub selection: Selection<Anchor>,
 1036    pub cursor_shape: CursorShape,
 1037    pub peer_id: PeerId,
 1038    pub line_mode: bool,
 1039    pub participant_index: Option<ParticipantIndex>,
 1040    pub user_name: Option<SharedString>,
 1041}
 1042
 1043#[derive(Clone, Debug)]
 1044struct SelectionHistoryEntry {
 1045    selections: Arc<[Selection<Anchor>]>,
 1046    select_next_state: Option<SelectNextState>,
 1047    select_prev_state: Option<SelectNextState>,
 1048    add_selections_state: Option<AddSelectionsState>,
 1049}
 1050
 1051enum SelectionHistoryMode {
 1052    Normal,
 1053    Undoing,
 1054    Redoing,
 1055}
 1056
 1057#[derive(Clone, PartialEq, Eq, Hash)]
 1058struct HoveredCursor {
 1059    replica_id: u16,
 1060    selection_id: usize,
 1061}
 1062
 1063impl Default for SelectionHistoryMode {
 1064    fn default() -> Self {
 1065        Self::Normal
 1066    }
 1067}
 1068
 1069#[derive(Default)]
 1070struct SelectionHistory {
 1071    #[allow(clippy::type_complexity)]
 1072    selections_by_transaction:
 1073        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1074    mode: SelectionHistoryMode,
 1075    undo_stack: VecDeque<SelectionHistoryEntry>,
 1076    redo_stack: VecDeque<SelectionHistoryEntry>,
 1077}
 1078
 1079impl SelectionHistory {
 1080    fn insert_transaction(
 1081        &mut self,
 1082        transaction_id: TransactionId,
 1083        selections: Arc<[Selection<Anchor>]>,
 1084    ) {
 1085        self.selections_by_transaction
 1086            .insert(transaction_id, (selections, None));
 1087    }
 1088
 1089    #[allow(clippy::type_complexity)]
 1090    fn transaction(
 1091        &self,
 1092        transaction_id: TransactionId,
 1093    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1094        self.selections_by_transaction.get(&transaction_id)
 1095    }
 1096
 1097    #[allow(clippy::type_complexity)]
 1098    fn transaction_mut(
 1099        &mut self,
 1100        transaction_id: TransactionId,
 1101    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1102        self.selections_by_transaction.get_mut(&transaction_id)
 1103    }
 1104
 1105    fn push(&mut self, entry: SelectionHistoryEntry) {
 1106        if !entry.selections.is_empty() {
 1107            match self.mode {
 1108                SelectionHistoryMode::Normal => {
 1109                    self.push_undo(entry);
 1110                    self.redo_stack.clear();
 1111                }
 1112                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1113                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1114            }
 1115        }
 1116    }
 1117
 1118    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1119        if self
 1120            .undo_stack
 1121            .back()
 1122            .map_or(true, |e| e.selections != entry.selections)
 1123        {
 1124            self.undo_stack.push_back(entry);
 1125            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1126                self.undo_stack.pop_front();
 1127            }
 1128        }
 1129    }
 1130
 1131    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1132        if self
 1133            .redo_stack
 1134            .back()
 1135            .map_or(true, |e| e.selections != entry.selections)
 1136        {
 1137            self.redo_stack.push_back(entry);
 1138            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1139                self.redo_stack.pop_front();
 1140            }
 1141        }
 1142    }
 1143}
 1144
 1145#[derive(Clone, Copy)]
 1146pub struct RowHighlightOptions {
 1147    pub autoscroll: bool,
 1148    pub include_gutter: bool,
 1149}
 1150
 1151impl Default for RowHighlightOptions {
 1152    fn default() -> Self {
 1153        Self {
 1154            autoscroll: Default::default(),
 1155            include_gutter: true,
 1156        }
 1157    }
 1158}
 1159
 1160struct RowHighlight {
 1161    index: usize,
 1162    range: Range<Anchor>,
 1163    color: Hsla,
 1164    options: RowHighlightOptions,
 1165    type_id: TypeId,
 1166}
 1167
 1168#[derive(Clone, Debug)]
 1169struct AddSelectionsState {
 1170    above: bool,
 1171    stack: Vec<usize>,
 1172}
 1173
 1174#[derive(Clone)]
 1175struct SelectNextState {
 1176    query: AhoCorasick,
 1177    wordwise: bool,
 1178    done: bool,
 1179}
 1180
 1181impl std::fmt::Debug for SelectNextState {
 1182    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1183        f.debug_struct(std::any::type_name::<Self>())
 1184            .field("wordwise", &self.wordwise)
 1185            .field("done", &self.done)
 1186            .finish()
 1187    }
 1188}
 1189
 1190#[derive(Debug)]
 1191struct AutocloseRegion {
 1192    selection_id: usize,
 1193    range: Range<Anchor>,
 1194    pair: BracketPair,
 1195}
 1196
 1197#[derive(Debug)]
 1198struct SnippetState {
 1199    ranges: Vec<Vec<Range<Anchor>>>,
 1200    active_index: usize,
 1201    choices: Vec<Option<Vec<String>>>,
 1202}
 1203
 1204#[doc(hidden)]
 1205pub struct RenameState {
 1206    pub range: Range<Anchor>,
 1207    pub old_name: Arc<str>,
 1208    pub editor: Entity<Editor>,
 1209    block_id: CustomBlockId,
 1210}
 1211
 1212struct InvalidationStack<T>(Vec<T>);
 1213
 1214struct RegisteredInlineCompletionProvider {
 1215    provider: Arc<dyn InlineCompletionProviderHandle>,
 1216    _subscription: Subscription,
 1217}
 1218
 1219#[derive(Debug, PartialEq, Eq)]
 1220pub struct ActiveDiagnosticGroup {
 1221    pub active_range: Range<Anchor>,
 1222    pub active_message: String,
 1223    pub group_id: usize,
 1224    pub blocks: HashSet<CustomBlockId>,
 1225}
 1226
 1227#[derive(Debug, PartialEq, Eq)]
 1228#[allow(clippy::large_enum_variant)]
 1229pub(crate) enum ActiveDiagnostic {
 1230    None,
 1231    All,
 1232    Group(ActiveDiagnosticGroup),
 1233}
 1234
 1235#[derive(Serialize, Deserialize, Clone, Debug)]
 1236pub struct ClipboardSelection {
 1237    /// The number of bytes in this selection.
 1238    pub len: usize,
 1239    /// Whether this was a full-line selection.
 1240    pub is_entire_line: bool,
 1241    /// The indentation of the first line when this content was originally copied.
 1242    pub first_line_indent: u32,
 1243}
 1244
 1245// selections, scroll behavior, was newest selection reversed
 1246type SelectSyntaxNodeHistoryState = (
 1247    Box<[Selection<usize>]>,
 1248    SelectSyntaxNodeScrollBehavior,
 1249    bool,
 1250);
 1251
 1252#[derive(Default)]
 1253struct SelectSyntaxNodeHistory {
 1254    stack: Vec<SelectSyntaxNodeHistoryState>,
 1255    // disable temporarily to allow changing selections without losing the stack
 1256    pub disable_clearing: bool,
 1257}
 1258
 1259impl SelectSyntaxNodeHistory {
 1260    pub fn try_clear(&mut self) {
 1261        if !self.disable_clearing {
 1262            self.stack.clear();
 1263        }
 1264    }
 1265
 1266    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1267        self.stack.push(selection);
 1268    }
 1269
 1270    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1271        self.stack.pop()
 1272    }
 1273}
 1274
 1275enum SelectSyntaxNodeScrollBehavior {
 1276    CursorTop,
 1277    FitSelection,
 1278    CursorBottom,
 1279}
 1280
 1281#[derive(Debug)]
 1282pub(crate) struct NavigationData {
 1283    cursor_anchor: Anchor,
 1284    cursor_position: Point,
 1285    scroll_anchor: ScrollAnchor,
 1286    scroll_top_row: u32,
 1287}
 1288
 1289#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1290pub enum GotoDefinitionKind {
 1291    Symbol,
 1292    Declaration,
 1293    Type,
 1294    Implementation,
 1295}
 1296
 1297#[derive(Debug, Clone)]
 1298enum InlayHintRefreshReason {
 1299    ModifiersChanged(bool),
 1300    Toggle(bool),
 1301    SettingsChange(InlayHintSettings),
 1302    NewLinesShown,
 1303    BufferEdited(HashSet<Arc<Language>>),
 1304    RefreshRequested,
 1305    ExcerptsRemoved(Vec<ExcerptId>),
 1306}
 1307
 1308impl InlayHintRefreshReason {
 1309    fn description(&self) -> &'static str {
 1310        match self {
 1311            Self::ModifiersChanged(_) => "modifiers changed",
 1312            Self::Toggle(_) => "toggle",
 1313            Self::SettingsChange(_) => "settings change",
 1314            Self::NewLinesShown => "new lines shown",
 1315            Self::BufferEdited(_) => "buffer edited",
 1316            Self::RefreshRequested => "refresh requested",
 1317            Self::ExcerptsRemoved(_) => "excerpts removed",
 1318        }
 1319    }
 1320}
 1321
 1322pub enum FormatTarget {
 1323    Buffers,
 1324    Ranges(Vec<Range<MultiBufferPoint>>),
 1325}
 1326
 1327pub(crate) struct FocusedBlock {
 1328    id: BlockId,
 1329    focus_handle: WeakFocusHandle,
 1330}
 1331
 1332#[derive(Clone)]
 1333enum JumpData {
 1334    MultiBufferRow {
 1335        row: MultiBufferRow,
 1336        line_offset_from_top: u32,
 1337    },
 1338    MultiBufferPoint {
 1339        excerpt_id: ExcerptId,
 1340        position: Point,
 1341        anchor: text::Anchor,
 1342        line_offset_from_top: u32,
 1343    },
 1344}
 1345
 1346pub enum MultibufferSelectionMode {
 1347    First,
 1348    All,
 1349}
 1350
 1351#[derive(Clone, Copy, Debug, Default)]
 1352pub struct RewrapOptions {
 1353    pub override_language_settings: bool,
 1354    pub preserve_existing_whitespace: bool,
 1355}
 1356
 1357impl Editor {
 1358    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1359        let buffer = cx.new(|cx| Buffer::local("", cx));
 1360        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1361        Self::new(
 1362            EditorMode::SingleLine { auto_width: false },
 1363            buffer,
 1364            None,
 1365            window,
 1366            cx,
 1367        )
 1368    }
 1369
 1370    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1371        let buffer = cx.new(|cx| Buffer::local("", cx));
 1372        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1373        Self::new(EditorMode::full(), buffer, None, window, cx)
 1374    }
 1375
 1376    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1377        let buffer = cx.new(|cx| Buffer::local("", cx));
 1378        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1379        Self::new(
 1380            EditorMode::SingleLine { auto_width: true },
 1381            buffer,
 1382            None,
 1383            window,
 1384            cx,
 1385        )
 1386    }
 1387
 1388    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1389        let buffer = cx.new(|cx| Buffer::local("", cx));
 1390        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1391        Self::new(
 1392            EditorMode::AutoHeight { max_lines },
 1393            buffer,
 1394            None,
 1395            window,
 1396            cx,
 1397        )
 1398    }
 1399
 1400    pub fn for_buffer(
 1401        buffer: Entity<Buffer>,
 1402        project: Option<Entity<Project>>,
 1403        window: &mut Window,
 1404        cx: &mut Context<Self>,
 1405    ) -> Self {
 1406        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1407        Self::new(EditorMode::full(), buffer, project, window, cx)
 1408    }
 1409
 1410    pub fn for_multibuffer(
 1411        buffer: Entity<MultiBuffer>,
 1412        project: Option<Entity<Project>>,
 1413        window: &mut Window,
 1414        cx: &mut Context<Self>,
 1415    ) -> Self {
 1416        Self::new(EditorMode::full(), buffer, project, window, cx)
 1417    }
 1418
 1419    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1420        let mut clone = Self::new(
 1421            self.mode,
 1422            self.buffer.clone(),
 1423            self.project.clone(),
 1424            window,
 1425            cx,
 1426        );
 1427        self.display_map.update(cx, |display_map, cx| {
 1428            let snapshot = display_map.snapshot(cx);
 1429            clone.display_map.update(cx, |display_map, cx| {
 1430                display_map.set_state(&snapshot, cx);
 1431            });
 1432        });
 1433        clone.folds_did_change(cx);
 1434        clone.selections.clone_state(&self.selections);
 1435        clone.scroll_manager.clone_state(&self.scroll_manager);
 1436        clone.searchable = self.searchable;
 1437        clone.read_only = self.read_only;
 1438        clone
 1439    }
 1440
 1441    pub fn new(
 1442        mode: EditorMode,
 1443        buffer: Entity<MultiBuffer>,
 1444        project: Option<Entity<Project>>,
 1445        window: &mut Window,
 1446        cx: &mut Context<Self>,
 1447    ) -> Self {
 1448        let style = window.text_style();
 1449        let font_size = style.font_size.to_pixels(window.rem_size());
 1450        let editor = cx.entity().downgrade();
 1451        let fold_placeholder = FoldPlaceholder {
 1452            constrain_width: true,
 1453            render: Arc::new(move |fold_id, fold_range, cx| {
 1454                let editor = editor.clone();
 1455                div()
 1456                    .id(fold_id)
 1457                    .bg(cx.theme().colors().ghost_element_background)
 1458                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1459                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1460                    .rounded_xs()
 1461                    .size_full()
 1462                    .cursor_pointer()
 1463                    .child("")
 1464                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1465                    .on_click(move |_, _window, cx| {
 1466                        editor
 1467                            .update(cx, |editor, cx| {
 1468                                editor.unfold_ranges(
 1469                                    &[fold_range.start..fold_range.end],
 1470                                    true,
 1471                                    false,
 1472                                    cx,
 1473                                );
 1474                                cx.stop_propagation();
 1475                            })
 1476                            .ok();
 1477                    })
 1478                    .into_any()
 1479            }),
 1480            merge_adjacent: true,
 1481            ..Default::default()
 1482        };
 1483        let display_map = cx.new(|cx| {
 1484            DisplayMap::new(
 1485                buffer.clone(),
 1486                style.font(),
 1487                font_size,
 1488                None,
 1489                FILE_HEADER_HEIGHT,
 1490                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1491                fold_placeholder,
 1492                cx,
 1493            )
 1494        });
 1495
 1496        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1497
 1498        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1499
 1500        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1501            .then(|| language_settings::SoftWrap::None);
 1502
 1503        let mut project_subscriptions = Vec::new();
 1504        if mode.is_full() {
 1505            if let Some(project) = project.as_ref() {
 1506                project_subscriptions.push(cx.subscribe_in(
 1507                    project,
 1508                    window,
 1509                    |editor, _, event, window, cx| match event {
 1510                        project::Event::RefreshCodeLens => {
 1511                            // we always query lens with actions, without storing them, always refreshing them
 1512                        }
 1513                        project::Event::RefreshInlayHints => {
 1514                            editor
 1515                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1516                        }
 1517                        project::Event::SnippetEdit(id, snippet_edits) => {
 1518                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1519                                let focus_handle = editor.focus_handle(cx);
 1520                                if focus_handle.is_focused(window) {
 1521                                    let snapshot = buffer.read(cx).snapshot();
 1522                                    for (range, snippet) in snippet_edits {
 1523                                        let editor_range =
 1524                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1525                                        editor
 1526                                            .insert_snippet(
 1527                                                &[editor_range],
 1528                                                snippet.clone(),
 1529                                                window,
 1530                                                cx,
 1531                                            )
 1532                                            .ok();
 1533                                    }
 1534                                }
 1535                            }
 1536                        }
 1537                        _ => {}
 1538                    },
 1539                ));
 1540                if let Some(task_inventory) = project
 1541                    .read(cx)
 1542                    .task_store()
 1543                    .read(cx)
 1544                    .task_inventory()
 1545                    .cloned()
 1546                {
 1547                    project_subscriptions.push(cx.observe_in(
 1548                        &task_inventory,
 1549                        window,
 1550                        |editor, _, window, cx| {
 1551                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1552                        },
 1553                    ));
 1554                };
 1555
 1556                project_subscriptions.push(cx.subscribe_in(
 1557                    &project.read(cx).breakpoint_store(),
 1558                    window,
 1559                    |editor, _, event, window, cx| match event {
 1560                        BreakpointStoreEvent::ActiveDebugLineChanged => {
 1561                            if editor.go_to_active_debug_line(window, cx) {
 1562                                cx.stop_propagation();
 1563                            }
 1564
 1565                            editor.refresh_inline_values(cx);
 1566                        }
 1567                        _ => {}
 1568                    },
 1569                ));
 1570            }
 1571        }
 1572
 1573        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1574
 1575        let inlay_hint_settings =
 1576            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1577        let focus_handle = cx.focus_handle();
 1578        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1579            .detach();
 1580        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1581            .detach();
 1582        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1583            .detach();
 1584        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1585            .detach();
 1586
 1587        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1588            Some(false)
 1589        } else {
 1590            None
 1591        };
 1592
 1593        let breakpoint_store = match (mode, project.as_ref()) {
 1594            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1595            _ => None,
 1596        };
 1597
 1598        let mut code_action_providers = Vec::new();
 1599        let mut load_uncommitted_diff = None;
 1600        if let Some(project) = project.clone() {
 1601            load_uncommitted_diff = Some(
 1602                get_uncommitted_diff_for_buffer(
 1603                    &project,
 1604                    buffer.read(cx).all_buffers(),
 1605                    buffer.clone(),
 1606                    cx,
 1607                )
 1608                .shared(),
 1609            );
 1610            code_action_providers.push(Rc::new(project) as Rc<_>);
 1611        }
 1612
 1613        let mut this = Self {
 1614            focus_handle,
 1615            show_cursor_when_unfocused: false,
 1616            last_focused_descendant: None,
 1617            buffer: buffer.clone(),
 1618            display_map: display_map.clone(),
 1619            selections,
 1620            scroll_manager: ScrollManager::new(cx),
 1621            columnar_selection_tail: None,
 1622            add_selections_state: None,
 1623            select_next_state: None,
 1624            select_prev_state: None,
 1625            selection_history: Default::default(),
 1626            autoclose_regions: Default::default(),
 1627            snippet_stack: Default::default(),
 1628            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1629            ime_transaction: Default::default(),
 1630            active_diagnostics: ActiveDiagnostic::None,
 1631            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1632            inline_diagnostics_update: Task::ready(()),
 1633            inline_diagnostics: Vec::new(),
 1634            soft_wrap_mode_override,
 1635            hard_wrap: None,
 1636            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1637            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1638            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1639            project,
 1640            blink_manager: blink_manager.clone(),
 1641            show_local_selections: true,
 1642            show_scrollbars: true,
 1643            disable_scrolling: false,
 1644            mode,
 1645            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1646            show_gutter: mode.is_full(),
 1647            show_line_numbers: None,
 1648            use_relative_line_numbers: None,
 1649            disable_expand_excerpt_buttons: false,
 1650            show_git_diff_gutter: None,
 1651            show_code_actions: None,
 1652            show_runnables: None,
 1653            show_breakpoints: None,
 1654            show_wrap_guides: None,
 1655            show_indent_guides,
 1656            placeholder_text: None,
 1657            highlight_order: 0,
 1658            highlighted_rows: HashMap::default(),
 1659            background_highlights: Default::default(),
 1660            gutter_highlights: TreeMap::default(),
 1661            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1662            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1663            nav_history: None,
 1664            context_menu: RefCell::new(None),
 1665            context_menu_options: None,
 1666            mouse_context_menu: None,
 1667            completion_tasks: Default::default(),
 1668            signature_help_state: SignatureHelpState::default(),
 1669            auto_signature_help: None,
 1670            find_all_references_task_sources: Vec::new(),
 1671            next_completion_id: 0,
 1672            next_inlay_id: 0,
 1673            code_action_providers,
 1674            available_code_actions: Default::default(),
 1675            code_actions_task: Default::default(),
 1676            quick_selection_highlight_task: Default::default(),
 1677            debounced_selection_highlight_task: Default::default(),
 1678            document_highlights_task: Default::default(),
 1679            linked_editing_range_task: Default::default(),
 1680            pending_rename: Default::default(),
 1681            searchable: true,
 1682            cursor_shape: EditorSettings::get_global(cx)
 1683                .cursor_shape
 1684                .unwrap_or_default(),
 1685            current_line_highlight: None,
 1686            autoindent_mode: Some(AutoindentMode::EachLine),
 1687            collapse_matches: false,
 1688            workspace: None,
 1689            input_enabled: true,
 1690            use_modal_editing: mode.is_full(),
 1691            read_only: false,
 1692            use_autoclose: true,
 1693            use_auto_surround: true,
 1694            auto_replace_emoji_shortcode: false,
 1695            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1696            leader_peer_id: None,
 1697            remote_id: None,
 1698            hover_state: Default::default(),
 1699            pending_mouse_down: None,
 1700            hovered_link_state: Default::default(),
 1701            edit_prediction_provider: None,
 1702            active_inline_completion: None,
 1703            stale_inline_completion_in_menu: None,
 1704            edit_prediction_preview: EditPredictionPreview::Inactive {
 1705                released_too_fast: false,
 1706            },
 1707            inline_diagnostics_enabled: mode.is_full(),
 1708            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1709            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1710
 1711            gutter_hovered: false,
 1712            pixel_position_of_newest_cursor: None,
 1713            last_bounds: None,
 1714            last_position_map: None,
 1715            expect_bounds_change: None,
 1716            gutter_dimensions: GutterDimensions::default(),
 1717            style: None,
 1718            show_cursor_names: false,
 1719            hovered_cursors: Default::default(),
 1720            next_editor_action_id: EditorActionId::default(),
 1721            editor_actions: Rc::default(),
 1722            inline_completions_hidden_for_vim_mode: false,
 1723            show_inline_completions_override: None,
 1724            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1725            edit_prediction_settings: EditPredictionSettings::Disabled,
 1726            edit_prediction_indent_conflict: false,
 1727            edit_prediction_requires_modifier_in_indent_conflict: true,
 1728            custom_context_menu: None,
 1729            show_git_blame_gutter: false,
 1730            show_git_blame_inline: false,
 1731            show_selection_menu: None,
 1732            show_git_blame_inline_delay_task: None,
 1733            git_blame_inline_tooltip: None,
 1734            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1735            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1736            serialize_dirty_buffers: ProjectSettings::get_global(cx)
 1737                .session
 1738                .restore_unsaved_buffers,
 1739            blame: None,
 1740            blame_subscription: None,
 1741            tasks: Default::default(),
 1742
 1743            breakpoint_store,
 1744            gutter_breakpoint_indicator: (None, None),
 1745            _subscriptions: vec![
 1746                cx.observe(&buffer, Self::on_buffer_changed),
 1747                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1748                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1749                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1750                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1751                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1752                cx.observe_window_activation(window, |editor, window, cx| {
 1753                    let active = window.is_window_active();
 1754                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1755                        if active {
 1756                            blink_manager.enable(cx);
 1757                        } else {
 1758                            blink_manager.disable(cx);
 1759                        }
 1760                    });
 1761                }),
 1762            ],
 1763            tasks_update_task: None,
 1764            linked_edit_ranges: Default::default(),
 1765            in_project_search: false,
 1766            previous_search_ranges: None,
 1767            breadcrumb_header: None,
 1768            focused_block: None,
 1769            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1770            addons: HashMap::default(),
 1771            registered_buffers: HashMap::default(),
 1772            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1773            selection_mark_mode: false,
 1774            toggle_fold_multiple_buffers: Task::ready(()),
 1775            serialize_selections: Task::ready(()),
 1776            serialize_folds: Task::ready(()),
 1777            text_style_refinement: None,
 1778            load_diff_task: load_uncommitted_diff,
 1779            mouse_cursor_hidden: false,
 1780            hide_mouse_mode: EditorSettings::get_global(cx)
 1781                .hide_mouse
 1782                .unwrap_or_default(),
 1783            change_list: ChangeList::new(),
 1784        };
 1785        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1786            this._subscriptions
 1787                .push(cx.observe(breakpoints, |_, _, cx| {
 1788                    cx.notify();
 1789                }));
 1790        }
 1791        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1792        this._subscriptions.extend(project_subscriptions);
 1793
 1794        this._subscriptions.push(cx.subscribe_in(
 1795            &cx.entity(),
 1796            window,
 1797            |editor, _, e: &EditorEvent, window, cx| match e {
 1798                EditorEvent::ScrollPositionChanged { local, .. } => {
 1799                    if *local {
 1800                        let new_anchor = editor.scroll_manager.anchor();
 1801                        let snapshot = editor.snapshot(window, cx);
 1802                        editor.update_restoration_data(cx, move |data| {
 1803                            data.scroll_position = (
 1804                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1805                                new_anchor.offset,
 1806                            );
 1807                        });
 1808                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1809                    }
 1810                }
 1811                EditorEvent::Edited { .. } => {
 1812                    if !vim_enabled(cx) {
 1813                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1814                        let pop_state = editor
 1815                            .change_list
 1816                            .last()
 1817                            .map(|previous| {
 1818                                previous.len() == selections.len()
 1819                                    && previous.iter().enumerate().all(|(ix, p)| {
 1820                                        p.to_display_point(&map).row()
 1821                                            == selections[ix].head().row()
 1822                                    })
 1823                            })
 1824                            .unwrap_or(false);
 1825                        let new_positions = selections
 1826                            .into_iter()
 1827                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1828                            .collect();
 1829                        editor
 1830                            .change_list
 1831                            .push_to_change_list(pop_state, new_positions);
 1832                    }
 1833                }
 1834                _ => (),
 1835            },
 1836        ));
 1837
 1838        if let Some(dap_store) = this
 1839            .project
 1840            .as_ref()
 1841            .map(|project| project.read(cx).dap_store())
 1842        {
 1843            let weak_editor = cx.weak_entity();
 1844
 1845            this._subscriptions
 1846                .push(
 1847                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1848                        let session_entity = cx.entity();
 1849                        weak_editor
 1850                            .update(cx, |editor, cx| {
 1851                                editor._subscriptions.push(
 1852                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1853                                );
 1854                            })
 1855                            .ok();
 1856                    }),
 1857                );
 1858
 1859            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1860                this._subscriptions
 1861                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1862            }
 1863        }
 1864
 1865        this.end_selection(window, cx);
 1866        this.scroll_manager.show_scrollbars(window, cx);
 1867        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1868
 1869        if mode.is_full() {
 1870            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1871            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1872
 1873            if this.git_blame_inline_enabled {
 1874                this.git_blame_inline_enabled = true;
 1875                this.start_git_blame_inline(false, window, cx);
 1876            }
 1877
 1878            this.go_to_active_debug_line(window, cx);
 1879
 1880            if let Some(buffer) = buffer.read(cx).as_singleton() {
 1881                if let Some(project) = this.project.as_ref() {
 1882                    let handle = project.update(cx, |project, cx| {
 1883                        project.register_buffer_with_language_servers(&buffer, cx)
 1884                    });
 1885                    this.registered_buffers
 1886                        .insert(buffer.read(cx).remote_id(), handle);
 1887                }
 1888            }
 1889        }
 1890
 1891        this.report_editor_event("Editor Opened", None, cx);
 1892        this
 1893    }
 1894
 1895    pub fn deploy_mouse_context_menu(
 1896        &mut self,
 1897        position: gpui::Point<Pixels>,
 1898        context_menu: Entity<ContextMenu>,
 1899        window: &mut Window,
 1900        cx: &mut Context<Self>,
 1901    ) {
 1902        self.mouse_context_menu = Some(MouseContextMenu::new(
 1903            self,
 1904            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 1905            context_menu,
 1906            window,
 1907            cx,
 1908        ));
 1909    }
 1910
 1911    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 1912        self.mouse_context_menu
 1913            .as_ref()
 1914            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 1915    }
 1916
 1917    fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 1918        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 1919    }
 1920
 1921    fn key_context_internal(
 1922        &self,
 1923        has_active_edit_prediction: bool,
 1924        window: &Window,
 1925        cx: &App,
 1926    ) -> KeyContext {
 1927        let mut key_context = KeyContext::new_with_defaults();
 1928        key_context.add("Editor");
 1929        let mode = match self.mode {
 1930            EditorMode::SingleLine { .. } => "single_line",
 1931            EditorMode::AutoHeight { .. } => "auto_height",
 1932            EditorMode::Full { .. } => "full",
 1933        };
 1934
 1935        if EditorSettings::jupyter_enabled(cx) {
 1936            key_context.add("jupyter");
 1937        }
 1938
 1939        key_context.set("mode", mode);
 1940        if self.pending_rename.is_some() {
 1941            key_context.add("renaming");
 1942        }
 1943
 1944        match self.context_menu.borrow().as_ref() {
 1945            Some(CodeContextMenu::Completions(_)) => {
 1946                key_context.add("menu");
 1947                key_context.add("showing_completions");
 1948            }
 1949            Some(CodeContextMenu::CodeActions(_)) => {
 1950                key_context.add("menu");
 1951                key_context.add("showing_code_actions")
 1952            }
 1953            None => {}
 1954        }
 1955
 1956        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 1957        if !self.focus_handle(cx).contains_focused(window, cx)
 1958            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 1959        {
 1960            for addon in self.addons.values() {
 1961                addon.extend_key_context(&mut key_context, cx)
 1962            }
 1963        }
 1964
 1965        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 1966            if let Some(extension) = singleton_buffer
 1967                .read(cx)
 1968                .file()
 1969                .and_then(|file| file.path().extension()?.to_str())
 1970            {
 1971                key_context.set("extension", extension.to_string());
 1972            }
 1973        } else {
 1974            key_context.add("multibuffer");
 1975        }
 1976
 1977        if has_active_edit_prediction {
 1978            if self.edit_prediction_in_conflict() {
 1979                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 1980            } else {
 1981                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 1982                key_context.add("copilot_suggestion");
 1983            }
 1984        }
 1985
 1986        if self.selection_mark_mode {
 1987            key_context.add("selection_mode");
 1988        }
 1989
 1990        key_context
 1991    }
 1992
 1993    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 1994        self.mouse_cursor_hidden = match origin {
 1995            HideMouseCursorOrigin::TypingAction => {
 1996                matches!(
 1997                    self.hide_mouse_mode,
 1998                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 1999                )
 2000            }
 2001            HideMouseCursorOrigin::MovementAction => {
 2002                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2003            }
 2004        };
 2005    }
 2006
 2007    pub fn edit_prediction_in_conflict(&self) -> bool {
 2008        if !self.show_edit_predictions_in_menu() {
 2009            return false;
 2010        }
 2011
 2012        let showing_completions = self
 2013            .context_menu
 2014            .borrow()
 2015            .as_ref()
 2016            .map_or(false, |context| {
 2017                matches!(context, CodeContextMenu::Completions(_))
 2018            });
 2019
 2020        showing_completions
 2021            || self.edit_prediction_requires_modifier()
 2022            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2023            // bindings to insert tab characters.
 2024            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2025    }
 2026
 2027    pub fn accept_edit_prediction_keybind(
 2028        &self,
 2029        window: &Window,
 2030        cx: &App,
 2031    ) -> AcceptEditPredictionBinding {
 2032        let key_context = self.key_context_internal(true, window, cx);
 2033        let in_conflict = self.edit_prediction_in_conflict();
 2034
 2035        AcceptEditPredictionBinding(
 2036            window
 2037                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2038                .into_iter()
 2039                .filter(|binding| {
 2040                    !in_conflict
 2041                        || binding
 2042                            .keystrokes()
 2043                            .first()
 2044                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2045                })
 2046                .rev()
 2047                .min_by_key(|binding| {
 2048                    binding
 2049                        .keystrokes()
 2050                        .first()
 2051                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2052                }),
 2053        )
 2054    }
 2055
 2056    pub fn new_file(
 2057        workspace: &mut Workspace,
 2058        _: &workspace::NewFile,
 2059        window: &mut Window,
 2060        cx: &mut Context<Workspace>,
 2061    ) {
 2062        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2063            "Failed to create buffer",
 2064            window,
 2065            cx,
 2066            |e, _, _| match e.error_code() {
 2067                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2068                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2069                e.error_tag("required").unwrap_or("the latest version")
 2070            )),
 2071                _ => None,
 2072            },
 2073        );
 2074    }
 2075
 2076    pub fn new_in_workspace(
 2077        workspace: &mut Workspace,
 2078        window: &mut Window,
 2079        cx: &mut Context<Workspace>,
 2080    ) -> Task<Result<Entity<Editor>>> {
 2081        let project = workspace.project().clone();
 2082        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2083
 2084        cx.spawn_in(window, async move |workspace, cx| {
 2085            let buffer = create.await?;
 2086            workspace.update_in(cx, |workspace, window, cx| {
 2087                let editor =
 2088                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2089                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2090                editor
 2091            })
 2092        })
 2093    }
 2094
 2095    fn new_file_vertical(
 2096        workspace: &mut Workspace,
 2097        _: &workspace::NewFileSplitVertical,
 2098        window: &mut Window,
 2099        cx: &mut Context<Workspace>,
 2100    ) {
 2101        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2102    }
 2103
 2104    fn new_file_horizontal(
 2105        workspace: &mut Workspace,
 2106        _: &workspace::NewFileSplitHorizontal,
 2107        window: &mut Window,
 2108        cx: &mut Context<Workspace>,
 2109    ) {
 2110        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2111    }
 2112
 2113    fn new_file_in_direction(
 2114        workspace: &mut Workspace,
 2115        direction: SplitDirection,
 2116        window: &mut Window,
 2117        cx: &mut Context<Workspace>,
 2118    ) {
 2119        let project = workspace.project().clone();
 2120        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2121
 2122        cx.spawn_in(window, async move |workspace, cx| {
 2123            let buffer = create.await?;
 2124            workspace.update_in(cx, move |workspace, window, cx| {
 2125                workspace.split_item(
 2126                    direction,
 2127                    Box::new(
 2128                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2129                    ),
 2130                    window,
 2131                    cx,
 2132                )
 2133            })?;
 2134            anyhow::Ok(())
 2135        })
 2136        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2137            match e.error_code() {
 2138                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2139                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2140                e.error_tag("required").unwrap_or("the latest version")
 2141            )),
 2142                _ => None,
 2143            }
 2144        });
 2145    }
 2146
 2147    pub fn leader_peer_id(&self) -> Option<PeerId> {
 2148        self.leader_peer_id
 2149    }
 2150
 2151    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2152        &self.buffer
 2153    }
 2154
 2155    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2156        self.workspace.as_ref()?.0.upgrade()
 2157    }
 2158
 2159    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2160        self.buffer().read(cx).title(cx)
 2161    }
 2162
 2163    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2164        let git_blame_gutter_max_author_length = self
 2165            .render_git_blame_gutter(cx)
 2166            .then(|| {
 2167                if let Some(blame) = self.blame.as_ref() {
 2168                    let max_author_length =
 2169                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2170                    Some(max_author_length)
 2171                } else {
 2172                    None
 2173                }
 2174            })
 2175            .flatten();
 2176
 2177        EditorSnapshot {
 2178            mode: self.mode,
 2179            show_gutter: self.show_gutter,
 2180            show_line_numbers: self.show_line_numbers,
 2181            show_git_diff_gutter: self.show_git_diff_gutter,
 2182            show_code_actions: self.show_code_actions,
 2183            show_runnables: self.show_runnables,
 2184            show_breakpoints: self.show_breakpoints,
 2185            git_blame_gutter_max_author_length,
 2186            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2187            scroll_anchor: self.scroll_manager.anchor(),
 2188            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2189            placeholder_text: self.placeholder_text.clone(),
 2190            is_focused: self.focus_handle.is_focused(window),
 2191            current_line_highlight: self
 2192                .current_line_highlight
 2193                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2194            gutter_hovered: self.gutter_hovered,
 2195        }
 2196    }
 2197
 2198    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2199        self.buffer.read(cx).language_at(point, cx)
 2200    }
 2201
 2202    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2203        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2204    }
 2205
 2206    pub fn active_excerpt(
 2207        &self,
 2208        cx: &App,
 2209    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2210        self.buffer
 2211            .read(cx)
 2212            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2213    }
 2214
 2215    pub fn mode(&self) -> EditorMode {
 2216        self.mode
 2217    }
 2218
 2219    pub fn set_mode(&mut self, mode: EditorMode) {
 2220        self.mode = mode;
 2221    }
 2222
 2223    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2224        self.collaboration_hub.as_deref()
 2225    }
 2226
 2227    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2228        self.collaboration_hub = Some(hub);
 2229    }
 2230
 2231    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2232        self.in_project_search = in_project_search;
 2233    }
 2234
 2235    pub fn set_custom_context_menu(
 2236        &mut self,
 2237        f: impl 'static
 2238        + Fn(
 2239            &mut Self,
 2240            DisplayPoint,
 2241            &mut Window,
 2242            &mut Context<Self>,
 2243        ) -> Option<Entity<ui::ContextMenu>>,
 2244    ) {
 2245        self.custom_context_menu = Some(Box::new(f))
 2246    }
 2247
 2248    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2249        self.completion_provider = provider;
 2250    }
 2251
 2252    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2253        self.semantics_provider.clone()
 2254    }
 2255
 2256    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2257        self.semantics_provider = provider;
 2258    }
 2259
 2260    pub fn set_edit_prediction_provider<T>(
 2261        &mut self,
 2262        provider: Option<Entity<T>>,
 2263        window: &mut Window,
 2264        cx: &mut Context<Self>,
 2265    ) where
 2266        T: EditPredictionProvider,
 2267    {
 2268        self.edit_prediction_provider =
 2269            provider.map(|provider| RegisteredInlineCompletionProvider {
 2270                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2271                    if this.focus_handle.is_focused(window) {
 2272                        this.update_visible_inline_completion(window, cx);
 2273                    }
 2274                }),
 2275                provider: Arc::new(provider),
 2276            });
 2277        self.update_edit_prediction_settings(cx);
 2278        self.refresh_inline_completion(false, false, window, cx);
 2279    }
 2280
 2281    pub fn placeholder_text(&self) -> Option<&str> {
 2282        self.placeholder_text.as_deref()
 2283    }
 2284
 2285    pub fn set_placeholder_text(
 2286        &mut self,
 2287        placeholder_text: impl Into<Arc<str>>,
 2288        cx: &mut Context<Self>,
 2289    ) {
 2290        let placeholder_text = Some(placeholder_text.into());
 2291        if self.placeholder_text != placeholder_text {
 2292            self.placeholder_text = placeholder_text;
 2293            cx.notify();
 2294        }
 2295    }
 2296
 2297    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2298        self.cursor_shape = cursor_shape;
 2299
 2300        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2301        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2302
 2303        cx.notify();
 2304    }
 2305
 2306    pub fn set_current_line_highlight(
 2307        &mut self,
 2308        current_line_highlight: Option<CurrentLineHighlight>,
 2309    ) {
 2310        self.current_line_highlight = current_line_highlight;
 2311    }
 2312
 2313    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2314        self.collapse_matches = collapse_matches;
 2315    }
 2316
 2317    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2318        let buffers = self.buffer.read(cx).all_buffers();
 2319        let Some(project) = self.project.as_ref() else {
 2320            return;
 2321        };
 2322        project.update(cx, |project, cx| {
 2323            for buffer in buffers {
 2324                self.registered_buffers
 2325                    .entry(buffer.read(cx).remote_id())
 2326                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2327            }
 2328        })
 2329    }
 2330
 2331    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2332        if self.collapse_matches {
 2333            return range.start..range.start;
 2334        }
 2335        range.clone()
 2336    }
 2337
 2338    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2339        if self.display_map.read(cx).clip_at_line_ends != clip {
 2340            self.display_map
 2341                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2342        }
 2343    }
 2344
 2345    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2346        self.input_enabled = input_enabled;
 2347    }
 2348
 2349    pub fn set_inline_completions_hidden_for_vim_mode(
 2350        &mut self,
 2351        hidden: bool,
 2352        window: &mut Window,
 2353        cx: &mut Context<Self>,
 2354    ) {
 2355        if hidden != self.inline_completions_hidden_for_vim_mode {
 2356            self.inline_completions_hidden_for_vim_mode = hidden;
 2357            if hidden {
 2358                self.update_visible_inline_completion(window, cx);
 2359            } else {
 2360                self.refresh_inline_completion(true, false, window, cx);
 2361            }
 2362        }
 2363    }
 2364
 2365    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2366        self.menu_inline_completions_policy = value;
 2367    }
 2368
 2369    pub fn set_autoindent(&mut self, autoindent: bool) {
 2370        if autoindent {
 2371            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2372        } else {
 2373            self.autoindent_mode = None;
 2374        }
 2375    }
 2376
 2377    pub fn read_only(&self, cx: &App) -> bool {
 2378        self.read_only || self.buffer.read(cx).read_only()
 2379    }
 2380
 2381    pub fn set_read_only(&mut self, read_only: bool) {
 2382        self.read_only = read_only;
 2383    }
 2384
 2385    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2386        self.use_autoclose = autoclose;
 2387    }
 2388
 2389    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2390        self.use_auto_surround = auto_surround;
 2391    }
 2392
 2393    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2394        self.auto_replace_emoji_shortcode = auto_replace;
 2395    }
 2396
 2397    pub fn toggle_edit_predictions(
 2398        &mut self,
 2399        _: &ToggleEditPrediction,
 2400        window: &mut Window,
 2401        cx: &mut Context<Self>,
 2402    ) {
 2403        if self.show_inline_completions_override.is_some() {
 2404            self.set_show_edit_predictions(None, window, cx);
 2405        } else {
 2406            let show_edit_predictions = !self.edit_predictions_enabled();
 2407            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2408        }
 2409    }
 2410
 2411    pub fn set_show_edit_predictions(
 2412        &mut self,
 2413        show_edit_predictions: Option<bool>,
 2414        window: &mut Window,
 2415        cx: &mut Context<Self>,
 2416    ) {
 2417        self.show_inline_completions_override = show_edit_predictions;
 2418        self.update_edit_prediction_settings(cx);
 2419
 2420        if let Some(false) = show_edit_predictions {
 2421            self.discard_inline_completion(false, cx);
 2422        } else {
 2423            self.refresh_inline_completion(false, true, window, cx);
 2424        }
 2425    }
 2426
 2427    fn inline_completions_disabled_in_scope(
 2428        &self,
 2429        buffer: &Entity<Buffer>,
 2430        buffer_position: language::Anchor,
 2431        cx: &App,
 2432    ) -> bool {
 2433        let snapshot = buffer.read(cx).snapshot();
 2434        let settings = snapshot.settings_at(buffer_position, cx);
 2435
 2436        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2437            return false;
 2438        };
 2439
 2440        scope.override_name().map_or(false, |scope_name| {
 2441            settings
 2442                .edit_predictions_disabled_in
 2443                .iter()
 2444                .any(|s| s == scope_name)
 2445        })
 2446    }
 2447
 2448    pub fn set_use_modal_editing(&mut self, to: bool) {
 2449        self.use_modal_editing = to;
 2450    }
 2451
 2452    pub fn use_modal_editing(&self) -> bool {
 2453        self.use_modal_editing
 2454    }
 2455
 2456    fn selections_did_change(
 2457        &mut self,
 2458        local: bool,
 2459        old_cursor_position: &Anchor,
 2460        show_completions: bool,
 2461        window: &mut Window,
 2462        cx: &mut Context<Self>,
 2463    ) {
 2464        window.invalidate_character_coordinates();
 2465
 2466        // Copy selections to primary selection buffer
 2467        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2468        if local {
 2469            let selections = self.selections.all::<usize>(cx);
 2470            let buffer_handle = self.buffer.read(cx).read(cx);
 2471
 2472            let mut text = String::new();
 2473            for (index, selection) in selections.iter().enumerate() {
 2474                let text_for_selection = buffer_handle
 2475                    .text_for_range(selection.start..selection.end)
 2476                    .collect::<String>();
 2477
 2478                text.push_str(&text_for_selection);
 2479                if index != selections.len() - 1 {
 2480                    text.push('\n');
 2481                }
 2482            }
 2483
 2484            if !text.is_empty() {
 2485                cx.write_to_primary(ClipboardItem::new_string(text));
 2486            }
 2487        }
 2488
 2489        if self.focus_handle.is_focused(window) && self.leader_peer_id.is_none() {
 2490            self.buffer.update(cx, |buffer, cx| {
 2491                buffer.set_active_selections(
 2492                    &self.selections.disjoint_anchors(),
 2493                    self.selections.line_mode,
 2494                    self.cursor_shape,
 2495                    cx,
 2496                )
 2497            });
 2498        }
 2499        let display_map = self
 2500            .display_map
 2501            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2502        let buffer = &display_map.buffer_snapshot;
 2503        self.add_selections_state = None;
 2504        self.select_next_state = None;
 2505        self.select_prev_state = None;
 2506        self.select_syntax_node_history.try_clear();
 2507        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2508        self.snippet_stack
 2509            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2510        self.take_rename(false, window, cx);
 2511
 2512        let new_cursor_position = self.selections.newest_anchor().head();
 2513
 2514        self.push_to_nav_history(
 2515            *old_cursor_position,
 2516            Some(new_cursor_position.to_point(buffer)),
 2517            false,
 2518            cx,
 2519        );
 2520
 2521        if local {
 2522            let new_cursor_position = self.selections.newest_anchor().head();
 2523            let mut context_menu = self.context_menu.borrow_mut();
 2524            let completion_menu = match context_menu.as_ref() {
 2525                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2526                _ => {
 2527                    *context_menu = None;
 2528                    None
 2529                }
 2530            };
 2531            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2532                if !self.registered_buffers.contains_key(&buffer_id) {
 2533                    if let Some(project) = self.project.as_ref() {
 2534                        project.update(cx, |project, cx| {
 2535                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2536                                return;
 2537                            };
 2538                            self.registered_buffers.insert(
 2539                                buffer_id,
 2540                                project.register_buffer_with_language_servers(&buffer, cx),
 2541                            );
 2542                        })
 2543                    }
 2544                }
 2545            }
 2546
 2547            if let Some(completion_menu) = completion_menu {
 2548                let cursor_position = new_cursor_position.to_offset(buffer);
 2549                let (word_range, kind) =
 2550                    buffer.surrounding_word(completion_menu.initial_position, true);
 2551                if kind == Some(CharKind::Word)
 2552                    && word_range.to_inclusive().contains(&cursor_position)
 2553                {
 2554                    let mut completion_menu = completion_menu.clone();
 2555                    drop(context_menu);
 2556
 2557                    let query = Self::completion_query(buffer, cursor_position);
 2558                    cx.spawn(async move |this, cx| {
 2559                        completion_menu
 2560                            .filter(query.as_deref(), cx.background_executor().clone())
 2561                            .await;
 2562
 2563                        this.update(cx, |this, cx| {
 2564                            let mut context_menu = this.context_menu.borrow_mut();
 2565                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2566                            else {
 2567                                return;
 2568                            };
 2569
 2570                            if menu.id > completion_menu.id {
 2571                                return;
 2572                            }
 2573
 2574                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2575                            drop(context_menu);
 2576                            cx.notify();
 2577                        })
 2578                    })
 2579                    .detach();
 2580
 2581                    if show_completions {
 2582                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2583                    }
 2584                } else {
 2585                    drop(context_menu);
 2586                    self.hide_context_menu(window, cx);
 2587                }
 2588            } else {
 2589                drop(context_menu);
 2590            }
 2591
 2592            hide_hover(self, cx);
 2593
 2594            if old_cursor_position.to_display_point(&display_map).row()
 2595                != new_cursor_position.to_display_point(&display_map).row()
 2596            {
 2597                self.available_code_actions.take();
 2598            }
 2599            self.refresh_code_actions(window, cx);
 2600            self.refresh_document_highlights(cx);
 2601            self.refresh_selected_text_highlights(window, cx);
 2602            refresh_matching_bracket_highlights(self, window, cx);
 2603            self.update_visible_inline_completion(window, cx);
 2604            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2605            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2606            if self.git_blame_inline_enabled {
 2607                self.start_inline_blame_timer(window, cx);
 2608            }
 2609        }
 2610
 2611        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2612        cx.emit(EditorEvent::SelectionsChanged { local });
 2613
 2614        let selections = &self.selections.disjoint;
 2615        if selections.len() == 1 {
 2616            cx.emit(SearchEvent::ActiveMatchChanged)
 2617        }
 2618        if local {
 2619            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2620                let inmemory_selections = selections
 2621                    .iter()
 2622                    .map(|s| {
 2623                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2624                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2625                    })
 2626                    .collect();
 2627                self.update_restoration_data(cx, |data| {
 2628                    data.selections = inmemory_selections;
 2629                });
 2630
 2631                if WorkspaceSettings::get(None, cx).restore_on_startup
 2632                    != RestoreOnStartupBehavior::None
 2633                {
 2634                    if let Some(workspace_id) =
 2635                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2636                    {
 2637                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2638                        let selections = selections.clone();
 2639                        let background_executor = cx.background_executor().clone();
 2640                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2641                        self.serialize_selections = cx.background_spawn(async move {
 2642                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2643                    let db_selections = selections
 2644                        .iter()
 2645                        .map(|selection| {
 2646                            (
 2647                                selection.start.to_offset(&snapshot),
 2648                                selection.end.to_offset(&snapshot),
 2649                            )
 2650                        })
 2651                        .collect();
 2652
 2653                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2654                        .await
 2655                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2656                        .log_err();
 2657                });
 2658                    }
 2659                }
 2660            }
 2661        }
 2662
 2663        cx.notify();
 2664    }
 2665
 2666    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2667        use text::ToOffset as _;
 2668        use text::ToPoint as _;
 2669
 2670        if WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None {
 2671            return;
 2672        }
 2673
 2674        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2675            return;
 2676        };
 2677
 2678        let snapshot = singleton.read(cx).snapshot();
 2679        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2680            let display_snapshot = display_map.snapshot(cx);
 2681
 2682            display_snapshot
 2683                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2684                .map(|fold| {
 2685                    fold.range.start.text_anchor.to_point(&snapshot)
 2686                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2687                })
 2688                .collect()
 2689        });
 2690        self.update_restoration_data(cx, |data| {
 2691            data.folds = inmemory_folds;
 2692        });
 2693
 2694        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2695            return;
 2696        };
 2697        let background_executor = cx.background_executor().clone();
 2698        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2699        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2700            display_map
 2701                .snapshot(cx)
 2702                .folds_in_range(0..snapshot.len())
 2703                .map(|fold| {
 2704                    (
 2705                        fold.range.start.text_anchor.to_offset(&snapshot),
 2706                        fold.range.end.text_anchor.to_offset(&snapshot),
 2707                    )
 2708                })
 2709                .collect()
 2710        });
 2711        self.serialize_folds = cx.background_spawn(async move {
 2712            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2713            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2714                .await
 2715                .with_context(|| {
 2716                    format!(
 2717                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2718                    )
 2719                })
 2720                .log_err();
 2721        });
 2722    }
 2723
 2724    pub fn sync_selections(
 2725        &mut self,
 2726        other: Entity<Editor>,
 2727        cx: &mut Context<Self>,
 2728    ) -> gpui::Subscription {
 2729        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2730        self.selections.change_with(cx, |selections| {
 2731            selections.select_anchors(other_selections);
 2732        });
 2733
 2734        let other_subscription =
 2735            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2736                EditorEvent::SelectionsChanged { local: true } => {
 2737                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2738                    if other_selections.is_empty() {
 2739                        return;
 2740                    }
 2741                    this.selections.change_with(cx, |selections| {
 2742                        selections.select_anchors(other_selections);
 2743                    });
 2744                }
 2745                _ => {}
 2746            });
 2747
 2748        let this_subscription =
 2749            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2750                EditorEvent::SelectionsChanged { local: true } => {
 2751                    let these_selections = this.selections.disjoint.to_vec();
 2752                    if these_selections.is_empty() {
 2753                        return;
 2754                    }
 2755                    other.update(cx, |other_editor, cx| {
 2756                        other_editor.selections.change_with(cx, |selections| {
 2757                            selections.select_anchors(these_selections);
 2758                        })
 2759                    });
 2760                }
 2761                _ => {}
 2762            });
 2763
 2764        Subscription::join(other_subscription, this_subscription)
 2765    }
 2766
 2767    pub fn change_selections<R>(
 2768        &mut self,
 2769        autoscroll: Option<Autoscroll>,
 2770        window: &mut Window,
 2771        cx: &mut Context<Self>,
 2772        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2773    ) -> R {
 2774        self.change_selections_inner(autoscroll, true, window, cx, change)
 2775    }
 2776
 2777    fn change_selections_inner<R>(
 2778        &mut self,
 2779        autoscroll: Option<Autoscroll>,
 2780        request_completions: bool,
 2781        window: &mut Window,
 2782        cx: &mut Context<Self>,
 2783        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2784    ) -> R {
 2785        let old_cursor_position = self.selections.newest_anchor().head();
 2786        self.push_to_selection_history();
 2787
 2788        let (changed, result) = self.selections.change_with(cx, change);
 2789
 2790        if changed {
 2791            if let Some(autoscroll) = autoscroll {
 2792                self.request_autoscroll(autoscroll, cx);
 2793            }
 2794            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2795
 2796            if self.should_open_signature_help_automatically(
 2797                &old_cursor_position,
 2798                self.signature_help_state.backspace_pressed(),
 2799                cx,
 2800            ) {
 2801                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2802            }
 2803            self.signature_help_state.set_backspace_pressed(false);
 2804        }
 2805
 2806        result
 2807    }
 2808
 2809    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2810    where
 2811        I: IntoIterator<Item = (Range<S>, T)>,
 2812        S: ToOffset,
 2813        T: Into<Arc<str>>,
 2814    {
 2815        if self.read_only(cx) {
 2816            return;
 2817        }
 2818
 2819        self.buffer
 2820            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2821    }
 2822
 2823    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2824    where
 2825        I: IntoIterator<Item = (Range<S>, T)>,
 2826        S: ToOffset,
 2827        T: Into<Arc<str>>,
 2828    {
 2829        if self.read_only(cx) {
 2830            return;
 2831        }
 2832
 2833        self.buffer.update(cx, |buffer, cx| {
 2834            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2835        });
 2836    }
 2837
 2838    pub fn edit_with_block_indent<I, S, T>(
 2839        &mut self,
 2840        edits: I,
 2841        original_indent_columns: Vec<Option<u32>>,
 2842        cx: &mut Context<Self>,
 2843    ) where
 2844        I: IntoIterator<Item = (Range<S>, T)>,
 2845        S: ToOffset,
 2846        T: Into<Arc<str>>,
 2847    {
 2848        if self.read_only(cx) {
 2849            return;
 2850        }
 2851
 2852        self.buffer.update(cx, |buffer, cx| {
 2853            buffer.edit(
 2854                edits,
 2855                Some(AutoindentMode::Block {
 2856                    original_indent_columns,
 2857                }),
 2858                cx,
 2859            )
 2860        });
 2861    }
 2862
 2863    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2864        self.hide_context_menu(window, cx);
 2865
 2866        match phase {
 2867            SelectPhase::Begin {
 2868                position,
 2869                add,
 2870                click_count,
 2871            } => self.begin_selection(position, add, click_count, window, cx),
 2872            SelectPhase::BeginColumnar {
 2873                position,
 2874                goal_column,
 2875                reset,
 2876            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 2877            SelectPhase::Extend {
 2878                position,
 2879                click_count,
 2880            } => self.extend_selection(position, click_count, window, cx),
 2881            SelectPhase::Update {
 2882                position,
 2883                goal_column,
 2884                scroll_delta,
 2885            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 2886            SelectPhase::End => self.end_selection(window, cx),
 2887        }
 2888    }
 2889
 2890    fn extend_selection(
 2891        &mut self,
 2892        position: DisplayPoint,
 2893        click_count: usize,
 2894        window: &mut Window,
 2895        cx: &mut Context<Self>,
 2896    ) {
 2897        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2898        let tail = self.selections.newest::<usize>(cx).tail();
 2899        self.begin_selection(position, false, click_count, window, cx);
 2900
 2901        let position = position.to_offset(&display_map, Bias::Left);
 2902        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 2903
 2904        let mut pending_selection = self
 2905            .selections
 2906            .pending_anchor()
 2907            .expect("extend_selection not called with pending selection");
 2908        if position >= tail {
 2909            pending_selection.start = tail_anchor;
 2910        } else {
 2911            pending_selection.end = tail_anchor;
 2912            pending_selection.reversed = true;
 2913        }
 2914
 2915        let mut pending_mode = self.selections.pending_mode().unwrap();
 2916        match &mut pending_mode {
 2917            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 2918            _ => {}
 2919        }
 2920
 2921        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 2922            s.set_pending(pending_selection, pending_mode)
 2923        });
 2924    }
 2925
 2926    fn begin_selection(
 2927        &mut self,
 2928        position: DisplayPoint,
 2929        add: bool,
 2930        click_count: usize,
 2931        window: &mut Window,
 2932        cx: &mut Context<Self>,
 2933    ) {
 2934        if !self.focus_handle.is_focused(window) {
 2935            self.last_focused_descendant = None;
 2936            window.focus(&self.focus_handle);
 2937        }
 2938
 2939        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2940        let buffer = &display_map.buffer_snapshot;
 2941        let newest_selection = self.selections.newest_anchor().clone();
 2942        let position = display_map.clip_point(position, Bias::Left);
 2943
 2944        let start;
 2945        let end;
 2946        let mode;
 2947        let mut auto_scroll;
 2948        match click_count {
 2949            1 => {
 2950                start = buffer.anchor_before(position.to_point(&display_map));
 2951                end = start;
 2952                mode = SelectMode::Character;
 2953                auto_scroll = true;
 2954            }
 2955            2 => {
 2956                let range = movement::surrounding_word(&display_map, position);
 2957                start = buffer.anchor_before(range.start.to_point(&display_map));
 2958                end = buffer.anchor_before(range.end.to_point(&display_map));
 2959                mode = SelectMode::Word(start..end);
 2960                auto_scroll = true;
 2961            }
 2962            3 => {
 2963                let position = display_map
 2964                    .clip_point(position, Bias::Left)
 2965                    .to_point(&display_map);
 2966                let line_start = display_map.prev_line_boundary(position).0;
 2967                let next_line_start = buffer.clip_point(
 2968                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2969                    Bias::Left,
 2970                );
 2971                start = buffer.anchor_before(line_start);
 2972                end = buffer.anchor_before(next_line_start);
 2973                mode = SelectMode::Line(start..end);
 2974                auto_scroll = true;
 2975            }
 2976            _ => {
 2977                start = buffer.anchor_before(0);
 2978                end = buffer.anchor_before(buffer.len());
 2979                mode = SelectMode::All;
 2980                auto_scroll = false;
 2981            }
 2982        }
 2983        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 2984
 2985        let point_to_delete: Option<usize> = {
 2986            let selected_points: Vec<Selection<Point>> =
 2987                self.selections.disjoint_in_range(start..end, cx);
 2988
 2989            if !add || click_count > 1 {
 2990                None
 2991            } else if !selected_points.is_empty() {
 2992                Some(selected_points[0].id)
 2993            } else {
 2994                let clicked_point_already_selected =
 2995                    self.selections.disjoint.iter().find(|selection| {
 2996                        selection.start.to_point(buffer) == start.to_point(buffer)
 2997                            || selection.end.to_point(buffer) == end.to_point(buffer)
 2998                    });
 2999
 3000                clicked_point_already_selected.map(|selection| selection.id)
 3001            }
 3002        };
 3003
 3004        let selections_count = self.selections.count();
 3005
 3006        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3007            if let Some(point_to_delete) = point_to_delete {
 3008                s.delete(point_to_delete);
 3009
 3010                if selections_count == 1 {
 3011                    s.set_pending_anchor_range(start..end, mode);
 3012                }
 3013            } else {
 3014                if !add {
 3015                    s.clear_disjoint();
 3016                } else if click_count > 1 {
 3017                    s.delete(newest_selection.id)
 3018                }
 3019
 3020                s.set_pending_anchor_range(start..end, mode);
 3021            }
 3022        });
 3023    }
 3024
 3025    fn begin_columnar_selection(
 3026        &mut self,
 3027        position: DisplayPoint,
 3028        goal_column: u32,
 3029        reset: bool,
 3030        window: &mut Window,
 3031        cx: &mut Context<Self>,
 3032    ) {
 3033        if !self.focus_handle.is_focused(window) {
 3034            self.last_focused_descendant = None;
 3035            window.focus(&self.focus_handle);
 3036        }
 3037
 3038        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3039
 3040        if reset {
 3041            let pointer_position = display_map
 3042                .buffer_snapshot
 3043                .anchor_before(position.to_point(&display_map));
 3044
 3045            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3046                s.clear_disjoint();
 3047                s.set_pending_anchor_range(
 3048                    pointer_position..pointer_position,
 3049                    SelectMode::Character,
 3050                );
 3051            });
 3052        }
 3053
 3054        let tail = self.selections.newest::<Point>(cx).tail();
 3055        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3056
 3057        if !reset {
 3058            self.select_columns(
 3059                tail.to_display_point(&display_map),
 3060                position,
 3061                goal_column,
 3062                &display_map,
 3063                window,
 3064                cx,
 3065            );
 3066        }
 3067    }
 3068
 3069    fn update_selection(
 3070        &mut self,
 3071        position: DisplayPoint,
 3072        goal_column: u32,
 3073        scroll_delta: gpui::Point<f32>,
 3074        window: &mut Window,
 3075        cx: &mut Context<Self>,
 3076    ) {
 3077        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3078
 3079        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3080            let tail = tail.to_display_point(&display_map);
 3081            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3082        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3083            let buffer = self.buffer.read(cx).snapshot(cx);
 3084            let head;
 3085            let tail;
 3086            let mode = self.selections.pending_mode().unwrap();
 3087            match &mode {
 3088                SelectMode::Character => {
 3089                    head = position.to_point(&display_map);
 3090                    tail = pending.tail().to_point(&buffer);
 3091                }
 3092                SelectMode::Word(original_range) => {
 3093                    let original_display_range = original_range.start.to_display_point(&display_map)
 3094                        ..original_range.end.to_display_point(&display_map);
 3095                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3096                        ..original_display_range.end.to_point(&display_map);
 3097                    if movement::is_inside_word(&display_map, position)
 3098                        || original_display_range.contains(&position)
 3099                    {
 3100                        let word_range = movement::surrounding_word(&display_map, position);
 3101                        if word_range.start < original_display_range.start {
 3102                            head = word_range.start.to_point(&display_map);
 3103                        } else {
 3104                            head = word_range.end.to_point(&display_map);
 3105                        }
 3106                    } else {
 3107                        head = position.to_point(&display_map);
 3108                    }
 3109
 3110                    if head <= original_buffer_range.start {
 3111                        tail = original_buffer_range.end;
 3112                    } else {
 3113                        tail = original_buffer_range.start;
 3114                    }
 3115                }
 3116                SelectMode::Line(original_range) => {
 3117                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3118
 3119                    let position = display_map
 3120                        .clip_point(position, Bias::Left)
 3121                        .to_point(&display_map);
 3122                    let line_start = display_map.prev_line_boundary(position).0;
 3123                    let next_line_start = buffer.clip_point(
 3124                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3125                        Bias::Left,
 3126                    );
 3127
 3128                    if line_start < original_range.start {
 3129                        head = line_start
 3130                    } else {
 3131                        head = next_line_start
 3132                    }
 3133
 3134                    if head <= original_range.start {
 3135                        tail = original_range.end;
 3136                    } else {
 3137                        tail = original_range.start;
 3138                    }
 3139                }
 3140                SelectMode::All => {
 3141                    return;
 3142                }
 3143            };
 3144
 3145            if head < tail {
 3146                pending.start = buffer.anchor_before(head);
 3147                pending.end = buffer.anchor_before(tail);
 3148                pending.reversed = true;
 3149            } else {
 3150                pending.start = buffer.anchor_before(tail);
 3151                pending.end = buffer.anchor_before(head);
 3152                pending.reversed = false;
 3153            }
 3154
 3155            self.change_selections(None, window, cx, |s| {
 3156                s.set_pending(pending, mode);
 3157            });
 3158        } else {
 3159            log::error!("update_selection dispatched with no pending selection");
 3160            return;
 3161        }
 3162
 3163        self.apply_scroll_delta(scroll_delta, window, cx);
 3164        cx.notify();
 3165    }
 3166
 3167    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3168        self.columnar_selection_tail.take();
 3169        if self.selections.pending_anchor().is_some() {
 3170            let selections = self.selections.all::<usize>(cx);
 3171            self.change_selections(None, window, cx, |s| {
 3172                s.select(selections);
 3173                s.clear_pending();
 3174            });
 3175        }
 3176    }
 3177
 3178    fn select_columns(
 3179        &mut self,
 3180        tail: DisplayPoint,
 3181        head: DisplayPoint,
 3182        goal_column: u32,
 3183        display_map: &DisplaySnapshot,
 3184        window: &mut Window,
 3185        cx: &mut Context<Self>,
 3186    ) {
 3187        let start_row = cmp::min(tail.row(), head.row());
 3188        let end_row = cmp::max(tail.row(), head.row());
 3189        let start_column = cmp::min(tail.column(), goal_column);
 3190        let end_column = cmp::max(tail.column(), goal_column);
 3191        let reversed = start_column < tail.column();
 3192
 3193        let selection_ranges = (start_row.0..=end_row.0)
 3194            .map(DisplayRow)
 3195            .filter_map(|row| {
 3196                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3197                    let start = display_map
 3198                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3199                        .to_point(display_map);
 3200                    let end = display_map
 3201                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3202                        .to_point(display_map);
 3203                    if reversed {
 3204                        Some(end..start)
 3205                    } else {
 3206                        Some(start..end)
 3207                    }
 3208                } else {
 3209                    None
 3210                }
 3211            })
 3212            .collect::<Vec<_>>();
 3213
 3214        self.change_selections(None, window, cx, |s| {
 3215            s.select_ranges(selection_ranges);
 3216        });
 3217        cx.notify();
 3218    }
 3219
 3220    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3221        self.selections
 3222            .all_adjusted(cx)
 3223            .iter()
 3224            .any(|selection| !selection.is_empty())
 3225    }
 3226
 3227    pub fn has_pending_nonempty_selection(&self) -> bool {
 3228        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3229            Some(Selection { start, end, .. }) => start != end,
 3230            None => false,
 3231        };
 3232
 3233        pending_nonempty_selection
 3234            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3235    }
 3236
 3237    pub fn has_pending_selection(&self) -> bool {
 3238        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3239    }
 3240
 3241    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3242        self.selection_mark_mode = false;
 3243
 3244        if self.clear_expanded_diff_hunks(cx) {
 3245            cx.notify();
 3246            return;
 3247        }
 3248        if self.dismiss_menus_and_popups(true, window, cx) {
 3249            return;
 3250        }
 3251
 3252        if self.mode.is_full()
 3253            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3254        {
 3255            return;
 3256        }
 3257
 3258        cx.propagate();
 3259    }
 3260
 3261    pub fn dismiss_menus_and_popups(
 3262        &mut self,
 3263        is_user_requested: bool,
 3264        window: &mut Window,
 3265        cx: &mut Context<Self>,
 3266    ) -> bool {
 3267        if self.take_rename(false, window, cx).is_some() {
 3268            return true;
 3269        }
 3270
 3271        if hide_hover(self, cx) {
 3272            return true;
 3273        }
 3274
 3275        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3276            return true;
 3277        }
 3278
 3279        if self.hide_context_menu(window, cx).is_some() {
 3280            return true;
 3281        }
 3282
 3283        if self.mouse_context_menu.take().is_some() {
 3284            return true;
 3285        }
 3286
 3287        if is_user_requested && self.discard_inline_completion(true, cx) {
 3288            return true;
 3289        }
 3290
 3291        if self.snippet_stack.pop().is_some() {
 3292            return true;
 3293        }
 3294
 3295        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3296            self.dismiss_diagnostics(cx);
 3297            return true;
 3298        }
 3299
 3300        false
 3301    }
 3302
 3303    fn linked_editing_ranges_for(
 3304        &self,
 3305        selection: Range<text::Anchor>,
 3306        cx: &App,
 3307    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3308        if self.linked_edit_ranges.is_empty() {
 3309            return None;
 3310        }
 3311        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3312            selection.end.buffer_id.and_then(|end_buffer_id| {
 3313                if selection.start.buffer_id != Some(end_buffer_id) {
 3314                    return None;
 3315                }
 3316                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3317                let snapshot = buffer.read(cx).snapshot();
 3318                self.linked_edit_ranges
 3319                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3320                    .map(|ranges| (ranges, snapshot, buffer))
 3321            })?;
 3322        use text::ToOffset as TO;
 3323        // find offset from the start of current range to current cursor position
 3324        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3325
 3326        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3327        let start_difference = start_offset - start_byte_offset;
 3328        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3329        let end_difference = end_offset - start_byte_offset;
 3330        // Current range has associated linked ranges.
 3331        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3332        for range in linked_ranges.iter() {
 3333            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3334            let end_offset = start_offset + end_difference;
 3335            let start_offset = start_offset + start_difference;
 3336            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3337                continue;
 3338            }
 3339            if self.selections.disjoint_anchor_ranges().any(|s| {
 3340                if s.start.buffer_id != selection.start.buffer_id
 3341                    || s.end.buffer_id != selection.end.buffer_id
 3342                {
 3343                    return false;
 3344                }
 3345                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3346                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3347            }) {
 3348                continue;
 3349            }
 3350            let start = buffer_snapshot.anchor_after(start_offset);
 3351            let end = buffer_snapshot.anchor_after(end_offset);
 3352            linked_edits
 3353                .entry(buffer.clone())
 3354                .or_default()
 3355                .push(start..end);
 3356        }
 3357        Some(linked_edits)
 3358    }
 3359
 3360    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3361        let text: Arc<str> = text.into();
 3362
 3363        if self.read_only(cx) {
 3364            return;
 3365        }
 3366
 3367        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3368
 3369        let selections = self.selections.all_adjusted(cx);
 3370        let mut bracket_inserted = false;
 3371        let mut edits = Vec::new();
 3372        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3373        let mut new_selections = Vec::with_capacity(selections.len());
 3374        let mut new_autoclose_regions = Vec::new();
 3375        let snapshot = self.buffer.read(cx).read(cx);
 3376        let mut clear_linked_edit_ranges = false;
 3377
 3378        for (selection, autoclose_region) in
 3379            self.selections_with_autoclose_regions(selections, &snapshot)
 3380        {
 3381            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3382                // Determine if the inserted text matches the opening or closing
 3383                // bracket of any of this language's bracket pairs.
 3384                let mut bracket_pair = None;
 3385                let mut is_bracket_pair_start = false;
 3386                let mut is_bracket_pair_end = false;
 3387                if !text.is_empty() {
 3388                    let mut bracket_pair_matching_end = None;
 3389                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3390                    //  and they are removing the character that triggered IME popup.
 3391                    for (pair, enabled) in scope.brackets() {
 3392                        if !pair.close && !pair.surround {
 3393                            continue;
 3394                        }
 3395
 3396                        if enabled && pair.start.ends_with(text.as_ref()) {
 3397                            let prefix_len = pair.start.len() - text.len();
 3398                            let preceding_text_matches_prefix = prefix_len == 0
 3399                                || (selection.start.column >= (prefix_len as u32)
 3400                                    && snapshot.contains_str_at(
 3401                                        Point::new(
 3402                                            selection.start.row,
 3403                                            selection.start.column - (prefix_len as u32),
 3404                                        ),
 3405                                        &pair.start[..prefix_len],
 3406                                    ));
 3407                            if preceding_text_matches_prefix {
 3408                                bracket_pair = Some(pair.clone());
 3409                                is_bracket_pair_start = true;
 3410                                break;
 3411                            }
 3412                        }
 3413                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3414                        {
 3415                            // take first bracket pair matching end, but don't break in case a later bracket
 3416                            // pair matches start
 3417                            bracket_pair_matching_end = Some(pair.clone());
 3418                        }
 3419                    }
 3420                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3421                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3422                        is_bracket_pair_end = true;
 3423                    }
 3424                }
 3425
 3426                if let Some(bracket_pair) = bracket_pair {
 3427                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3428                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3429                    let auto_surround =
 3430                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3431                    if selection.is_empty() {
 3432                        if is_bracket_pair_start {
 3433                            // If the inserted text is a suffix of an opening bracket and the
 3434                            // selection is preceded by the rest of the opening bracket, then
 3435                            // insert the closing bracket.
 3436                            let following_text_allows_autoclose = snapshot
 3437                                .chars_at(selection.start)
 3438                                .next()
 3439                                .map_or(true, |c| scope.should_autoclose_before(c));
 3440
 3441                            let preceding_text_allows_autoclose = selection.start.column == 0
 3442                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3443                                    true,
 3444                                    |c| {
 3445                                        bracket_pair.start != bracket_pair.end
 3446                                            || !snapshot
 3447                                                .char_classifier_at(selection.start)
 3448                                                .is_word(c)
 3449                                    },
 3450                                );
 3451
 3452                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3453                                && bracket_pair.start.len() == 1
 3454                            {
 3455                                let target = bracket_pair.start.chars().next().unwrap();
 3456                                let current_line_count = snapshot
 3457                                    .reversed_chars_at(selection.start)
 3458                                    .take_while(|&c| c != '\n')
 3459                                    .filter(|&c| c == target)
 3460                                    .count();
 3461                                current_line_count % 2 == 1
 3462                            } else {
 3463                                false
 3464                            };
 3465
 3466                            if autoclose
 3467                                && bracket_pair.close
 3468                                && following_text_allows_autoclose
 3469                                && preceding_text_allows_autoclose
 3470                                && !is_closing_quote
 3471                            {
 3472                                let anchor = snapshot.anchor_before(selection.end);
 3473                                new_selections.push((selection.map(|_| anchor), text.len()));
 3474                                new_autoclose_regions.push((
 3475                                    anchor,
 3476                                    text.len(),
 3477                                    selection.id,
 3478                                    bracket_pair.clone(),
 3479                                ));
 3480                                edits.push((
 3481                                    selection.range(),
 3482                                    format!("{}{}", text, bracket_pair.end).into(),
 3483                                ));
 3484                                bracket_inserted = true;
 3485                                continue;
 3486                            }
 3487                        }
 3488
 3489                        if let Some(region) = autoclose_region {
 3490                            // If the selection is followed by an auto-inserted closing bracket,
 3491                            // then don't insert that closing bracket again; just move the selection
 3492                            // past the closing bracket.
 3493                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3494                                && text.as_ref() == region.pair.end.as_str();
 3495                            if should_skip {
 3496                                let anchor = snapshot.anchor_after(selection.end);
 3497                                new_selections
 3498                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3499                                continue;
 3500                            }
 3501                        }
 3502
 3503                        let always_treat_brackets_as_autoclosed = snapshot
 3504                            .language_settings_at(selection.start, cx)
 3505                            .always_treat_brackets_as_autoclosed;
 3506                        if always_treat_brackets_as_autoclosed
 3507                            && is_bracket_pair_end
 3508                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3509                        {
 3510                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3511                            // and the inserted text is a closing bracket and the selection is followed
 3512                            // by the closing bracket then move the selection past the closing bracket.
 3513                            let anchor = snapshot.anchor_after(selection.end);
 3514                            new_selections.push((selection.map(|_| anchor), text.len()));
 3515                            continue;
 3516                        }
 3517                    }
 3518                    // If an opening bracket is 1 character long and is typed while
 3519                    // text is selected, then surround that text with the bracket pair.
 3520                    else if auto_surround
 3521                        && bracket_pair.surround
 3522                        && is_bracket_pair_start
 3523                        && bracket_pair.start.chars().count() == 1
 3524                    {
 3525                        edits.push((selection.start..selection.start, text.clone()));
 3526                        edits.push((
 3527                            selection.end..selection.end,
 3528                            bracket_pair.end.as_str().into(),
 3529                        ));
 3530                        bracket_inserted = true;
 3531                        new_selections.push((
 3532                            Selection {
 3533                                id: selection.id,
 3534                                start: snapshot.anchor_after(selection.start),
 3535                                end: snapshot.anchor_before(selection.end),
 3536                                reversed: selection.reversed,
 3537                                goal: selection.goal,
 3538                            },
 3539                            0,
 3540                        ));
 3541                        continue;
 3542                    }
 3543                }
 3544            }
 3545
 3546            if self.auto_replace_emoji_shortcode
 3547                && selection.is_empty()
 3548                && text.as_ref().ends_with(':')
 3549            {
 3550                if let Some(possible_emoji_short_code) =
 3551                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3552                {
 3553                    if !possible_emoji_short_code.is_empty() {
 3554                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3555                            let emoji_shortcode_start = Point::new(
 3556                                selection.start.row,
 3557                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3558                            );
 3559
 3560                            // Remove shortcode from buffer
 3561                            edits.push((
 3562                                emoji_shortcode_start..selection.start,
 3563                                "".to_string().into(),
 3564                            ));
 3565                            new_selections.push((
 3566                                Selection {
 3567                                    id: selection.id,
 3568                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3569                                    end: snapshot.anchor_before(selection.start),
 3570                                    reversed: selection.reversed,
 3571                                    goal: selection.goal,
 3572                                },
 3573                                0,
 3574                            ));
 3575
 3576                            // Insert emoji
 3577                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3578                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3579                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3580
 3581                            continue;
 3582                        }
 3583                    }
 3584                }
 3585            }
 3586
 3587            // If not handling any auto-close operation, then just replace the selected
 3588            // text with the given input and move the selection to the end of the
 3589            // newly inserted text.
 3590            let anchor = snapshot.anchor_after(selection.end);
 3591            if !self.linked_edit_ranges.is_empty() {
 3592                let start_anchor = snapshot.anchor_before(selection.start);
 3593
 3594                let is_word_char = text.chars().next().map_or(true, |char| {
 3595                    let classifier = snapshot.char_classifier_at(start_anchor.to_offset(&snapshot));
 3596                    classifier.is_word(char)
 3597                });
 3598
 3599                if is_word_char {
 3600                    if let Some(ranges) = self
 3601                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3602                    {
 3603                        for (buffer, edits) in ranges {
 3604                            linked_edits
 3605                                .entry(buffer.clone())
 3606                                .or_default()
 3607                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3608                        }
 3609                    }
 3610                } else {
 3611                    clear_linked_edit_ranges = true;
 3612                }
 3613            }
 3614
 3615            new_selections.push((selection.map(|_| anchor), 0));
 3616            edits.push((selection.start..selection.end, text.clone()));
 3617        }
 3618
 3619        drop(snapshot);
 3620
 3621        self.transact(window, cx, |this, window, cx| {
 3622            if clear_linked_edit_ranges {
 3623                this.linked_edit_ranges.clear();
 3624            }
 3625            let initial_buffer_versions =
 3626                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3627
 3628            this.buffer.update(cx, |buffer, cx| {
 3629                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3630            });
 3631            for (buffer, edits) in linked_edits {
 3632                buffer.update(cx, |buffer, cx| {
 3633                    let snapshot = buffer.snapshot();
 3634                    let edits = edits
 3635                        .into_iter()
 3636                        .map(|(range, text)| {
 3637                            use text::ToPoint as TP;
 3638                            let end_point = TP::to_point(&range.end, &snapshot);
 3639                            let start_point = TP::to_point(&range.start, &snapshot);
 3640                            (start_point..end_point, text)
 3641                        })
 3642                        .sorted_by_key(|(range, _)| range.start);
 3643                    buffer.edit(edits, None, cx);
 3644                })
 3645            }
 3646            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3647            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3648            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3649            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3650                .zip(new_selection_deltas)
 3651                .map(|(selection, delta)| Selection {
 3652                    id: selection.id,
 3653                    start: selection.start + delta,
 3654                    end: selection.end + delta,
 3655                    reversed: selection.reversed,
 3656                    goal: SelectionGoal::None,
 3657                })
 3658                .collect::<Vec<_>>();
 3659
 3660            let mut i = 0;
 3661            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3662                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3663                let start = map.buffer_snapshot.anchor_before(position);
 3664                let end = map.buffer_snapshot.anchor_after(position);
 3665                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3666                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3667                        Ordering::Less => i += 1,
 3668                        Ordering::Greater => break,
 3669                        Ordering::Equal => {
 3670                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3671                                Ordering::Less => i += 1,
 3672                                Ordering::Equal => break,
 3673                                Ordering::Greater => break,
 3674                            }
 3675                        }
 3676                    }
 3677                }
 3678                this.autoclose_regions.insert(
 3679                    i,
 3680                    AutocloseRegion {
 3681                        selection_id,
 3682                        range: start..end,
 3683                        pair,
 3684                    },
 3685                );
 3686            }
 3687
 3688            let had_active_inline_completion = this.has_active_inline_completion();
 3689            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3690                s.select(new_selections)
 3691            });
 3692
 3693            if !bracket_inserted {
 3694                if let Some(on_type_format_task) =
 3695                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3696                {
 3697                    on_type_format_task.detach_and_log_err(cx);
 3698                }
 3699            }
 3700
 3701            let editor_settings = EditorSettings::get_global(cx);
 3702            if bracket_inserted
 3703                && (editor_settings.auto_signature_help
 3704                    || editor_settings.show_signature_help_after_edits)
 3705            {
 3706                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3707            }
 3708
 3709            let trigger_in_words =
 3710                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3711            if this.hard_wrap.is_some() {
 3712                let latest: Range<Point> = this.selections.newest(cx).range();
 3713                if latest.is_empty()
 3714                    && this
 3715                        .buffer()
 3716                        .read(cx)
 3717                        .snapshot(cx)
 3718                        .line_len(MultiBufferRow(latest.start.row))
 3719                        == latest.start.column
 3720                {
 3721                    this.rewrap_impl(
 3722                        RewrapOptions {
 3723                            override_language_settings: true,
 3724                            preserve_existing_whitespace: true,
 3725                        },
 3726                        cx,
 3727                    )
 3728                }
 3729            }
 3730            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3731            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3732            this.refresh_inline_completion(true, false, window, cx);
 3733            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3734        });
 3735    }
 3736
 3737    fn find_possible_emoji_shortcode_at_position(
 3738        snapshot: &MultiBufferSnapshot,
 3739        position: Point,
 3740    ) -> Option<String> {
 3741        let mut chars = Vec::new();
 3742        let mut found_colon = false;
 3743        for char in snapshot.reversed_chars_at(position).take(100) {
 3744            // Found a possible emoji shortcode in the middle of the buffer
 3745            if found_colon {
 3746                if char.is_whitespace() {
 3747                    chars.reverse();
 3748                    return Some(chars.iter().collect());
 3749                }
 3750                // If the previous character is not a whitespace, we are in the middle of a word
 3751                // and we only want to complete the shortcode if the word is made up of other emojis
 3752                let mut containing_word = String::new();
 3753                for ch in snapshot
 3754                    .reversed_chars_at(position)
 3755                    .skip(chars.len() + 1)
 3756                    .take(100)
 3757                {
 3758                    if ch.is_whitespace() {
 3759                        break;
 3760                    }
 3761                    containing_word.push(ch);
 3762                }
 3763                let containing_word = containing_word.chars().rev().collect::<String>();
 3764                if util::word_consists_of_emojis(containing_word.as_str()) {
 3765                    chars.reverse();
 3766                    return Some(chars.iter().collect());
 3767                }
 3768            }
 3769
 3770            if char.is_whitespace() || !char.is_ascii() {
 3771                return None;
 3772            }
 3773            if char == ':' {
 3774                found_colon = true;
 3775            } else {
 3776                chars.push(char);
 3777            }
 3778        }
 3779        // Found a possible emoji shortcode at the beginning of the buffer
 3780        chars.reverse();
 3781        Some(chars.iter().collect())
 3782    }
 3783
 3784    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3785        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3786        self.transact(window, cx, |this, window, cx| {
 3787            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
 3788                let selections = this.selections.all::<usize>(cx);
 3789                let multi_buffer = this.buffer.read(cx);
 3790                let buffer = multi_buffer.snapshot(cx);
 3791                selections
 3792                    .iter()
 3793                    .map(|selection| {
 3794                        let start_point = selection.start.to_point(&buffer);
 3795                        let mut indent =
 3796                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3797                        indent.len = cmp::min(indent.len, start_point.column);
 3798                        let start = selection.start;
 3799                        let end = selection.end;
 3800                        let selection_is_empty = start == end;
 3801                        let language_scope = buffer.language_scope_at(start);
 3802                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
 3803                            &language_scope
 3804                        {
 3805                            let insert_extra_newline =
 3806                                insert_extra_newline_brackets(&buffer, start..end, language)
 3807                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3808
 3809                            // Comment extension on newline is allowed only for cursor selections
 3810                            let comment_delimiter = maybe!({
 3811                                if !selection_is_empty {
 3812                                    return None;
 3813                                }
 3814
 3815                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3816                                    return None;
 3817                                }
 3818
 3819                                let delimiters = language.line_comment_prefixes();
 3820                                let max_len_of_delimiter =
 3821                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3822                                let (snapshot, range) =
 3823                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3824
 3825                                let mut index_of_first_non_whitespace = 0;
 3826                                let comment_candidate = snapshot
 3827                                    .chars_for_range(range)
 3828                                    .skip_while(|c| {
 3829                                        let should_skip = c.is_whitespace();
 3830                                        if should_skip {
 3831                                            index_of_first_non_whitespace += 1;
 3832                                        }
 3833                                        should_skip
 3834                                    })
 3835                                    .take(max_len_of_delimiter)
 3836                                    .collect::<String>();
 3837                                let comment_prefix = delimiters.iter().find(|comment_prefix| {
 3838                                    comment_candidate.starts_with(comment_prefix.as_ref())
 3839                                })?;
 3840                                let cursor_is_placed_after_comment_marker =
 3841                                    index_of_first_non_whitespace + comment_prefix.len()
 3842                                        <= start_point.column as usize;
 3843                                if cursor_is_placed_after_comment_marker {
 3844                                    Some(comment_prefix.clone())
 3845                                } else {
 3846                                    None
 3847                                }
 3848                            });
 3849                            (comment_delimiter, insert_extra_newline)
 3850                        } else {
 3851                            (None, false)
 3852                        };
 3853
 3854                        let capacity_for_delimiter = comment_delimiter
 3855                            .as_deref()
 3856                            .map(str::len)
 3857                            .unwrap_or_default();
 3858                        let mut new_text =
 3859                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
 3860                        new_text.push('\n');
 3861                        new_text.extend(indent.chars());
 3862                        if let Some(delimiter) = &comment_delimiter {
 3863                            new_text.push_str(delimiter);
 3864                        }
 3865                        if insert_extra_newline {
 3866                            new_text = new_text.repeat(2);
 3867                        }
 3868
 3869                        let anchor = buffer.anchor_after(end);
 3870                        let new_selection = selection.map(|_| anchor);
 3871                        (
 3872                            (start..end, new_text),
 3873                            (insert_extra_newline, new_selection),
 3874                        )
 3875                    })
 3876                    .unzip()
 3877            };
 3878
 3879            this.edit_with_autoindent(edits, cx);
 3880            let buffer = this.buffer.read(cx).snapshot(cx);
 3881            let new_selections = selection_fixup_info
 3882                .into_iter()
 3883                .map(|(extra_newline_inserted, new_selection)| {
 3884                    let mut cursor = new_selection.end.to_point(&buffer);
 3885                    if extra_newline_inserted {
 3886                        cursor.row -= 1;
 3887                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 3888                    }
 3889                    new_selection.map(|_| cursor)
 3890                })
 3891                .collect();
 3892
 3893            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3894                s.select(new_selections)
 3895            });
 3896            this.refresh_inline_completion(true, false, window, cx);
 3897        });
 3898    }
 3899
 3900    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 3901        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3902
 3903        let buffer = self.buffer.read(cx);
 3904        let snapshot = buffer.snapshot(cx);
 3905
 3906        let mut edits = Vec::new();
 3907        let mut rows = Vec::new();
 3908
 3909        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 3910            let cursor = selection.head();
 3911            let row = cursor.row;
 3912
 3913            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 3914
 3915            let newline = "\n".to_string();
 3916            edits.push((start_of_line..start_of_line, newline));
 3917
 3918            rows.push(row + rows_inserted as u32);
 3919        }
 3920
 3921        self.transact(window, cx, |editor, window, cx| {
 3922            editor.edit(edits, cx);
 3923
 3924            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3925                let mut index = 0;
 3926                s.move_cursors_with(|map, _, _| {
 3927                    let row = rows[index];
 3928                    index += 1;
 3929
 3930                    let point = Point::new(row, 0);
 3931                    let boundary = map.next_line_boundary(point).1;
 3932                    let clipped = map.clip_point(boundary, Bias::Left);
 3933
 3934                    (clipped, SelectionGoal::None)
 3935                });
 3936            });
 3937
 3938            let mut indent_edits = Vec::new();
 3939            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3940            for row in rows {
 3941                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3942                for (row, indent) in indents {
 3943                    if indent.len == 0 {
 3944                        continue;
 3945                    }
 3946
 3947                    let text = match indent.kind {
 3948                        IndentKind::Space => " ".repeat(indent.len as usize),
 3949                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3950                    };
 3951                    let point = Point::new(row.0, 0);
 3952                    indent_edits.push((point..point, text));
 3953                }
 3954            }
 3955            editor.edit(indent_edits, cx);
 3956        });
 3957    }
 3958
 3959    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 3960        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3961
 3962        let buffer = self.buffer.read(cx);
 3963        let snapshot = buffer.snapshot(cx);
 3964
 3965        let mut edits = Vec::new();
 3966        let mut rows = Vec::new();
 3967        let mut rows_inserted = 0;
 3968
 3969        for selection in self.selections.all_adjusted(cx) {
 3970            let cursor = selection.head();
 3971            let row = cursor.row;
 3972
 3973            let point = Point::new(row + 1, 0);
 3974            let start_of_line = snapshot.clip_point(point, Bias::Left);
 3975
 3976            let newline = "\n".to_string();
 3977            edits.push((start_of_line..start_of_line, newline));
 3978
 3979            rows_inserted += 1;
 3980            rows.push(row + rows_inserted);
 3981        }
 3982
 3983        self.transact(window, cx, |editor, window, cx| {
 3984            editor.edit(edits, cx);
 3985
 3986            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3987                let mut index = 0;
 3988                s.move_cursors_with(|map, _, _| {
 3989                    let row = rows[index];
 3990                    index += 1;
 3991
 3992                    let point = Point::new(row, 0);
 3993                    let boundary = map.next_line_boundary(point).1;
 3994                    let clipped = map.clip_point(boundary, Bias::Left);
 3995
 3996                    (clipped, SelectionGoal::None)
 3997                });
 3998            });
 3999
 4000            let mut indent_edits = Vec::new();
 4001            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4002            for row in rows {
 4003                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4004                for (row, indent) in indents {
 4005                    if indent.len == 0 {
 4006                        continue;
 4007                    }
 4008
 4009                    let text = match indent.kind {
 4010                        IndentKind::Space => " ".repeat(indent.len as usize),
 4011                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4012                    };
 4013                    let point = Point::new(row.0, 0);
 4014                    indent_edits.push((point..point, text));
 4015                }
 4016            }
 4017            editor.edit(indent_edits, cx);
 4018        });
 4019    }
 4020
 4021    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4022        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4023            original_indent_columns: Vec::new(),
 4024        });
 4025        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4026    }
 4027
 4028    fn insert_with_autoindent_mode(
 4029        &mut self,
 4030        text: &str,
 4031        autoindent_mode: Option<AutoindentMode>,
 4032        window: &mut Window,
 4033        cx: &mut Context<Self>,
 4034    ) {
 4035        if self.read_only(cx) {
 4036            return;
 4037        }
 4038
 4039        let text: Arc<str> = text.into();
 4040        self.transact(window, cx, |this, window, cx| {
 4041            let old_selections = this.selections.all_adjusted(cx);
 4042            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4043                let anchors = {
 4044                    let snapshot = buffer.read(cx);
 4045                    old_selections
 4046                        .iter()
 4047                        .map(|s| {
 4048                            let anchor = snapshot.anchor_after(s.head());
 4049                            s.map(|_| anchor)
 4050                        })
 4051                        .collect::<Vec<_>>()
 4052                };
 4053                buffer.edit(
 4054                    old_selections
 4055                        .iter()
 4056                        .map(|s| (s.start..s.end, text.clone())),
 4057                    autoindent_mode,
 4058                    cx,
 4059                );
 4060                anchors
 4061            });
 4062
 4063            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4064                s.select_anchors(selection_anchors);
 4065            });
 4066
 4067            cx.notify();
 4068        });
 4069    }
 4070
 4071    fn trigger_completion_on_input(
 4072        &mut self,
 4073        text: &str,
 4074        trigger_in_words: bool,
 4075        window: &mut Window,
 4076        cx: &mut Context<Self>,
 4077    ) {
 4078        let ignore_completion_provider = self
 4079            .context_menu
 4080            .borrow()
 4081            .as_ref()
 4082            .map(|menu| match menu {
 4083                CodeContextMenu::Completions(completions_menu) => {
 4084                    completions_menu.ignore_completion_provider
 4085                }
 4086                CodeContextMenu::CodeActions(_) => false,
 4087            })
 4088            .unwrap_or(false);
 4089
 4090        if ignore_completion_provider {
 4091            self.show_word_completions(&ShowWordCompletions, window, cx);
 4092        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4093            self.show_completions(
 4094                &ShowCompletions {
 4095                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4096                },
 4097                window,
 4098                cx,
 4099            );
 4100        } else {
 4101            self.hide_context_menu(window, cx);
 4102        }
 4103    }
 4104
 4105    fn is_completion_trigger(
 4106        &self,
 4107        text: &str,
 4108        trigger_in_words: bool,
 4109        cx: &mut Context<Self>,
 4110    ) -> bool {
 4111        let position = self.selections.newest_anchor().head();
 4112        let multibuffer = self.buffer.read(cx);
 4113        let Some(buffer) = position
 4114            .buffer_id
 4115            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4116        else {
 4117            return false;
 4118        };
 4119
 4120        if let Some(completion_provider) = &self.completion_provider {
 4121            completion_provider.is_completion_trigger(
 4122                &buffer,
 4123                position.text_anchor,
 4124                text,
 4125                trigger_in_words,
 4126                cx,
 4127            )
 4128        } else {
 4129            false
 4130        }
 4131    }
 4132
 4133    /// If any empty selections is touching the start of its innermost containing autoclose
 4134    /// region, expand it to select the brackets.
 4135    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4136        let selections = self.selections.all::<usize>(cx);
 4137        let buffer = self.buffer.read(cx).read(cx);
 4138        let new_selections = self
 4139            .selections_with_autoclose_regions(selections, &buffer)
 4140            .map(|(mut selection, region)| {
 4141                if !selection.is_empty() {
 4142                    return selection;
 4143                }
 4144
 4145                if let Some(region) = region {
 4146                    let mut range = region.range.to_offset(&buffer);
 4147                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4148                        range.start -= region.pair.start.len();
 4149                        if buffer.contains_str_at(range.start, &region.pair.start)
 4150                            && buffer.contains_str_at(range.end, &region.pair.end)
 4151                        {
 4152                            range.end += region.pair.end.len();
 4153                            selection.start = range.start;
 4154                            selection.end = range.end;
 4155
 4156                            return selection;
 4157                        }
 4158                    }
 4159                }
 4160
 4161                let always_treat_brackets_as_autoclosed = buffer
 4162                    .language_settings_at(selection.start, cx)
 4163                    .always_treat_brackets_as_autoclosed;
 4164
 4165                if !always_treat_brackets_as_autoclosed {
 4166                    return selection;
 4167                }
 4168
 4169                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4170                    for (pair, enabled) in scope.brackets() {
 4171                        if !enabled || !pair.close {
 4172                            continue;
 4173                        }
 4174
 4175                        if buffer.contains_str_at(selection.start, &pair.end) {
 4176                            let pair_start_len = pair.start.len();
 4177                            if buffer.contains_str_at(
 4178                                selection.start.saturating_sub(pair_start_len),
 4179                                &pair.start,
 4180                            ) {
 4181                                selection.start -= pair_start_len;
 4182                                selection.end += pair.end.len();
 4183
 4184                                return selection;
 4185                            }
 4186                        }
 4187                    }
 4188                }
 4189
 4190                selection
 4191            })
 4192            .collect();
 4193
 4194        drop(buffer);
 4195        self.change_selections(None, window, cx, |selections| {
 4196            selections.select(new_selections)
 4197        });
 4198    }
 4199
 4200    /// Iterate the given selections, and for each one, find the smallest surrounding
 4201    /// autoclose region. This uses the ordering of the selections and the autoclose
 4202    /// regions to avoid repeated comparisons.
 4203    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4204        &'a self,
 4205        selections: impl IntoIterator<Item = Selection<D>>,
 4206        buffer: &'a MultiBufferSnapshot,
 4207    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4208        let mut i = 0;
 4209        let mut regions = self.autoclose_regions.as_slice();
 4210        selections.into_iter().map(move |selection| {
 4211            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4212
 4213            let mut enclosing = None;
 4214            while let Some(pair_state) = regions.get(i) {
 4215                if pair_state.range.end.to_offset(buffer) < range.start {
 4216                    regions = &regions[i + 1..];
 4217                    i = 0;
 4218                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4219                    break;
 4220                } else {
 4221                    if pair_state.selection_id == selection.id {
 4222                        enclosing = Some(pair_state);
 4223                    }
 4224                    i += 1;
 4225                }
 4226            }
 4227
 4228            (selection, enclosing)
 4229        })
 4230    }
 4231
 4232    /// Remove any autoclose regions that no longer contain their selection.
 4233    fn invalidate_autoclose_regions(
 4234        &mut self,
 4235        mut selections: &[Selection<Anchor>],
 4236        buffer: &MultiBufferSnapshot,
 4237    ) {
 4238        self.autoclose_regions.retain(|state| {
 4239            let mut i = 0;
 4240            while let Some(selection) = selections.get(i) {
 4241                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4242                    selections = &selections[1..];
 4243                    continue;
 4244                }
 4245                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4246                    break;
 4247                }
 4248                if selection.id == state.selection_id {
 4249                    return true;
 4250                } else {
 4251                    i += 1;
 4252                }
 4253            }
 4254            false
 4255        });
 4256    }
 4257
 4258    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4259        let offset = position.to_offset(buffer);
 4260        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4261        if offset > word_range.start && kind == Some(CharKind::Word) {
 4262            Some(
 4263                buffer
 4264                    .text_for_range(word_range.start..offset)
 4265                    .collect::<String>(),
 4266            )
 4267        } else {
 4268            None
 4269        }
 4270    }
 4271
 4272    pub fn toggle_inline_values(
 4273        &mut self,
 4274        _: &ToggleInlineValues,
 4275        _: &mut Window,
 4276        cx: &mut Context<Self>,
 4277    ) {
 4278        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4279
 4280        self.refresh_inline_values(cx);
 4281    }
 4282
 4283    pub fn toggle_inlay_hints(
 4284        &mut self,
 4285        _: &ToggleInlayHints,
 4286        _: &mut Window,
 4287        cx: &mut Context<Self>,
 4288    ) {
 4289        self.refresh_inlay_hints(
 4290            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4291            cx,
 4292        );
 4293    }
 4294
 4295    pub fn inlay_hints_enabled(&self) -> bool {
 4296        self.inlay_hint_cache.enabled
 4297    }
 4298
 4299    pub fn inline_values_enabled(&self) -> bool {
 4300        self.inline_value_cache.enabled
 4301    }
 4302
 4303    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4304        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4305            return;
 4306        }
 4307
 4308        let reason_description = reason.description();
 4309        let ignore_debounce = matches!(
 4310            reason,
 4311            InlayHintRefreshReason::SettingsChange(_)
 4312                | InlayHintRefreshReason::Toggle(_)
 4313                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4314                | InlayHintRefreshReason::ModifiersChanged(_)
 4315        );
 4316        let (invalidate_cache, required_languages) = match reason {
 4317            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4318                match self.inlay_hint_cache.modifiers_override(enabled) {
 4319                    Some(enabled) => {
 4320                        if enabled {
 4321                            (InvalidationStrategy::RefreshRequested, None)
 4322                        } else {
 4323                            self.splice_inlays(
 4324                                &self
 4325                                    .visible_inlay_hints(cx)
 4326                                    .iter()
 4327                                    .map(|inlay| inlay.id)
 4328                                    .collect::<Vec<InlayId>>(),
 4329                                Vec::new(),
 4330                                cx,
 4331                            );
 4332                            return;
 4333                        }
 4334                    }
 4335                    None => return,
 4336                }
 4337            }
 4338            InlayHintRefreshReason::Toggle(enabled) => {
 4339                if self.inlay_hint_cache.toggle(enabled) {
 4340                    if enabled {
 4341                        (InvalidationStrategy::RefreshRequested, None)
 4342                    } else {
 4343                        self.splice_inlays(
 4344                            &self
 4345                                .visible_inlay_hints(cx)
 4346                                .iter()
 4347                                .map(|inlay| inlay.id)
 4348                                .collect::<Vec<InlayId>>(),
 4349                            Vec::new(),
 4350                            cx,
 4351                        );
 4352                        return;
 4353                    }
 4354                } else {
 4355                    return;
 4356                }
 4357            }
 4358            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4359                match self.inlay_hint_cache.update_settings(
 4360                    &self.buffer,
 4361                    new_settings,
 4362                    self.visible_inlay_hints(cx),
 4363                    cx,
 4364                ) {
 4365                    ControlFlow::Break(Some(InlaySplice {
 4366                        to_remove,
 4367                        to_insert,
 4368                    })) => {
 4369                        self.splice_inlays(&to_remove, to_insert, cx);
 4370                        return;
 4371                    }
 4372                    ControlFlow::Break(None) => return,
 4373                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4374                }
 4375            }
 4376            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4377                if let Some(InlaySplice {
 4378                    to_remove,
 4379                    to_insert,
 4380                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4381                {
 4382                    self.splice_inlays(&to_remove, to_insert, cx);
 4383                }
 4384                self.display_map.update(cx, |display_map, _| {
 4385                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4386                });
 4387                return;
 4388            }
 4389            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4390            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4391                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4392            }
 4393            InlayHintRefreshReason::RefreshRequested => {
 4394                (InvalidationStrategy::RefreshRequested, None)
 4395            }
 4396        };
 4397
 4398        if let Some(InlaySplice {
 4399            to_remove,
 4400            to_insert,
 4401        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4402            reason_description,
 4403            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4404            invalidate_cache,
 4405            ignore_debounce,
 4406            cx,
 4407        ) {
 4408            self.splice_inlays(&to_remove, to_insert, cx);
 4409        }
 4410    }
 4411
 4412    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4413        self.display_map
 4414            .read(cx)
 4415            .current_inlays()
 4416            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4417            .cloned()
 4418            .collect()
 4419    }
 4420
 4421    pub fn excerpts_for_inlay_hints_query(
 4422        &self,
 4423        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4424        cx: &mut Context<Editor>,
 4425    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4426        let Some(project) = self.project.as_ref() else {
 4427            return HashMap::default();
 4428        };
 4429        let project = project.read(cx);
 4430        let multi_buffer = self.buffer().read(cx);
 4431        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4432        let multi_buffer_visible_start = self
 4433            .scroll_manager
 4434            .anchor()
 4435            .anchor
 4436            .to_point(&multi_buffer_snapshot);
 4437        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4438            multi_buffer_visible_start
 4439                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4440            Bias::Left,
 4441        );
 4442        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4443        multi_buffer_snapshot
 4444            .range_to_buffer_ranges(multi_buffer_visible_range)
 4445            .into_iter()
 4446            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4447            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4448                let buffer_file = project::File::from_dyn(buffer.file())?;
 4449                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4450                let worktree_entry = buffer_worktree
 4451                    .read(cx)
 4452                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4453                if worktree_entry.is_ignored {
 4454                    return None;
 4455                }
 4456
 4457                let language = buffer.language()?;
 4458                if let Some(restrict_to_languages) = restrict_to_languages {
 4459                    if !restrict_to_languages.contains(language) {
 4460                        return None;
 4461                    }
 4462                }
 4463                Some((
 4464                    excerpt_id,
 4465                    (
 4466                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4467                        buffer.version().clone(),
 4468                        excerpt_visible_range,
 4469                    ),
 4470                ))
 4471            })
 4472            .collect()
 4473    }
 4474
 4475    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4476        TextLayoutDetails {
 4477            text_system: window.text_system().clone(),
 4478            editor_style: self.style.clone().unwrap(),
 4479            rem_size: window.rem_size(),
 4480            scroll_anchor: self.scroll_manager.anchor(),
 4481            visible_rows: self.visible_line_count(),
 4482            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4483        }
 4484    }
 4485
 4486    pub fn splice_inlays(
 4487        &self,
 4488        to_remove: &[InlayId],
 4489        to_insert: Vec<Inlay>,
 4490        cx: &mut Context<Self>,
 4491    ) {
 4492        self.display_map.update(cx, |display_map, cx| {
 4493            display_map.splice_inlays(to_remove, to_insert, cx)
 4494        });
 4495        cx.notify();
 4496    }
 4497
 4498    fn trigger_on_type_formatting(
 4499        &self,
 4500        input: String,
 4501        window: &mut Window,
 4502        cx: &mut Context<Self>,
 4503    ) -> Option<Task<Result<()>>> {
 4504        if input.len() != 1 {
 4505            return None;
 4506        }
 4507
 4508        let project = self.project.as_ref()?;
 4509        let position = self.selections.newest_anchor().head();
 4510        let (buffer, buffer_position) = self
 4511            .buffer
 4512            .read(cx)
 4513            .text_anchor_for_position(position, cx)?;
 4514
 4515        let settings = language_settings::language_settings(
 4516            buffer
 4517                .read(cx)
 4518                .language_at(buffer_position)
 4519                .map(|l| l.name()),
 4520            buffer.read(cx).file(),
 4521            cx,
 4522        );
 4523        if !settings.use_on_type_format {
 4524            return None;
 4525        }
 4526
 4527        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4528        // hence we do LSP request & edit on host side only — add formats to host's history.
 4529        let push_to_lsp_host_history = true;
 4530        // If this is not the host, append its history with new edits.
 4531        let push_to_client_history = project.read(cx).is_via_collab();
 4532
 4533        let on_type_formatting = project.update(cx, |project, cx| {
 4534            project.on_type_format(
 4535                buffer.clone(),
 4536                buffer_position,
 4537                input,
 4538                push_to_lsp_host_history,
 4539                cx,
 4540            )
 4541        });
 4542        Some(cx.spawn_in(window, async move |editor, cx| {
 4543            if let Some(transaction) = on_type_formatting.await? {
 4544                if push_to_client_history {
 4545                    buffer
 4546                        .update(cx, |buffer, _| {
 4547                            buffer.push_transaction(transaction, Instant::now());
 4548                            buffer.finalize_last_transaction();
 4549                        })
 4550                        .ok();
 4551                }
 4552                editor.update(cx, |editor, cx| {
 4553                    editor.refresh_document_highlights(cx);
 4554                })?;
 4555            }
 4556            Ok(())
 4557        }))
 4558    }
 4559
 4560    pub fn show_word_completions(
 4561        &mut self,
 4562        _: &ShowWordCompletions,
 4563        window: &mut Window,
 4564        cx: &mut Context<Self>,
 4565    ) {
 4566        self.open_completions_menu(true, None, window, cx);
 4567    }
 4568
 4569    pub fn show_completions(
 4570        &mut self,
 4571        options: &ShowCompletions,
 4572        window: &mut Window,
 4573        cx: &mut Context<Self>,
 4574    ) {
 4575        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4576    }
 4577
 4578    fn open_completions_menu(
 4579        &mut self,
 4580        ignore_completion_provider: bool,
 4581        trigger: Option<&str>,
 4582        window: &mut Window,
 4583        cx: &mut Context<Self>,
 4584    ) {
 4585        if self.pending_rename.is_some() {
 4586            return;
 4587        }
 4588        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4589            return;
 4590        }
 4591
 4592        let position = self.selections.newest_anchor().head();
 4593        if position.diff_base_anchor.is_some() {
 4594            return;
 4595        }
 4596        let (buffer, buffer_position) =
 4597            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4598                output
 4599            } else {
 4600                return;
 4601            };
 4602        let buffer_snapshot = buffer.read(cx).snapshot();
 4603        let show_completion_documentation = buffer_snapshot
 4604            .settings_at(buffer_position, cx)
 4605            .show_completion_documentation;
 4606
 4607        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4608
 4609        let trigger_kind = match trigger {
 4610            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4611                CompletionTriggerKind::TRIGGER_CHARACTER
 4612            }
 4613            _ => CompletionTriggerKind::INVOKED,
 4614        };
 4615        let completion_context = CompletionContext {
 4616            trigger_character: trigger.and_then(|trigger| {
 4617                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4618                    Some(String::from(trigger))
 4619                } else {
 4620                    None
 4621                }
 4622            }),
 4623            trigger_kind,
 4624        };
 4625
 4626        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4627        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4628            let word_to_exclude = buffer_snapshot
 4629                .text_for_range(old_range.clone())
 4630                .collect::<String>();
 4631            (
 4632                buffer_snapshot.anchor_before(old_range.start)
 4633                    ..buffer_snapshot.anchor_after(old_range.end),
 4634                Some(word_to_exclude),
 4635            )
 4636        } else {
 4637            (buffer_position..buffer_position, None)
 4638        };
 4639
 4640        let completion_settings = language_settings(
 4641            buffer_snapshot
 4642                .language_at(buffer_position)
 4643                .map(|language| language.name()),
 4644            buffer_snapshot.file(),
 4645            cx,
 4646        )
 4647        .completions;
 4648
 4649        // The document can be large, so stay in reasonable bounds when searching for words,
 4650        // otherwise completion pop-up might be slow to appear.
 4651        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4652        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4653        let min_word_search = buffer_snapshot.clip_point(
 4654            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4655            Bias::Left,
 4656        );
 4657        let max_word_search = buffer_snapshot.clip_point(
 4658            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4659            Bias::Right,
 4660        );
 4661        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4662            ..buffer_snapshot.point_to_offset(max_word_search);
 4663
 4664        let provider = self
 4665            .completion_provider
 4666            .as_ref()
 4667            .filter(|_| !ignore_completion_provider);
 4668        let skip_digits = query
 4669            .as_ref()
 4670            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4671
 4672        let (mut words, provided_completions) = match provider {
 4673            Some(provider) => {
 4674                let completions = provider.completions(
 4675                    position.excerpt_id,
 4676                    &buffer,
 4677                    buffer_position,
 4678                    completion_context,
 4679                    window,
 4680                    cx,
 4681                );
 4682
 4683                let words = match completion_settings.words {
 4684                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4685                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4686                        .background_spawn(async move {
 4687                            buffer_snapshot.words_in_range(WordsQuery {
 4688                                fuzzy_contents: None,
 4689                                range: word_search_range,
 4690                                skip_digits,
 4691                            })
 4692                        }),
 4693                };
 4694
 4695                (words, completions)
 4696            }
 4697            None => (
 4698                cx.background_spawn(async move {
 4699                    buffer_snapshot.words_in_range(WordsQuery {
 4700                        fuzzy_contents: None,
 4701                        range: word_search_range,
 4702                        skip_digits,
 4703                    })
 4704                }),
 4705                Task::ready(Ok(None)),
 4706            ),
 4707        };
 4708
 4709        let sort_completions = provider
 4710            .as_ref()
 4711            .map_or(false, |provider| provider.sort_completions());
 4712
 4713        let filter_completions = provider
 4714            .as_ref()
 4715            .map_or(true, |provider| provider.filter_completions());
 4716
 4717        let id = post_inc(&mut self.next_completion_id);
 4718        let task = cx.spawn_in(window, async move |editor, cx| {
 4719            async move {
 4720                editor.update(cx, |this, _| {
 4721                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 4722                })?;
 4723
 4724                let mut completions = Vec::new();
 4725                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 4726                    completions.extend(provided_completions);
 4727                    if completion_settings.words == WordsCompletionMode::Fallback {
 4728                        words = Task::ready(BTreeMap::default());
 4729                    }
 4730                }
 4731
 4732                let mut words = words.await;
 4733                if let Some(word_to_exclude) = &word_to_exclude {
 4734                    words.remove(word_to_exclude);
 4735                }
 4736                for lsp_completion in &completions {
 4737                    words.remove(&lsp_completion.new_text);
 4738                }
 4739                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 4740                    replace_range: old_range.clone(),
 4741                    new_text: word.clone(),
 4742                    label: CodeLabel::plain(word, None),
 4743                    icon_path: None,
 4744                    documentation: None,
 4745                    source: CompletionSource::BufferWord {
 4746                        word_range,
 4747                        resolved: false,
 4748                    },
 4749                    insert_text_mode: Some(InsertTextMode::AS_IS),
 4750                    confirm: None,
 4751                }));
 4752
 4753                let menu = if completions.is_empty() {
 4754                    None
 4755                } else {
 4756                    let mut menu = CompletionsMenu::new(
 4757                        id,
 4758                        sort_completions,
 4759                        show_completion_documentation,
 4760                        ignore_completion_provider,
 4761                        position,
 4762                        buffer.clone(),
 4763                        completions.into(),
 4764                    );
 4765
 4766                    menu.filter(
 4767                        if filter_completions {
 4768                            query.as_deref()
 4769                        } else {
 4770                            None
 4771                        },
 4772                        cx.background_executor().clone(),
 4773                    )
 4774                    .await;
 4775
 4776                    menu.visible().then_some(menu)
 4777                };
 4778
 4779                editor.update_in(cx, |editor, window, cx| {
 4780                    match editor.context_menu.borrow().as_ref() {
 4781                        None => {}
 4782                        Some(CodeContextMenu::Completions(prev_menu)) => {
 4783                            if prev_menu.id > id {
 4784                                return;
 4785                            }
 4786                        }
 4787                        _ => return,
 4788                    }
 4789
 4790                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 4791                        let mut menu = menu.unwrap();
 4792                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 4793
 4794                        *editor.context_menu.borrow_mut() =
 4795                            Some(CodeContextMenu::Completions(menu));
 4796
 4797                        if editor.show_edit_predictions_in_menu() {
 4798                            editor.update_visible_inline_completion(window, cx);
 4799                        } else {
 4800                            editor.discard_inline_completion(false, cx);
 4801                        }
 4802
 4803                        cx.notify();
 4804                    } else if editor.completion_tasks.len() <= 1 {
 4805                        // If there are no more completion tasks and the last menu was
 4806                        // empty, we should hide it.
 4807                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 4808                        // If it was already hidden and we don't show inline
 4809                        // completions in the menu, we should also show the
 4810                        // inline-completion when available.
 4811                        if was_hidden && editor.show_edit_predictions_in_menu() {
 4812                            editor.update_visible_inline_completion(window, cx);
 4813                        }
 4814                    }
 4815                })?;
 4816
 4817                anyhow::Ok(())
 4818            }
 4819            .log_err()
 4820            .await
 4821        });
 4822
 4823        self.completion_tasks.push((id, task));
 4824    }
 4825
 4826    #[cfg(feature = "test-support")]
 4827    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 4828        let menu = self.context_menu.borrow();
 4829        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 4830            let completions = menu.completions.borrow();
 4831            Some(completions.to_vec())
 4832        } else {
 4833            None
 4834        }
 4835    }
 4836
 4837    pub fn confirm_completion(
 4838        &mut self,
 4839        action: &ConfirmCompletion,
 4840        window: &mut Window,
 4841        cx: &mut Context<Self>,
 4842    ) -> Option<Task<Result<()>>> {
 4843        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4844        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 4845    }
 4846
 4847    pub fn confirm_completion_insert(
 4848        &mut self,
 4849        _: &ConfirmCompletionInsert,
 4850        window: &mut Window,
 4851        cx: &mut Context<Self>,
 4852    ) -> Option<Task<Result<()>>> {
 4853        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4854        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 4855    }
 4856
 4857    pub fn confirm_completion_replace(
 4858        &mut self,
 4859        _: &ConfirmCompletionReplace,
 4860        window: &mut Window,
 4861        cx: &mut Context<Self>,
 4862    ) -> Option<Task<Result<()>>> {
 4863        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4864        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 4865    }
 4866
 4867    pub fn compose_completion(
 4868        &mut self,
 4869        action: &ComposeCompletion,
 4870        window: &mut Window,
 4871        cx: &mut Context<Self>,
 4872    ) -> Option<Task<Result<()>>> {
 4873        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4874        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 4875    }
 4876
 4877    fn do_completion(
 4878        &mut self,
 4879        item_ix: Option<usize>,
 4880        intent: CompletionIntent,
 4881        window: &mut Window,
 4882        cx: &mut Context<Editor>,
 4883    ) -> Option<Task<Result<()>>> {
 4884        use language::ToOffset as _;
 4885
 4886        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 4887        else {
 4888            return None;
 4889        };
 4890
 4891        let candidate_id = {
 4892            let entries = completions_menu.entries.borrow();
 4893            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 4894            if self.show_edit_predictions_in_menu() {
 4895                self.discard_inline_completion(true, cx);
 4896            }
 4897            mat.candidate_id
 4898        };
 4899
 4900        let buffer_handle = completions_menu.buffer;
 4901        let completion = completions_menu
 4902            .completions
 4903            .borrow()
 4904            .get(candidate_id)?
 4905            .clone();
 4906        cx.stop_propagation();
 4907
 4908        let snippet;
 4909        let new_text;
 4910        if completion.is_snippet() {
 4911            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
 4912            new_text = snippet.as_ref().unwrap().text.clone();
 4913        } else {
 4914            snippet = None;
 4915            new_text = completion.new_text.clone();
 4916        };
 4917
 4918        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 4919        let buffer = buffer_handle.read(cx);
 4920        let snapshot = self.buffer.read(cx).snapshot(cx);
 4921        let replace_range_multibuffer = {
 4922            let excerpt = snapshot
 4923                .excerpt_containing(self.selections.newest_anchor().range())
 4924                .unwrap();
 4925            let multibuffer_anchor = snapshot
 4926                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 4927                .unwrap()
 4928                ..snapshot
 4929                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 4930                    .unwrap();
 4931            multibuffer_anchor.start.to_offset(&snapshot)
 4932                ..multibuffer_anchor.end.to_offset(&snapshot)
 4933        };
 4934        let newest_anchor = self.selections.newest_anchor();
 4935        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 4936            return None;
 4937        }
 4938
 4939        let old_text = buffer
 4940            .text_for_range(replace_range.clone())
 4941            .collect::<String>();
 4942        let lookbehind = newest_anchor
 4943            .start
 4944            .text_anchor
 4945            .to_offset(buffer)
 4946            .saturating_sub(replace_range.start);
 4947        let lookahead = replace_range
 4948            .end
 4949            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 4950        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 4951        let suffix = &old_text[lookbehind.min(old_text.len())..];
 4952
 4953        let selections = self.selections.all::<usize>(cx);
 4954        let mut ranges = Vec::new();
 4955        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4956
 4957        for selection in &selections {
 4958            let range = if selection.id == newest_anchor.id {
 4959                replace_range_multibuffer.clone()
 4960            } else {
 4961                let mut range = selection.range();
 4962
 4963                // if prefix is present, don't duplicate it
 4964                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 4965                    range.start = range.start.saturating_sub(lookbehind);
 4966
 4967                    // if suffix is also present, mimic the newest cursor and replace it
 4968                    if selection.id != newest_anchor.id
 4969                        && snapshot.contains_str_at(range.end, suffix)
 4970                    {
 4971                        range.end += lookahead;
 4972                    }
 4973                }
 4974                range
 4975            };
 4976
 4977            ranges.push(range);
 4978
 4979            if !self.linked_edit_ranges.is_empty() {
 4980                let start_anchor = snapshot.anchor_before(selection.head());
 4981                let end_anchor = snapshot.anchor_after(selection.tail());
 4982                if let Some(ranges) = self
 4983                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 4984                {
 4985                    for (buffer, edits) in ranges {
 4986                        linked_edits
 4987                            .entry(buffer.clone())
 4988                            .or_default()
 4989                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 4990                    }
 4991                }
 4992            }
 4993        }
 4994
 4995        cx.emit(EditorEvent::InputHandled {
 4996            utf16_range_to_replace: None,
 4997            text: new_text.clone().into(),
 4998        });
 4999
 5000        self.transact(window, cx, |this, window, cx| {
 5001            if let Some(mut snippet) = snippet {
 5002                snippet.text = new_text.to_string();
 5003                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5004            } else {
 5005                this.buffer.update(cx, |buffer, cx| {
 5006                    let auto_indent = match completion.insert_text_mode {
 5007                        Some(InsertTextMode::AS_IS) => None,
 5008                        _ => this.autoindent_mode.clone(),
 5009                    };
 5010                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5011                    buffer.edit(edits, auto_indent, cx);
 5012                });
 5013            }
 5014            for (buffer, edits) in linked_edits {
 5015                buffer.update(cx, |buffer, cx| {
 5016                    let snapshot = buffer.snapshot();
 5017                    let edits = edits
 5018                        .into_iter()
 5019                        .map(|(range, text)| {
 5020                            use text::ToPoint as TP;
 5021                            let end_point = TP::to_point(&range.end, &snapshot);
 5022                            let start_point = TP::to_point(&range.start, &snapshot);
 5023                            (start_point..end_point, text)
 5024                        })
 5025                        .sorted_by_key(|(range, _)| range.start);
 5026                    buffer.edit(edits, None, cx);
 5027                })
 5028            }
 5029
 5030            this.refresh_inline_completion(true, false, window, cx);
 5031        });
 5032
 5033        let show_new_completions_on_confirm = completion
 5034            .confirm
 5035            .as_ref()
 5036            .map_or(false, |confirm| confirm(intent, window, cx));
 5037        if show_new_completions_on_confirm {
 5038            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5039        }
 5040
 5041        let provider = self.completion_provider.as_ref()?;
 5042        drop(completion);
 5043        let apply_edits = provider.apply_additional_edits_for_completion(
 5044            buffer_handle,
 5045            completions_menu.completions.clone(),
 5046            candidate_id,
 5047            true,
 5048            cx,
 5049        );
 5050
 5051        let editor_settings = EditorSettings::get_global(cx);
 5052        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5053            // After the code completion is finished, users often want to know what signatures are needed.
 5054            // so we should automatically call signature_help
 5055            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5056        }
 5057
 5058        Some(cx.foreground_executor().spawn(async move {
 5059            apply_edits.await?;
 5060            Ok(())
 5061        }))
 5062    }
 5063
 5064    pub fn toggle_code_actions(
 5065        &mut self,
 5066        action: &ToggleCodeActions,
 5067        window: &mut Window,
 5068        cx: &mut Context<Self>,
 5069    ) {
 5070        let mut context_menu = self.context_menu.borrow_mut();
 5071        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5072            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 5073                // Toggle if we're selecting the same one
 5074                *context_menu = None;
 5075                cx.notify();
 5076                return;
 5077            } else {
 5078                // Otherwise, clear it and start a new one
 5079                *context_menu = None;
 5080                cx.notify();
 5081            }
 5082        }
 5083        drop(context_menu);
 5084        let snapshot = self.snapshot(window, cx);
 5085        let deployed_from_indicator = action.deployed_from_indicator;
 5086        let mut task = self.code_actions_task.take();
 5087        let action = action.clone();
 5088        cx.spawn_in(window, async move |editor, cx| {
 5089            while let Some(prev_task) = task {
 5090                prev_task.await.log_err();
 5091                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5092            }
 5093
 5094            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5095                if editor.focus_handle.is_focused(window) {
 5096                    let multibuffer_point = action
 5097                        .deployed_from_indicator
 5098                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 5099                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 5100                    let (buffer, buffer_row) = snapshot
 5101                        .buffer_snapshot
 5102                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5103                        .and_then(|(buffer_snapshot, range)| {
 5104                            editor
 5105                                .buffer
 5106                                .read(cx)
 5107                                .buffer(buffer_snapshot.remote_id())
 5108                                .map(|buffer| (buffer, range.start.row))
 5109                        })?;
 5110                    let (_, code_actions) = editor
 5111                        .available_code_actions
 5112                        .clone()
 5113                        .and_then(|(location, code_actions)| {
 5114                            let snapshot = location.buffer.read(cx).snapshot();
 5115                            let point_range = location.range.to_point(&snapshot);
 5116                            let point_range = point_range.start.row..=point_range.end.row;
 5117                            if point_range.contains(&buffer_row) {
 5118                                Some((location, code_actions))
 5119                            } else {
 5120                                None
 5121                            }
 5122                        })
 5123                        .unzip();
 5124                    let buffer_id = buffer.read(cx).remote_id();
 5125                    let tasks = editor
 5126                        .tasks
 5127                        .get(&(buffer_id, buffer_row))
 5128                        .map(|t| Arc::new(t.to_owned()));
 5129                    if tasks.is_none() && code_actions.is_none() {
 5130                        return None;
 5131                    }
 5132
 5133                    editor.completion_tasks.clear();
 5134                    editor.discard_inline_completion(false, cx);
 5135                    let task_context =
 5136                        tasks
 5137                            .as_ref()
 5138                            .zip(editor.project.clone())
 5139                            .map(|(tasks, project)| {
 5140                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5141                            });
 5142
 5143                    let debugger_flag = cx.has_flag::<Debugger>();
 5144
 5145                    Some(cx.spawn_in(window, async move |editor, cx| {
 5146                        let task_context = match task_context {
 5147                            Some(task_context) => task_context.await,
 5148                            None => None,
 5149                        };
 5150                        let resolved_tasks =
 5151                            tasks
 5152                                .zip(task_context)
 5153                                .map(|(tasks, task_context)| ResolvedTasks {
 5154                                    templates: tasks.resolve(&task_context).collect(),
 5155                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5156                                        multibuffer_point.row,
 5157                                        tasks.column,
 5158                                    )),
 5159                                });
 5160                        let spawn_straight_away = resolved_tasks.as_ref().map_or(false, |tasks| {
 5161                            tasks
 5162                                .templates
 5163                                .iter()
 5164                                .filter(|task| {
 5165                                    if matches!(task.1.task_type(), task::TaskType::Debug(_)) {
 5166                                        debugger_flag
 5167                                    } else {
 5168                                        true
 5169                                    }
 5170                                })
 5171                                .count()
 5172                                == 1
 5173                        }) && code_actions
 5174                            .as_ref()
 5175                            .map_or(true, |actions| actions.is_empty());
 5176                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5177                            *editor.context_menu.borrow_mut() =
 5178                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5179                                    buffer,
 5180                                    actions: CodeActionContents::new(
 5181                                        resolved_tasks,
 5182                                        code_actions,
 5183                                        cx,
 5184                                    ),
 5185                                    selected_item: Default::default(),
 5186                                    scroll_handle: UniformListScrollHandle::default(),
 5187                                    deployed_from_indicator,
 5188                                }));
 5189                            if spawn_straight_away {
 5190                                if let Some(task) = editor.confirm_code_action(
 5191                                    &ConfirmCodeAction { item_ix: Some(0) },
 5192                                    window,
 5193                                    cx,
 5194                                ) {
 5195                                    cx.notify();
 5196                                    return task;
 5197                                }
 5198                            }
 5199                            cx.notify();
 5200                            Task::ready(Ok(()))
 5201                        }) {
 5202                            task.await
 5203                        } else {
 5204                            Ok(())
 5205                        }
 5206                    }))
 5207                } else {
 5208                    Some(Task::ready(Ok(())))
 5209                }
 5210            })?;
 5211            if let Some(task) = spawned_test_task {
 5212                task.await?;
 5213            }
 5214
 5215            Ok::<_, anyhow::Error>(())
 5216        })
 5217        .detach_and_log_err(cx);
 5218    }
 5219
 5220    pub fn confirm_code_action(
 5221        &mut self,
 5222        action: &ConfirmCodeAction,
 5223        window: &mut Window,
 5224        cx: &mut Context<Self>,
 5225    ) -> Option<Task<Result<()>>> {
 5226        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5227
 5228        let actions_menu =
 5229            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5230                menu
 5231            } else {
 5232                return None;
 5233            };
 5234
 5235        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5236        let action = actions_menu.actions.get(action_ix)?;
 5237        let title = action.label();
 5238        let buffer = actions_menu.buffer;
 5239        let workspace = self.workspace()?;
 5240
 5241        match action {
 5242            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5243                match resolved_task.task_type() {
 5244                    task::TaskType::Script => workspace.update(cx, |workspace, cx| {
 5245                        workspace.schedule_resolved_task(
 5246                            task_source_kind,
 5247                            resolved_task,
 5248                            false,
 5249                            window,
 5250                            cx,
 5251                        );
 5252
 5253                        Some(Task::ready(Ok(())))
 5254                    }),
 5255                    task::TaskType::Debug(_) => {
 5256                        workspace.update(cx, |workspace, cx| {
 5257                            workspace.schedule_debug_task(resolved_task, window, cx);
 5258                        });
 5259                        Some(Task::ready(Ok(())))
 5260                    }
 5261                }
 5262            }
 5263            CodeActionsItem::CodeAction {
 5264                excerpt_id,
 5265                action,
 5266                provider,
 5267            } => {
 5268                let apply_code_action =
 5269                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5270                let workspace = workspace.downgrade();
 5271                Some(cx.spawn_in(window, async move |editor, cx| {
 5272                    let project_transaction = apply_code_action.await?;
 5273                    Self::open_project_transaction(
 5274                        &editor,
 5275                        workspace,
 5276                        project_transaction,
 5277                        title,
 5278                        cx,
 5279                    )
 5280                    .await
 5281                }))
 5282            }
 5283        }
 5284    }
 5285
 5286    pub async fn open_project_transaction(
 5287        this: &WeakEntity<Editor>,
 5288        workspace: WeakEntity<Workspace>,
 5289        transaction: ProjectTransaction,
 5290        title: String,
 5291        cx: &mut AsyncWindowContext,
 5292    ) -> Result<()> {
 5293        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5294        cx.update(|_, cx| {
 5295            entries.sort_unstable_by_key(|(buffer, _)| {
 5296                buffer.read(cx).file().map(|f| f.path().clone())
 5297            });
 5298        })?;
 5299
 5300        // If the project transaction's edits are all contained within this editor, then
 5301        // avoid opening a new editor to display them.
 5302
 5303        if let Some((buffer, transaction)) = entries.first() {
 5304            if entries.len() == 1 {
 5305                let excerpt = this.update(cx, |editor, cx| {
 5306                    editor
 5307                        .buffer()
 5308                        .read(cx)
 5309                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5310                })?;
 5311                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5312                    if excerpted_buffer == *buffer {
 5313                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5314                            let excerpt_range = excerpt_range.to_offset(buffer);
 5315                            buffer
 5316                                .edited_ranges_for_transaction::<usize>(transaction)
 5317                                .all(|range| {
 5318                                    excerpt_range.start <= range.start
 5319                                        && excerpt_range.end >= range.end
 5320                                })
 5321                        })?;
 5322
 5323                        if all_edits_within_excerpt {
 5324                            return Ok(());
 5325                        }
 5326                    }
 5327                }
 5328            }
 5329        } else {
 5330            return Ok(());
 5331        }
 5332
 5333        let mut ranges_to_highlight = Vec::new();
 5334        let excerpt_buffer = cx.new(|cx| {
 5335            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5336            for (buffer_handle, transaction) in &entries {
 5337                let edited_ranges = buffer_handle
 5338                    .read(cx)
 5339                    .edited_ranges_for_transaction::<Point>(transaction)
 5340                    .collect::<Vec<_>>();
 5341                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5342                    PathKey::for_buffer(buffer_handle, cx),
 5343                    buffer_handle.clone(),
 5344                    edited_ranges,
 5345                    DEFAULT_MULTIBUFFER_CONTEXT,
 5346                    cx,
 5347                );
 5348
 5349                ranges_to_highlight.extend(ranges);
 5350            }
 5351            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5352            multibuffer
 5353        })?;
 5354
 5355        workspace.update_in(cx, |workspace, window, cx| {
 5356            let project = workspace.project().clone();
 5357            let editor =
 5358                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5359            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5360            editor.update(cx, |editor, cx| {
 5361                editor.highlight_background::<Self>(
 5362                    &ranges_to_highlight,
 5363                    |theme| theme.editor_highlighted_line_background,
 5364                    cx,
 5365                );
 5366            });
 5367        })?;
 5368
 5369        Ok(())
 5370    }
 5371
 5372    pub fn clear_code_action_providers(&mut self) {
 5373        self.code_action_providers.clear();
 5374        self.available_code_actions.take();
 5375    }
 5376
 5377    pub fn add_code_action_provider(
 5378        &mut self,
 5379        provider: Rc<dyn CodeActionProvider>,
 5380        window: &mut Window,
 5381        cx: &mut Context<Self>,
 5382    ) {
 5383        if self
 5384            .code_action_providers
 5385            .iter()
 5386            .any(|existing_provider| existing_provider.id() == provider.id())
 5387        {
 5388            return;
 5389        }
 5390
 5391        self.code_action_providers.push(provider);
 5392        self.refresh_code_actions(window, cx);
 5393    }
 5394
 5395    pub fn remove_code_action_provider(
 5396        &mut self,
 5397        id: Arc<str>,
 5398        window: &mut Window,
 5399        cx: &mut Context<Self>,
 5400    ) {
 5401        self.code_action_providers
 5402            .retain(|provider| provider.id() != id);
 5403        self.refresh_code_actions(window, cx);
 5404    }
 5405
 5406    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5407        let newest_selection = self.selections.newest_anchor().clone();
 5408        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5409        let buffer = self.buffer.read(cx);
 5410        if newest_selection.head().diff_base_anchor.is_some() {
 5411            return None;
 5412        }
 5413        let (start_buffer, start) =
 5414            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5415        let (end_buffer, end) =
 5416            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5417        if start_buffer != end_buffer {
 5418            return None;
 5419        }
 5420
 5421        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5422            cx.background_executor()
 5423                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5424                .await;
 5425
 5426            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5427                let providers = this.code_action_providers.clone();
 5428                let tasks = this
 5429                    .code_action_providers
 5430                    .iter()
 5431                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5432                    .collect::<Vec<_>>();
 5433                (providers, tasks)
 5434            })?;
 5435
 5436            let mut actions = Vec::new();
 5437            for (provider, provider_actions) in
 5438                providers.into_iter().zip(future::join_all(tasks).await)
 5439            {
 5440                if let Some(provider_actions) = provider_actions.log_err() {
 5441                    actions.extend(provider_actions.into_iter().map(|action| {
 5442                        AvailableCodeAction {
 5443                            excerpt_id: newest_selection.start.excerpt_id,
 5444                            action,
 5445                            provider: provider.clone(),
 5446                        }
 5447                    }));
 5448                }
 5449            }
 5450
 5451            this.update(cx, |this, cx| {
 5452                this.available_code_actions = if actions.is_empty() {
 5453                    None
 5454                } else {
 5455                    Some((
 5456                        Location {
 5457                            buffer: start_buffer,
 5458                            range: start..end,
 5459                        },
 5460                        actions.into(),
 5461                    ))
 5462                };
 5463                cx.notify();
 5464            })
 5465        }));
 5466        None
 5467    }
 5468
 5469    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5470        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5471            self.show_git_blame_inline = false;
 5472
 5473            self.show_git_blame_inline_delay_task =
 5474                Some(cx.spawn_in(window, async move |this, cx| {
 5475                    cx.background_executor().timer(delay).await;
 5476
 5477                    this.update(cx, |this, cx| {
 5478                        this.show_git_blame_inline = true;
 5479                        cx.notify();
 5480                    })
 5481                    .log_err();
 5482                }));
 5483        }
 5484    }
 5485
 5486    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5487        if self.pending_rename.is_some() {
 5488            return None;
 5489        }
 5490
 5491        let provider = self.semantics_provider.clone()?;
 5492        let buffer = self.buffer.read(cx);
 5493        let newest_selection = self.selections.newest_anchor().clone();
 5494        let cursor_position = newest_selection.head();
 5495        let (cursor_buffer, cursor_buffer_position) =
 5496            buffer.text_anchor_for_position(cursor_position, cx)?;
 5497        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5498        if cursor_buffer != tail_buffer {
 5499            return None;
 5500        }
 5501        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5502        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5503            cx.background_executor()
 5504                .timer(Duration::from_millis(debounce))
 5505                .await;
 5506
 5507            let highlights = if let Some(highlights) = cx
 5508                .update(|cx| {
 5509                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5510                })
 5511                .ok()
 5512                .flatten()
 5513            {
 5514                highlights.await.log_err()
 5515            } else {
 5516                None
 5517            };
 5518
 5519            if let Some(highlights) = highlights {
 5520                this.update(cx, |this, cx| {
 5521                    if this.pending_rename.is_some() {
 5522                        return;
 5523                    }
 5524
 5525                    let buffer_id = cursor_position.buffer_id;
 5526                    let buffer = this.buffer.read(cx);
 5527                    if !buffer
 5528                        .text_anchor_for_position(cursor_position, cx)
 5529                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5530                    {
 5531                        return;
 5532                    }
 5533
 5534                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5535                    let mut write_ranges = Vec::new();
 5536                    let mut read_ranges = Vec::new();
 5537                    for highlight in highlights {
 5538                        for (excerpt_id, excerpt_range) in
 5539                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5540                        {
 5541                            let start = highlight
 5542                                .range
 5543                                .start
 5544                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5545                            let end = highlight
 5546                                .range
 5547                                .end
 5548                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5549                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5550                                continue;
 5551                            }
 5552
 5553                            let range = Anchor {
 5554                                buffer_id,
 5555                                excerpt_id,
 5556                                text_anchor: start,
 5557                                diff_base_anchor: None,
 5558                            }..Anchor {
 5559                                buffer_id,
 5560                                excerpt_id,
 5561                                text_anchor: end,
 5562                                diff_base_anchor: None,
 5563                            };
 5564                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5565                                write_ranges.push(range);
 5566                            } else {
 5567                                read_ranges.push(range);
 5568                            }
 5569                        }
 5570                    }
 5571
 5572                    this.highlight_background::<DocumentHighlightRead>(
 5573                        &read_ranges,
 5574                        |theme| theme.editor_document_highlight_read_background,
 5575                        cx,
 5576                    );
 5577                    this.highlight_background::<DocumentHighlightWrite>(
 5578                        &write_ranges,
 5579                        |theme| theme.editor_document_highlight_write_background,
 5580                        cx,
 5581                    );
 5582                    cx.notify();
 5583                })
 5584                .log_err();
 5585            }
 5586        }));
 5587        None
 5588    }
 5589
 5590    fn prepare_highlight_query_from_selection(
 5591        &mut self,
 5592        cx: &mut Context<Editor>,
 5593    ) -> Option<(String, Range<Anchor>)> {
 5594        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 5595            return None;
 5596        }
 5597        if !EditorSettings::get_global(cx).selection_highlight {
 5598            return None;
 5599        }
 5600        if self.selections.count() != 1 || self.selections.line_mode {
 5601            return None;
 5602        }
 5603        let selection = self.selections.newest::<Point>(cx);
 5604        if selection.is_empty() || selection.start.row != selection.end.row {
 5605            return None;
 5606        }
 5607        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5608        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 5609        let query = multi_buffer_snapshot
 5610            .text_for_range(selection_anchor_range.clone())
 5611            .collect::<String>();
 5612        if query.trim().is_empty() {
 5613            return None;
 5614        }
 5615        Some((query, selection_anchor_range))
 5616    }
 5617
 5618    fn update_selection_occurrence_highlights(
 5619        &mut self,
 5620        query_text: String,
 5621        query_range: Range<Anchor>,
 5622        multi_buffer_range_to_query: Range<Point>,
 5623        use_debounce: bool,
 5624        window: &mut Window,
 5625        cx: &mut Context<Editor>,
 5626    ) -> Task<()> {
 5627        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5628        cx.spawn_in(window, async move |editor, cx| {
 5629            if use_debounce {
 5630                cx.background_executor()
 5631                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 5632                    .await;
 5633            }
 5634            let match_task = cx.background_spawn(async move {
 5635                let buffer_ranges = multi_buffer_snapshot
 5636                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 5637                    .into_iter()
 5638                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 5639                let mut match_ranges = Vec::new();
 5640                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 5641                    match_ranges.extend(
 5642                        project::search::SearchQuery::text(
 5643                            query_text.clone(),
 5644                            false,
 5645                            false,
 5646                            false,
 5647                            Default::default(),
 5648                            Default::default(),
 5649                            false,
 5650                            None,
 5651                        )
 5652                        .unwrap()
 5653                        .search(&buffer_snapshot, Some(search_range.clone()))
 5654                        .await
 5655                        .into_iter()
 5656                        .filter_map(|match_range| {
 5657                            let match_start = buffer_snapshot
 5658                                .anchor_after(search_range.start + match_range.start);
 5659                            let match_end =
 5660                                buffer_snapshot.anchor_before(search_range.start + match_range.end);
 5661                            let match_anchor_range = Anchor::range_in_buffer(
 5662                                excerpt_id,
 5663                                buffer_snapshot.remote_id(),
 5664                                match_start..match_end,
 5665                            );
 5666                            (match_anchor_range != query_range).then_some(match_anchor_range)
 5667                        }),
 5668                    );
 5669                }
 5670                match_ranges
 5671            });
 5672            let match_ranges = match_task.await;
 5673            editor
 5674                .update_in(cx, |editor, _, cx| {
 5675                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 5676                    if !match_ranges.is_empty() {
 5677                        editor.highlight_background::<SelectedTextHighlight>(
 5678                            &match_ranges,
 5679                            |theme| theme.editor_document_highlight_bracket_background,
 5680                            cx,
 5681                        )
 5682                    }
 5683                })
 5684                .log_err();
 5685        })
 5686    }
 5687
 5688    fn refresh_selected_text_highlights(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 5689        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 5690        else {
 5691            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 5692            self.quick_selection_highlight_task.take();
 5693            self.debounced_selection_highlight_task.take();
 5694            return;
 5695        };
 5696        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5697        if self
 5698            .quick_selection_highlight_task
 5699            .as_ref()
 5700            .map_or(true, |(prev_anchor_range, _)| {
 5701                prev_anchor_range != &query_range
 5702            })
 5703        {
 5704            let multi_buffer_visible_start = self
 5705                .scroll_manager
 5706                .anchor()
 5707                .anchor
 5708                .to_point(&multi_buffer_snapshot);
 5709            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5710                multi_buffer_visible_start
 5711                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5712                Bias::Left,
 5713            );
 5714            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5715            self.quick_selection_highlight_task = Some((
 5716                query_range.clone(),
 5717                self.update_selection_occurrence_highlights(
 5718                    query_text.clone(),
 5719                    query_range.clone(),
 5720                    multi_buffer_visible_range,
 5721                    false,
 5722                    window,
 5723                    cx,
 5724                ),
 5725            ));
 5726        }
 5727        if self
 5728            .debounced_selection_highlight_task
 5729            .as_ref()
 5730            .map_or(true, |(prev_anchor_range, _)| {
 5731                prev_anchor_range != &query_range
 5732            })
 5733        {
 5734            let multi_buffer_start = multi_buffer_snapshot
 5735                .anchor_before(0)
 5736                .to_point(&multi_buffer_snapshot);
 5737            let multi_buffer_end = multi_buffer_snapshot
 5738                .anchor_after(multi_buffer_snapshot.len())
 5739                .to_point(&multi_buffer_snapshot);
 5740            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 5741            self.debounced_selection_highlight_task = Some((
 5742                query_range.clone(),
 5743                self.update_selection_occurrence_highlights(
 5744                    query_text,
 5745                    query_range,
 5746                    multi_buffer_full_range,
 5747                    true,
 5748                    window,
 5749                    cx,
 5750                ),
 5751            ));
 5752        }
 5753    }
 5754
 5755    pub fn refresh_inline_completion(
 5756        &mut self,
 5757        debounce: bool,
 5758        user_requested: bool,
 5759        window: &mut Window,
 5760        cx: &mut Context<Self>,
 5761    ) -> Option<()> {
 5762        let provider = self.edit_prediction_provider()?;
 5763        let cursor = self.selections.newest_anchor().head();
 5764        let (buffer, cursor_buffer_position) =
 5765            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 5766
 5767        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 5768            self.discard_inline_completion(false, cx);
 5769            return None;
 5770        }
 5771
 5772        if !user_requested
 5773            && (!self.should_show_edit_predictions()
 5774                || !self.is_focused(window)
 5775                || buffer.read(cx).is_empty())
 5776        {
 5777            self.discard_inline_completion(false, cx);
 5778            return None;
 5779        }
 5780
 5781        self.update_visible_inline_completion(window, cx);
 5782        provider.refresh(
 5783            self.project.clone(),
 5784            buffer,
 5785            cursor_buffer_position,
 5786            debounce,
 5787            cx,
 5788        );
 5789        Some(())
 5790    }
 5791
 5792    fn show_edit_predictions_in_menu(&self) -> bool {
 5793        match self.edit_prediction_settings {
 5794            EditPredictionSettings::Disabled => false,
 5795            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 5796        }
 5797    }
 5798
 5799    pub fn edit_predictions_enabled(&self) -> bool {
 5800        match self.edit_prediction_settings {
 5801            EditPredictionSettings::Disabled => false,
 5802            EditPredictionSettings::Enabled { .. } => true,
 5803        }
 5804    }
 5805
 5806    fn edit_prediction_requires_modifier(&self) -> bool {
 5807        match self.edit_prediction_settings {
 5808            EditPredictionSettings::Disabled => false,
 5809            EditPredictionSettings::Enabled {
 5810                preview_requires_modifier,
 5811                ..
 5812            } => preview_requires_modifier,
 5813        }
 5814    }
 5815
 5816    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 5817        if self.edit_prediction_provider.is_none() {
 5818            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 5819        } else {
 5820            let selection = self.selections.newest_anchor();
 5821            let cursor = selection.head();
 5822
 5823            if let Some((buffer, cursor_buffer_position)) =
 5824                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 5825            {
 5826                self.edit_prediction_settings =
 5827                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 5828            }
 5829        }
 5830    }
 5831
 5832    fn edit_prediction_settings_at_position(
 5833        &self,
 5834        buffer: &Entity<Buffer>,
 5835        buffer_position: language::Anchor,
 5836        cx: &App,
 5837    ) -> EditPredictionSettings {
 5838        if !self.mode.is_full()
 5839            || !self.show_inline_completions_override.unwrap_or(true)
 5840            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 5841        {
 5842            return EditPredictionSettings::Disabled;
 5843        }
 5844
 5845        let buffer = buffer.read(cx);
 5846
 5847        let file = buffer.file();
 5848
 5849        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 5850            return EditPredictionSettings::Disabled;
 5851        };
 5852
 5853        let by_provider = matches!(
 5854            self.menu_inline_completions_policy,
 5855            MenuInlineCompletionsPolicy::ByProvider
 5856        );
 5857
 5858        let show_in_menu = by_provider
 5859            && self
 5860                .edit_prediction_provider
 5861                .as_ref()
 5862                .map_or(false, |provider| {
 5863                    provider.provider.show_completions_in_menu()
 5864                });
 5865
 5866        let preview_requires_modifier =
 5867            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 5868
 5869        EditPredictionSettings::Enabled {
 5870            show_in_menu,
 5871            preview_requires_modifier,
 5872        }
 5873    }
 5874
 5875    fn should_show_edit_predictions(&self) -> bool {
 5876        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 5877    }
 5878
 5879    pub fn edit_prediction_preview_is_active(&self) -> bool {
 5880        matches!(
 5881            self.edit_prediction_preview,
 5882            EditPredictionPreview::Active { .. }
 5883        )
 5884    }
 5885
 5886    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 5887        let cursor = self.selections.newest_anchor().head();
 5888        if let Some((buffer, cursor_position)) =
 5889            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 5890        {
 5891            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 5892        } else {
 5893            false
 5894        }
 5895    }
 5896
 5897    fn edit_predictions_enabled_in_buffer(
 5898        &self,
 5899        buffer: &Entity<Buffer>,
 5900        buffer_position: language::Anchor,
 5901        cx: &App,
 5902    ) -> bool {
 5903        maybe!({
 5904            if self.read_only(cx) {
 5905                return Some(false);
 5906            }
 5907            let provider = self.edit_prediction_provider()?;
 5908            if !provider.is_enabled(&buffer, buffer_position, cx) {
 5909                return Some(false);
 5910            }
 5911            let buffer = buffer.read(cx);
 5912            let Some(file) = buffer.file() else {
 5913                return Some(true);
 5914            };
 5915            let settings = all_language_settings(Some(file), cx);
 5916            Some(settings.edit_predictions_enabled_for_file(file, cx))
 5917        })
 5918        .unwrap_or(false)
 5919    }
 5920
 5921    fn cycle_inline_completion(
 5922        &mut self,
 5923        direction: Direction,
 5924        window: &mut Window,
 5925        cx: &mut Context<Self>,
 5926    ) -> Option<()> {
 5927        let provider = self.edit_prediction_provider()?;
 5928        let cursor = self.selections.newest_anchor().head();
 5929        let (buffer, cursor_buffer_position) =
 5930            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 5931        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 5932            return None;
 5933        }
 5934
 5935        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 5936        self.update_visible_inline_completion(window, cx);
 5937
 5938        Some(())
 5939    }
 5940
 5941    pub fn show_inline_completion(
 5942        &mut self,
 5943        _: &ShowEditPrediction,
 5944        window: &mut Window,
 5945        cx: &mut Context<Self>,
 5946    ) {
 5947        if !self.has_active_inline_completion() {
 5948            self.refresh_inline_completion(false, true, window, cx);
 5949            return;
 5950        }
 5951
 5952        self.update_visible_inline_completion(window, cx);
 5953    }
 5954
 5955    pub fn display_cursor_names(
 5956        &mut self,
 5957        _: &DisplayCursorNames,
 5958        window: &mut Window,
 5959        cx: &mut Context<Self>,
 5960    ) {
 5961        self.show_cursor_names(window, cx);
 5962    }
 5963
 5964    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5965        self.show_cursor_names = true;
 5966        cx.notify();
 5967        cx.spawn_in(window, async move |this, cx| {
 5968            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 5969            this.update(cx, |this, cx| {
 5970                this.show_cursor_names = false;
 5971                cx.notify()
 5972            })
 5973            .ok()
 5974        })
 5975        .detach();
 5976    }
 5977
 5978    pub fn next_edit_prediction(
 5979        &mut self,
 5980        _: &NextEditPrediction,
 5981        window: &mut Window,
 5982        cx: &mut Context<Self>,
 5983    ) {
 5984        if self.has_active_inline_completion() {
 5985            self.cycle_inline_completion(Direction::Next, window, cx);
 5986        } else {
 5987            let is_copilot_disabled = self
 5988                .refresh_inline_completion(false, true, window, cx)
 5989                .is_none();
 5990            if is_copilot_disabled {
 5991                cx.propagate();
 5992            }
 5993        }
 5994    }
 5995
 5996    pub fn previous_edit_prediction(
 5997        &mut self,
 5998        _: &PreviousEditPrediction,
 5999        window: &mut Window,
 6000        cx: &mut Context<Self>,
 6001    ) {
 6002        if self.has_active_inline_completion() {
 6003            self.cycle_inline_completion(Direction::Prev, window, cx);
 6004        } else {
 6005            let is_copilot_disabled = self
 6006                .refresh_inline_completion(false, true, window, cx)
 6007                .is_none();
 6008            if is_copilot_disabled {
 6009                cx.propagate();
 6010            }
 6011        }
 6012    }
 6013
 6014    pub fn accept_edit_prediction(
 6015        &mut self,
 6016        _: &AcceptEditPrediction,
 6017        window: &mut Window,
 6018        cx: &mut Context<Self>,
 6019    ) {
 6020        if self.show_edit_predictions_in_menu() {
 6021            self.hide_context_menu(window, cx);
 6022        }
 6023
 6024        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6025            return;
 6026        };
 6027
 6028        self.report_inline_completion_event(
 6029            active_inline_completion.completion_id.clone(),
 6030            true,
 6031            cx,
 6032        );
 6033
 6034        match &active_inline_completion.completion {
 6035            InlineCompletion::Move { target, .. } => {
 6036                let target = *target;
 6037
 6038                if let Some(position_map) = &self.last_position_map {
 6039                    if position_map
 6040                        .visible_row_range
 6041                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6042                        || !self.edit_prediction_requires_modifier()
 6043                    {
 6044                        self.unfold_ranges(&[target..target], true, false, cx);
 6045                        // Note that this is also done in vim's handler of the Tab action.
 6046                        self.change_selections(
 6047                            Some(Autoscroll::newest()),
 6048                            window,
 6049                            cx,
 6050                            |selections| {
 6051                                selections.select_anchor_ranges([target..target]);
 6052                            },
 6053                        );
 6054                        self.clear_row_highlights::<EditPredictionPreview>();
 6055
 6056                        self.edit_prediction_preview
 6057                            .set_previous_scroll_position(None);
 6058                    } else {
 6059                        self.edit_prediction_preview
 6060                            .set_previous_scroll_position(Some(
 6061                                position_map.snapshot.scroll_anchor,
 6062                            ));
 6063
 6064                        self.highlight_rows::<EditPredictionPreview>(
 6065                            target..target,
 6066                            cx.theme().colors().editor_highlighted_line_background,
 6067                            RowHighlightOptions {
 6068                                autoscroll: true,
 6069                                ..Default::default()
 6070                            },
 6071                            cx,
 6072                        );
 6073                        self.request_autoscroll(Autoscroll::fit(), cx);
 6074                    }
 6075                }
 6076            }
 6077            InlineCompletion::Edit { edits, .. } => {
 6078                if let Some(provider) = self.edit_prediction_provider() {
 6079                    provider.accept(cx);
 6080                }
 6081
 6082                let snapshot = self.buffer.read(cx).snapshot(cx);
 6083                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6084
 6085                self.buffer.update(cx, |buffer, cx| {
 6086                    buffer.edit(edits.iter().cloned(), None, cx)
 6087                });
 6088
 6089                self.change_selections(None, window, cx, |s| {
 6090                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 6091                });
 6092
 6093                self.update_visible_inline_completion(window, cx);
 6094                if self.active_inline_completion.is_none() {
 6095                    self.refresh_inline_completion(true, true, window, cx);
 6096                }
 6097
 6098                cx.notify();
 6099            }
 6100        }
 6101
 6102        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6103    }
 6104
 6105    pub fn accept_partial_inline_completion(
 6106        &mut self,
 6107        _: &AcceptPartialEditPrediction,
 6108        window: &mut Window,
 6109        cx: &mut Context<Self>,
 6110    ) {
 6111        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6112            return;
 6113        };
 6114        if self.selections.count() != 1 {
 6115            return;
 6116        }
 6117
 6118        self.report_inline_completion_event(
 6119            active_inline_completion.completion_id.clone(),
 6120            true,
 6121            cx,
 6122        );
 6123
 6124        match &active_inline_completion.completion {
 6125            InlineCompletion::Move { target, .. } => {
 6126                let target = *target;
 6127                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6128                    selections.select_anchor_ranges([target..target]);
 6129                });
 6130            }
 6131            InlineCompletion::Edit { edits, .. } => {
 6132                // Find an insertion that starts at the cursor position.
 6133                let snapshot = self.buffer.read(cx).snapshot(cx);
 6134                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6135                let insertion = edits.iter().find_map(|(range, text)| {
 6136                    let range = range.to_offset(&snapshot);
 6137                    if range.is_empty() && range.start == cursor_offset {
 6138                        Some(text)
 6139                    } else {
 6140                        None
 6141                    }
 6142                });
 6143
 6144                if let Some(text) = insertion {
 6145                    let mut partial_completion = text
 6146                        .chars()
 6147                        .by_ref()
 6148                        .take_while(|c| c.is_alphabetic())
 6149                        .collect::<String>();
 6150                    if partial_completion.is_empty() {
 6151                        partial_completion = text
 6152                            .chars()
 6153                            .by_ref()
 6154                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6155                            .collect::<String>();
 6156                    }
 6157
 6158                    cx.emit(EditorEvent::InputHandled {
 6159                        utf16_range_to_replace: None,
 6160                        text: partial_completion.clone().into(),
 6161                    });
 6162
 6163                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6164
 6165                    self.refresh_inline_completion(true, true, window, cx);
 6166                    cx.notify();
 6167                } else {
 6168                    self.accept_edit_prediction(&Default::default(), window, cx);
 6169                }
 6170            }
 6171        }
 6172    }
 6173
 6174    fn discard_inline_completion(
 6175        &mut self,
 6176        should_report_inline_completion_event: bool,
 6177        cx: &mut Context<Self>,
 6178    ) -> bool {
 6179        if should_report_inline_completion_event {
 6180            let completion_id = self
 6181                .active_inline_completion
 6182                .as_ref()
 6183                .and_then(|active_completion| active_completion.completion_id.clone());
 6184
 6185            self.report_inline_completion_event(completion_id, false, cx);
 6186        }
 6187
 6188        if let Some(provider) = self.edit_prediction_provider() {
 6189            provider.discard(cx);
 6190        }
 6191
 6192        self.take_active_inline_completion(cx)
 6193    }
 6194
 6195    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6196        let Some(provider) = self.edit_prediction_provider() else {
 6197            return;
 6198        };
 6199
 6200        let Some((_, buffer, _)) = self
 6201            .buffer
 6202            .read(cx)
 6203            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6204        else {
 6205            return;
 6206        };
 6207
 6208        let extension = buffer
 6209            .read(cx)
 6210            .file()
 6211            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6212
 6213        let event_type = match accepted {
 6214            true => "Edit Prediction Accepted",
 6215            false => "Edit Prediction Discarded",
 6216        };
 6217        telemetry::event!(
 6218            event_type,
 6219            provider = provider.name(),
 6220            prediction_id = id,
 6221            suggestion_accepted = accepted,
 6222            file_extension = extension,
 6223        );
 6224    }
 6225
 6226    pub fn has_active_inline_completion(&self) -> bool {
 6227        self.active_inline_completion.is_some()
 6228    }
 6229
 6230    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6231        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6232            return false;
 6233        };
 6234
 6235        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6236        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6237        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6238        true
 6239    }
 6240
 6241    /// Returns true when we're displaying the edit prediction popover below the cursor
 6242    /// like we are not previewing and the LSP autocomplete menu is visible
 6243    /// or we are in `when_holding_modifier` mode.
 6244    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6245        if self.edit_prediction_preview_is_active()
 6246            || !self.show_edit_predictions_in_menu()
 6247            || !self.edit_predictions_enabled()
 6248        {
 6249            return false;
 6250        }
 6251
 6252        if self.has_visible_completions_menu() {
 6253            return true;
 6254        }
 6255
 6256        has_completion && self.edit_prediction_requires_modifier()
 6257    }
 6258
 6259    fn handle_modifiers_changed(
 6260        &mut self,
 6261        modifiers: Modifiers,
 6262        position_map: &PositionMap,
 6263        window: &mut Window,
 6264        cx: &mut Context<Self>,
 6265    ) {
 6266        if self.show_edit_predictions_in_menu() {
 6267            self.update_edit_prediction_preview(&modifiers, window, cx);
 6268        }
 6269
 6270        self.update_selection_mode(&modifiers, position_map, window, cx);
 6271
 6272        let mouse_position = window.mouse_position();
 6273        if !position_map.text_hitbox.is_hovered(window) {
 6274            return;
 6275        }
 6276
 6277        self.update_hovered_link(
 6278            position_map.point_for_position(mouse_position),
 6279            &position_map.snapshot,
 6280            modifiers,
 6281            window,
 6282            cx,
 6283        )
 6284    }
 6285
 6286    fn update_selection_mode(
 6287        &mut self,
 6288        modifiers: &Modifiers,
 6289        position_map: &PositionMap,
 6290        window: &mut Window,
 6291        cx: &mut Context<Self>,
 6292    ) {
 6293        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6294            return;
 6295        }
 6296
 6297        let mouse_position = window.mouse_position();
 6298        let point_for_position = position_map.point_for_position(mouse_position);
 6299        let position = point_for_position.previous_valid;
 6300
 6301        self.select(
 6302            SelectPhase::BeginColumnar {
 6303                position,
 6304                reset: false,
 6305                goal_column: point_for_position.exact_unclipped.column(),
 6306            },
 6307            window,
 6308            cx,
 6309        );
 6310    }
 6311
 6312    fn update_edit_prediction_preview(
 6313        &mut self,
 6314        modifiers: &Modifiers,
 6315        window: &mut Window,
 6316        cx: &mut Context<Self>,
 6317    ) {
 6318        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6319        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6320            return;
 6321        };
 6322
 6323        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6324            if matches!(
 6325                self.edit_prediction_preview,
 6326                EditPredictionPreview::Inactive { .. }
 6327            ) {
 6328                self.edit_prediction_preview = EditPredictionPreview::Active {
 6329                    previous_scroll_position: None,
 6330                    since: Instant::now(),
 6331                };
 6332
 6333                self.update_visible_inline_completion(window, cx);
 6334                cx.notify();
 6335            }
 6336        } else if let EditPredictionPreview::Active {
 6337            previous_scroll_position,
 6338            since,
 6339        } = self.edit_prediction_preview
 6340        {
 6341            if let (Some(previous_scroll_position), Some(position_map)) =
 6342                (previous_scroll_position, self.last_position_map.as_ref())
 6343            {
 6344                self.set_scroll_position(
 6345                    previous_scroll_position
 6346                        .scroll_position(&position_map.snapshot.display_snapshot),
 6347                    window,
 6348                    cx,
 6349                );
 6350            }
 6351
 6352            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6353                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6354            };
 6355            self.clear_row_highlights::<EditPredictionPreview>();
 6356            self.update_visible_inline_completion(window, cx);
 6357            cx.notify();
 6358        }
 6359    }
 6360
 6361    fn update_visible_inline_completion(
 6362        &mut self,
 6363        _window: &mut Window,
 6364        cx: &mut Context<Self>,
 6365    ) -> Option<()> {
 6366        let selection = self.selections.newest_anchor();
 6367        let cursor = selection.head();
 6368        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6369        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6370        let excerpt_id = cursor.excerpt_id;
 6371
 6372        let show_in_menu = self.show_edit_predictions_in_menu();
 6373        let completions_menu_has_precedence = !show_in_menu
 6374            && (self.context_menu.borrow().is_some()
 6375                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6376
 6377        if completions_menu_has_precedence
 6378            || !offset_selection.is_empty()
 6379            || self
 6380                .active_inline_completion
 6381                .as_ref()
 6382                .map_or(false, |completion| {
 6383                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6384                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6385                    !invalidation_range.contains(&offset_selection.head())
 6386                })
 6387        {
 6388            self.discard_inline_completion(false, cx);
 6389            return None;
 6390        }
 6391
 6392        self.take_active_inline_completion(cx);
 6393        let Some(provider) = self.edit_prediction_provider() else {
 6394            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6395            return None;
 6396        };
 6397
 6398        let (buffer, cursor_buffer_position) =
 6399            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6400
 6401        self.edit_prediction_settings =
 6402            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6403
 6404        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6405
 6406        if self.edit_prediction_indent_conflict {
 6407            let cursor_point = cursor.to_point(&multibuffer);
 6408
 6409            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6410
 6411            if let Some((_, indent)) = indents.iter().next() {
 6412                if indent.len == cursor_point.column {
 6413                    self.edit_prediction_indent_conflict = false;
 6414                }
 6415            }
 6416        }
 6417
 6418        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6419        let edits = inline_completion
 6420            .edits
 6421            .into_iter()
 6422            .flat_map(|(range, new_text)| {
 6423                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6424                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6425                Some((start..end, new_text))
 6426            })
 6427            .collect::<Vec<_>>();
 6428        if edits.is_empty() {
 6429            return None;
 6430        }
 6431
 6432        let first_edit_start = edits.first().unwrap().0.start;
 6433        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6434        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6435
 6436        let last_edit_end = edits.last().unwrap().0.end;
 6437        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6438        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6439
 6440        let cursor_row = cursor.to_point(&multibuffer).row;
 6441
 6442        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6443
 6444        let mut inlay_ids = Vec::new();
 6445        let invalidation_row_range;
 6446        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6447            Some(cursor_row..edit_end_row)
 6448        } else if cursor_row > edit_end_row {
 6449            Some(edit_start_row..cursor_row)
 6450        } else {
 6451            None
 6452        };
 6453        let is_move =
 6454            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6455        let completion = if is_move {
 6456            invalidation_row_range =
 6457                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6458            let target = first_edit_start;
 6459            InlineCompletion::Move { target, snapshot }
 6460        } else {
 6461            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6462                && !self.inline_completions_hidden_for_vim_mode;
 6463
 6464            if show_completions_in_buffer {
 6465                if edits
 6466                    .iter()
 6467                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6468                {
 6469                    let mut inlays = Vec::new();
 6470                    for (range, new_text) in &edits {
 6471                        let inlay = Inlay::inline_completion(
 6472                            post_inc(&mut self.next_inlay_id),
 6473                            range.start,
 6474                            new_text.as_str(),
 6475                        );
 6476                        inlay_ids.push(inlay.id);
 6477                        inlays.push(inlay);
 6478                    }
 6479
 6480                    self.splice_inlays(&[], inlays, cx);
 6481                } else {
 6482                    let background_color = cx.theme().status().deleted_background;
 6483                    self.highlight_text::<InlineCompletionHighlight>(
 6484                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6485                        HighlightStyle {
 6486                            background_color: Some(background_color),
 6487                            ..Default::default()
 6488                        },
 6489                        cx,
 6490                    );
 6491                }
 6492            }
 6493
 6494            invalidation_row_range = edit_start_row..edit_end_row;
 6495
 6496            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6497                if provider.show_tab_accept_marker() {
 6498                    EditDisplayMode::TabAccept
 6499                } else {
 6500                    EditDisplayMode::Inline
 6501                }
 6502            } else {
 6503                EditDisplayMode::DiffPopover
 6504            };
 6505
 6506            InlineCompletion::Edit {
 6507                edits,
 6508                edit_preview: inline_completion.edit_preview,
 6509                display_mode,
 6510                snapshot,
 6511            }
 6512        };
 6513
 6514        let invalidation_range = multibuffer
 6515            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6516            ..multibuffer.anchor_after(Point::new(
 6517                invalidation_row_range.end,
 6518                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6519            ));
 6520
 6521        self.stale_inline_completion_in_menu = None;
 6522        self.active_inline_completion = Some(InlineCompletionState {
 6523            inlay_ids,
 6524            completion,
 6525            completion_id: inline_completion.id,
 6526            invalidation_range,
 6527        });
 6528
 6529        cx.notify();
 6530
 6531        Some(())
 6532    }
 6533
 6534    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6535        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6536    }
 6537
 6538    fn render_code_actions_indicator(
 6539        &self,
 6540        _style: &EditorStyle,
 6541        row: DisplayRow,
 6542        is_active: bool,
 6543        breakpoint: Option<&(Anchor, Breakpoint)>,
 6544        cx: &mut Context<Self>,
 6545    ) -> Option<IconButton> {
 6546        let color = Color::Muted;
 6547        let position = breakpoint.as_ref().map(|(anchor, _)| *anchor);
 6548        let show_tooltip = !self.context_menu_visible();
 6549
 6550        if self.available_code_actions.is_some() {
 6551            Some(
 6552                IconButton::new("code_actions_indicator", ui::IconName::Bolt)
 6553                    .shape(ui::IconButtonShape::Square)
 6554                    .icon_size(IconSize::XSmall)
 6555                    .icon_color(color)
 6556                    .toggle_state(is_active)
 6557                    .when(show_tooltip, |this| {
 6558                        this.tooltip({
 6559                            let focus_handle = self.focus_handle.clone();
 6560                            move |window, cx| {
 6561                                Tooltip::for_action_in(
 6562                                    "Toggle Code Actions",
 6563                                    &ToggleCodeActions {
 6564                                        deployed_from_indicator: None,
 6565                                    },
 6566                                    &focus_handle,
 6567                                    window,
 6568                                    cx,
 6569                                )
 6570                            }
 6571                        })
 6572                    })
 6573                    .on_click(cx.listener(move |editor, _e, window, cx| {
 6574                        window.focus(&editor.focus_handle(cx));
 6575                        editor.toggle_code_actions(
 6576                            &ToggleCodeActions {
 6577                                deployed_from_indicator: Some(row),
 6578                            },
 6579                            window,
 6580                            cx,
 6581                        );
 6582                    }))
 6583                    .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 6584                        editor.set_breakpoint_context_menu(
 6585                            row,
 6586                            position,
 6587                            event.down.position,
 6588                            window,
 6589                            cx,
 6590                        );
 6591                    })),
 6592            )
 6593        } else {
 6594            None
 6595        }
 6596    }
 6597
 6598    fn clear_tasks(&mut self) {
 6599        self.tasks.clear()
 6600    }
 6601
 6602    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 6603        if self.tasks.insert(key, value).is_some() {
 6604            // This case should hopefully be rare, but just in case...
 6605            log::error!(
 6606                "multiple different run targets found on a single line, only the last target will be rendered"
 6607            )
 6608        }
 6609    }
 6610
 6611    /// Get all display points of breakpoints that will be rendered within editor
 6612    ///
 6613    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 6614    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 6615    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 6616    fn active_breakpoints(
 6617        &self,
 6618        range: Range<DisplayRow>,
 6619        window: &mut Window,
 6620        cx: &mut Context<Self>,
 6621    ) -> HashMap<DisplayRow, (Anchor, Breakpoint)> {
 6622        let mut breakpoint_display_points = HashMap::default();
 6623
 6624        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 6625            return breakpoint_display_points;
 6626        };
 6627
 6628        let snapshot = self.snapshot(window, cx);
 6629
 6630        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 6631        let Some(project) = self.project.as_ref() else {
 6632            return breakpoint_display_points;
 6633        };
 6634
 6635        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 6636            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 6637
 6638        for (buffer_snapshot, range, excerpt_id) in
 6639            multi_buffer_snapshot.range_to_buffer_ranges(range)
 6640        {
 6641            let Some(buffer) = project.read_with(cx, |this, cx| {
 6642                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 6643            }) else {
 6644                continue;
 6645            };
 6646            let breakpoints = breakpoint_store.read(cx).breakpoints(
 6647                &buffer,
 6648                Some(
 6649                    buffer_snapshot.anchor_before(range.start)
 6650                        ..buffer_snapshot.anchor_after(range.end),
 6651                ),
 6652                buffer_snapshot,
 6653                cx,
 6654            );
 6655            for (anchor, breakpoint) in breakpoints {
 6656                let multi_buffer_anchor =
 6657                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), *anchor);
 6658                let position = multi_buffer_anchor
 6659                    .to_point(&multi_buffer_snapshot)
 6660                    .to_display_point(&snapshot);
 6661
 6662                breakpoint_display_points
 6663                    .insert(position.row(), (multi_buffer_anchor, breakpoint.clone()));
 6664            }
 6665        }
 6666
 6667        breakpoint_display_points
 6668    }
 6669
 6670    fn breakpoint_context_menu(
 6671        &self,
 6672        anchor: Anchor,
 6673        window: &mut Window,
 6674        cx: &mut Context<Self>,
 6675    ) -> Entity<ui::ContextMenu> {
 6676        let weak_editor = cx.weak_entity();
 6677        let focus_handle = self.focus_handle(cx);
 6678
 6679        let row = self
 6680            .buffer
 6681            .read(cx)
 6682            .snapshot(cx)
 6683            .summary_for_anchor::<Point>(&anchor)
 6684            .row;
 6685
 6686        let breakpoint = self
 6687            .breakpoint_at_row(row, window, cx)
 6688            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 6689
 6690        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 6691            "Edit Log Breakpoint"
 6692        } else {
 6693            "Set Log Breakpoint"
 6694        };
 6695
 6696        let condition_breakpoint_msg = if breakpoint
 6697            .as_ref()
 6698            .is_some_and(|bp| bp.1.condition.is_some())
 6699        {
 6700            "Edit Condition Breakpoint"
 6701        } else {
 6702            "Set Condition Breakpoint"
 6703        };
 6704
 6705        let hit_condition_breakpoint_msg = if breakpoint
 6706            .as_ref()
 6707            .is_some_and(|bp| bp.1.hit_condition.is_some())
 6708        {
 6709            "Edit Hit Condition Breakpoint"
 6710        } else {
 6711            "Set Hit Condition Breakpoint"
 6712        };
 6713
 6714        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 6715            "Unset Breakpoint"
 6716        } else {
 6717            "Set Breakpoint"
 6718        };
 6719
 6720        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 6721            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 6722
 6723        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 6724            BreakpointState::Enabled => Some("Disable"),
 6725            BreakpointState::Disabled => Some("Enable"),
 6726        });
 6727
 6728        let (anchor, breakpoint) =
 6729            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 6730
 6731        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 6732            menu.on_blur_subscription(Subscription::new(|| {}))
 6733                .context(focus_handle)
 6734                .when(run_to_cursor, |this| {
 6735                    let weak_editor = weak_editor.clone();
 6736                    this.entry("Run to cursor", None, move |window, cx| {
 6737                        weak_editor
 6738                            .update(cx, |editor, cx| {
 6739                                editor.change_selections(None, window, cx, |s| {
 6740                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 6741                                });
 6742                            })
 6743                            .ok();
 6744
 6745                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 6746                    })
 6747                    .separator()
 6748                })
 6749                .when_some(toggle_state_msg, |this, msg| {
 6750                    this.entry(msg, None, {
 6751                        let weak_editor = weak_editor.clone();
 6752                        let breakpoint = breakpoint.clone();
 6753                        move |_window, cx| {
 6754                            weak_editor
 6755                                .update(cx, |this, cx| {
 6756                                    this.edit_breakpoint_at_anchor(
 6757                                        anchor,
 6758                                        breakpoint.as_ref().clone(),
 6759                                        BreakpointEditAction::InvertState,
 6760                                        cx,
 6761                                    );
 6762                                })
 6763                                .log_err();
 6764                        }
 6765                    })
 6766                })
 6767                .entry(set_breakpoint_msg, None, {
 6768                    let weak_editor = weak_editor.clone();
 6769                    let breakpoint = breakpoint.clone();
 6770                    move |_window, cx| {
 6771                        weak_editor
 6772                            .update(cx, |this, cx| {
 6773                                this.edit_breakpoint_at_anchor(
 6774                                    anchor,
 6775                                    breakpoint.as_ref().clone(),
 6776                                    BreakpointEditAction::Toggle,
 6777                                    cx,
 6778                                );
 6779                            })
 6780                            .log_err();
 6781                    }
 6782                })
 6783                .entry(log_breakpoint_msg, None, {
 6784                    let breakpoint = breakpoint.clone();
 6785                    let weak_editor = weak_editor.clone();
 6786                    move |window, cx| {
 6787                        weak_editor
 6788                            .update(cx, |this, cx| {
 6789                                this.add_edit_breakpoint_block(
 6790                                    anchor,
 6791                                    breakpoint.as_ref(),
 6792                                    BreakpointPromptEditAction::Log,
 6793                                    window,
 6794                                    cx,
 6795                                );
 6796                            })
 6797                            .log_err();
 6798                    }
 6799                })
 6800                .entry(condition_breakpoint_msg, None, {
 6801                    let breakpoint = breakpoint.clone();
 6802                    let weak_editor = weak_editor.clone();
 6803                    move |window, cx| {
 6804                        weak_editor
 6805                            .update(cx, |this, cx| {
 6806                                this.add_edit_breakpoint_block(
 6807                                    anchor,
 6808                                    breakpoint.as_ref(),
 6809                                    BreakpointPromptEditAction::Condition,
 6810                                    window,
 6811                                    cx,
 6812                                );
 6813                            })
 6814                            .log_err();
 6815                    }
 6816                })
 6817                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 6818                    weak_editor
 6819                        .update(cx, |this, cx| {
 6820                            this.add_edit_breakpoint_block(
 6821                                anchor,
 6822                                breakpoint.as_ref(),
 6823                                BreakpointPromptEditAction::HitCondition,
 6824                                window,
 6825                                cx,
 6826                            );
 6827                        })
 6828                        .log_err();
 6829                })
 6830        })
 6831    }
 6832
 6833    fn render_breakpoint(
 6834        &self,
 6835        position: Anchor,
 6836        row: DisplayRow,
 6837        breakpoint: &Breakpoint,
 6838        cx: &mut Context<Self>,
 6839    ) -> IconButton {
 6840        let (color, icon) = {
 6841            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 6842                (false, false) => ui::IconName::DebugBreakpoint,
 6843                (true, false) => ui::IconName::DebugLogBreakpoint,
 6844                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 6845                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 6846            };
 6847
 6848            let color = if self
 6849                .gutter_breakpoint_indicator
 6850                .0
 6851                .is_some_and(|(point, is_visible)| is_visible && point.row() == row)
 6852            {
 6853                Color::Hint
 6854            } else {
 6855                Color::Debugger
 6856            };
 6857
 6858            (color, icon)
 6859        };
 6860
 6861        let breakpoint = Arc::from(breakpoint.clone());
 6862
 6863        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 6864            .icon_size(IconSize::XSmall)
 6865            .size(ui::ButtonSize::None)
 6866            .icon_color(color)
 6867            .style(ButtonStyle::Transparent)
 6868            .on_click(cx.listener({
 6869                let breakpoint = breakpoint.clone();
 6870
 6871                move |editor, event: &ClickEvent, window, cx| {
 6872                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 6873                        BreakpointEditAction::InvertState
 6874                    } else {
 6875                        BreakpointEditAction::Toggle
 6876                    };
 6877
 6878                    window.focus(&editor.focus_handle(cx));
 6879                    editor.edit_breakpoint_at_anchor(
 6880                        position,
 6881                        breakpoint.as_ref().clone(),
 6882                        edit_action,
 6883                        cx,
 6884                    );
 6885                }
 6886            }))
 6887            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 6888                editor.set_breakpoint_context_menu(
 6889                    row,
 6890                    Some(position),
 6891                    event.down.position,
 6892                    window,
 6893                    cx,
 6894                );
 6895            }))
 6896    }
 6897
 6898    fn build_tasks_context(
 6899        project: &Entity<Project>,
 6900        buffer: &Entity<Buffer>,
 6901        buffer_row: u32,
 6902        tasks: &Arc<RunnableTasks>,
 6903        cx: &mut Context<Self>,
 6904    ) -> Task<Option<task::TaskContext>> {
 6905        let position = Point::new(buffer_row, tasks.column);
 6906        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 6907        let location = Location {
 6908            buffer: buffer.clone(),
 6909            range: range_start..range_start,
 6910        };
 6911        // Fill in the environmental variables from the tree-sitter captures
 6912        let mut captured_task_variables = TaskVariables::default();
 6913        for (capture_name, value) in tasks.extra_variables.clone() {
 6914            captured_task_variables.insert(
 6915                task::VariableName::Custom(capture_name.into()),
 6916                value.clone(),
 6917            );
 6918        }
 6919        project.update(cx, |project, cx| {
 6920            project.task_store().update(cx, |task_store, cx| {
 6921                task_store.task_context_for_location(captured_task_variables, location, cx)
 6922            })
 6923        })
 6924    }
 6925
 6926    pub fn spawn_nearest_task(
 6927        &mut self,
 6928        action: &SpawnNearestTask,
 6929        window: &mut Window,
 6930        cx: &mut Context<Self>,
 6931    ) {
 6932        let Some((workspace, _)) = self.workspace.clone() else {
 6933            return;
 6934        };
 6935        let Some(project) = self.project.clone() else {
 6936            return;
 6937        };
 6938
 6939        // Try to find a closest, enclosing node using tree-sitter that has a
 6940        // task
 6941        let Some((buffer, buffer_row, tasks)) = self
 6942            .find_enclosing_node_task(cx)
 6943            // Or find the task that's closest in row-distance.
 6944            .or_else(|| self.find_closest_task(cx))
 6945        else {
 6946            return;
 6947        };
 6948
 6949        let reveal_strategy = action.reveal;
 6950        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6951        cx.spawn_in(window, async move |_, cx| {
 6952            let context = task_context.await?;
 6953            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 6954
 6955            let resolved = resolved_task.resolved.as_mut()?;
 6956            resolved.reveal = reveal_strategy;
 6957
 6958            workspace
 6959                .update_in(cx, |workspace, window, cx| {
 6960                    workspace.schedule_resolved_task(
 6961                        task_source_kind,
 6962                        resolved_task,
 6963                        false,
 6964                        window,
 6965                        cx,
 6966                    );
 6967                })
 6968                .ok()
 6969        })
 6970        .detach();
 6971    }
 6972
 6973    fn find_closest_task(
 6974        &mut self,
 6975        cx: &mut Context<Self>,
 6976    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 6977        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 6978
 6979        let ((buffer_id, row), tasks) = self
 6980            .tasks
 6981            .iter()
 6982            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 6983
 6984        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 6985        let tasks = Arc::new(tasks.to_owned());
 6986        Some((buffer, *row, tasks))
 6987    }
 6988
 6989    fn find_enclosing_node_task(
 6990        &mut self,
 6991        cx: &mut Context<Self>,
 6992    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 6993        let snapshot = self.buffer.read(cx).snapshot(cx);
 6994        let offset = self.selections.newest::<usize>(cx).head();
 6995        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 6996        let buffer_id = excerpt.buffer().remote_id();
 6997
 6998        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 6999        let mut cursor = layer.node().walk();
 7000
 7001        while cursor.goto_first_child_for_byte(offset).is_some() {
 7002            if cursor.node().end_byte() == offset {
 7003                cursor.goto_next_sibling();
 7004            }
 7005        }
 7006
 7007        // Ascend to the smallest ancestor that contains the range and has a task.
 7008        loop {
 7009            let node = cursor.node();
 7010            let node_range = node.byte_range();
 7011            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7012
 7013            // Check if this node contains our offset
 7014            if node_range.start <= offset && node_range.end >= offset {
 7015                // If it contains offset, check for task
 7016                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7017                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7018                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7019                }
 7020            }
 7021
 7022            if !cursor.goto_parent() {
 7023                break;
 7024            }
 7025        }
 7026        None
 7027    }
 7028
 7029    fn render_run_indicator(
 7030        &self,
 7031        _style: &EditorStyle,
 7032        is_active: bool,
 7033        row: DisplayRow,
 7034        breakpoint: Option<(Anchor, Breakpoint)>,
 7035        cx: &mut Context<Self>,
 7036    ) -> IconButton {
 7037        let color = Color::Muted;
 7038        let position = breakpoint.as_ref().map(|(anchor, _)| *anchor);
 7039
 7040        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7041            .shape(ui::IconButtonShape::Square)
 7042            .icon_size(IconSize::XSmall)
 7043            .icon_color(color)
 7044            .toggle_state(is_active)
 7045            .on_click(cx.listener(move |editor, _e, window, cx| {
 7046                window.focus(&editor.focus_handle(cx));
 7047                editor.toggle_code_actions(
 7048                    &ToggleCodeActions {
 7049                        deployed_from_indicator: Some(row),
 7050                    },
 7051                    window,
 7052                    cx,
 7053                );
 7054            }))
 7055            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7056                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7057            }))
 7058    }
 7059
 7060    pub fn context_menu_visible(&self) -> bool {
 7061        !self.edit_prediction_preview_is_active()
 7062            && self
 7063                .context_menu
 7064                .borrow()
 7065                .as_ref()
 7066                .map_or(false, |menu| menu.visible())
 7067    }
 7068
 7069    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7070        self.context_menu
 7071            .borrow()
 7072            .as_ref()
 7073            .map(|menu| menu.origin())
 7074    }
 7075
 7076    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7077        self.context_menu_options = Some(options);
 7078    }
 7079
 7080    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7081    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7082
 7083    fn render_edit_prediction_popover(
 7084        &mut self,
 7085        text_bounds: &Bounds<Pixels>,
 7086        content_origin: gpui::Point<Pixels>,
 7087        editor_snapshot: &EditorSnapshot,
 7088        visible_row_range: Range<DisplayRow>,
 7089        scroll_top: f32,
 7090        scroll_bottom: f32,
 7091        line_layouts: &[LineWithInvisibles],
 7092        line_height: Pixels,
 7093        scroll_pixel_position: gpui::Point<Pixels>,
 7094        newest_selection_head: Option<DisplayPoint>,
 7095        editor_width: Pixels,
 7096        style: &EditorStyle,
 7097        window: &mut Window,
 7098        cx: &mut App,
 7099    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7100        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7101
 7102        if self.edit_prediction_visible_in_cursor_popover(true) {
 7103            return None;
 7104        }
 7105
 7106        match &active_inline_completion.completion {
 7107            InlineCompletion::Move { target, .. } => {
 7108                let target_display_point = target.to_display_point(editor_snapshot);
 7109
 7110                if self.edit_prediction_requires_modifier() {
 7111                    if !self.edit_prediction_preview_is_active() {
 7112                        return None;
 7113                    }
 7114
 7115                    self.render_edit_prediction_modifier_jump_popover(
 7116                        text_bounds,
 7117                        content_origin,
 7118                        visible_row_range,
 7119                        line_layouts,
 7120                        line_height,
 7121                        scroll_pixel_position,
 7122                        newest_selection_head,
 7123                        target_display_point,
 7124                        window,
 7125                        cx,
 7126                    )
 7127                } else {
 7128                    self.render_edit_prediction_eager_jump_popover(
 7129                        text_bounds,
 7130                        content_origin,
 7131                        editor_snapshot,
 7132                        visible_row_range,
 7133                        scroll_top,
 7134                        scroll_bottom,
 7135                        line_height,
 7136                        scroll_pixel_position,
 7137                        target_display_point,
 7138                        editor_width,
 7139                        window,
 7140                        cx,
 7141                    )
 7142                }
 7143            }
 7144            InlineCompletion::Edit {
 7145                display_mode: EditDisplayMode::Inline,
 7146                ..
 7147            } => None,
 7148            InlineCompletion::Edit {
 7149                display_mode: EditDisplayMode::TabAccept,
 7150                edits,
 7151                ..
 7152            } => {
 7153                let range = &edits.first()?.0;
 7154                let target_display_point = range.end.to_display_point(editor_snapshot);
 7155
 7156                self.render_edit_prediction_end_of_line_popover(
 7157                    "Accept",
 7158                    editor_snapshot,
 7159                    visible_row_range,
 7160                    target_display_point,
 7161                    line_height,
 7162                    scroll_pixel_position,
 7163                    content_origin,
 7164                    editor_width,
 7165                    window,
 7166                    cx,
 7167                )
 7168            }
 7169            InlineCompletion::Edit {
 7170                edits,
 7171                edit_preview,
 7172                display_mode: EditDisplayMode::DiffPopover,
 7173                snapshot,
 7174            } => self.render_edit_prediction_diff_popover(
 7175                text_bounds,
 7176                content_origin,
 7177                editor_snapshot,
 7178                visible_row_range,
 7179                line_layouts,
 7180                line_height,
 7181                scroll_pixel_position,
 7182                newest_selection_head,
 7183                editor_width,
 7184                style,
 7185                edits,
 7186                edit_preview,
 7187                snapshot,
 7188                window,
 7189                cx,
 7190            ),
 7191        }
 7192    }
 7193
 7194    fn render_edit_prediction_modifier_jump_popover(
 7195        &mut self,
 7196        text_bounds: &Bounds<Pixels>,
 7197        content_origin: gpui::Point<Pixels>,
 7198        visible_row_range: Range<DisplayRow>,
 7199        line_layouts: &[LineWithInvisibles],
 7200        line_height: Pixels,
 7201        scroll_pixel_position: gpui::Point<Pixels>,
 7202        newest_selection_head: Option<DisplayPoint>,
 7203        target_display_point: DisplayPoint,
 7204        window: &mut Window,
 7205        cx: &mut App,
 7206    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7207        let scrolled_content_origin =
 7208            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7209
 7210        const SCROLL_PADDING_Y: Pixels = px(12.);
 7211
 7212        if target_display_point.row() < visible_row_range.start {
 7213            return self.render_edit_prediction_scroll_popover(
 7214                |_| SCROLL_PADDING_Y,
 7215                IconName::ArrowUp,
 7216                visible_row_range,
 7217                line_layouts,
 7218                newest_selection_head,
 7219                scrolled_content_origin,
 7220                window,
 7221                cx,
 7222            );
 7223        } else if target_display_point.row() >= visible_row_range.end {
 7224            return self.render_edit_prediction_scroll_popover(
 7225                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7226                IconName::ArrowDown,
 7227                visible_row_range,
 7228                line_layouts,
 7229                newest_selection_head,
 7230                scrolled_content_origin,
 7231                window,
 7232                cx,
 7233            );
 7234        }
 7235
 7236        const POLE_WIDTH: Pixels = px(2.);
 7237
 7238        let line_layout =
 7239            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7240        let target_column = target_display_point.column() as usize;
 7241
 7242        let target_x = line_layout.x_for_index(target_column);
 7243        let target_y =
 7244            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7245
 7246        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7247
 7248        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7249        border_color.l += 0.001;
 7250
 7251        let mut element = v_flex()
 7252            .items_end()
 7253            .when(flag_on_right, |el| el.items_start())
 7254            .child(if flag_on_right {
 7255                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7256                    .rounded_bl(px(0.))
 7257                    .rounded_tl(px(0.))
 7258                    .border_l_2()
 7259                    .border_color(border_color)
 7260            } else {
 7261                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7262                    .rounded_br(px(0.))
 7263                    .rounded_tr(px(0.))
 7264                    .border_r_2()
 7265                    .border_color(border_color)
 7266            })
 7267            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7268            .into_any();
 7269
 7270        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7271
 7272        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7273            - point(
 7274                if flag_on_right {
 7275                    POLE_WIDTH
 7276                } else {
 7277                    size.width - POLE_WIDTH
 7278                },
 7279                size.height - line_height,
 7280            );
 7281
 7282        origin.x = origin.x.max(content_origin.x);
 7283
 7284        element.prepaint_at(origin, window, cx);
 7285
 7286        Some((element, origin))
 7287    }
 7288
 7289    fn render_edit_prediction_scroll_popover(
 7290        &mut self,
 7291        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7292        scroll_icon: IconName,
 7293        visible_row_range: Range<DisplayRow>,
 7294        line_layouts: &[LineWithInvisibles],
 7295        newest_selection_head: Option<DisplayPoint>,
 7296        scrolled_content_origin: gpui::Point<Pixels>,
 7297        window: &mut Window,
 7298        cx: &mut App,
 7299    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7300        let mut element = self
 7301            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7302            .into_any();
 7303
 7304        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7305
 7306        let cursor = newest_selection_head?;
 7307        let cursor_row_layout =
 7308            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7309        let cursor_column = cursor.column() as usize;
 7310
 7311        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7312
 7313        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7314
 7315        element.prepaint_at(origin, window, cx);
 7316        Some((element, origin))
 7317    }
 7318
 7319    fn render_edit_prediction_eager_jump_popover(
 7320        &mut self,
 7321        text_bounds: &Bounds<Pixels>,
 7322        content_origin: gpui::Point<Pixels>,
 7323        editor_snapshot: &EditorSnapshot,
 7324        visible_row_range: Range<DisplayRow>,
 7325        scroll_top: f32,
 7326        scroll_bottom: f32,
 7327        line_height: Pixels,
 7328        scroll_pixel_position: gpui::Point<Pixels>,
 7329        target_display_point: DisplayPoint,
 7330        editor_width: Pixels,
 7331        window: &mut Window,
 7332        cx: &mut App,
 7333    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7334        if target_display_point.row().as_f32() < scroll_top {
 7335            let mut element = self
 7336                .render_edit_prediction_line_popover(
 7337                    "Jump to Edit",
 7338                    Some(IconName::ArrowUp),
 7339                    window,
 7340                    cx,
 7341                )?
 7342                .into_any();
 7343
 7344            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7345            let offset = point(
 7346                (text_bounds.size.width - size.width) / 2.,
 7347                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7348            );
 7349
 7350            let origin = text_bounds.origin + offset;
 7351            element.prepaint_at(origin, window, cx);
 7352            Some((element, origin))
 7353        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7354            let mut element = self
 7355                .render_edit_prediction_line_popover(
 7356                    "Jump to Edit",
 7357                    Some(IconName::ArrowDown),
 7358                    window,
 7359                    cx,
 7360                )?
 7361                .into_any();
 7362
 7363            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7364            let offset = point(
 7365                (text_bounds.size.width - size.width) / 2.,
 7366                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7367            );
 7368
 7369            let origin = text_bounds.origin + offset;
 7370            element.prepaint_at(origin, window, cx);
 7371            Some((element, origin))
 7372        } else {
 7373            self.render_edit_prediction_end_of_line_popover(
 7374                "Jump to Edit",
 7375                editor_snapshot,
 7376                visible_row_range,
 7377                target_display_point,
 7378                line_height,
 7379                scroll_pixel_position,
 7380                content_origin,
 7381                editor_width,
 7382                window,
 7383                cx,
 7384            )
 7385        }
 7386    }
 7387
 7388    fn render_edit_prediction_end_of_line_popover(
 7389        self: &mut Editor,
 7390        label: &'static str,
 7391        editor_snapshot: &EditorSnapshot,
 7392        visible_row_range: Range<DisplayRow>,
 7393        target_display_point: DisplayPoint,
 7394        line_height: Pixels,
 7395        scroll_pixel_position: gpui::Point<Pixels>,
 7396        content_origin: gpui::Point<Pixels>,
 7397        editor_width: Pixels,
 7398        window: &mut Window,
 7399        cx: &mut App,
 7400    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7401        let target_line_end = DisplayPoint::new(
 7402            target_display_point.row(),
 7403            editor_snapshot.line_len(target_display_point.row()),
 7404        );
 7405
 7406        let mut element = self
 7407            .render_edit_prediction_line_popover(label, None, window, cx)?
 7408            .into_any();
 7409
 7410        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7411
 7412        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7413
 7414        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7415        let mut origin = start_point
 7416            + line_origin
 7417            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7418        origin.x = origin.x.max(content_origin.x);
 7419
 7420        let max_x = content_origin.x + editor_width - size.width;
 7421
 7422        if origin.x > max_x {
 7423            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7424
 7425            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7426                origin.y += offset;
 7427                IconName::ArrowUp
 7428            } else {
 7429                origin.y -= offset;
 7430                IconName::ArrowDown
 7431            };
 7432
 7433            element = self
 7434                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7435                .into_any();
 7436
 7437            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7438
 7439            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7440        }
 7441
 7442        element.prepaint_at(origin, window, cx);
 7443        Some((element, origin))
 7444    }
 7445
 7446    fn render_edit_prediction_diff_popover(
 7447        self: &Editor,
 7448        text_bounds: &Bounds<Pixels>,
 7449        content_origin: gpui::Point<Pixels>,
 7450        editor_snapshot: &EditorSnapshot,
 7451        visible_row_range: Range<DisplayRow>,
 7452        line_layouts: &[LineWithInvisibles],
 7453        line_height: Pixels,
 7454        scroll_pixel_position: gpui::Point<Pixels>,
 7455        newest_selection_head: Option<DisplayPoint>,
 7456        editor_width: Pixels,
 7457        style: &EditorStyle,
 7458        edits: &Vec<(Range<Anchor>, String)>,
 7459        edit_preview: &Option<language::EditPreview>,
 7460        snapshot: &language::BufferSnapshot,
 7461        window: &mut Window,
 7462        cx: &mut App,
 7463    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7464        let edit_start = edits
 7465            .first()
 7466            .unwrap()
 7467            .0
 7468            .start
 7469            .to_display_point(editor_snapshot);
 7470        let edit_end = edits
 7471            .last()
 7472            .unwrap()
 7473            .0
 7474            .end
 7475            .to_display_point(editor_snapshot);
 7476
 7477        let is_visible = visible_row_range.contains(&edit_start.row())
 7478            || visible_row_range.contains(&edit_end.row());
 7479        if !is_visible {
 7480            return None;
 7481        }
 7482
 7483        let highlighted_edits =
 7484            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7485
 7486        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7487        let line_count = highlighted_edits.text.lines().count();
 7488
 7489        const BORDER_WIDTH: Pixels = px(1.);
 7490
 7491        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7492        let has_keybind = keybind.is_some();
 7493
 7494        let mut element = h_flex()
 7495            .items_start()
 7496            .child(
 7497                h_flex()
 7498                    .bg(cx.theme().colors().editor_background)
 7499                    .border(BORDER_WIDTH)
 7500                    .shadow_sm()
 7501                    .border_color(cx.theme().colors().border)
 7502                    .rounded_l_lg()
 7503                    .when(line_count > 1, |el| el.rounded_br_lg())
 7504                    .pr_1()
 7505                    .child(styled_text),
 7506            )
 7507            .child(
 7508                h_flex()
 7509                    .h(line_height + BORDER_WIDTH * 2.)
 7510                    .px_1p5()
 7511                    .gap_1()
 7512                    // Workaround: For some reason, there's a gap if we don't do this
 7513                    .ml(-BORDER_WIDTH)
 7514                    .shadow(smallvec![gpui::BoxShadow {
 7515                        color: gpui::black().opacity(0.05),
 7516                        offset: point(px(1.), px(1.)),
 7517                        blur_radius: px(2.),
 7518                        spread_radius: px(0.),
 7519                    }])
 7520                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7521                    .border(BORDER_WIDTH)
 7522                    .border_color(cx.theme().colors().border)
 7523                    .rounded_r_lg()
 7524                    .id("edit_prediction_diff_popover_keybind")
 7525                    .when(!has_keybind, |el| {
 7526                        let status_colors = cx.theme().status();
 7527
 7528                        el.bg(status_colors.error_background)
 7529                            .border_color(status_colors.error.opacity(0.6))
 7530                            .child(Icon::new(IconName::Info).color(Color::Error))
 7531                            .cursor_default()
 7532                            .hoverable_tooltip(move |_window, cx| {
 7533                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7534                            })
 7535                    })
 7536                    .children(keybind),
 7537            )
 7538            .into_any();
 7539
 7540        let longest_row =
 7541            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 7542        let longest_line_width = if visible_row_range.contains(&longest_row) {
 7543            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 7544        } else {
 7545            layout_line(
 7546                longest_row,
 7547                editor_snapshot,
 7548                style,
 7549                editor_width,
 7550                |_| false,
 7551                window,
 7552                cx,
 7553            )
 7554            .width
 7555        };
 7556
 7557        let viewport_bounds =
 7558            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 7559                right: -EditorElement::SCROLLBAR_WIDTH,
 7560                ..Default::default()
 7561            });
 7562
 7563        let x_after_longest =
 7564            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 7565                - scroll_pixel_position.x;
 7566
 7567        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7568
 7569        // Fully visible if it can be displayed within the window (allow overlapping other
 7570        // panes). However, this is only allowed if the popover starts within text_bounds.
 7571        let can_position_to_the_right = x_after_longest < text_bounds.right()
 7572            && x_after_longest + element_bounds.width < viewport_bounds.right();
 7573
 7574        let mut origin = if can_position_to_the_right {
 7575            point(
 7576                x_after_longest,
 7577                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 7578                    - scroll_pixel_position.y,
 7579            )
 7580        } else {
 7581            let cursor_row = newest_selection_head.map(|head| head.row());
 7582            let above_edit = edit_start
 7583                .row()
 7584                .0
 7585                .checked_sub(line_count as u32)
 7586                .map(DisplayRow);
 7587            let below_edit = Some(edit_end.row() + 1);
 7588            let above_cursor =
 7589                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 7590            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 7591
 7592            // Place the edit popover adjacent to the edit if there is a location
 7593            // available that is onscreen and does not obscure the cursor. Otherwise,
 7594            // place it adjacent to the cursor.
 7595            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 7596                .into_iter()
 7597                .flatten()
 7598                .find(|&start_row| {
 7599                    let end_row = start_row + line_count as u32;
 7600                    visible_row_range.contains(&start_row)
 7601                        && visible_row_range.contains(&end_row)
 7602                        && cursor_row.map_or(true, |cursor_row| {
 7603                            !((start_row..end_row).contains(&cursor_row))
 7604                        })
 7605                })?;
 7606
 7607            content_origin
 7608                + point(
 7609                    -scroll_pixel_position.x,
 7610                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 7611                )
 7612        };
 7613
 7614        origin.x -= BORDER_WIDTH;
 7615
 7616        window.defer_draw(element, origin, 1);
 7617
 7618        // Do not return an element, since it will already be drawn due to defer_draw.
 7619        None
 7620    }
 7621
 7622    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 7623        px(30.)
 7624    }
 7625
 7626    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 7627        if self.read_only(cx) {
 7628            cx.theme().players().read_only()
 7629        } else {
 7630            self.style.as_ref().unwrap().local_player
 7631        }
 7632    }
 7633
 7634    fn render_edit_prediction_accept_keybind(
 7635        &self,
 7636        window: &mut Window,
 7637        cx: &App,
 7638    ) -> Option<AnyElement> {
 7639        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 7640        let accept_keystroke = accept_binding.keystroke()?;
 7641
 7642        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 7643
 7644        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 7645            Color::Accent
 7646        } else {
 7647            Color::Muted
 7648        };
 7649
 7650        h_flex()
 7651            .px_0p5()
 7652            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 7653            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 7654            .text_size(TextSize::XSmall.rems(cx))
 7655            .child(h_flex().children(ui::render_modifiers(
 7656                &accept_keystroke.modifiers,
 7657                PlatformStyle::platform(),
 7658                Some(modifiers_color),
 7659                Some(IconSize::XSmall.rems().into()),
 7660                true,
 7661            )))
 7662            .when(is_platform_style_mac, |parent| {
 7663                parent.child(accept_keystroke.key.clone())
 7664            })
 7665            .when(!is_platform_style_mac, |parent| {
 7666                parent.child(
 7667                    Key::new(
 7668                        util::capitalize(&accept_keystroke.key),
 7669                        Some(Color::Default),
 7670                    )
 7671                    .size(Some(IconSize::XSmall.rems().into())),
 7672                )
 7673            })
 7674            .into_any()
 7675            .into()
 7676    }
 7677
 7678    fn render_edit_prediction_line_popover(
 7679        &self,
 7680        label: impl Into<SharedString>,
 7681        icon: Option<IconName>,
 7682        window: &mut Window,
 7683        cx: &App,
 7684    ) -> Option<Stateful<Div>> {
 7685        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 7686
 7687        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7688        let has_keybind = keybind.is_some();
 7689
 7690        let result = h_flex()
 7691            .id("ep-line-popover")
 7692            .py_0p5()
 7693            .pl_1()
 7694            .pr(padding_right)
 7695            .gap_1()
 7696            .rounded_md()
 7697            .border_1()
 7698            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 7699            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 7700            .shadow_sm()
 7701            .when(!has_keybind, |el| {
 7702                let status_colors = cx.theme().status();
 7703
 7704                el.bg(status_colors.error_background)
 7705                    .border_color(status_colors.error.opacity(0.6))
 7706                    .pl_2()
 7707                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 7708                    .cursor_default()
 7709                    .hoverable_tooltip(move |_window, cx| {
 7710                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7711                    })
 7712            })
 7713            .children(keybind)
 7714            .child(
 7715                Label::new(label)
 7716                    .size(LabelSize::Small)
 7717                    .when(!has_keybind, |el| {
 7718                        el.color(cx.theme().status().error.into()).strikethrough()
 7719                    }),
 7720            )
 7721            .when(!has_keybind, |el| {
 7722                el.child(
 7723                    h_flex().ml_1().child(
 7724                        Icon::new(IconName::Info)
 7725                            .size(IconSize::Small)
 7726                            .color(cx.theme().status().error.into()),
 7727                    ),
 7728                )
 7729            })
 7730            .when_some(icon, |element, icon| {
 7731                element.child(
 7732                    div()
 7733                        .mt(px(1.5))
 7734                        .child(Icon::new(icon).size(IconSize::Small)),
 7735                )
 7736            });
 7737
 7738        Some(result)
 7739    }
 7740
 7741    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 7742        let accent_color = cx.theme().colors().text_accent;
 7743        let editor_bg_color = cx.theme().colors().editor_background;
 7744        editor_bg_color.blend(accent_color.opacity(0.1))
 7745    }
 7746
 7747    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 7748        let accent_color = cx.theme().colors().text_accent;
 7749        let editor_bg_color = cx.theme().colors().editor_background;
 7750        editor_bg_color.blend(accent_color.opacity(0.6))
 7751    }
 7752
 7753    fn render_edit_prediction_cursor_popover(
 7754        &self,
 7755        min_width: Pixels,
 7756        max_width: Pixels,
 7757        cursor_point: Point,
 7758        style: &EditorStyle,
 7759        accept_keystroke: Option<&gpui::Keystroke>,
 7760        _window: &Window,
 7761        cx: &mut Context<Editor>,
 7762    ) -> Option<AnyElement> {
 7763        let provider = self.edit_prediction_provider.as_ref()?;
 7764
 7765        if provider.provider.needs_terms_acceptance(cx) {
 7766            return Some(
 7767                h_flex()
 7768                    .min_w(min_width)
 7769                    .flex_1()
 7770                    .px_2()
 7771                    .py_1()
 7772                    .gap_3()
 7773                    .elevation_2(cx)
 7774                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 7775                    .id("accept-terms")
 7776                    .cursor_pointer()
 7777                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 7778                    .on_click(cx.listener(|this, _event, window, cx| {
 7779                        cx.stop_propagation();
 7780                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 7781                        window.dispatch_action(
 7782                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 7783                            cx,
 7784                        );
 7785                    }))
 7786                    .child(
 7787                        h_flex()
 7788                            .flex_1()
 7789                            .gap_2()
 7790                            .child(Icon::new(IconName::ZedPredict))
 7791                            .child(Label::new("Accept Terms of Service"))
 7792                            .child(div().w_full())
 7793                            .child(
 7794                                Icon::new(IconName::ArrowUpRight)
 7795                                    .color(Color::Muted)
 7796                                    .size(IconSize::Small),
 7797                            )
 7798                            .into_any_element(),
 7799                    )
 7800                    .into_any(),
 7801            );
 7802        }
 7803
 7804        let is_refreshing = provider.provider.is_refreshing(cx);
 7805
 7806        fn pending_completion_container() -> Div {
 7807            h_flex()
 7808                .h_full()
 7809                .flex_1()
 7810                .gap_2()
 7811                .child(Icon::new(IconName::ZedPredict))
 7812        }
 7813
 7814        let completion = match &self.active_inline_completion {
 7815            Some(prediction) => {
 7816                if !self.has_visible_completions_menu() {
 7817                    const RADIUS: Pixels = px(6.);
 7818                    const BORDER_WIDTH: Pixels = px(1.);
 7819
 7820                    return Some(
 7821                        h_flex()
 7822                            .elevation_2(cx)
 7823                            .border(BORDER_WIDTH)
 7824                            .border_color(cx.theme().colors().border)
 7825                            .when(accept_keystroke.is_none(), |el| {
 7826                                el.border_color(cx.theme().status().error)
 7827                            })
 7828                            .rounded(RADIUS)
 7829                            .rounded_tl(px(0.))
 7830                            .overflow_hidden()
 7831                            .child(div().px_1p5().child(match &prediction.completion {
 7832                                InlineCompletion::Move { target, snapshot } => {
 7833                                    use text::ToPoint as _;
 7834                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 7835                                    {
 7836                                        Icon::new(IconName::ZedPredictDown)
 7837                                    } else {
 7838                                        Icon::new(IconName::ZedPredictUp)
 7839                                    }
 7840                                }
 7841                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 7842                            }))
 7843                            .child(
 7844                                h_flex()
 7845                                    .gap_1()
 7846                                    .py_1()
 7847                                    .px_2()
 7848                                    .rounded_r(RADIUS - BORDER_WIDTH)
 7849                                    .border_l_1()
 7850                                    .border_color(cx.theme().colors().border)
 7851                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 7852                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 7853                                        el.child(
 7854                                            Label::new("Hold")
 7855                                                .size(LabelSize::Small)
 7856                                                .when(accept_keystroke.is_none(), |el| {
 7857                                                    el.strikethrough()
 7858                                                })
 7859                                                .line_height_style(LineHeightStyle::UiLabel),
 7860                                        )
 7861                                    })
 7862                                    .id("edit_prediction_cursor_popover_keybind")
 7863                                    .when(accept_keystroke.is_none(), |el| {
 7864                                        let status_colors = cx.theme().status();
 7865
 7866                                        el.bg(status_colors.error_background)
 7867                                            .border_color(status_colors.error.opacity(0.6))
 7868                                            .child(Icon::new(IconName::Info).color(Color::Error))
 7869                                            .cursor_default()
 7870                                            .hoverable_tooltip(move |_window, cx| {
 7871                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 7872                                                    .into()
 7873                                            })
 7874                                    })
 7875                                    .when_some(
 7876                                        accept_keystroke.as_ref(),
 7877                                        |el, accept_keystroke| {
 7878                                            el.child(h_flex().children(ui::render_modifiers(
 7879                                                &accept_keystroke.modifiers,
 7880                                                PlatformStyle::platform(),
 7881                                                Some(Color::Default),
 7882                                                Some(IconSize::XSmall.rems().into()),
 7883                                                false,
 7884                                            )))
 7885                                        },
 7886                                    ),
 7887                            )
 7888                            .into_any(),
 7889                    );
 7890                }
 7891
 7892                self.render_edit_prediction_cursor_popover_preview(
 7893                    prediction,
 7894                    cursor_point,
 7895                    style,
 7896                    cx,
 7897                )?
 7898            }
 7899
 7900            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 7901                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 7902                    stale_completion,
 7903                    cursor_point,
 7904                    style,
 7905                    cx,
 7906                )?,
 7907
 7908                None => {
 7909                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 7910                }
 7911            },
 7912
 7913            None => pending_completion_container().child(Label::new("No Prediction")),
 7914        };
 7915
 7916        let completion = if is_refreshing {
 7917            completion
 7918                .with_animation(
 7919                    "loading-completion",
 7920                    Animation::new(Duration::from_secs(2))
 7921                        .repeat()
 7922                        .with_easing(pulsating_between(0.4, 0.8)),
 7923                    |label, delta| label.opacity(delta),
 7924                )
 7925                .into_any_element()
 7926        } else {
 7927            completion.into_any_element()
 7928        };
 7929
 7930        let has_completion = self.active_inline_completion.is_some();
 7931
 7932        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 7933        Some(
 7934            h_flex()
 7935                .min_w(min_width)
 7936                .max_w(max_width)
 7937                .flex_1()
 7938                .elevation_2(cx)
 7939                .border_color(cx.theme().colors().border)
 7940                .child(
 7941                    div()
 7942                        .flex_1()
 7943                        .py_1()
 7944                        .px_2()
 7945                        .overflow_hidden()
 7946                        .child(completion),
 7947                )
 7948                .when_some(accept_keystroke, |el, accept_keystroke| {
 7949                    if !accept_keystroke.modifiers.modified() {
 7950                        return el;
 7951                    }
 7952
 7953                    el.child(
 7954                        h_flex()
 7955                            .h_full()
 7956                            .border_l_1()
 7957                            .rounded_r_lg()
 7958                            .border_color(cx.theme().colors().border)
 7959                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 7960                            .gap_1()
 7961                            .py_1()
 7962                            .px_2()
 7963                            .child(
 7964                                h_flex()
 7965                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 7966                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 7967                                    .child(h_flex().children(ui::render_modifiers(
 7968                                        &accept_keystroke.modifiers,
 7969                                        PlatformStyle::platform(),
 7970                                        Some(if !has_completion {
 7971                                            Color::Muted
 7972                                        } else {
 7973                                            Color::Default
 7974                                        }),
 7975                                        None,
 7976                                        false,
 7977                                    ))),
 7978                            )
 7979                            .child(Label::new("Preview").into_any_element())
 7980                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 7981                    )
 7982                })
 7983                .into_any(),
 7984        )
 7985    }
 7986
 7987    fn render_edit_prediction_cursor_popover_preview(
 7988        &self,
 7989        completion: &InlineCompletionState,
 7990        cursor_point: Point,
 7991        style: &EditorStyle,
 7992        cx: &mut Context<Editor>,
 7993    ) -> Option<Div> {
 7994        use text::ToPoint as _;
 7995
 7996        fn render_relative_row_jump(
 7997            prefix: impl Into<String>,
 7998            current_row: u32,
 7999            target_row: u32,
 8000        ) -> Div {
 8001            let (row_diff, arrow) = if target_row < current_row {
 8002                (current_row - target_row, IconName::ArrowUp)
 8003            } else {
 8004                (target_row - current_row, IconName::ArrowDown)
 8005            };
 8006
 8007            h_flex()
 8008                .child(
 8009                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8010                        .color(Color::Muted)
 8011                        .size(LabelSize::Small),
 8012                )
 8013                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8014        }
 8015
 8016        match &completion.completion {
 8017            InlineCompletion::Move {
 8018                target, snapshot, ..
 8019            } => Some(
 8020                h_flex()
 8021                    .px_2()
 8022                    .gap_2()
 8023                    .flex_1()
 8024                    .child(
 8025                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8026                            Icon::new(IconName::ZedPredictDown)
 8027                        } else {
 8028                            Icon::new(IconName::ZedPredictUp)
 8029                        },
 8030                    )
 8031                    .child(Label::new("Jump to Edit")),
 8032            ),
 8033
 8034            InlineCompletion::Edit {
 8035                edits,
 8036                edit_preview,
 8037                snapshot,
 8038                display_mode: _,
 8039            } => {
 8040                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8041
 8042                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8043                    &snapshot,
 8044                    &edits,
 8045                    edit_preview.as_ref()?,
 8046                    true,
 8047                    cx,
 8048                )
 8049                .first_line_preview();
 8050
 8051                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8052                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8053
 8054                let preview = h_flex()
 8055                    .gap_1()
 8056                    .min_w_16()
 8057                    .child(styled_text)
 8058                    .when(has_more_lines, |parent| parent.child(""));
 8059
 8060                let left = if first_edit_row != cursor_point.row {
 8061                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8062                        .into_any_element()
 8063                } else {
 8064                    Icon::new(IconName::ZedPredict).into_any_element()
 8065                };
 8066
 8067                Some(
 8068                    h_flex()
 8069                        .h_full()
 8070                        .flex_1()
 8071                        .gap_2()
 8072                        .pr_1()
 8073                        .overflow_x_hidden()
 8074                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8075                        .child(left)
 8076                        .child(preview),
 8077                )
 8078            }
 8079        }
 8080    }
 8081
 8082    fn render_context_menu(
 8083        &self,
 8084        style: &EditorStyle,
 8085        max_height_in_lines: u32,
 8086        window: &mut Window,
 8087        cx: &mut Context<Editor>,
 8088    ) -> Option<AnyElement> {
 8089        let menu = self.context_menu.borrow();
 8090        let menu = menu.as_ref()?;
 8091        if !menu.visible() {
 8092            return None;
 8093        };
 8094        Some(menu.render(style, max_height_in_lines, window, cx))
 8095    }
 8096
 8097    fn render_context_menu_aside(
 8098        &mut self,
 8099        max_size: Size<Pixels>,
 8100        window: &mut Window,
 8101        cx: &mut Context<Editor>,
 8102    ) -> Option<AnyElement> {
 8103        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8104            if menu.visible() {
 8105                menu.render_aside(self, max_size, window, cx)
 8106            } else {
 8107                None
 8108            }
 8109        })
 8110    }
 8111
 8112    fn hide_context_menu(
 8113        &mut self,
 8114        window: &mut Window,
 8115        cx: &mut Context<Self>,
 8116    ) -> Option<CodeContextMenu> {
 8117        cx.notify();
 8118        self.completion_tasks.clear();
 8119        let context_menu = self.context_menu.borrow_mut().take();
 8120        self.stale_inline_completion_in_menu.take();
 8121        self.update_visible_inline_completion(window, cx);
 8122        context_menu
 8123    }
 8124
 8125    fn show_snippet_choices(
 8126        &mut self,
 8127        choices: &Vec<String>,
 8128        selection: Range<Anchor>,
 8129        cx: &mut Context<Self>,
 8130    ) {
 8131        if selection.start.buffer_id.is_none() {
 8132            return;
 8133        }
 8134        let buffer_id = selection.start.buffer_id.unwrap();
 8135        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8136        let id = post_inc(&mut self.next_completion_id);
 8137
 8138        if let Some(buffer) = buffer {
 8139            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8140                CompletionsMenu::new_snippet_choices(id, true, choices, selection, buffer),
 8141            ));
 8142        }
 8143    }
 8144
 8145    pub fn insert_snippet(
 8146        &mut self,
 8147        insertion_ranges: &[Range<usize>],
 8148        snippet: Snippet,
 8149        window: &mut Window,
 8150        cx: &mut Context<Self>,
 8151    ) -> Result<()> {
 8152        struct Tabstop<T> {
 8153            is_end_tabstop: bool,
 8154            ranges: Vec<Range<T>>,
 8155            choices: Option<Vec<String>>,
 8156        }
 8157
 8158        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8159            let snippet_text: Arc<str> = snippet.text.clone().into();
 8160            let edits = insertion_ranges
 8161                .iter()
 8162                .cloned()
 8163                .map(|range| (range, snippet_text.clone()));
 8164            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8165
 8166            let snapshot = &*buffer.read(cx);
 8167            let snippet = &snippet;
 8168            snippet
 8169                .tabstops
 8170                .iter()
 8171                .map(|tabstop| {
 8172                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8173                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8174                    });
 8175                    let mut tabstop_ranges = tabstop
 8176                        .ranges
 8177                        .iter()
 8178                        .flat_map(|tabstop_range| {
 8179                            let mut delta = 0_isize;
 8180                            insertion_ranges.iter().map(move |insertion_range| {
 8181                                let insertion_start = insertion_range.start as isize + delta;
 8182                                delta +=
 8183                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8184
 8185                                let start = ((insertion_start + tabstop_range.start) as usize)
 8186                                    .min(snapshot.len());
 8187                                let end = ((insertion_start + tabstop_range.end) as usize)
 8188                                    .min(snapshot.len());
 8189                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8190                            })
 8191                        })
 8192                        .collect::<Vec<_>>();
 8193                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8194
 8195                    Tabstop {
 8196                        is_end_tabstop,
 8197                        ranges: tabstop_ranges,
 8198                        choices: tabstop.choices.clone(),
 8199                    }
 8200                })
 8201                .collect::<Vec<_>>()
 8202        });
 8203        if let Some(tabstop) = tabstops.first() {
 8204            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8205                s.select_ranges(tabstop.ranges.iter().cloned());
 8206            });
 8207
 8208            if let Some(choices) = &tabstop.choices {
 8209                if let Some(selection) = tabstop.ranges.first() {
 8210                    self.show_snippet_choices(choices, selection.clone(), cx)
 8211                }
 8212            }
 8213
 8214            // If we're already at the last tabstop and it's at the end of the snippet,
 8215            // we're done, we don't need to keep the state around.
 8216            if !tabstop.is_end_tabstop {
 8217                let choices = tabstops
 8218                    .iter()
 8219                    .map(|tabstop| tabstop.choices.clone())
 8220                    .collect();
 8221
 8222                let ranges = tabstops
 8223                    .into_iter()
 8224                    .map(|tabstop| tabstop.ranges)
 8225                    .collect::<Vec<_>>();
 8226
 8227                self.snippet_stack.push(SnippetState {
 8228                    active_index: 0,
 8229                    ranges,
 8230                    choices,
 8231                });
 8232            }
 8233
 8234            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8235            if self.autoclose_regions.is_empty() {
 8236                let snapshot = self.buffer.read(cx).snapshot(cx);
 8237                for selection in &mut self.selections.all::<Point>(cx) {
 8238                    let selection_head = selection.head();
 8239                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8240                        continue;
 8241                    };
 8242
 8243                    let mut bracket_pair = None;
 8244                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8245                    let prev_chars = snapshot
 8246                        .reversed_chars_at(selection_head)
 8247                        .collect::<String>();
 8248                    for (pair, enabled) in scope.brackets() {
 8249                        if enabled
 8250                            && pair.close
 8251                            && prev_chars.starts_with(pair.start.as_str())
 8252                            && next_chars.starts_with(pair.end.as_str())
 8253                        {
 8254                            bracket_pair = Some(pair.clone());
 8255                            break;
 8256                        }
 8257                    }
 8258                    if let Some(pair) = bracket_pair {
 8259                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8260                        let autoclose_enabled =
 8261                            self.use_autoclose && snapshot_settings.use_autoclose;
 8262                        if autoclose_enabled {
 8263                            let start = snapshot.anchor_after(selection_head);
 8264                            let end = snapshot.anchor_after(selection_head);
 8265                            self.autoclose_regions.push(AutocloseRegion {
 8266                                selection_id: selection.id,
 8267                                range: start..end,
 8268                                pair,
 8269                            });
 8270                        }
 8271                    }
 8272                }
 8273            }
 8274        }
 8275        Ok(())
 8276    }
 8277
 8278    pub fn move_to_next_snippet_tabstop(
 8279        &mut self,
 8280        window: &mut Window,
 8281        cx: &mut Context<Self>,
 8282    ) -> bool {
 8283        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8284    }
 8285
 8286    pub fn move_to_prev_snippet_tabstop(
 8287        &mut self,
 8288        window: &mut Window,
 8289        cx: &mut Context<Self>,
 8290    ) -> bool {
 8291        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8292    }
 8293
 8294    pub fn move_to_snippet_tabstop(
 8295        &mut self,
 8296        bias: Bias,
 8297        window: &mut Window,
 8298        cx: &mut Context<Self>,
 8299    ) -> bool {
 8300        if let Some(mut snippet) = self.snippet_stack.pop() {
 8301            match bias {
 8302                Bias::Left => {
 8303                    if snippet.active_index > 0 {
 8304                        snippet.active_index -= 1;
 8305                    } else {
 8306                        self.snippet_stack.push(snippet);
 8307                        return false;
 8308                    }
 8309                }
 8310                Bias::Right => {
 8311                    if snippet.active_index + 1 < snippet.ranges.len() {
 8312                        snippet.active_index += 1;
 8313                    } else {
 8314                        self.snippet_stack.push(snippet);
 8315                        return false;
 8316                    }
 8317                }
 8318            }
 8319            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8320                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8321                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8322                });
 8323
 8324                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8325                    if let Some(selection) = current_ranges.first() {
 8326                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8327                    }
 8328                }
 8329
 8330                // If snippet state is not at the last tabstop, push it back on the stack
 8331                if snippet.active_index + 1 < snippet.ranges.len() {
 8332                    self.snippet_stack.push(snippet);
 8333                }
 8334                return true;
 8335            }
 8336        }
 8337
 8338        false
 8339    }
 8340
 8341    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8342        self.transact(window, cx, |this, window, cx| {
 8343            this.select_all(&SelectAll, window, cx);
 8344            this.insert("", window, cx);
 8345        });
 8346    }
 8347
 8348    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8349        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8350        self.transact(window, cx, |this, window, cx| {
 8351            this.select_autoclose_pair(window, cx);
 8352            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8353            if !this.linked_edit_ranges.is_empty() {
 8354                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8355                let snapshot = this.buffer.read(cx).snapshot(cx);
 8356
 8357                for selection in selections.iter() {
 8358                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8359                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8360                    if selection_start.buffer_id != selection_end.buffer_id {
 8361                        continue;
 8362                    }
 8363                    if let Some(ranges) =
 8364                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8365                    {
 8366                        for (buffer, entries) in ranges {
 8367                            linked_ranges.entry(buffer).or_default().extend(entries);
 8368                        }
 8369                    }
 8370                }
 8371            }
 8372
 8373            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8374            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8375            for selection in &mut selections {
 8376                if selection.is_empty() {
 8377                    let old_head = selection.head();
 8378                    let mut new_head =
 8379                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8380                            .to_point(&display_map);
 8381                    if let Some((buffer, line_buffer_range)) = display_map
 8382                        .buffer_snapshot
 8383                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8384                    {
 8385                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8386                        let indent_len = match indent_size.kind {
 8387                            IndentKind::Space => {
 8388                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8389                            }
 8390                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8391                        };
 8392                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8393                            let indent_len = indent_len.get();
 8394                            new_head = cmp::min(
 8395                                new_head,
 8396                                MultiBufferPoint::new(
 8397                                    old_head.row,
 8398                                    ((old_head.column - 1) / indent_len) * indent_len,
 8399                                ),
 8400                            );
 8401                        }
 8402                    }
 8403
 8404                    selection.set_head(new_head, SelectionGoal::None);
 8405                }
 8406            }
 8407
 8408            this.signature_help_state.set_backspace_pressed(true);
 8409            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8410                s.select(selections)
 8411            });
 8412            this.insert("", window, cx);
 8413            let empty_str: Arc<str> = Arc::from("");
 8414            for (buffer, edits) in linked_ranges {
 8415                let snapshot = buffer.read(cx).snapshot();
 8416                use text::ToPoint as TP;
 8417
 8418                let edits = edits
 8419                    .into_iter()
 8420                    .map(|range| {
 8421                        let end_point = TP::to_point(&range.end, &snapshot);
 8422                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8423
 8424                        if end_point == start_point {
 8425                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8426                                .saturating_sub(1);
 8427                            start_point =
 8428                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8429                        };
 8430
 8431                        (start_point..end_point, empty_str.clone())
 8432                    })
 8433                    .sorted_by_key(|(range, _)| range.start)
 8434                    .collect::<Vec<_>>();
 8435                buffer.update(cx, |this, cx| {
 8436                    this.edit(edits, None, cx);
 8437                })
 8438            }
 8439            this.refresh_inline_completion(true, false, window, cx);
 8440            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8441        });
 8442    }
 8443
 8444    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8445        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8446        self.transact(window, cx, |this, window, cx| {
 8447            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8448                s.move_with(|map, selection| {
 8449                    if selection.is_empty() {
 8450                        let cursor = movement::right(map, selection.head());
 8451                        selection.end = cursor;
 8452                        selection.reversed = true;
 8453                        selection.goal = SelectionGoal::None;
 8454                    }
 8455                })
 8456            });
 8457            this.insert("", window, cx);
 8458            this.refresh_inline_completion(true, false, window, cx);
 8459        });
 8460    }
 8461
 8462    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8463        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8464        if self.move_to_prev_snippet_tabstop(window, cx) {
 8465            return;
 8466        }
 8467        self.outdent(&Outdent, window, cx);
 8468    }
 8469
 8470    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8471        if self.move_to_next_snippet_tabstop(window, cx) {
 8472            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8473            return;
 8474        }
 8475        if self.read_only(cx) {
 8476            return;
 8477        }
 8478        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8479        let mut selections = self.selections.all_adjusted(cx);
 8480        let buffer = self.buffer.read(cx);
 8481        let snapshot = buffer.snapshot(cx);
 8482        let rows_iter = selections.iter().map(|s| s.head().row);
 8483        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8484
 8485        let mut edits = Vec::new();
 8486        let mut prev_edited_row = 0;
 8487        let mut row_delta = 0;
 8488        for selection in &mut selections {
 8489            if selection.start.row != prev_edited_row {
 8490                row_delta = 0;
 8491            }
 8492            prev_edited_row = selection.end.row;
 8493
 8494            // If the selection is non-empty, then increase the indentation of the selected lines.
 8495            if !selection.is_empty() {
 8496                row_delta =
 8497                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8498                continue;
 8499            }
 8500
 8501            // If the selection is empty and the cursor is in the leading whitespace before the
 8502            // suggested indentation, then auto-indent the line.
 8503            let cursor = selection.head();
 8504            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8505            if let Some(suggested_indent) =
 8506                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8507            {
 8508                if cursor.column < suggested_indent.len
 8509                    && cursor.column <= current_indent.len
 8510                    && current_indent.len <= suggested_indent.len
 8511                {
 8512                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8513                    selection.end = selection.start;
 8514                    if row_delta == 0 {
 8515                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 8516                            cursor.row,
 8517                            current_indent,
 8518                            suggested_indent,
 8519                        ));
 8520                        row_delta = suggested_indent.len - current_indent.len;
 8521                    }
 8522                    continue;
 8523                }
 8524            }
 8525
 8526            // Otherwise, insert a hard or soft tab.
 8527            let settings = buffer.language_settings_at(cursor, cx);
 8528            let tab_size = if settings.hard_tabs {
 8529                IndentSize::tab()
 8530            } else {
 8531                let tab_size = settings.tab_size.get();
 8532                let indent_remainder = snapshot
 8533                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 8534                    .flat_map(str::chars)
 8535                    .fold(row_delta % tab_size, |counter: u32, c| {
 8536                        if c == '\t' {
 8537                            0
 8538                        } else {
 8539                            (counter + 1) % tab_size
 8540                        }
 8541                    });
 8542
 8543                let chars_to_next_tab_stop = tab_size - indent_remainder;
 8544                IndentSize::spaces(chars_to_next_tab_stop)
 8545            };
 8546            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 8547            selection.end = selection.start;
 8548            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 8549            row_delta += tab_size.len;
 8550        }
 8551
 8552        self.transact(window, cx, |this, window, cx| {
 8553            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 8554            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8555                s.select(selections)
 8556            });
 8557            this.refresh_inline_completion(true, false, window, cx);
 8558        });
 8559    }
 8560
 8561    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 8562        if self.read_only(cx) {
 8563            return;
 8564        }
 8565        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8566        let mut selections = self.selections.all::<Point>(cx);
 8567        let mut prev_edited_row = 0;
 8568        let mut row_delta = 0;
 8569        let mut edits = Vec::new();
 8570        let buffer = self.buffer.read(cx);
 8571        let snapshot = buffer.snapshot(cx);
 8572        for selection in &mut selections {
 8573            if selection.start.row != prev_edited_row {
 8574                row_delta = 0;
 8575            }
 8576            prev_edited_row = selection.end.row;
 8577
 8578            row_delta =
 8579                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8580        }
 8581
 8582        self.transact(window, cx, |this, window, cx| {
 8583            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 8584            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8585                s.select(selections)
 8586            });
 8587        });
 8588    }
 8589
 8590    fn indent_selection(
 8591        buffer: &MultiBuffer,
 8592        snapshot: &MultiBufferSnapshot,
 8593        selection: &mut Selection<Point>,
 8594        edits: &mut Vec<(Range<Point>, String)>,
 8595        delta_for_start_row: u32,
 8596        cx: &App,
 8597    ) -> u32 {
 8598        let settings = buffer.language_settings_at(selection.start, cx);
 8599        let tab_size = settings.tab_size.get();
 8600        let indent_kind = if settings.hard_tabs {
 8601            IndentKind::Tab
 8602        } else {
 8603            IndentKind::Space
 8604        };
 8605        let mut start_row = selection.start.row;
 8606        let mut end_row = selection.end.row + 1;
 8607
 8608        // If a selection ends at the beginning of a line, don't indent
 8609        // that last line.
 8610        if selection.end.column == 0 && selection.end.row > selection.start.row {
 8611            end_row -= 1;
 8612        }
 8613
 8614        // Avoid re-indenting a row that has already been indented by a
 8615        // previous selection, but still update this selection's column
 8616        // to reflect that indentation.
 8617        if delta_for_start_row > 0 {
 8618            start_row += 1;
 8619            selection.start.column += delta_for_start_row;
 8620            if selection.end.row == selection.start.row {
 8621                selection.end.column += delta_for_start_row;
 8622            }
 8623        }
 8624
 8625        let mut delta_for_end_row = 0;
 8626        let has_multiple_rows = start_row + 1 != end_row;
 8627        for row in start_row..end_row {
 8628            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 8629            let indent_delta = match (current_indent.kind, indent_kind) {
 8630                (IndentKind::Space, IndentKind::Space) => {
 8631                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 8632                    IndentSize::spaces(columns_to_next_tab_stop)
 8633                }
 8634                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 8635                (_, IndentKind::Tab) => IndentSize::tab(),
 8636            };
 8637
 8638            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 8639                0
 8640            } else {
 8641                selection.start.column
 8642            };
 8643            let row_start = Point::new(row, start);
 8644            edits.push((
 8645                row_start..row_start,
 8646                indent_delta.chars().collect::<String>(),
 8647            ));
 8648
 8649            // Update this selection's endpoints to reflect the indentation.
 8650            if row == selection.start.row {
 8651                selection.start.column += indent_delta.len;
 8652            }
 8653            if row == selection.end.row {
 8654                selection.end.column += indent_delta.len;
 8655                delta_for_end_row = indent_delta.len;
 8656            }
 8657        }
 8658
 8659        if selection.start.row == selection.end.row {
 8660            delta_for_start_row + delta_for_end_row
 8661        } else {
 8662            delta_for_end_row
 8663        }
 8664    }
 8665
 8666    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 8667        if self.read_only(cx) {
 8668            return;
 8669        }
 8670        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8671        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8672        let selections = self.selections.all::<Point>(cx);
 8673        let mut deletion_ranges = Vec::new();
 8674        let mut last_outdent = None;
 8675        {
 8676            let buffer = self.buffer.read(cx);
 8677            let snapshot = buffer.snapshot(cx);
 8678            for selection in &selections {
 8679                let settings = buffer.language_settings_at(selection.start, cx);
 8680                let tab_size = settings.tab_size.get();
 8681                let mut rows = selection.spanned_rows(false, &display_map);
 8682
 8683                // Avoid re-outdenting a row that has already been outdented by a
 8684                // previous selection.
 8685                if let Some(last_row) = last_outdent {
 8686                    if last_row == rows.start {
 8687                        rows.start = rows.start.next_row();
 8688                    }
 8689                }
 8690                let has_multiple_rows = rows.len() > 1;
 8691                for row in rows.iter_rows() {
 8692                    let indent_size = snapshot.indent_size_for_line(row);
 8693                    if indent_size.len > 0 {
 8694                        let deletion_len = match indent_size.kind {
 8695                            IndentKind::Space => {
 8696                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 8697                                if columns_to_prev_tab_stop == 0 {
 8698                                    tab_size
 8699                                } else {
 8700                                    columns_to_prev_tab_stop
 8701                                }
 8702                            }
 8703                            IndentKind::Tab => 1,
 8704                        };
 8705                        let start = if has_multiple_rows
 8706                            || deletion_len > selection.start.column
 8707                            || indent_size.len < selection.start.column
 8708                        {
 8709                            0
 8710                        } else {
 8711                            selection.start.column - deletion_len
 8712                        };
 8713                        deletion_ranges.push(
 8714                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 8715                        );
 8716                        last_outdent = Some(row);
 8717                    }
 8718                }
 8719            }
 8720        }
 8721
 8722        self.transact(window, cx, |this, window, cx| {
 8723            this.buffer.update(cx, |buffer, cx| {
 8724                let empty_str: Arc<str> = Arc::default();
 8725                buffer.edit(
 8726                    deletion_ranges
 8727                        .into_iter()
 8728                        .map(|range| (range, empty_str.clone())),
 8729                    None,
 8730                    cx,
 8731                );
 8732            });
 8733            let selections = this.selections.all::<usize>(cx);
 8734            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8735                s.select(selections)
 8736            });
 8737        });
 8738    }
 8739
 8740    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 8741        if self.read_only(cx) {
 8742            return;
 8743        }
 8744        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8745        let selections = self
 8746            .selections
 8747            .all::<usize>(cx)
 8748            .into_iter()
 8749            .map(|s| s.range());
 8750
 8751        self.transact(window, cx, |this, window, cx| {
 8752            this.buffer.update(cx, |buffer, cx| {
 8753                buffer.autoindent_ranges(selections, cx);
 8754            });
 8755            let selections = this.selections.all::<usize>(cx);
 8756            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8757                s.select(selections)
 8758            });
 8759        });
 8760    }
 8761
 8762    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 8763        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8764        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8765        let selections = self.selections.all::<Point>(cx);
 8766
 8767        let mut new_cursors = Vec::new();
 8768        let mut edit_ranges = Vec::new();
 8769        let mut selections = selections.iter().peekable();
 8770        while let Some(selection) = selections.next() {
 8771            let mut rows = selection.spanned_rows(false, &display_map);
 8772            let goal_display_column = selection.head().to_display_point(&display_map).column();
 8773
 8774            // Accumulate contiguous regions of rows that we want to delete.
 8775            while let Some(next_selection) = selections.peek() {
 8776                let next_rows = next_selection.spanned_rows(false, &display_map);
 8777                if next_rows.start <= rows.end {
 8778                    rows.end = next_rows.end;
 8779                    selections.next().unwrap();
 8780                } else {
 8781                    break;
 8782                }
 8783            }
 8784
 8785            let buffer = &display_map.buffer_snapshot;
 8786            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 8787            let edit_end;
 8788            let cursor_buffer_row;
 8789            if buffer.max_point().row >= rows.end.0 {
 8790                // If there's a line after the range, delete the \n from the end of the row range
 8791                // and position the cursor on the next line.
 8792                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 8793                cursor_buffer_row = rows.end;
 8794            } else {
 8795                // If there isn't a line after the range, delete the \n from the line before the
 8796                // start of the row range and position the cursor there.
 8797                edit_start = edit_start.saturating_sub(1);
 8798                edit_end = buffer.len();
 8799                cursor_buffer_row = rows.start.previous_row();
 8800            }
 8801
 8802            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 8803            *cursor.column_mut() =
 8804                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 8805
 8806            new_cursors.push((
 8807                selection.id,
 8808                buffer.anchor_after(cursor.to_point(&display_map)),
 8809            ));
 8810            edit_ranges.push(edit_start..edit_end);
 8811        }
 8812
 8813        self.transact(window, cx, |this, window, cx| {
 8814            let buffer = this.buffer.update(cx, |buffer, cx| {
 8815                let empty_str: Arc<str> = Arc::default();
 8816                buffer.edit(
 8817                    edit_ranges
 8818                        .into_iter()
 8819                        .map(|range| (range, empty_str.clone())),
 8820                    None,
 8821                    cx,
 8822                );
 8823                buffer.snapshot(cx)
 8824            });
 8825            let new_selections = new_cursors
 8826                .into_iter()
 8827                .map(|(id, cursor)| {
 8828                    let cursor = cursor.to_point(&buffer);
 8829                    Selection {
 8830                        id,
 8831                        start: cursor,
 8832                        end: cursor,
 8833                        reversed: false,
 8834                        goal: SelectionGoal::None,
 8835                    }
 8836                })
 8837                .collect();
 8838
 8839            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8840                s.select(new_selections);
 8841            });
 8842        });
 8843    }
 8844
 8845    pub fn join_lines_impl(
 8846        &mut self,
 8847        insert_whitespace: bool,
 8848        window: &mut Window,
 8849        cx: &mut Context<Self>,
 8850    ) {
 8851        if self.read_only(cx) {
 8852            return;
 8853        }
 8854        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 8855        for selection in self.selections.all::<Point>(cx) {
 8856            let start = MultiBufferRow(selection.start.row);
 8857            // Treat single line selections as if they include the next line. Otherwise this action
 8858            // would do nothing for single line selections individual cursors.
 8859            let end = if selection.start.row == selection.end.row {
 8860                MultiBufferRow(selection.start.row + 1)
 8861            } else {
 8862                MultiBufferRow(selection.end.row)
 8863            };
 8864
 8865            if let Some(last_row_range) = row_ranges.last_mut() {
 8866                if start <= last_row_range.end {
 8867                    last_row_range.end = end;
 8868                    continue;
 8869                }
 8870            }
 8871            row_ranges.push(start..end);
 8872        }
 8873
 8874        let snapshot = self.buffer.read(cx).snapshot(cx);
 8875        let mut cursor_positions = Vec::new();
 8876        for row_range in &row_ranges {
 8877            let anchor = snapshot.anchor_before(Point::new(
 8878                row_range.end.previous_row().0,
 8879                snapshot.line_len(row_range.end.previous_row()),
 8880            ));
 8881            cursor_positions.push(anchor..anchor);
 8882        }
 8883
 8884        self.transact(window, cx, |this, window, cx| {
 8885            for row_range in row_ranges.into_iter().rev() {
 8886                for row in row_range.iter_rows().rev() {
 8887                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 8888                    let next_line_row = row.next_row();
 8889                    let indent = snapshot.indent_size_for_line(next_line_row);
 8890                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 8891
 8892                    let replace =
 8893                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 8894                            " "
 8895                        } else {
 8896                            ""
 8897                        };
 8898
 8899                    this.buffer.update(cx, |buffer, cx| {
 8900                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 8901                    });
 8902                }
 8903            }
 8904
 8905            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8906                s.select_anchor_ranges(cursor_positions)
 8907            });
 8908        });
 8909    }
 8910
 8911    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 8912        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8913        self.join_lines_impl(true, window, cx);
 8914    }
 8915
 8916    pub fn sort_lines_case_sensitive(
 8917        &mut self,
 8918        _: &SortLinesCaseSensitive,
 8919        window: &mut Window,
 8920        cx: &mut Context<Self>,
 8921    ) {
 8922        self.manipulate_lines(window, cx, |lines| lines.sort())
 8923    }
 8924
 8925    pub fn sort_lines_case_insensitive(
 8926        &mut self,
 8927        _: &SortLinesCaseInsensitive,
 8928        window: &mut Window,
 8929        cx: &mut Context<Self>,
 8930    ) {
 8931        self.manipulate_lines(window, cx, |lines| {
 8932            lines.sort_by_key(|line| line.to_lowercase())
 8933        })
 8934    }
 8935
 8936    pub fn unique_lines_case_insensitive(
 8937        &mut self,
 8938        _: &UniqueLinesCaseInsensitive,
 8939        window: &mut Window,
 8940        cx: &mut Context<Self>,
 8941    ) {
 8942        self.manipulate_lines(window, cx, |lines| {
 8943            let mut seen = HashSet::default();
 8944            lines.retain(|line| seen.insert(line.to_lowercase()));
 8945        })
 8946    }
 8947
 8948    pub fn unique_lines_case_sensitive(
 8949        &mut self,
 8950        _: &UniqueLinesCaseSensitive,
 8951        window: &mut Window,
 8952        cx: &mut Context<Self>,
 8953    ) {
 8954        self.manipulate_lines(window, cx, |lines| {
 8955            let mut seen = HashSet::default();
 8956            lines.retain(|line| seen.insert(*line));
 8957        })
 8958    }
 8959
 8960    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 8961        let Some(project) = self.project.clone() else {
 8962            return;
 8963        };
 8964        self.reload(project, window, cx)
 8965            .detach_and_notify_err(window, cx);
 8966    }
 8967
 8968    pub fn restore_file(
 8969        &mut self,
 8970        _: &::git::RestoreFile,
 8971        window: &mut Window,
 8972        cx: &mut Context<Self>,
 8973    ) {
 8974        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8975        let mut buffer_ids = HashSet::default();
 8976        let snapshot = self.buffer().read(cx).snapshot(cx);
 8977        for selection in self.selections.all::<usize>(cx) {
 8978            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 8979        }
 8980
 8981        let buffer = self.buffer().read(cx);
 8982        let ranges = buffer_ids
 8983            .into_iter()
 8984            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 8985            .collect::<Vec<_>>();
 8986
 8987        self.restore_hunks_in_ranges(ranges, window, cx);
 8988    }
 8989
 8990    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 8991        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8992        let selections = self
 8993            .selections
 8994            .all(cx)
 8995            .into_iter()
 8996            .map(|s| s.range())
 8997            .collect();
 8998        self.restore_hunks_in_ranges(selections, window, cx);
 8999    }
 9000
 9001    pub fn restore_hunks_in_ranges(
 9002        &mut self,
 9003        ranges: Vec<Range<Point>>,
 9004        window: &mut Window,
 9005        cx: &mut Context<Editor>,
 9006    ) {
 9007        let mut revert_changes = HashMap::default();
 9008        let chunk_by = self
 9009            .snapshot(window, cx)
 9010            .hunks_for_ranges(ranges)
 9011            .into_iter()
 9012            .chunk_by(|hunk| hunk.buffer_id);
 9013        for (buffer_id, hunks) in &chunk_by {
 9014            let hunks = hunks.collect::<Vec<_>>();
 9015            for hunk in &hunks {
 9016                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9017            }
 9018            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9019        }
 9020        drop(chunk_by);
 9021        if !revert_changes.is_empty() {
 9022            self.transact(window, cx, |editor, window, cx| {
 9023                editor.restore(revert_changes, window, cx);
 9024            });
 9025        }
 9026    }
 9027
 9028    pub fn open_active_item_in_terminal(
 9029        &mut self,
 9030        _: &OpenInTerminal,
 9031        window: &mut Window,
 9032        cx: &mut Context<Self>,
 9033    ) {
 9034        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9035            let project_path = buffer.read(cx).project_path(cx)?;
 9036            let project = self.project.as_ref()?.read(cx);
 9037            let entry = project.entry_for_path(&project_path, cx)?;
 9038            let parent = match &entry.canonical_path {
 9039                Some(canonical_path) => canonical_path.to_path_buf(),
 9040                None => project.absolute_path(&project_path, cx)?,
 9041            }
 9042            .parent()?
 9043            .to_path_buf();
 9044            Some(parent)
 9045        }) {
 9046            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9047        }
 9048    }
 9049
 9050    fn set_breakpoint_context_menu(
 9051        &mut self,
 9052        display_row: DisplayRow,
 9053        position: Option<Anchor>,
 9054        clicked_point: gpui::Point<Pixels>,
 9055        window: &mut Window,
 9056        cx: &mut Context<Self>,
 9057    ) {
 9058        if !cx.has_flag::<Debugger>() {
 9059            return;
 9060        }
 9061        let source = self
 9062            .buffer
 9063            .read(cx)
 9064            .snapshot(cx)
 9065            .anchor_before(Point::new(display_row.0, 0u32));
 9066
 9067        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9068
 9069        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9070            self,
 9071            source,
 9072            clicked_point,
 9073            context_menu,
 9074            window,
 9075            cx,
 9076        );
 9077    }
 9078
 9079    fn add_edit_breakpoint_block(
 9080        &mut self,
 9081        anchor: Anchor,
 9082        breakpoint: &Breakpoint,
 9083        edit_action: BreakpointPromptEditAction,
 9084        window: &mut Window,
 9085        cx: &mut Context<Self>,
 9086    ) {
 9087        let weak_editor = cx.weak_entity();
 9088        let bp_prompt = cx.new(|cx| {
 9089            BreakpointPromptEditor::new(
 9090                weak_editor,
 9091                anchor,
 9092                breakpoint.clone(),
 9093                edit_action,
 9094                window,
 9095                cx,
 9096            )
 9097        });
 9098
 9099        let height = bp_prompt.update(cx, |this, cx| {
 9100            this.prompt
 9101                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9102        });
 9103        let cloned_prompt = bp_prompt.clone();
 9104        let blocks = vec![BlockProperties {
 9105            style: BlockStyle::Sticky,
 9106            placement: BlockPlacement::Above(anchor),
 9107            height: Some(height),
 9108            render: Arc::new(move |cx| {
 9109                *cloned_prompt.read(cx).gutter_dimensions.lock() = *cx.gutter_dimensions;
 9110                cloned_prompt.clone().into_any_element()
 9111            }),
 9112            priority: 0,
 9113        }];
 9114
 9115        let focus_handle = bp_prompt.focus_handle(cx);
 9116        window.focus(&focus_handle);
 9117
 9118        let block_ids = self.insert_blocks(blocks, None, cx);
 9119        bp_prompt.update(cx, |prompt, _| {
 9120            prompt.add_block_ids(block_ids);
 9121        });
 9122    }
 9123
 9124    pub(crate) fn breakpoint_at_row(
 9125        &self,
 9126        row: u32,
 9127        window: &mut Window,
 9128        cx: &mut Context<Self>,
 9129    ) -> Option<(Anchor, Breakpoint)> {
 9130        let snapshot = self.snapshot(window, cx);
 9131        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9132
 9133        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9134    }
 9135
 9136    pub(crate) fn breakpoint_at_anchor(
 9137        &self,
 9138        breakpoint_position: Anchor,
 9139        snapshot: &EditorSnapshot,
 9140        cx: &mut Context<Self>,
 9141    ) -> Option<(Anchor, Breakpoint)> {
 9142        let project = self.project.clone()?;
 9143
 9144        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9145            snapshot
 9146                .buffer_snapshot
 9147                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9148        })?;
 9149
 9150        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9151        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9152        let buffer_snapshot = buffer.read(cx).snapshot();
 9153
 9154        let row = buffer_snapshot
 9155            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9156            .row;
 9157
 9158        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9159        let anchor_end = snapshot
 9160            .buffer_snapshot
 9161            .anchor_after(Point::new(row, line_len));
 9162
 9163        let bp = self
 9164            .breakpoint_store
 9165            .as_ref()?
 9166            .read_with(cx, |breakpoint_store, cx| {
 9167                breakpoint_store
 9168                    .breakpoints(
 9169                        &buffer,
 9170                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9171                        &buffer_snapshot,
 9172                        cx,
 9173                    )
 9174                    .next()
 9175                    .and_then(|(anchor, bp)| {
 9176                        let breakpoint_row = buffer_snapshot
 9177                            .summary_for_anchor::<text::PointUtf16>(anchor)
 9178                            .row;
 9179
 9180                        if breakpoint_row == row {
 9181                            snapshot
 9182                                .buffer_snapshot
 9183                                .anchor_in_excerpt(enclosing_excerpt, *anchor)
 9184                                .map(|anchor| (anchor, bp.clone()))
 9185                        } else {
 9186                            None
 9187                        }
 9188                    })
 9189            });
 9190        bp
 9191    }
 9192
 9193    pub fn edit_log_breakpoint(
 9194        &mut self,
 9195        _: &EditLogBreakpoint,
 9196        window: &mut Window,
 9197        cx: &mut Context<Self>,
 9198    ) {
 9199        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9200            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9201                message: None,
 9202                state: BreakpointState::Enabled,
 9203                condition: None,
 9204                hit_condition: None,
 9205            });
 9206
 9207            self.add_edit_breakpoint_block(
 9208                anchor,
 9209                &breakpoint,
 9210                BreakpointPromptEditAction::Log,
 9211                window,
 9212                cx,
 9213            );
 9214        }
 9215    }
 9216
 9217    fn breakpoints_at_cursors(
 9218        &self,
 9219        window: &mut Window,
 9220        cx: &mut Context<Self>,
 9221    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9222        let snapshot = self.snapshot(window, cx);
 9223        let cursors = self
 9224            .selections
 9225            .disjoint_anchors()
 9226            .into_iter()
 9227            .map(|selection| {
 9228                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9229
 9230                let breakpoint_position = self
 9231                    .breakpoint_at_row(cursor_position.row, window, cx)
 9232                    .map(|bp| bp.0)
 9233                    .unwrap_or_else(|| {
 9234                        snapshot
 9235                            .display_snapshot
 9236                            .buffer_snapshot
 9237                            .anchor_after(Point::new(cursor_position.row, 0))
 9238                    });
 9239
 9240                let breakpoint = self
 9241                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9242                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9243
 9244                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9245            })
 9246            // 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.
 9247            .collect::<HashMap<Anchor, _>>();
 9248
 9249        cursors.into_iter().collect()
 9250    }
 9251
 9252    pub fn enable_breakpoint(
 9253        &mut self,
 9254        _: &crate::actions::EnableBreakpoint,
 9255        window: &mut Window,
 9256        cx: &mut Context<Self>,
 9257    ) {
 9258        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9259            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9260                continue;
 9261            };
 9262            self.edit_breakpoint_at_anchor(
 9263                anchor,
 9264                breakpoint,
 9265                BreakpointEditAction::InvertState,
 9266                cx,
 9267            );
 9268        }
 9269    }
 9270
 9271    pub fn disable_breakpoint(
 9272        &mut self,
 9273        _: &crate::actions::DisableBreakpoint,
 9274        window: &mut Window,
 9275        cx: &mut Context<Self>,
 9276    ) {
 9277        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9278            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9279                continue;
 9280            };
 9281            self.edit_breakpoint_at_anchor(
 9282                anchor,
 9283                breakpoint,
 9284                BreakpointEditAction::InvertState,
 9285                cx,
 9286            );
 9287        }
 9288    }
 9289
 9290    pub fn toggle_breakpoint(
 9291        &mut self,
 9292        _: &crate::actions::ToggleBreakpoint,
 9293        window: &mut Window,
 9294        cx: &mut Context<Self>,
 9295    ) {
 9296        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9297            if let Some(breakpoint) = breakpoint {
 9298                self.edit_breakpoint_at_anchor(
 9299                    anchor,
 9300                    breakpoint,
 9301                    BreakpointEditAction::Toggle,
 9302                    cx,
 9303                );
 9304            } else {
 9305                self.edit_breakpoint_at_anchor(
 9306                    anchor,
 9307                    Breakpoint::new_standard(),
 9308                    BreakpointEditAction::Toggle,
 9309                    cx,
 9310                );
 9311            }
 9312        }
 9313    }
 9314
 9315    pub fn edit_breakpoint_at_anchor(
 9316        &mut self,
 9317        breakpoint_position: Anchor,
 9318        breakpoint: Breakpoint,
 9319        edit_action: BreakpointEditAction,
 9320        cx: &mut Context<Self>,
 9321    ) {
 9322        let Some(breakpoint_store) = &self.breakpoint_store else {
 9323            return;
 9324        };
 9325
 9326        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9327            if breakpoint_position == Anchor::min() {
 9328                self.buffer()
 9329                    .read(cx)
 9330                    .excerpt_buffer_ids()
 9331                    .into_iter()
 9332                    .next()
 9333            } else {
 9334                None
 9335            }
 9336        }) else {
 9337            return;
 9338        };
 9339
 9340        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9341            return;
 9342        };
 9343
 9344        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9345            breakpoint_store.toggle_breakpoint(
 9346                buffer,
 9347                (breakpoint_position.text_anchor, breakpoint),
 9348                edit_action,
 9349                cx,
 9350            );
 9351        });
 9352
 9353        cx.notify();
 9354    }
 9355
 9356    #[cfg(any(test, feature = "test-support"))]
 9357    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9358        self.breakpoint_store.clone()
 9359    }
 9360
 9361    pub fn prepare_restore_change(
 9362        &self,
 9363        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9364        hunk: &MultiBufferDiffHunk,
 9365        cx: &mut App,
 9366    ) -> Option<()> {
 9367        if hunk.is_created_file() {
 9368            return None;
 9369        }
 9370        let buffer = self.buffer.read(cx);
 9371        let diff = buffer.diff_for(hunk.buffer_id)?;
 9372        let buffer = buffer.buffer(hunk.buffer_id)?;
 9373        let buffer = buffer.read(cx);
 9374        let original_text = diff
 9375            .read(cx)
 9376            .base_text()
 9377            .as_rope()
 9378            .slice(hunk.diff_base_byte_range.clone());
 9379        let buffer_snapshot = buffer.snapshot();
 9380        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9381        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9382            probe
 9383                .0
 9384                .start
 9385                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9386                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9387        }) {
 9388            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9389            Some(())
 9390        } else {
 9391            None
 9392        }
 9393    }
 9394
 9395    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9396        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9397    }
 9398
 9399    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9400        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9401    }
 9402
 9403    fn manipulate_lines<Fn>(
 9404        &mut self,
 9405        window: &mut Window,
 9406        cx: &mut Context<Self>,
 9407        mut callback: Fn,
 9408    ) where
 9409        Fn: FnMut(&mut Vec<&str>),
 9410    {
 9411        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9412
 9413        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9414        let buffer = self.buffer.read(cx).snapshot(cx);
 9415
 9416        let mut edits = Vec::new();
 9417
 9418        let selections = self.selections.all::<Point>(cx);
 9419        let mut selections = selections.iter().peekable();
 9420        let mut contiguous_row_selections = Vec::new();
 9421        let mut new_selections = Vec::new();
 9422        let mut added_lines = 0;
 9423        let mut removed_lines = 0;
 9424
 9425        while let Some(selection) = selections.next() {
 9426            let (start_row, end_row) = consume_contiguous_rows(
 9427                &mut contiguous_row_selections,
 9428                selection,
 9429                &display_map,
 9430                &mut selections,
 9431            );
 9432
 9433            let start_point = Point::new(start_row.0, 0);
 9434            let end_point = Point::new(
 9435                end_row.previous_row().0,
 9436                buffer.line_len(end_row.previous_row()),
 9437            );
 9438            let text = buffer
 9439                .text_for_range(start_point..end_point)
 9440                .collect::<String>();
 9441
 9442            let mut lines = text.split('\n').collect_vec();
 9443
 9444            let lines_before = lines.len();
 9445            callback(&mut lines);
 9446            let lines_after = lines.len();
 9447
 9448            edits.push((start_point..end_point, lines.join("\n")));
 9449
 9450            // Selections must change based on added and removed line count
 9451            let start_row =
 9452                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9453            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9454            new_selections.push(Selection {
 9455                id: selection.id,
 9456                start: start_row,
 9457                end: end_row,
 9458                goal: SelectionGoal::None,
 9459                reversed: selection.reversed,
 9460            });
 9461
 9462            if lines_after > lines_before {
 9463                added_lines += lines_after - lines_before;
 9464            } else if lines_before > lines_after {
 9465                removed_lines += lines_before - lines_after;
 9466            }
 9467        }
 9468
 9469        self.transact(window, cx, |this, window, cx| {
 9470            let buffer = this.buffer.update(cx, |buffer, cx| {
 9471                buffer.edit(edits, None, cx);
 9472                buffer.snapshot(cx)
 9473            });
 9474
 9475            // Recalculate offsets on newly edited buffer
 9476            let new_selections = new_selections
 9477                .iter()
 9478                .map(|s| {
 9479                    let start_point = Point::new(s.start.0, 0);
 9480                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9481                    Selection {
 9482                        id: s.id,
 9483                        start: buffer.point_to_offset(start_point),
 9484                        end: buffer.point_to_offset(end_point),
 9485                        goal: s.goal,
 9486                        reversed: s.reversed,
 9487                    }
 9488                })
 9489                .collect();
 9490
 9491            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9492                s.select(new_selections);
 9493            });
 9494
 9495            this.request_autoscroll(Autoscroll::fit(), cx);
 9496        });
 9497    }
 9498
 9499    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9500        self.manipulate_text(window, cx, |text| {
 9501            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9502            if has_upper_case_characters {
 9503                text.to_lowercase()
 9504            } else {
 9505                text.to_uppercase()
 9506            }
 9507        })
 9508    }
 9509
 9510    pub fn convert_to_upper_case(
 9511        &mut self,
 9512        _: &ConvertToUpperCase,
 9513        window: &mut Window,
 9514        cx: &mut Context<Self>,
 9515    ) {
 9516        self.manipulate_text(window, cx, |text| text.to_uppercase())
 9517    }
 9518
 9519    pub fn convert_to_lower_case(
 9520        &mut self,
 9521        _: &ConvertToLowerCase,
 9522        window: &mut Window,
 9523        cx: &mut Context<Self>,
 9524    ) {
 9525        self.manipulate_text(window, cx, |text| text.to_lowercase())
 9526    }
 9527
 9528    pub fn convert_to_title_case(
 9529        &mut self,
 9530        _: &ConvertToTitleCase,
 9531        window: &mut Window,
 9532        cx: &mut Context<Self>,
 9533    ) {
 9534        self.manipulate_text(window, cx, |text| {
 9535            text.split('\n')
 9536                .map(|line| line.to_case(Case::Title))
 9537                .join("\n")
 9538        })
 9539    }
 9540
 9541    pub fn convert_to_snake_case(
 9542        &mut self,
 9543        _: &ConvertToSnakeCase,
 9544        window: &mut Window,
 9545        cx: &mut Context<Self>,
 9546    ) {
 9547        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
 9548    }
 9549
 9550    pub fn convert_to_kebab_case(
 9551        &mut self,
 9552        _: &ConvertToKebabCase,
 9553        window: &mut Window,
 9554        cx: &mut Context<Self>,
 9555    ) {
 9556        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
 9557    }
 9558
 9559    pub fn convert_to_upper_camel_case(
 9560        &mut self,
 9561        _: &ConvertToUpperCamelCase,
 9562        window: &mut Window,
 9563        cx: &mut Context<Self>,
 9564    ) {
 9565        self.manipulate_text(window, cx, |text| {
 9566            text.split('\n')
 9567                .map(|line| line.to_case(Case::UpperCamel))
 9568                .join("\n")
 9569        })
 9570    }
 9571
 9572    pub fn convert_to_lower_camel_case(
 9573        &mut self,
 9574        _: &ConvertToLowerCamelCase,
 9575        window: &mut Window,
 9576        cx: &mut Context<Self>,
 9577    ) {
 9578        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
 9579    }
 9580
 9581    pub fn convert_to_opposite_case(
 9582        &mut self,
 9583        _: &ConvertToOppositeCase,
 9584        window: &mut Window,
 9585        cx: &mut Context<Self>,
 9586    ) {
 9587        self.manipulate_text(window, cx, |text| {
 9588            text.chars()
 9589                .fold(String::with_capacity(text.len()), |mut t, c| {
 9590                    if c.is_uppercase() {
 9591                        t.extend(c.to_lowercase());
 9592                    } else {
 9593                        t.extend(c.to_uppercase());
 9594                    }
 9595                    t
 9596                })
 9597        })
 9598    }
 9599
 9600    pub fn convert_to_rot13(
 9601        &mut self,
 9602        _: &ConvertToRot13,
 9603        window: &mut Window,
 9604        cx: &mut Context<Self>,
 9605    ) {
 9606        self.manipulate_text(window, cx, |text| {
 9607            text.chars()
 9608                .map(|c| match c {
 9609                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
 9610                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
 9611                    _ => c,
 9612                })
 9613                .collect()
 9614        })
 9615    }
 9616
 9617    pub fn convert_to_rot47(
 9618        &mut self,
 9619        _: &ConvertToRot47,
 9620        window: &mut Window,
 9621        cx: &mut Context<Self>,
 9622    ) {
 9623        self.manipulate_text(window, cx, |text| {
 9624            text.chars()
 9625                .map(|c| {
 9626                    let code_point = c as u32;
 9627                    if code_point >= 33 && code_point <= 126 {
 9628                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
 9629                    }
 9630                    c
 9631                })
 9632                .collect()
 9633        })
 9634    }
 9635
 9636    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
 9637    where
 9638        Fn: FnMut(&str) -> String,
 9639    {
 9640        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9641        let buffer = self.buffer.read(cx).snapshot(cx);
 9642
 9643        let mut new_selections = Vec::new();
 9644        let mut edits = Vec::new();
 9645        let mut selection_adjustment = 0i32;
 9646
 9647        for selection in self.selections.all::<usize>(cx) {
 9648            let selection_is_empty = selection.is_empty();
 9649
 9650            let (start, end) = if selection_is_empty {
 9651                let word_range = movement::surrounding_word(
 9652                    &display_map,
 9653                    selection.start.to_display_point(&display_map),
 9654                );
 9655                let start = word_range.start.to_offset(&display_map, Bias::Left);
 9656                let end = word_range.end.to_offset(&display_map, Bias::Left);
 9657                (start, end)
 9658            } else {
 9659                (selection.start, selection.end)
 9660            };
 9661
 9662            let text = buffer.text_for_range(start..end).collect::<String>();
 9663            let old_length = text.len() as i32;
 9664            let text = callback(&text);
 9665
 9666            new_selections.push(Selection {
 9667                start: (start as i32 - selection_adjustment) as usize,
 9668                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
 9669                goal: SelectionGoal::None,
 9670                ..selection
 9671            });
 9672
 9673            selection_adjustment += old_length - text.len() as i32;
 9674
 9675            edits.push((start..end, text));
 9676        }
 9677
 9678        self.transact(window, cx, |this, window, cx| {
 9679            this.buffer.update(cx, |buffer, cx| {
 9680                buffer.edit(edits, None, cx);
 9681            });
 9682
 9683            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9684                s.select(new_selections);
 9685            });
 9686
 9687            this.request_autoscroll(Autoscroll::fit(), cx);
 9688        });
 9689    }
 9690
 9691    pub fn duplicate(
 9692        &mut self,
 9693        upwards: bool,
 9694        whole_lines: bool,
 9695        window: &mut Window,
 9696        cx: &mut Context<Self>,
 9697    ) {
 9698        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9699
 9700        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9701        let buffer = &display_map.buffer_snapshot;
 9702        let selections = self.selections.all::<Point>(cx);
 9703
 9704        let mut edits = Vec::new();
 9705        let mut selections_iter = selections.iter().peekable();
 9706        while let Some(selection) = selections_iter.next() {
 9707            let mut rows = selection.spanned_rows(false, &display_map);
 9708            // duplicate line-wise
 9709            if whole_lines || selection.start == selection.end {
 9710                // Avoid duplicating the same lines twice.
 9711                while let Some(next_selection) = selections_iter.peek() {
 9712                    let next_rows = next_selection.spanned_rows(false, &display_map);
 9713                    if next_rows.start < rows.end {
 9714                        rows.end = next_rows.end;
 9715                        selections_iter.next().unwrap();
 9716                    } else {
 9717                        break;
 9718                    }
 9719                }
 9720
 9721                // Copy the text from the selected row region and splice it either at the start
 9722                // or end of the region.
 9723                let start = Point::new(rows.start.0, 0);
 9724                let end = Point::new(
 9725                    rows.end.previous_row().0,
 9726                    buffer.line_len(rows.end.previous_row()),
 9727                );
 9728                let text = buffer
 9729                    .text_for_range(start..end)
 9730                    .chain(Some("\n"))
 9731                    .collect::<String>();
 9732                let insert_location = if upwards {
 9733                    Point::new(rows.end.0, 0)
 9734                } else {
 9735                    start
 9736                };
 9737                edits.push((insert_location..insert_location, text));
 9738            } else {
 9739                // duplicate character-wise
 9740                let start = selection.start;
 9741                let end = selection.end;
 9742                let text = buffer.text_for_range(start..end).collect::<String>();
 9743                edits.push((selection.end..selection.end, text));
 9744            }
 9745        }
 9746
 9747        self.transact(window, cx, |this, _, cx| {
 9748            this.buffer.update(cx, |buffer, cx| {
 9749                buffer.edit(edits, None, cx);
 9750            });
 9751
 9752            this.request_autoscroll(Autoscroll::fit(), cx);
 9753        });
 9754    }
 9755
 9756    pub fn duplicate_line_up(
 9757        &mut self,
 9758        _: &DuplicateLineUp,
 9759        window: &mut Window,
 9760        cx: &mut Context<Self>,
 9761    ) {
 9762        self.duplicate(true, true, window, cx);
 9763    }
 9764
 9765    pub fn duplicate_line_down(
 9766        &mut self,
 9767        _: &DuplicateLineDown,
 9768        window: &mut Window,
 9769        cx: &mut Context<Self>,
 9770    ) {
 9771        self.duplicate(false, true, window, cx);
 9772    }
 9773
 9774    pub fn duplicate_selection(
 9775        &mut self,
 9776        _: &DuplicateSelection,
 9777        window: &mut Window,
 9778        cx: &mut Context<Self>,
 9779    ) {
 9780        self.duplicate(false, false, window, cx);
 9781    }
 9782
 9783    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
 9784        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9785
 9786        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9787        let buffer = self.buffer.read(cx).snapshot(cx);
 9788
 9789        let mut edits = Vec::new();
 9790        let mut unfold_ranges = Vec::new();
 9791        let mut refold_creases = Vec::new();
 9792
 9793        let selections = self.selections.all::<Point>(cx);
 9794        let mut selections = selections.iter().peekable();
 9795        let mut contiguous_row_selections = Vec::new();
 9796        let mut new_selections = Vec::new();
 9797
 9798        while let Some(selection) = selections.next() {
 9799            // Find all the selections that span a contiguous row range
 9800            let (start_row, end_row) = consume_contiguous_rows(
 9801                &mut contiguous_row_selections,
 9802                selection,
 9803                &display_map,
 9804                &mut selections,
 9805            );
 9806
 9807            // Move the text spanned by the row range to be before the line preceding the row range
 9808            if start_row.0 > 0 {
 9809                let range_to_move = Point::new(
 9810                    start_row.previous_row().0,
 9811                    buffer.line_len(start_row.previous_row()),
 9812                )
 9813                    ..Point::new(
 9814                        end_row.previous_row().0,
 9815                        buffer.line_len(end_row.previous_row()),
 9816                    );
 9817                let insertion_point = display_map
 9818                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
 9819                    .0;
 9820
 9821                // Don't move lines across excerpts
 9822                if buffer
 9823                    .excerpt_containing(insertion_point..range_to_move.end)
 9824                    .is_some()
 9825                {
 9826                    let text = buffer
 9827                        .text_for_range(range_to_move.clone())
 9828                        .flat_map(|s| s.chars())
 9829                        .skip(1)
 9830                        .chain(['\n'])
 9831                        .collect::<String>();
 9832
 9833                    edits.push((
 9834                        buffer.anchor_after(range_to_move.start)
 9835                            ..buffer.anchor_before(range_to_move.end),
 9836                        String::new(),
 9837                    ));
 9838                    let insertion_anchor = buffer.anchor_after(insertion_point);
 9839                    edits.push((insertion_anchor..insertion_anchor, text));
 9840
 9841                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
 9842
 9843                    // Move selections up
 9844                    new_selections.extend(contiguous_row_selections.drain(..).map(
 9845                        |mut selection| {
 9846                            selection.start.row -= row_delta;
 9847                            selection.end.row -= row_delta;
 9848                            selection
 9849                        },
 9850                    ));
 9851
 9852                    // Move folds up
 9853                    unfold_ranges.push(range_to_move.clone());
 9854                    for fold in display_map.folds_in_range(
 9855                        buffer.anchor_before(range_to_move.start)
 9856                            ..buffer.anchor_after(range_to_move.end),
 9857                    ) {
 9858                        let mut start = fold.range.start.to_point(&buffer);
 9859                        let mut end = fold.range.end.to_point(&buffer);
 9860                        start.row -= row_delta;
 9861                        end.row -= row_delta;
 9862                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
 9863                    }
 9864                }
 9865            }
 9866
 9867            // If we didn't move line(s), preserve the existing selections
 9868            new_selections.append(&mut contiguous_row_selections);
 9869        }
 9870
 9871        self.transact(window, cx, |this, window, cx| {
 9872            this.unfold_ranges(&unfold_ranges, true, true, cx);
 9873            this.buffer.update(cx, |buffer, cx| {
 9874                for (range, text) in edits {
 9875                    buffer.edit([(range, text)], None, cx);
 9876                }
 9877            });
 9878            this.fold_creases(refold_creases, true, window, cx);
 9879            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9880                s.select(new_selections);
 9881            })
 9882        });
 9883    }
 9884
 9885    pub fn move_line_down(
 9886        &mut self,
 9887        _: &MoveLineDown,
 9888        window: &mut Window,
 9889        cx: &mut Context<Self>,
 9890    ) {
 9891        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9892
 9893        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9894        let buffer = self.buffer.read(cx).snapshot(cx);
 9895
 9896        let mut edits = Vec::new();
 9897        let mut unfold_ranges = Vec::new();
 9898        let mut refold_creases = Vec::new();
 9899
 9900        let selections = self.selections.all::<Point>(cx);
 9901        let mut selections = selections.iter().peekable();
 9902        let mut contiguous_row_selections = Vec::new();
 9903        let mut new_selections = Vec::new();
 9904
 9905        while let Some(selection) = selections.next() {
 9906            // Find all the selections that span a contiguous row range
 9907            let (start_row, end_row) = consume_contiguous_rows(
 9908                &mut contiguous_row_selections,
 9909                selection,
 9910                &display_map,
 9911                &mut selections,
 9912            );
 9913
 9914            // Move the text spanned by the row range to be after the last line of the row range
 9915            if end_row.0 <= buffer.max_point().row {
 9916                let range_to_move =
 9917                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
 9918                let insertion_point = display_map
 9919                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
 9920                    .0;
 9921
 9922                // Don't move lines across excerpt boundaries
 9923                if buffer
 9924                    .excerpt_containing(range_to_move.start..insertion_point)
 9925                    .is_some()
 9926                {
 9927                    let mut text = String::from("\n");
 9928                    text.extend(buffer.text_for_range(range_to_move.clone()));
 9929                    text.pop(); // Drop trailing newline
 9930                    edits.push((
 9931                        buffer.anchor_after(range_to_move.start)
 9932                            ..buffer.anchor_before(range_to_move.end),
 9933                        String::new(),
 9934                    ));
 9935                    let insertion_anchor = buffer.anchor_after(insertion_point);
 9936                    edits.push((insertion_anchor..insertion_anchor, text));
 9937
 9938                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
 9939
 9940                    // Move selections down
 9941                    new_selections.extend(contiguous_row_selections.drain(..).map(
 9942                        |mut selection| {
 9943                            selection.start.row += row_delta;
 9944                            selection.end.row += row_delta;
 9945                            selection
 9946                        },
 9947                    ));
 9948
 9949                    // Move folds down
 9950                    unfold_ranges.push(range_to_move.clone());
 9951                    for fold in display_map.folds_in_range(
 9952                        buffer.anchor_before(range_to_move.start)
 9953                            ..buffer.anchor_after(range_to_move.end),
 9954                    ) {
 9955                        let mut start = fold.range.start.to_point(&buffer);
 9956                        let mut end = fold.range.end.to_point(&buffer);
 9957                        start.row += row_delta;
 9958                        end.row += row_delta;
 9959                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
 9960                    }
 9961                }
 9962            }
 9963
 9964            // If we didn't move line(s), preserve the existing selections
 9965            new_selections.append(&mut contiguous_row_selections);
 9966        }
 9967
 9968        self.transact(window, cx, |this, window, cx| {
 9969            this.unfold_ranges(&unfold_ranges, true, true, cx);
 9970            this.buffer.update(cx, |buffer, cx| {
 9971                for (range, text) in edits {
 9972                    buffer.edit([(range, text)], None, cx);
 9973                }
 9974            });
 9975            this.fold_creases(refold_creases, true, window, cx);
 9976            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9977                s.select(new_selections)
 9978            });
 9979        });
 9980    }
 9981
 9982    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
 9983        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9984        let text_layout_details = &self.text_layout_details(window);
 9985        self.transact(window, cx, |this, window, cx| {
 9986            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9987                let mut edits: Vec<(Range<usize>, String)> = Default::default();
 9988                s.move_with(|display_map, selection| {
 9989                    if !selection.is_empty() {
 9990                        return;
 9991                    }
 9992
 9993                    let mut head = selection.head();
 9994                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
 9995                    if head.column() == display_map.line_len(head.row()) {
 9996                        transpose_offset = display_map
 9997                            .buffer_snapshot
 9998                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 9999                    }
10000
10001                    if transpose_offset == 0 {
10002                        return;
10003                    }
10004
10005                    *head.column_mut() += 1;
10006                    head = display_map.clip_point(head, Bias::Right);
10007                    let goal = SelectionGoal::HorizontalPosition(
10008                        display_map
10009                            .x_for_display_point(head, text_layout_details)
10010                            .into(),
10011                    );
10012                    selection.collapse_to(head, goal);
10013
10014                    let transpose_start = display_map
10015                        .buffer_snapshot
10016                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10017                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10018                        let transpose_end = display_map
10019                            .buffer_snapshot
10020                            .clip_offset(transpose_offset + 1, Bias::Right);
10021                        if let Some(ch) =
10022                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10023                        {
10024                            edits.push((transpose_start..transpose_offset, String::new()));
10025                            edits.push((transpose_end..transpose_end, ch.to_string()));
10026                        }
10027                    }
10028                });
10029                edits
10030            });
10031            this.buffer
10032                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10033            let selections = this.selections.all::<usize>(cx);
10034            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10035                s.select(selections);
10036            });
10037        });
10038    }
10039
10040    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10041        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10042        self.rewrap_impl(RewrapOptions::default(), cx)
10043    }
10044
10045    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10046        let buffer = self.buffer.read(cx).snapshot(cx);
10047        let selections = self.selections.all::<Point>(cx);
10048        let mut selections = selections.iter().peekable();
10049
10050        let mut edits = Vec::new();
10051        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10052
10053        while let Some(selection) = selections.next() {
10054            let mut start_row = selection.start.row;
10055            let mut end_row = selection.end.row;
10056
10057            // Skip selections that overlap with a range that has already been rewrapped.
10058            let selection_range = start_row..end_row;
10059            if rewrapped_row_ranges
10060                .iter()
10061                .any(|range| range.overlaps(&selection_range))
10062            {
10063                continue;
10064            }
10065
10066            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10067
10068            // Since not all lines in the selection may be at the same indent
10069            // level, choose the indent size that is the most common between all
10070            // of the lines.
10071            //
10072            // If there is a tie, we use the deepest indent.
10073            let (indent_size, indent_end) = {
10074                let mut indent_size_occurrences = HashMap::default();
10075                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10076
10077                for row in start_row..=end_row {
10078                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10079                    rows_by_indent_size.entry(indent).or_default().push(row);
10080                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10081                }
10082
10083                let indent_size = indent_size_occurrences
10084                    .into_iter()
10085                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10086                    .map(|(indent, _)| indent)
10087                    .unwrap_or_default();
10088                let row = rows_by_indent_size[&indent_size][0];
10089                let indent_end = Point::new(row, indent_size.len);
10090
10091                (indent_size, indent_end)
10092            };
10093
10094            let mut line_prefix = indent_size.chars().collect::<String>();
10095
10096            let mut inside_comment = false;
10097            if let Some(comment_prefix) =
10098                buffer
10099                    .language_scope_at(selection.head())
10100                    .and_then(|language| {
10101                        language
10102                            .line_comment_prefixes()
10103                            .iter()
10104                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10105                            .cloned()
10106                    })
10107            {
10108                line_prefix.push_str(&comment_prefix);
10109                inside_comment = true;
10110            }
10111
10112            let language_settings = buffer.language_settings_at(selection.head(), cx);
10113            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10114                RewrapBehavior::InComments => inside_comment,
10115                RewrapBehavior::InSelections => !selection.is_empty(),
10116                RewrapBehavior::Anywhere => true,
10117            };
10118
10119            let should_rewrap = options.override_language_settings
10120                || allow_rewrap_based_on_language
10121                || self.hard_wrap.is_some();
10122            if !should_rewrap {
10123                continue;
10124            }
10125
10126            if selection.is_empty() {
10127                'expand_upwards: while start_row > 0 {
10128                    let prev_row = start_row - 1;
10129                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10130                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10131                    {
10132                        start_row = prev_row;
10133                    } else {
10134                        break 'expand_upwards;
10135                    }
10136                }
10137
10138                'expand_downwards: while end_row < buffer.max_point().row {
10139                    let next_row = end_row + 1;
10140                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10141                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10142                    {
10143                        end_row = next_row;
10144                    } else {
10145                        break 'expand_downwards;
10146                    }
10147                }
10148            }
10149
10150            let start = Point::new(start_row, 0);
10151            let start_offset = start.to_offset(&buffer);
10152            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10153            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10154            let Some(lines_without_prefixes) = selection_text
10155                .lines()
10156                .map(|line| {
10157                    line.strip_prefix(&line_prefix)
10158                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10159                        .ok_or_else(|| {
10160                            anyhow!("line did not start with prefix {line_prefix:?}: {line:?}")
10161                        })
10162                })
10163                .collect::<Result<Vec<_>, _>>()
10164                .log_err()
10165            else {
10166                continue;
10167            };
10168
10169            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10170                buffer
10171                    .language_settings_at(Point::new(start_row, 0), cx)
10172                    .preferred_line_length as usize
10173            });
10174            let wrapped_text = wrap_with_prefix(
10175                line_prefix,
10176                lines_without_prefixes.join("\n"),
10177                wrap_column,
10178                tab_size,
10179                options.preserve_existing_whitespace,
10180            );
10181
10182            // TODO: should always use char-based diff while still supporting cursor behavior that
10183            // matches vim.
10184            let mut diff_options = DiffOptions::default();
10185            if options.override_language_settings {
10186                diff_options.max_word_diff_len = 0;
10187                diff_options.max_word_diff_line_count = 0;
10188            } else {
10189                diff_options.max_word_diff_len = usize::MAX;
10190                diff_options.max_word_diff_line_count = usize::MAX;
10191            }
10192
10193            for (old_range, new_text) in
10194                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10195            {
10196                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10197                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10198                edits.push((edit_start..edit_end, new_text));
10199            }
10200
10201            rewrapped_row_ranges.push(start_row..=end_row);
10202        }
10203
10204        self.buffer
10205            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10206    }
10207
10208    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10209        let mut text = String::new();
10210        let buffer = self.buffer.read(cx).snapshot(cx);
10211        let mut selections = self.selections.all::<Point>(cx);
10212        let mut clipboard_selections = Vec::with_capacity(selections.len());
10213        {
10214            let max_point = buffer.max_point();
10215            let mut is_first = true;
10216            for selection in &mut selections {
10217                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10218                if is_entire_line {
10219                    selection.start = Point::new(selection.start.row, 0);
10220                    if !selection.is_empty() && selection.end.column == 0 {
10221                        selection.end = cmp::min(max_point, selection.end);
10222                    } else {
10223                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10224                    }
10225                    selection.goal = SelectionGoal::None;
10226                }
10227                if is_first {
10228                    is_first = false;
10229                } else {
10230                    text += "\n";
10231                }
10232                let mut len = 0;
10233                for chunk in buffer.text_for_range(selection.start..selection.end) {
10234                    text.push_str(chunk);
10235                    len += chunk.len();
10236                }
10237                clipboard_selections.push(ClipboardSelection {
10238                    len,
10239                    is_entire_line,
10240                    first_line_indent: buffer
10241                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10242                        .len,
10243                });
10244            }
10245        }
10246
10247        self.transact(window, cx, |this, window, cx| {
10248            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10249                s.select(selections);
10250            });
10251            this.insert("", window, cx);
10252        });
10253        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10254    }
10255
10256    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10257        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10258        let item = self.cut_common(window, cx);
10259        cx.write_to_clipboard(item);
10260    }
10261
10262    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10263        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10264        self.change_selections(None, window, cx, |s| {
10265            s.move_with(|snapshot, sel| {
10266                if sel.is_empty() {
10267                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10268                }
10269            });
10270        });
10271        let item = self.cut_common(window, cx);
10272        cx.set_global(KillRing(item))
10273    }
10274
10275    pub fn kill_ring_yank(
10276        &mut self,
10277        _: &KillRingYank,
10278        window: &mut Window,
10279        cx: &mut Context<Self>,
10280    ) {
10281        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10282        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10283            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10284                (kill_ring.text().to_string(), kill_ring.metadata_json())
10285            } else {
10286                return;
10287            }
10288        } else {
10289            return;
10290        };
10291        self.do_paste(&text, metadata, false, window, cx);
10292    }
10293
10294    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10295        self.do_copy(true, cx);
10296    }
10297
10298    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10299        self.do_copy(false, cx);
10300    }
10301
10302    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10303        let selections = self.selections.all::<Point>(cx);
10304        let buffer = self.buffer.read(cx).read(cx);
10305        let mut text = String::new();
10306
10307        let mut clipboard_selections = Vec::with_capacity(selections.len());
10308        {
10309            let max_point = buffer.max_point();
10310            let mut is_first = true;
10311            for selection in &selections {
10312                let mut start = selection.start;
10313                let mut end = selection.end;
10314                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10315                if is_entire_line {
10316                    start = Point::new(start.row, 0);
10317                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10318                }
10319
10320                let mut trimmed_selections = Vec::new();
10321                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10322                    let row = MultiBufferRow(start.row);
10323                    let first_indent = buffer.indent_size_for_line(row);
10324                    if first_indent.len == 0 || start.column > first_indent.len {
10325                        trimmed_selections.push(start..end);
10326                    } else {
10327                        trimmed_selections.push(
10328                            Point::new(row.0, first_indent.len)
10329                                ..Point::new(row.0, buffer.line_len(row)),
10330                        );
10331                        for row in start.row + 1..=end.row {
10332                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10333                            if row == end.row {
10334                                line_len = end.column;
10335                            }
10336                            if line_len == 0 {
10337                                trimmed_selections
10338                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10339                                continue;
10340                            }
10341                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10342                            if row_indent_size.len >= first_indent.len {
10343                                trimmed_selections.push(
10344                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10345                                );
10346                            } else {
10347                                trimmed_selections.clear();
10348                                trimmed_selections.push(start..end);
10349                                break;
10350                            }
10351                        }
10352                    }
10353                } else {
10354                    trimmed_selections.push(start..end);
10355                }
10356
10357                for trimmed_range in trimmed_selections {
10358                    if is_first {
10359                        is_first = false;
10360                    } else {
10361                        text += "\n";
10362                    }
10363                    let mut len = 0;
10364                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10365                        text.push_str(chunk);
10366                        len += chunk.len();
10367                    }
10368                    clipboard_selections.push(ClipboardSelection {
10369                        len,
10370                        is_entire_line,
10371                        first_line_indent: buffer
10372                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10373                            .len,
10374                    });
10375                }
10376            }
10377        }
10378
10379        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10380            text,
10381            clipboard_selections,
10382        ));
10383    }
10384
10385    pub fn do_paste(
10386        &mut self,
10387        text: &String,
10388        clipboard_selections: Option<Vec<ClipboardSelection>>,
10389        handle_entire_lines: bool,
10390        window: &mut Window,
10391        cx: &mut Context<Self>,
10392    ) {
10393        if self.read_only(cx) {
10394            return;
10395        }
10396
10397        let clipboard_text = Cow::Borrowed(text);
10398
10399        self.transact(window, cx, |this, window, cx| {
10400            if let Some(mut clipboard_selections) = clipboard_selections {
10401                let old_selections = this.selections.all::<usize>(cx);
10402                let all_selections_were_entire_line =
10403                    clipboard_selections.iter().all(|s| s.is_entire_line);
10404                let first_selection_indent_column =
10405                    clipboard_selections.first().map(|s| s.first_line_indent);
10406                if clipboard_selections.len() != old_selections.len() {
10407                    clipboard_selections.drain(..);
10408                }
10409                let cursor_offset = this.selections.last::<usize>(cx).head();
10410                let mut auto_indent_on_paste = true;
10411
10412                this.buffer.update(cx, |buffer, cx| {
10413                    let snapshot = buffer.read(cx);
10414                    auto_indent_on_paste = snapshot
10415                        .language_settings_at(cursor_offset, cx)
10416                        .auto_indent_on_paste;
10417
10418                    let mut start_offset = 0;
10419                    let mut edits = Vec::new();
10420                    let mut original_indent_columns = Vec::new();
10421                    for (ix, selection) in old_selections.iter().enumerate() {
10422                        let to_insert;
10423                        let entire_line;
10424                        let original_indent_column;
10425                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10426                            let end_offset = start_offset + clipboard_selection.len;
10427                            to_insert = &clipboard_text[start_offset..end_offset];
10428                            entire_line = clipboard_selection.is_entire_line;
10429                            start_offset = end_offset + 1;
10430                            original_indent_column = Some(clipboard_selection.first_line_indent);
10431                        } else {
10432                            to_insert = clipboard_text.as_str();
10433                            entire_line = all_selections_were_entire_line;
10434                            original_indent_column = first_selection_indent_column
10435                        }
10436
10437                        // If the corresponding selection was empty when this slice of the
10438                        // clipboard text was written, then the entire line containing the
10439                        // selection was copied. If this selection is also currently empty,
10440                        // then paste the line before the current line of the buffer.
10441                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10442                            let column = selection.start.to_point(&snapshot).column as usize;
10443                            let line_start = selection.start - column;
10444                            line_start..line_start
10445                        } else {
10446                            selection.range()
10447                        };
10448
10449                        edits.push((range, to_insert));
10450                        original_indent_columns.push(original_indent_column);
10451                    }
10452                    drop(snapshot);
10453
10454                    buffer.edit(
10455                        edits,
10456                        if auto_indent_on_paste {
10457                            Some(AutoindentMode::Block {
10458                                original_indent_columns,
10459                            })
10460                        } else {
10461                            None
10462                        },
10463                        cx,
10464                    );
10465                });
10466
10467                let selections = this.selections.all::<usize>(cx);
10468                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10469                    s.select(selections)
10470                });
10471            } else {
10472                this.insert(&clipboard_text, window, cx);
10473            }
10474        });
10475    }
10476
10477    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10478        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10479        if let Some(item) = cx.read_from_clipboard() {
10480            let entries = item.entries();
10481
10482            match entries.first() {
10483                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10484                // of all the pasted entries.
10485                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10486                    .do_paste(
10487                        clipboard_string.text(),
10488                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10489                        true,
10490                        window,
10491                        cx,
10492                    ),
10493                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10494            }
10495        }
10496    }
10497
10498    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10499        if self.read_only(cx) {
10500            return;
10501        }
10502
10503        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10504
10505        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
10506            if let Some((selections, _)) =
10507                self.selection_history.transaction(transaction_id).cloned()
10508            {
10509                self.change_selections(None, window, cx, |s| {
10510                    s.select_anchors(selections.to_vec());
10511                });
10512            } else {
10513                log::error!(
10514                    "No entry in selection_history found for undo. \
10515                     This may correspond to a bug where undo does not update the selection. \
10516                     If this is occurring, please add details to \
10517                     https://github.com/zed-industries/zed/issues/22692"
10518                );
10519            }
10520            self.request_autoscroll(Autoscroll::fit(), cx);
10521            self.unmark_text(window, cx);
10522            self.refresh_inline_completion(true, false, window, cx);
10523            cx.emit(EditorEvent::Edited { transaction_id });
10524            cx.emit(EditorEvent::TransactionUndone { transaction_id });
10525        }
10526    }
10527
10528    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
10529        if self.read_only(cx) {
10530            return;
10531        }
10532
10533        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10534
10535        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
10536            if let Some((_, Some(selections))) =
10537                self.selection_history.transaction(transaction_id).cloned()
10538            {
10539                self.change_selections(None, window, cx, |s| {
10540                    s.select_anchors(selections.to_vec());
10541                });
10542            } else {
10543                log::error!(
10544                    "No entry in selection_history found for redo. \
10545                     This may correspond to a bug where undo does not update the selection. \
10546                     If this is occurring, please add details to \
10547                     https://github.com/zed-industries/zed/issues/22692"
10548                );
10549            }
10550            self.request_autoscroll(Autoscroll::fit(), cx);
10551            self.unmark_text(window, cx);
10552            self.refresh_inline_completion(true, false, window, cx);
10553            cx.emit(EditorEvent::Edited { transaction_id });
10554        }
10555    }
10556
10557    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
10558        self.buffer
10559            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
10560    }
10561
10562    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
10563        self.buffer
10564            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
10565    }
10566
10567    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
10568        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10569        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10570            s.move_with(|map, selection| {
10571                let cursor = if selection.is_empty() {
10572                    movement::left(map, selection.start)
10573                } else {
10574                    selection.start
10575                };
10576                selection.collapse_to(cursor, SelectionGoal::None);
10577            });
10578        })
10579    }
10580
10581    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
10582        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10583        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10584            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
10585        })
10586    }
10587
10588    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
10589        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10590        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10591            s.move_with(|map, selection| {
10592                let cursor = if selection.is_empty() {
10593                    movement::right(map, selection.end)
10594                } else {
10595                    selection.end
10596                };
10597                selection.collapse_to(cursor, SelectionGoal::None)
10598            });
10599        })
10600    }
10601
10602    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
10603        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10604        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10605            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
10606        })
10607    }
10608
10609    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
10610        if self.take_rename(true, window, cx).is_some() {
10611            return;
10612        }
10613
10614        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10615            cx.propagate();
10616            return;
10617        }
10618
10619        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10620
10621        let text_layout_details = &self.text_layout_details(window);
10622        let selection_count = self.selections.count();
10623        let first_selection = self.selections.first_anchor();
10624
10625        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10626            s.move_with(|map, selection| {
10627                if !selection.is_empty() {
10628                    selection.goal = SelectionGoal::None;
10629                }
10630                let (cursor, goal) = movement::up(
10631                    map,
10632                    selection.start,
10633                    selection.goal,
10634                    false,
10635                    text_layout_details,
10636                );
10637                selection.collapse_to(cursor, goal);
10638            });
10639        });
10640
10641        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
10642        {
10643            cx.propagate();
10644        }
10645    }
10646
10647    pub fn move_up_by_lines(
10648        &mut self,
10649        action: &MoveUpByLines,
10650        window: &mut Window,
10651        cx: &mut Context<Self>,
10652    ) {
10653        if self.take_rename(true, window, cx).is_some() {
10654            return;
10655        }
10656
10657        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10658            cx.propagate();
10659            return;
10660        }
10661
10662        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10663
10664        let text_layout_details = &self.text_layout_details(window);
10665
10666        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10667            s.move_with(|map, selection| {
10668                if !selection.is_empty() {
10669                    selection.goal = SelectionGoal::None;
10670                }
10671                let (cursor, goal) = movement::up_by_rows(
10672                    map,
10673                    selection.start,
10674                    action.lines,
10675                    selection.goal,
10676                    false,
10677                    text_layout_details,
10678                );
10679                selection.collapse_to(cursor, goal);
10680            });
10681        })
10682    }
10683
10684    pub fn move_down_by_lines(
10685        &mut self,
10686        action: &MoveDownByLines,
10687        window: &mut Window,
10688        cx: &mut Context<Self>,
10689    ) {
10690        if self.take_rename(true, window, cx).is_some() {
10691            return;
10692        }
10693
10694        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10695            cx.propagate();
10696            return;
10697        }
10698
10699        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10700
10701        let text_layout_details = &self.text_layout_details(window);
10702
10703        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10704            s.move_with(|map, selection| {
10705                if !selection.is_empty() {
10706                    selection.goal = SelectionGoal::None;
10707                }
10708                let (cursor, goal) = movement::down_by_rows(
10709                    map,
10710                    selection.start,
10711                    action.lines,
10712                    selection.goal,
10713                    false,
10714                    text_layout_details,
10715                );
10716                selection.collapse_to(cursor, goal);
10717            });
10718        })
10719    }
10720
10721    pub fn select_down_by_lines(
10722        &mut self,
10723        action: &SelectDownByLines,
10724        window: &mut Window,
10725        cx: &mut Context<Self>,
10726    ) {
10727        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10728        let text_layout_details = &self.text_layout_details(window);
10729        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10730            s.move_heads_with(|map, head, goal| {
10731                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
10732            })
10733        })
10734    }
10735
10736    pub fn select_up_by_lines(
10737        &mut self,
10738        action: &SelectUpByLines,
10739        window: &mut Window,
10740        cx: &mut Context<Self>,
10741    ) {
10742        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10743        let text_layout_details = &self.text_layout_details(window);
10744        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10745            s.move_heads_with(|map, head, goal| {
10746                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
10747            })
10748        })
10749    }
10750
10751    pub fn select_page_up(
10752        &mut self,
10753        _: &SelectPageUp,
10754        window: &mut Window,
10755        cx: &mut Context<Self>,
10756    ) {
10757        let Some(row_count) = self.visible_row_count() else {
10758            return;
10759        };
10760
10761        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10762
10763        let text_layout_details = &self.text_layout_details(window);
10764
10765        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10766            s.move_heads_with(|map, head, goal| {
10767                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
10768            })
10769        })
10770    }
10771
10772    pub fn move_page_up(
10773        &mut self,
10774        action: &MovePageUp,
10775        window: &mut Window,
10776        cx: &mut Context<Self>,
10777    ) {
10778        if self.take_rename(true, window, cx).is_some() {
10779            return;
10780        }
10781
10782        if self
10783            .context_menu
10784            .borrow_mut()
10785            .as_mut()
10786            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
10787            .unwrap_or(false)
10788        {
10789            return;
10790        }
10791
10792        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10793            cx.propagate();
10794            return;
10795        }
10796
10797        let Some(row_count) = self.visible_row_count() else {
10798            return;
10799        };
10800
10801        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10802
10803        let autoscroll = if action.center_cursor {
10804            Autoscroll::center()
10805        } else {
10806            Autoscroll::fit()
10807        };
10808
10809        let text_layout_details = &self.text_layout_details(window);
10810
10811        self.change_selections(Some(autoscroll), window, cx, |s| {
10812            s.move_with(|map, selection| {
10813                if !selection.is_empty() {
10814                    selection.goal = SelectionGoal::None;
10815                }
10816                let (cursor, goal) = movement::up_by_rows(
10817                    map,
10818                    selection.end,
10819                    row_count,
10820                    selection.goal,
10821                    false,
10822                    text_layout_details,
10823                );
10824                selection.collapse_to(cursor, goal);
10825            });
10826        });
10827    }
10828
10829    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
10830        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10831        let text_layout_details = &self.text_layout_details(window);
10832        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10833            s.move_heads_with(|map, head, goal| {
10834                movement::up(map, head, goal, false, text_layout_details)
10835            })
10836        })
10837    }
10838
10839    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
10840        self.take_rename(true, window, cx);
10841
10842        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10843            cx.propagate();
10844            return;
10845        }
10846
10847        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10848
10849        let text_layout_details = &self.text_layout_details(window);
10850        let selection_count = self.selections.count();
10851        let first_selection = self.selections.first_anchor();
10852
10853        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10854            s.move_with(|map, selection| {
10855                if !selection.is_empty() {
10856                    selection.goal = SelectionGoal::None;
10857                }
10858                let (cursor, goal) = movement::down(
10859                    map,
10860                    selection.end,
10861                    selection.goal,
10862                    false,
10863                    text_layout_details,
10864                );
10865                selection.collapse_to(cursor, goal);
10866            });
10867        });
10868
10869        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
10870        {
10871            cx.propagate();
10872        }
10873    }
10874
10875    pub fn select_page_down(
10876        &mut self,
10877        _: &SelectPageDown,
10878        window: &mut Window,
10879        cx: &mut Context<Self>,
10880    ) {
10881        let Some(row_count) = self.visible_row_count() else {
10882            return;
10883        };
10884
10885        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10886
10887        let text_layout_details = &self.text_layout_details(window);
10888
10889        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10890            s.move_heads_with(|map, head, goal| {
10891                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
10892            })
10893        })
10894    }
10895
10896    pub fn move_page_down(
10897        &mut self,
10898        action: &MovePageDown,
10899        window: &mut Window,
10900        cx: &mut Context<Self>,
10901    ) {
10902        if self.take_rename(true, window, cx).is_some() {
10903            return;
10904        }
10905
10906        if self
10907            .context_menu
10908            .borrow_mut()
10909            .as_mut()
10910            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
10911            .unwrap_or(false)
10912        {
10913            return;
10914        }
10915
10916        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10917            cx.propagate();
10918            return;
10919        }
10920
10921        let Some(row_count) = self.visible_row_count() else {
10922            return;
10923        };
10924
10925        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10926
10927        let autoscroll = if action.center_cursor {
10928            Autoscroll::center()
10929        } else {
10930            Autoscroll::fit()
10931        };
10932
10933        let text_layout_details = &self.text_layout_details(window);
10934        self.change_selections(Some(autoscroll), window, cx, |s| {
10935            s.move_with(|map, selection| {
10936                if !selection.is_empty() {
10937                    selection.goal = SelectionGoal::None;
10938                }
10939                let (cursor, goal) = movement::down_by_rows(
10940                    map,
10941                    selection.end,
10942                    row_count,
10943                    selection.goal,
10944                    false,
10945                    text_layout_details,
10946                );
10947                selection.collapse_to(cursor, goal);
10948            });
10949        });
10950    }
10951
10952    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
10953        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10954        let text_layout_details = &self.text_layout_details(window);
10955        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10956            s.move_heads_with(|map, head, goal| {
10957                movement::down(map, head, goal, false, text_layout_details)
10958            })
10959        });
10960    }
10961
10962    pub fn context_menu_first(
10963        &mut self,
10964        _: &ContextMenuFirst,
10965        _window: &mut Window,
10966        cx: &mut Context<Self>,
10967    ) {
10968        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
10969            context_menu.select_first(self.completion_provider.as_deref(), cx);
10970        }
10971    }
10972
10973    pub fn context_menu_prev(
10974        &mut self,
10975        _: &ContextMenuPrevious,
10976        _window: &mut Window,
10977        cx: &mut Context<Self>,
10978    ) {
10979        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
10980            context_menu.select_prev(self.completion_provider.as_deref(), cx);
10981        }
10982    }
10983
10984    pub fn context_menu_next(
10985        &mut self,
10986        _: &ContextMenuNext,
10987        _window: &mut Window,
10988        cx: &mut Context<Self>,
10989    ) {
10990        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
10991            context_menu.select_next(self.completion_provider.as_deref(), cx);
10992        }
10993    }
10994
10995    pub fn context_menu_last(
10996        &mut self,
10997        _: &ContextMenuLast,
10998        _window: &mut Window,
10999        cx: &mut Context<Self>,
11000    ) {
11001        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11002            context_menu.select_last(self.completion_provider.as_deref(), cx);
11003        }
11004    }
11005
11006    pub fn move_to_previous_word_start(
11007        &mut self,
11008        _: &MoveToPreviousWordStart,
11009        window: &mut Window,
11010        cx: &mut Context<Self>,
11011    ) {
11012        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11013        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11014            s.move_cursors_with(|map, head, _| {
11015                (
11016                    movement::previous_word_start(map, head),
11017                    SelectionGoal::None,
11018                )
11019            });
11020        })
11021    }
11022
11023    pub fn move_to_previous_subword_start(
11024        &mut self,
11025        _: &MoveToPreviousSubwordStart,
11026        window: &mut Window,
11027        cx: &mut Context<Self>,
11028    ) {
11029        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11030        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11031            s.move_cursors_with(|map, head, _| {
11032                (
11033                    movement::previous_subword_start(map, head),
11034                    SelectionGoal::None,
11035                )
11036            });
11037        })
11038    }
11039
11040    pub fn select_to_previous_word_start(
11041        &mut self,
11042        _: &SelectToPreviousWordStart,
11043        window: &mut Window,
11044        cx: &mut Context<Self>,
11045    ) {
11046        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11047        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11048            s.move_heads_with(|map, head, _| {
11049                (
11050                    movement::previous_word_start(map, head),
11051                    SelectionGoal::None,
11052                )
11053            });
11054        })
11055    }
11056
11057    pub fn select_to_previous_subword_start(
11058        &mut self,
11059        _: &SelectToPreviousSubwordStart,
11060        window: &mut Window,
11061        cx: &mut Context<Self>,
11062    ) {
11063        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11064        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11065            s.move_heads_with(|map, head, _| {
11066                (
11067                    movement::previous_subword_start(map, head),
11068                    SelectionGoal::None,
11069                )
11070            });
11071        })
11072    }
11073
11074    pub fn delete_to_previous_word_start(
11075        &mut self,
11076        action: &DeleteToPreviousWordStart,
11077        window: &mut Window,
11078        cx: &mut Context<Self>,
11079    ) {
11080        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11081        self.transact(window, cx, |this, window, cx| {
11082            this.select_autoclose_pair(window, cx);
11083            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11084                s.move_with(|map, selection| {
11085                    if selection.is_empty() {
11086                        let cursor = if action.ignore_newlines {
11087                            movement::previous_word_start(map, selection.head())
11088                        } else {
11089                            movement::previous_word_start_or_newline(map, selection.head())
11090                        };
11091                        selection.set_head(cursor, SelectionGoal::None);
11092                    }
11093                });
11094            });
11095            this.insert("", window, cx);
11096        });
11097    }
11098
11099    pub fn delete_to_previous_subword_start(
11100        &mut self,
11101        _: &DeleteToPreviousSubwordStart,
11102        window: &mut Window,
11103        cx: &mut Context<Self>,
11104    ) {
11105        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11106        self.transact(window, cx, |this, window, cx| {
11107            this.select_autoclose_pair(window, cx);
11108            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11109                s.move_with(|map, selection| {
11110                    if selection.is_empty() {
11111                        let cursor = movement::previous_subword_start(map, selection.head());
11112                        selection.set_head(cursor, SelectionGoal::None);
11113                    }
11114                });
11115            });
11116            this.insert("", window, cx);
11117        });
11118    }
11119
11120    pub fn move_to_next_word_end(
11121        &mut self,
11122        _: &MoveToNextWordEnd,
11123        window: &mut Window,
11124        cx: &mut Context<Self>,
11125    ) {
11126        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11127        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11128            s.move_cursors_with(|map, head, _| {
11129                (movement::next_word_end(map, head), SelectionGoal::None)
11130            });
11131        })
11132    }
11133
11134    pub fn move_to_next_subword_end(
11135        &mut self,
11136        _: &MoveToNextSubwordEnd,
11137        window: &mut Window,
11138        cx: &mut Context<Self>,
11139    ) {
11140        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11141        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11142            s.move_cursors_with(|map, head, _| {
11143                (movement::next_subword_end(map, head), SelectionGoal::None)
11144            });
11145        })
11146    }
11147
11148    pub fn select_to_next_word_end(
11149        &mut self,
11150        _: &SelectToNextWordEnd,
11151        window: &mut Window,
11152        cx: &mut Context<Self>,
11153    ) {
11154        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11155        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11156            s.move_heads_with(|map, head, _| {
11157                (movement::next_word_end(map, head), SelectionGoal::None)
11158            });
11159        })
11160    }
11161
11162    pub fn select_to_next_subword_end(
11163        &mut self,
11164        _: &SelectToNextSubwordEnd,
11165        window: &mut Window,
11166        cx: &mut Context<Self>,
11167    ) {
11168        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11169        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11170            s.move_heads_with(|map, head, _| {
11171                (movement::next_subword_end(map, head), SelectionGoal::None)
11172            });
11173        })
11174    }
11175
11176    pub fn delete_to_next_word_end(
11177        &mut self,
11178        action: &DeleteToNextWordEnd,
11179        window: &mut Window,
11180        cx: &mut Context<Self>,
11181    ) {
11182        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11183        self.transact(window, cx, |this, window, cx| {
11184            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11185                s.move_with(|map, selection| {
11186                    if selection.is_empty() {
11187                        let cursor = if action.ignore_newlines {
11188                            movement::next_word_end(map, selection.head())
11189                        } else {
11190                            movement::next_word_end_or_newline(map, selection.head())
11191                        };
11192                        selection.set_head(cursor, SelectionGoal::None);
11193                    }
11194                });
11195            });
11196            this.insert("", window, cx);
11197        });
11198    }
11199
11200    pub fn delete_to_next_subword_end(
11201        &mut self,
11202        _: &DeleteToNextSubwordEnd,
11203        window: &mut Window,
11204        cx: &mut Context<Self>,
11205    ) {
11206        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11207        self.transact(window, cx, |this, window, cx| {
11208            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11209                s.move_with(|map, selection| {
11210                    if selection.is_empty() {
11211                        let cursor = movement::next_subword_end(map, selection.head());
11212                        selection.set_head(cursor, SelectionGoal::None);
11213                    }
11214                });
11215            });
11216            this.insert("", window, cx);
11217        });
11218    }
11219
11220    pub fn move_to_beginning_of_line(
11221        &mut self,
11222        action: &MoveToBeginningOfLine,
11223        window: &mut Window,
11224        cx: &mut Context<Self>,
11225    ) {
11226        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11227        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11228            s.move_cursors_with(|map, head, _| {
11229                (
11230                    movement::indented_line_beginning(
11231                        map,
11232                        head,
11233                        action.stop_at_soft_wraps,
11234                        action.stop_at_indent,
11235                    ),
11236                    SelectionGoal::None,
11237                )
11238            });
11239        })
11240    }
11241
11242    pub fn select_to_beginning_of_line(
11243        &mut self,
11244        action: &SelectToBeginningOfLine,
11245        window: &mut Window,
11246        cx: &mut Context<Self>,
11247    ) {
11248        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11249        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11250            s.move_heads_with(|map, head, _| {
11251                (
11252                    movement::indented_line_beginning(
11253                        map,
11254                        head,
11255                        action.stop_at_soft_wraps,
11256                        action.stop_at_indent,
11257                    ),
11258                    SelectionGoal::None,
11259                )
11260            });
11261        });
11262    }
11263
11264    pub fn delete_to_beginning_of_line(
11265        &mut self,
11266        action: &DeleteToBeginningOfLine,
11267        window: &mut Window,
11268        cx: &mut Context<Self>,
11269    ) {
11270        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11271        self.transact(window, cx, |this, window, cx| {
11272            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11273                s.move_with(|_, selection| {
11274                    selection.reversed = true;
11275                });
11276            });
11277
11278            this.select_to_beginning_of_line(
11279                &SelectToBeginningOfLine {
11280                    stop_at_soft_wraps: false,
11281                    stop_at_indent: action.stop_at_indent,
11282                },
11283                window,
11284                cx,
11285            );
11286            this.backspace(&Backspace, window, cx);
11287        });
11288    }
11289
11290    pub fn move_to_end_of_line(
11291        &mut self,
11292        action: &MoveToEndOfLine,
11293        window: &mut Window,
11294        cx: &mut Context<Self>,
11295    ) {
11296        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11297        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11298            s.move_cursors_with(|map, head, _| {
11299                (
11300                    movement::line_end(map, head, action.stop_at_soft_wraps),
11301                    SelectionGoal::None,
11302                )
11303            });
11304        })
11305    }
11306
11307    pub fn select_to_end_of_line(
11308        &mut self,
11309        action: &SelectToEndOfLine,
11310        window: &mut Window,
11311        cx: &mut Context<Self>,
11312    ) {
11313        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11314        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11315            s.move_heads_with(|map, head, _| {
11316                (
11317                    movement::line_end(map, head, action.stop_at_soft_wraps),
11318                    SelectionGoal::None,
11319                )
11320            });
11321        })
11322    }
11323
11324    pub fn delete_to_end_of_line(
11325        &mut self,
11326        _: &DeleteToEndOfLine,
11327        window: &mut Window,
11328        cx: &mut Context<Self>,
11329    ) {
11330        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11331        self.transact(window, cx, |this, window, cx| {
11332            this.select_to_end_of_line(
11333                &SelectToEndOfLine {
11334                    stop_at_soft_wraps: false,
11335                },
11336                window,
11337                cx,
11338            );
11339            this.delete(&Delete, window, cx);
11340        });
11341    }
11342
11343    pub fn cut_to_end_of_line(
11344        &mut self,
11345        _: &CutToEndOfLine,
11346        window: &mut Window,
11347        cx: &mut Context<Self>,
11348    ) {
11349        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11350        self.transact(window, cx, |this, window, cx| {
11351            this.select_to_end_of_line(
11352                &SelectToEndOfLine {
11353                    stop_at_soft_wraps: false,
11354                },
11355                window,
11356                cx,
11357            );
11358            this.cut(&Cut, window, cx);
11359        });
11360    }
11361
11362    pub fn move_to_start_of_paragraph(
11363        &mut self,
11364        _: &MoveToStartOfParagraph,
11365        window: &mut Window,
11366        cx: &mut Context<Self>,
11367    ) {
11368        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11369            cx.propagate();
11370            return;
11371        }
11372        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11373        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11374            s.move_with(|map, selection| {
11375                selection.collapse_to(
11376                    movement::start_of_paragraph(map, selection.head(), 1),
11377                    SelectionGoal::None,
11378                )
11379            });
11380        })
11381    }
11382
11383    pub fn move_to_end_of_paragraph(
11384        &mut self,
11385        _: &MoveToEndOfParagraph,
11386        window: &mut Window,
11387        cx: &mut Context<Self>,
11388    ) {
11389        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11390            cx.propagate();
11391            return;
11392        }
11393        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11394        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11395            s.move_with(|map, selection| {
11396                selection.collapse_to(
11397                    movement::end_of_paragraph(map, selection.head(), 1),
11398                    SelectionGoal::None,
11399                )
11400            });
11401        })
11402    }
11403
11404    pub fn select_to_start_of_paragraph(
11405        &mut self,
11406        _: &SelectToStartOfParagraph,
11407        window: &mut Window,
11408        cx: &mut Context<Self>,
11409    ) {
11410        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11411            cx.propagate();
11412            return;
11413        }
11414        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11415        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11416            s.move_heads_with(|map, head, _| {
11417                (
11418                    movement::start_of_paragraph(map, head, 1),
11419                    SelectionGoal::None,
11420                )
11421            });
11422        })
11423    }
11424
11425    pub fn select_to_end_of_paragraph(
11426        &mut self,
11427        _: &SelectToEndOfParagraph,
11428        window: &mut Window,
11429        cx: &mut Context<Self>,
11430    ) {
11431        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11432            cx.propagate();
11433            return;
11434        }
11435        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11436        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11437            s.move_heads_with(|map, head, _| {
11438                (
11439                    movement::end_of_paragraph(map, head, 1),
11440                    SelectionGoal::None,
11441                )
11442            });
11443        })
11444    }
11445
11446    pub fn move_to_start_of_excerpt(
11447        &mut self,
11448        _: &MoveToStartOfExcerpt,
11449        window: &mut Window,
11450        cx: &mut Context<Self>,
11451    ) {
11452        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11453            cx.propagate();
11454            return;
11455        }
11456        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11457        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11458            s.move_with(|map, selection| {
11459                selection.collapse_to(
11460                    movement::start_of_excerpt(
11461                        map,
11462                        selection.head(),
11463                        workspace::searchable::Direction::Prev,
11464                    ),
11465                    SelectionGoal::None,
11466                )
11467            });
11468        })
11469    }
11470
11471    pub fn move_to_start_of_next_excerpt(
11472        &mut self,
11473        _: &MoveToStartOfNextExcerpt,
11474        window: &mut Window,
11475        cx: &mut Context<Self>,
11476    ) {
11477        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11478            cx.propagate();
11479            return;
11480        }
11481
11482        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11483            s.move_with(|map, selection| {
11484                selection.collapse_to(
11485                    movement::start_of_excerpt(
11486                        map,
11487                        selection.head(),
11488                        workspace::searchable::Direction::Next,
11489                    ),
11490                    SelectionGoal::None,
11491                )
11492            });
11493        })
11494    }
11495
11496    pub fn move_to_end_of_excerpt(
11497        &mut self,
11498        _: &MoveToEndOfExcerpt,
11499        window: &mut Window,
11500        cx: &mut Context<Self>,
11501    ) {
11502        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11503            cx.propagate();
11504            return;
11505        }
11506        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11507        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11508            s.move_with(|map, selection| {
11509                selection.collapse_to(
11510                    movement::end_of_excerpt(
11511                        map,
11512                        selection.head(),
11513                        workspace::searchable::Direction::Next,
11514                    ),
11515                    SelectionGoal::None,
11516                )
11517            });
11518        })
11519    }
11520
11521    pub fn move_to_end_of_previous_excerpt(
11522        &mut self,
11523        _: &MoveToEndOfPreviousExcerpt,
11524        window: &mut Window,
11525        cx: &mut Context<Self>,
11526    ) {
11527        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11528            cx.propagate();
11529            return;
11530        }
11531        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11532        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11533            s.move_with(|map, selection| {
11534                selection.collapse_to(
11535                    movement::end_of_excerpt(
11536                        map,
11537                        selection.head(),
11538                        workspace::searchable::Direction::Prev,
11539                    ),
11540                    SelectionGoal::None,
11541                )
11542            });
11543        })
11544    }
11545
11546    pub fn select_to_start_of_excerpt(
11547        &mut self,
11548        _: &SelectToStartOfExcerpt,
11549        window: &mut Window,
11550        cx: &mut Context<Self>,
11551    ) {
11552        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11553            cx.propagate();
11554            return;
11555        }
11556        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11557        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11558            s.move_heads_with(|map, head, _| {
11559                (
11560                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
11561                    SelectionGoal::None,
11562                )
11563            });
11564        })
11565    }
11566
11567    pub fn select_to_start_of_next_excerpt(
11568        &mut self,
11569        _: &SelectToStartOfNextExcerpt,
11570        window: &mut Window,
11571        cx: &mut Context<Self>,
11572    ) {
11573        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11574            cx.propagate();
11575            return;
11576        }
11577        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11578        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11579            s.move_heads_with(|map, head, _| {
11580                (
11581                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
11582                    SelectionGoal::None,
11583                )
11584            });
11585        })
11586    }
11587
11588    pub fn select_to_end_of_excerpt(
11589        &mut self,
11590        _: &SelectToEndOfExcerpt,
11591        window: &mut Window,
11592        cx: &mut Context<Self>,
11593    ) {
11594        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11595            cx.propagate();
11596            return;
11597        }
11598        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11599        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11600            s.move_heads_with(|map, head, _| {
11601                (
11602                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
11603                    SelectionGoal::None,
11604                )
11605            });
11606        })
11607    }
11608
11609    pub fn select_to_end_of_previous_excerpt(
11610        &mut self,
11611        _: &SelectToEndOfPreviousExcerpt,
11612        window: &mut Window,
11613        cx: &mut Context<Self>,
11614    ) {
11615        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11616            cx.propagate();
11617            return;
11618        }
11619        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11620        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11621            s.move_heads_with(|map, head, _| {
11622                (
11623                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
11624                    SelectionGoal::None,
11625                )
11626            });
11627        })
11628    }
11629
11630    pub fn move_to_beginning(
11631        &mut self,
11632        _: &MoveToBeginning,
11633        window: &mut Window,
11634        cx: &mut Context<Self>,
11635    ) {
11636        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11637            cx.propagate();
11638            return;
11639        }
11640        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11641        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11642            s.select_ranges(vec![0..0]);
11643        });
11644    }
11645
11646    pub fn select_to_beginning(
11647        &mut self,
11648        _: &SelectToBeginning,
11649        window: &mut Window,
11650        cx: &mut Context<Self>,
11651    ) {
11652        let mut selection = self.selections.last::<Point>(cx);
11653        selection.set_head(Point::zero(), SelectionGoal::None);
11654        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11655        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11656            s.select(vec![selection]);
11657        });
11658    }
11659
11660    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
11661        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11662            cx.propagate();
11663            return;
11664        }
11665        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11666        let cursor = self.buffer.read(cx).read(cx).len();
11667        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11668            s.select_ranges(vec![cursor..cursor])
11669        });
11670    }
11671
11672    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
11673        self.nav_history = nav_history;
11674    }
11675
11676    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
11677        self.nav_history.as_ref()
11678    }
11679
11680    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
11681        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
11682    }
11683
11684    fn push_to_nav_history(
11685        &mut self,
11686        cursor_anchor: Anchor,
11687        new_position: Option<Point>,
11688        is_deactivate: bool,
11689        cx: &mut Context<Self>,
11690    ) {
11691        if let Some(nav_history) = self.nav_history.as_mut() {
11692            let buffer = self.buffer.read(cx).read(cx);
11693            let cursor_position = cursor_anchor.to_point(&buffer);
11694            let scroll_state = self.scroll_manager.anchor();
11695            let scroll_top_row = scroll_state.top_row(&buffer);
11696            drop(buffer);
11697
11698            if let Some(new_position) = new_position {
11699                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
11700                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
11701                    return;
11702                }
11703            }
11704
11705            nav_history.push(
11706                Some(NavigationData {
11707                    cursor_anchor,
11708                    cursor_position,
11709                    scroll_anchor: scroll_state,
11710                    scroll_top_row,
11711                }),
11712                cx,
11713            );
11714            cx.emit(EditorEvent::PushedToNavHistory {
11715                anchor: cursor_anchor,
11716                is_deactivate,
11717            })
11718        }
11719    }
11720
11721    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
11722        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11723        let buffer = self.buffer.read(cx).snapshot(cx);
11724        let mut selection = self.selections.first::<usize>(cx);
11725        selection.set_head(buffer.len(), SelectionGoal::None);
11726        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11727            s.select(vec![selection]);
11728        });
11729    }
11730
11731    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
11732        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11733        let end = self.buffer.read(cx).read(cx).len();
11734        self.change_selections(None, window, cx, |s| {
11735            s.select_ranges(vec![0..end]);
11736        });
11737    }
11738
11739    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
11740        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11741        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11742        let mut selections = self.selections.all::<Point>(cx);
11743        let max_point = display_map.buffer_snapshot.max_point();
11744        for selection in &mut selections {
11745            let rows = selection.spanned_rows(true, &display_map);
11746            selection.start = Point::new(rows.start.0, 0);
11747            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
11748            selection.reversed = false;
11749        }
11750        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11751            s.select(selections);
11752        });
11753    }
11754
11755    pub fn split_selection_into_lines(
11756        &mut self,
11757        _: &SplitSelectionIntoLines,
11758        window: &mut Window,
11759        cx: &mut Context<Self>,
11760    ) {
11761        let selections = self
11762            .selections
11763            .all::<Point>(cx)
11764            .into_iter()
11765            .map(|selection| selection.start..selection.end)
11766            .collect::<Vec<_>>();
11767        self.unfold_ranges(&selections, true, true, cx);
11768
11769        let mut new_selection_ranges = Vec::new();
11770        {
11771            let buffer = self.buffer.read(cx).read(cx);
11772            for selection in selections {
11773                for row in selection.start.row..selection.end.row {
11774                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11775                    new_selection_ranges.push(cursor..cursor);
11776                }
11777
11778                let is_multiline_selection = selection.start.row != selection.end.row;
11779                // Don't insert last one if it's a multi-line selection ending at the start of a line,
11780                // so this action feels more ergonomic when paired with other selection operations
11781                let should_skip_last = is_multiline_selection && selection.end.column == 0;
11782                if !should_skip_last {
11783                    new_selection_ranges.push(selection.end..selection.end);
11784                }
11785            }
11786        }
11787        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11788            s.select_ranges(new_selection_ranges);
11789        });
11790    }
11791
11792    pub fn add_selection_above(
11793        &mut self,
11794        _: &AddSelectionAbove,
11795        window: &mut Window,
11796        cx: &mut Context<Self>,
11797    ) {
11798        self.add_selection(true, window, cx);
11799    }
11800
11801    pub fn add_selection_below(
11802        &mut self,
11803        _: &AddSelectionBelow,
11804        window: &mut Window,
11805        cx: &mut Context<Self>,
11806    ) {
11807        self.add_selection(false, window, cx);
11808    }
11809
11810    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
11811        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11812
11813        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11814        let mut selections = self.selections.all::<Point>(cx);
11815        let text_layout_details = self.text_layout_details(window);
11816        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
11817            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
11818            let range = oldest_selection.display_range(&display_map).sorted();
11819
11820            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
11821            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
11822            let positions = start_x.min(end_x)..start_x.max(end_x);
11823
11824            selections.clear();
11825            let mut stack = Vec::new();
11826            for row in range.start.row().0..=range.end.row().0 {
11827                if let Some(selection) = self.selections.build_columnar_selection(
11828                    &display_map,
11829                    DisplayRow(row),
11830                    &positions,
11831                    oldest_selection.reversed,
11832                    &text_layout_details,
11833                ) {
11834                    stack.push(selection.id);
11835                    selections.push(selection);
11836                }
11837            }
11838
11839            if above {
11840                stack.reverse();
11841            }
11842
11843            AddSelectionsState { above, stack }
11844        });
11845
11846        let last_added_selection = *state.stack.last().unwrap();
11847        let mut new_selections = Vec::new();
11848        if above == state.above {
11849            let end_row = if above {
11850                DisplayRow(0)
11851            } else {
11852                display_map.max_point().row()
11853            };
11854
11855            'outer: for selection in selections {
11856                if selection.id == last_added_selection {
11857                    let range = selection.display_range(&display_map).sorted();
11858                    debug_assert_eq!(range.start.row(), range.end.row());
11859                    let mut row = range.start.row();
11860                    let positions =
11861                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
11862                            px(start)..px(end)
11863                        } else {
11864                            let start_x =
11865                                display_map.x_for_display_point(range.start, &text_layout_details);
11866                            let end_x =
11867                                display_map.x_for_display_point(range.end, &text_layout_details);
11868                            start_x.min(end_x)..start_x.max(end_x)
11869                        };
11870
11871                    while row != end_row {
11872                        if above {
11873                            row.0 -= 1;
11874                        } else {
11875                            row.0 += 1;
11876                        }
11877
11878                        if let Some(new_selection) = self.selections.build_columnar_selection(
11879                            &display_map,
11880                            row,
11881                            &positions,
11882                            selection.reversed,
11883                            &text_layout_details,
11884                        ) {
11885                            state.stack.push(new_selection.id);
11886                            if above {
11887                                new_selections.push(new_selection);
11888                                new_selections.push(selection);
11889                            } else {
11890                                new_selections.push(selection);
11891                                new_selections.push(new_selection);
11892                            }
11893
11894                            continue 'outer;
11895                        }
11896                    }
11897                }
11898
11899                new_selections.push(selection);
11900            }
11901        } else {
11902            new_selections = selections;
11903            new_selections.retain(|s| s.id != last_added_selection);
11904            state.stack.pop();
11905        }
11906
11907        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11908            s.select(new_selections);
11909        });
11910        if state.stack.len() > 1 {
11911            self.add_selections_state = Some(state);
11912        }
11913    }
11914
11915    pub fn select_next_match_internal(
11916        &mut self,
11917        display_map: &DisplaySnapshot,
11918        replace_newest: bool,
11919        autoscroll: Option<Autoscroll>,
11920        window: &mut Window,
11921        cx: &mut Context<Self>,
11922    ) -> Result<()> {
11923        fn select_next_match_ranges(
11924            this: &mut Editor,
11925            range: Range<usize>,
11926            reversed: bool,
11927            replace_newest: bool,
11928            auto_scroll: Option<Autoscroll>,
11929            window: &mut Window,
11930            cx: &mut Context<Editor>,
11931        ) {
11932            this.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
11933            this.change_selections(auto_scroll, window, cx, |s| {
11934                if replace_newest {
11935                    s.delete(s.newest_anchor().id);
11936                }
11937                if reversed {
11938                    s.insert_range(range.end..range.start);
11939                } else {
11940                    s.insert_range(range);
11941                }
11942            });
11943        }
11944
11945        let buffer = &display_map.buffer_snapshot;
11946        let mut selections = self.selections.all::<usize>(cx);
11947        if let Some(mut select_next_state) = self.select_next_state.take() {
11948            let query = &select_next_state.query;
11949            if !select_next_state.done {
11950                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
11951                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
11952                let mut next_selected_range = None;
11953
11954                let bytes_after_last_selection =
11955                    buffer.bytes_in_range(last_selection.end..buffer.len());
11956                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
11957                let query_matches = query
11958                    .stream_find_iter(bytes_after_last_selection)
11959                    .map(|result| (last_selection.end, result))
11960                    .chain(
11961                        query
11962                            .stream_find_iter(bytes_before_first_selection)
11963                            .map(|result| (0, result)),
11964                    );
11965
11966                for (start_offset, query_match) in query_matches {
11967                    let query_match = query_match.unwrap(); // can only fail due to I/O
11968                    let offset_range =
11969                        start_offset + query_match.start()..start_offset + query_match.end();
11970                    let display_range = offset_range.start.to_display_point(display_map)
11971                        ..offset_range.end.to_display_point(display_map);
11972
11973                    if !select_next_state.wordwise
11974                        || (!movement::is_inside_word(display_map, display_range.start)
11975                            && !movement::is_inside_word(display_map, display_range.end))
11976                    {
11977                        // TODO: This is n^2, because we might check all the selections
11978                        if !selections
11979                            .iter()
11980                            .any(|selection| selection.range().overlaps(&offset_range))
11981                        {
11982                            next_selected_range = Some(offset_range);
11983                            break;
11984                        }
11985                    }
11986                }
11987
11988                if let Some(next_selected_range) = next_selected_range {
11989                    select_next_match_ranges(
11990                        self,
11991                        next_selected_range,
11992                        last_selection.reversed,
11993                        replace_newest,
11994                        autoscroll,
11995                        window,
11996                        cx,
11997                    );
11998                } else {
11999                    select_next_state.done = true;
12000                }
12001            }
12002
12003            self.select_next_state = Some(select_next_state);
12004        } else {
12005            let mut only_carets = true;
12006            let mut same_text_selected = true;
12007            let mut selected_text = None;
12008
12009            let mut selections_iter = selections.iter().peekable();
12010            while let Some(selection) = selections_iter.next() {
12011                if selection.start != selection.end {
12012                    only_carets = false;
12013                }
12014
12015                if same_text_selected {
12016                    if selected_text.is_none() {
12017                        selected_text =
12018                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12019                    }
12020
12021                    if let Some(next_selection) = selections_iter.peek() {
12022                        if next_selection.range().len() == selection.range().len() {
12023                            let next_selected_text = buffer
12024                                .text_for_range(next_selection.range())
12025                                .collect::<String>();
12026                            if Some(next_selected_text) != selected_text {
12027                                same_text_selected = false;
12028                                selected_text = None;
12029                            }
12030                        } else {
12031                            same_text_selected = false;
12032                            selected_text = None;
12033                        }
12034                    }
12035                }
12036            }
12037
12038            if only_carets {
12039                for selection in &mut selections {
12040                    let word_range = movement::surrounding_word(
12041                        display_map,
12042                        selection.start.to_display_point(display_map),
12043                    );
12044                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12045                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12046                    selection.goal = SelectionGoal::None;
12047                    selection.reversed = false;
12048                    select_next_match_ranges(
12049                        self,
12050                        selection.start..selection.end,
12051                        selection.reversed,
12052                        replace_newest,
12053                        autoscroll,
12054                        window,
12055                        cx,
12056                    );
12057                }
12058
12059                if selections.len() == 1 {
12060                    let selection = selections
12061                        .last()
12062                        .expect("ensured that there's only one selection");
12063                    let query = buffer
12064                        .text_for_range(selection.start..selection.end)
12065                        .collect::<String>();
12066                    let is_empty = query.is_empty();
12067                    let select_state = SelectNextState {
12068                        query: AhoCorasick::new(&[query])?,
12069                        wordwise: true,
12070                        done: is_empty,
12071                    };
12072                    self.select_next_state = Some(select_state);
12073                } else {
12074                    self.select_next_state = None;
12075                }
12076            } else if let Some(selected_text) = selected_text {
12077                self.select_next_state = Some(SelectNextState {
12078                    query: AhoCorasick::new(&[selected_text])?,
12079                    wordwise: false,
12080                    done: false,
12081                });
12082                self.select_next_match_internal(
12083                    display_map,
12084                    replace_newest,
12085                    autoscroll,
12086                    window,
12087                    cx,
12088                )?;
12089            }
12090        }
12091        Ok(())
12092    }
12093
12094    pub fn select_all_matches(
12095        &mut self,
12096        _action: &SelectAllMatches,
12097        window: &mut Window,
12098        cx: &mut Context<Self>,
12099    ) -> Result<()> {
12100        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12101
12102        self.push_to_selection_history();
12103        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12104
12105        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12106        let Some(select_next_state) = self.select_next_state.as_mut() else {
12107            return Ok(());
12108        };
12109        if select_next_state.done {
12110            return Ok(());
12111        }
12112
12113        let mut new_selections = Vec::new();
12114
12115        let reversed = self.selections.oldest::<usize>(cx).reversed;
12116        let buffer = &display_map.buffer_snapshot;
12117        let query_matches = select_next_state
12118            .query
12119            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12120
12121        for query_match in query_matches.into_iter() {
12122            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12123            let offset_range = if reversed {
12124                query_match.end()..query_match.start()
12125            } else {
12126                query_match.start()..query_match.end()
12127            };
12128            let display_range = offset_range.start.to_display_point(&display_map)
12129                ..offset_range.end.to_display_point(&display_map);
12130
12131            if !select_next_state.wordwise
12132                || (!movement::is_inside_word(&display_map, display_range.start)
12133                    && !movement::is_inside_word(&display_map, display_range.end))
12134            {
12135                new_selections.push(offset_range.start..offset_range.end);
12136            }
12137        }
12138
12139        select_next_state.done = true;
12140        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12141        self.change_selections(None, window, cx, |selections| {
12142            selections.select_ranges(new_selections)
12143        });
12144
12145        Ok(())
12146    }
12147
12148    pub fn select_next(
12149        &mut self,
12150        action: &SelectNext,
12151        window: &mut Window,
12152        cx: &mut Context<Self>,
12153    ) -> Result<()> {
12154        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12155        self.push_to_selection_history();
12156        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12157        self.select_next_match_internal(
12158            &display_map,
12159            action.replace_newest,
12160            Some(Autoscroll::newest()),
12161            window,
12162            cx,
12163        )?;
12164        Ok(())
12165    }
12166
12167    pub fn select_previous(
12168        &mut self,
12169        action: &SelectPrevious,
12170        window: &mut Window,
12171        cx: &mut Context<Self>,
12172    ) -> Result<()> {
12173        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12174        self.push_to_selection_history();
12175        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12176        let buffer = &display_map.buffer_snapshot;
12177        let mut selections = self.selections.all::<usize>(cx);
12178        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12179            let query = &select_prev_state.query;
12180            if !select_prev_state.done {
12181                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12182                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12183                let mut next_selected_range = None;
12184                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12185                let bytes_before_last_selection =
12186                    buffer.reversed_bytes_in_range(0..last_selection.start);
12187                let bytes_after_first_selection =
12188                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12189                let query_matches = query
12190                    .stream_find_iter(bytes_before_last_selection)
12191                    .map(|result| (last_selection.start, result))
12192                    .chain(
12193                        query
12194                            .stream_find_iter(bytes_after_first_selection)
12195                            .map(|result| (buffer.len(), result)),
12196                    );
12197                for (end_offset, query_match) in query_matches {
12198                    let query_match = query_match.unwrap(); // can only fail due to I/O
12199                    let offset_range =
12200                        end_offset - query_match.end()..end_offset - query_match.start();
12201                    let display_range = offset_range.start.to_display_point(&display_map)
12202                        ..offset_range.end.to_display_point(&display_map);
12203
12204                    if !select_prev_state.wordwise
12205                        || (!movement::is_inside_word(&display_map, display_range.start)
12206                            && !movement::is_inside_word(&display_map, display_range.end))
12207                    {
12208                        next_selected_range = Some(offset_range);
12209                        break;
12210                    }
12211                }
12212
12213                if let Some(next_selected_range) = next_selected_range {
12214                    self.unfold_ranges(&[next_selected_range.clone()], false, true, cx);
12215                    self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
12216                        if action.replace_newest {
12217                            s.delete(s.newest_anchor().id);
12218                        }
12219                        if last_selection.reversed {
12220                            s.insert_range(next_selected_range.end..next_selected_range.start);
12221                        } else {
12222                            s.insert_range(next_selected_range);
12223                        }
12224                    });
12225                } else {
12226                    select_prev_state.done = true;
12227                }
12228            }
12229
12230            self.select_prev_state = Some(select_prev_state);
12231        } else {
12232            let mut only_carets = true;
12233            let mut same_text_selected = true;
12234            let mut selected_text = None;
12235
12236            let mut selections_iter = selections.iter().peekable();
12237            while let Some(selection) = selections_iter.next() {
12238                if selection.start != selection.end {
12239                    only_carets = false;
12240                }
12241
12242                if same_text_selected {
12243                    if selected_text.is_none() {
12244                        selected_text =
12245                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12246                    }
12247
12248                    if let Some(next_selection) = selections_iter.peek() {
12249                        if next_selection.range().len() == selection.range().len() {
12250                            let next_selected_text = buffer
12251                                .text_for_range(next_selection.range())
12252                                .collect::<String>();
12253                            if Some(next_selected_text) != selected_text {
12254                                same_text_selected = false;
12255                                selected_text = None;
12256                            }
12257                        } else {
12258                            same_text_selected = false;
12259                            selected_text = None;
12260                        }
12261                    }
12262                }
12263            }
12264
12265            if only_carets {
12266                for selection in &mut selections {
12267                    let word_range = movement::surrounding_word(
12268                        &display_map,
12269                        selection.start.to_display_point(&display_map),
12270                    );
12271                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12272                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12273                    selection.goal = SelectionGoal::None;
12274                    selection.reversed = false;
12275                }
12276                if selections.len() == 1 {
12277                    let selection = selections
12278                        .last()
12279                        .expect("ensured that there's only one selection");
12280                    let query = buffer
12281                        .text_for_range(selection.start..selection.end)
12282                        .collect::<String>();
12283                    let is_empty = query.is_empty();
12284                    let select_state = SelectNextState {
12285                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12286                        wordwise: true,
12287                        done: is_empty,
12288                    };
12289                    self.select_prev_state = Some(select_state);
12290                } else {
12291                    self.select_prev_state = None;
12292                }
12293
12294                self.unfold_ranges(
12295                    &selections.iter().map(|s| s.range()).collect::<Vec<_>>(),
12296                    false,
12297                    true,
12298                    cx,
12299                );
12300                self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
12301                    s.select(selections);
12302                });
12303            } else if let Some(selected_text) = selected_text {
12304                self.select_prev_state = Some(SelectNextState {
12305                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12306                    wordwise: false,
12307                    done: false,
12308                });
12309                self.select_previous(action, window, cx)?;
12310            }
12311        }
12312        Ok(())
12313    }
12314
12315    pub fn find_next_match(
12316        &mut self,
12317        _: &FindNextMatch,
12318        window: &mut Window,
12319        cx: &mut Context<Self>,
12320    ) -> Result<()> {
12321        let selections = self.selections.disjoint_anchors();
12322        match selections.first() {
12323            Some(first) if selections.len() >= 2 => {
12324                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12325                    s.select_ranges([first.range()]);
12326                });
12327            }
12328            _ => self.select_next(
12329                &SelectNext {
12330                    replace_newest: true,
12331                },
12332                window,
12333                cx,
12334            )?,
12335        }
12336        Ok(())
12337    }
12338
12339    pub fn find_previous_match(
12340        &mut self,
12341        _: &FindPreviousMatch,
12342        window: &mut Window,
12343        cx: &mut Context<Self>,
12344    ) -> Result<()> {
12345        let selections = self.selections.disjoint_anchors();
12346        match selections.last() {
12347            Some(last) if selections.len() >= 2 => {
12348                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12349                    s.select_ranges([last.range()]);
12350                });
12351            }
12352            _ => self.select_previous(
12353                &SelectPrevious {
12354                    replace_newest: true,
12355                },
12356                window,
12357                cx,
12358            )?,
12359        }
12360        Ok(())
12361    }
12362
12363    pub fn toggle_comments(
12364        &mut self,
12365        action: &ToggleComments,
12366        window: &mut Window,
12367        cx: &mut Context<Self>,
12368    ) {
12369        if self.read_only(cx) {
12370            return;
12371        }
12372        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12373        let text_layout_details = &self.text_layout_details(window);
12374        self.transact(window, cx, |this, window, cx| {
12375            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12376            let mut edits = Vec::new();
12377            let mut selection_edit_ranges = Vec::new();
12378            let mut last_toggled_row = None;
12379            let snapshot = this.buffer.read(cx).read(cx);
12380            let empty_str: Arc<str> = Arc::default();
12381            let mut suffixes_inserted = Vec::new();
12382            let ignore_indent = action.ignore_indent;
12383
12384            fn comment_prefix_range(
12385                snapshot: &MultiBufferSnapshot,
12386                row: MultiBufferRow,
12387                comment_prefix: &str,
12388                comment_prefix_whitespace: &str,
12389                ignore_indent: bool,
12390            ) -> Range<Point> {
12391                let indent_size = if ignore_indent {
12392                    0
12393                } else {
12394                    snapshot.indent_size_for_line(row).len
12395                };
12396
12397                let start = Point::new(row.0, indent_size);
12398
12399                let mut line_bytes = snapshot
12400                    .bytes_in_range(start..snapshot.max_point())
12401                    .flatten()
12402                    .copied();
12403
12404                // If this line currently begins with the line comment prefix, then record
12405                // the range containing the prefix.
12406                if line_bytes
12407                    .by_ref()
12408                    .take(comment_prefix.len())
12409                    .eq(comment_prefix.bytes())
12410                {
12411                    // Include any whitespace that matches the comment prefix.
12412                    let matching_whitespace_len = line_bytes
12413                        .zip(comment_prefix_whitespace.bytes())
12414                        .take_while(|(a, b)| a == b)
12415                        .count() as u32;
12416                    let end = Point::new(
12417                        start.row,
12418                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12419                    );
12420                    start..end
12421                } else {
12422                    start..start
12423                }
12424            }
12425
12426            fn comment_suffix_range(
12427                snapshot: &MultiBufferSnapshot,
12428                row: MultiBufferRow,
12429                comment_suffix: &str,
12430                comment_suffix_has_leading_space: bool,
12431            ) -> Range<Point> {
12432                let end = Point::new(row.0, snapshot.line_len(row));
12433                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12434
12435                let mut line_end_bytes = snapshot
12436                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12437                    .flatten()
12438                    .copied();
12439
12440                let leading_space_len = if suffix_start_column > 0
12441                    && line_end_bytes.next() == Some(b' ')
12442                    && comment_suffix_has_leading_space
12443                {
12444                    1
12445                } else {
12446                    0
12447                };
12448
12449                // If this line currently begins with the line comment prefix, then record
12450                // the range containing the prefix.
12451                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12452                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12453                    start..end
12454                } else {
12455                    end..end
12456                }
12457            }
12458
12459            // TODO: Handle selections that cross excerpts
12460            for selection in &mut selections {
12461                let start_column = snapshot
12462                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12463                    .len;
12464                let language = if let Some(language) =
12465                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12466                {
12467                    language
12468                } else {
12469                    continue;
12470                };
12471
12472                selection_edit_ranges.clear();
12473
12474                // If multiple selections contain a given row, avoid processing that
12475                // row more than once.
12476                let mut start_row = MultiBufferRow(selection.start.row);
12477                if last_toggled_row == Some(start_row) {
12478                    start_row = start_row.next_row();
12479                }
12480                let end_row =
12481                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12482                        MultiBufferRow(selection.end.row - 1)
12483                    } else {
12484                        MultiBufferRow(selection.end.row)
12485                    };
12486                last_toggled_row = Some(end_row);
12487
12488                if start_row > end_row {
12489                    continue;
12490                }
12491
12492                // If the language has line comments, toggle those.
12493                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12494
12495                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12496                if ignore_indent {
12497                    full_comment_prefixes = full_comment_prefixes
12498                        .into_iter()
12499                        .map(|s| Arc::from(s.trim_end()))
12500                        .collect();
12501                }
12502
12503                if !full_comment_prefixes.is_empty() {
12504                    let first_prefix = full_comment_prefixes
12505                        .first()
12506                        .expect("prefixes is non-empty");
12507                    let prefix_trimmed_lengths = full_comment_prefixes
12508                        .iter()
12509                        .map(|p| p.trim_end_matches(' ').len())
12510                        .collect::<SmallVec<[usize; 4]>>();
12511
12512                    let mut all_selection_lines_are_comments = true;
12513
12514                    for row in start_row.0..=end_row.0 {
12515                        let row = MultiBufferRow(row);
12516                        if start_row < end_row && snapshot.is_line_blank(row) {
12517                            continue;
12518                        }
12519
12520                        let prefix_range = full_comment_prefixes
12521                            .iter()
12522                            .zip(prefix_trimmed_lengths.iter().copied())
12523                            .map(|(prefix, trimmed_prefix_len)| {
12524                                comment_prefix_range(
12525                                    snapshot.deref(),
12526                                    row,
12527                                    &prefix[..trimmed_prefix_len],
12528                                    &prefix[trimmed_prefix_len..],
12529                                    ignore_indent,
12530                                )
12531                            })
12532                            .max_by_key(|range| range.end.column - range.start.column)
12533                            .expect("prefixes is non-empty");
12534
12535                        if prefix_range.is_empty() {
12536                            all_selection_lines_are_comments = false;
12537                        }
12538
12539                        selection_edit_ranges.push(prefix_range);
12540                    }
12541
12542                    if all_selection_lines_are_comments {
12543                        edits.extend(
12544                            selection_edit_ranges
12545                                .iter()
12546                                .cloned()
12547                                .map(|range| (range, empty_str.clone())),
12548                        );
12549                    } else {
12550                        let min_column = selection_edit_ranges
12551                            .iter()
12552                            .map(|range| range.start.column)
12553                            .min()
12554                            .unwrap_or(0);
12555                        edits.extend(selection_edit_ranges.iter().map(|range| {
12556                            let position = Point::new(range.start.row, min_column);
12557                            (position..position, first_prefix.clone())
12558                        }));
12559                    }
12560                } else if let Some((full_comment_prefix, comment_suffix)) =
12561                    language.block_comment_delimiters()
12562                {
12563                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
12564                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
12565                    let prefix_range = comment_prefix_range(
12566                        snapshot.deref(),
12567                        start_row,
12568                        comment_prefix,
12569                        comment_prefix_whitespace,
12570                        ignore_indent,
12571                    );
12572                    let suffix_range = comment_suffix_range(
12573                        snapshot.deref(),
12574                        end_row,
12575                        comment_suffix.trim_start_matches(' '),
12576                        comment_suffix.starts_with(' '),
12577                    );
12578
12579                    if prefix_range.is_empty() || suffix_range.is_empty() {
12580                        edits.push((
12581                            prefix_range.start..prefix_range.start,
12582                            full_comment_prefix.clone(),
12583                        ));
12584                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
12585                        suffixes_inserted.push((end_row, comment_suffix.len()));
12586                    } else {
12587                        edits.push((prefix_range, empty_str.clone()));
12588                        edits.push((suffix_range, empty_str.clone()));
12589                    }
12590                } else {
12591                    continue;
12592                }
12593            }
12594
12595            drop(snapshot);
12596            this.buffer.update(cx, |buffer, cx| {
12597                buffer.edit(edits, None, cx);
12598            });
12599
12600            // Adjust selections so that they end before any comment suffixes that
12601            // were inserted.
12602            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
12603            let mut selections = this.selections.all::<Point>(cx);
12604            let snapshot = this.buffer.read(cx).read(cx);
12605            for selection in &mut selections {
12606                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
12607                    match row.cmp(&MultiBufferRow(selection.end.row)) {
12608                        Ordering::Less => {
12609                            suffixes_inserted.next();
12610                            continue;
12611                        }
12612                        Ordering::Greater => break,
12613                        Ordering::Equal => {
12614                            if selection.end.column == snapshot.line_len(row) {
12615                                if selection.is_empty() {
12616                                    selection.start.column -= suffix_len as u32;
12617                                }
12618                                selection.end.column -= suffix_len as u32;
12619                            }
12620                            break;
12621                        }
12622                    }
12623                }
12624            }
12625
12626            drop(snapshot);
12627            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12628                s.select(selections)
12629            });
12630
12631            let selections = this.selections.all::<Point>(cx);
12632            let selections_on_single_row = selections.windows(2).all(|selections| {
12633                selections[0].start.row == selections[1].start.row
12634                    && selections[0].end.row == selections[1].end.row
12635                    && selections[0].start.row == selections[0].end.row
12636            });
12637            let selections_selecting = selections
12638                .iter()
12639                .any(|selection| selection.start != selection.end);
12640            let advance_downwards = action.advance_downwards
12641                && selections_on_single_row
12642                && !selections_selecting
12643                && !matches!(this.mode, EditorMode::SingleLine { .. });
12644
12645            if advance_downwards {
12646                let snapshot = this.buffer.read(cx).snapshot(cx);
12647
12648                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12649                    s.move_cursors_with(|display_snapshot, display_point, _| {
12650                        let mut point = display_point.to_point(display_snapshot);
12651                        point.row += 1;
12652                        point = snapshot.clip_point(point, Bias::Left);
12653                        let display_point = point.to_display_point(display_snapshot);
12654                        let goal = SelectionGoal::HorizontalPosition(
12655                            display_snapshot
12656                                .x_for_display_point(display_point, text_layout_details)
12657                                .into(),
12658                        );
12659                        (display_point, goal)
12660                    })
12661                });
12662            }
12663        });
12664    }
12665
12666    pub fn select_enclosing_symbol(
12667        &mut self,
12668        _: &SelectEnclosingSymbol,
12669        window: &mut Window,
12670        cx: &mut Context<Self>,
12671    ) {
12672        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12673
12674        let buffer = self.buffer.read(cx).snapshot(cx);
12675        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
12676
12677        fn update_selection(
12678            selection: &Selection<usize>,
12679            buffer_snap: &MultiBufferSnapshot,
12680        ) -> Option<Selection<usize>> {
12681            let cursor = selection.head();
12682            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
12683            for symbol in symbols.iter().rev() {
12684                let start = symbol.range.start.to_offset(buffer_snap);
12685                let end = symbol.range.end.to_offset(buffer_snap);
12686                let new_range = start..end;
12687                if start < selection.start || end > selection.end {
12688                    return Some(Selection {
12689                        id: selection.id,
12690                        start: new_range.start,
12691                        end: new_range.end,
12692                        goal: SelectionGoal::None,
12693                        reversed: selection.reversed,
12694                    });
12695                }
12696            }
12697            None
12698        }
12699
12700        let mut selected_larger_symbol = false;
12701        let new_selections = old_selections
12702            .iter()
12703            .map(|selection| match update_selection(selection, &buffer) {
12704                Some(new_selection) => {
12705                    if new_selection.range() != selection.range() {
12706                        selected_larger_symbol = true;
12707                    }
12708                    new_selection
12709                }
12710                None => selection.clone(),
12711            })
12712            .collect::<Vec<_>>();
12713
12714        if selected_larger_symbol {
12715            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12716                s.select(new_selections);
12717            });
12718        }
12719    }
12720
12721    pub fn select_larger_syntax_node(
12722        &mut self,
12723        _: &SelectLargerSyntaxNode,
12724        window: &mut Window,
12725        cx: &mut Context<Self>,
12726    ) {
12727        let Some(visible_row_count) = self.visible_row_count() else {
12728            return;
12729        };
12730        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
12731        if old_selections.is_empty() {
12732            return;
12733        }
12734
12735        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12736
12737        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12738        let buffer = self.buffer.read(cx).snapshot(cx);
12739
12740        let mut selected_larger_node = false;
12741        let mut new_selections = old_selections
12742            .iter()
12743            .map(|selection| {
12744                let old_range = selection.start..selection.end;
12745
12746                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
12747                    // manually select word at selection
12748                    if ["string_content", "inline"].contains(&node.kind()) {
12749                        let word_range = {
12750                            let display_point = buffer
12751                                .offset_to_point(old_range.start)
12752                                .to_display_point(&display_map);
12753                            let Range { start, end } =
12754                                movement::surrounding_word(&display_map, display_point);
12755                            start.to_point(&display_map).to_offset(&buffer)
12756                                ..end.to_point(&display_map).to_offset(&buffer)
12757                        };
12758                        // ignore if word is already selected
12759                        if !word_range.is_empty() && old_range != word_range {
12760                            let last_word_range = {
12761                                let display_point = buffer
12762                                    .offset_to_point(old_range.end)
12763                                    .to_display_point(&display_map);
12764                                let Range { start, end } =
12765                                    movement::surrounding_word(&display_map, display_point);
12766                                start.to_point(&display_map).to_offset(&buffer)
12767                                    ..end.to_point(&display_map).to_offset(&buffer)
12768                            };
12769                            // only select word if start and end point belongs to same word
12770                            if word_range == last_word_range {
12771                                selected_larger_node = true;
12772                                return Selection {
12773                                    id: selection.id,
12774                                    start: word_range.start,
12775                                    end: word_range.end,
12776                                    goal: SelectionGoal::None,
12777                                    reversed: selection.reversed,
12778                                };
12779                            }
12780                        }
12781                    }
12782                }
12783
12784                let mut new_range = old_range.clone();
12785                let mut new_node = None;
12786                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
12787                {
12788                    new_node = Some(node);
12789                    new_range = match containing_range {
12790                        MultiOrSingleBufferOffsetRange::Single(_) => break,
12791                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
12792                    };
12793                    if !display_map.intersects_fold(new_range.start)
12794                        && !display_map.intersects_fold(new_range.end)
12795                    {
12796                        break;
12797                    }
12798                }
12799
12800                if let Some(node) = new_node {
12801                    // Log the ancestor, to support using this action as a way to explore TreeSitter
12802                    // nodes. Parent and grandparent are also logged because this operation will not
12803                    // visit nodes that have the same range as their parent.
12804                    log::info!("Node: {node:?}");
12805                    let parent = node.parent();
12806                    log::info!("Parent: {parent:?}");
12807                    let grandparent = parent.and_then(|x| x.parent());
12808                    log::info!("Grandparent: {grandparent:?}");
12809                }
12810
12811                selected_larger_node |= new_range != old_range;
12812                Selection {
12813                    id: selection.id,
12814                    start: new_range.start,
12815                    end: new_range.end,
12816                    goal: SelectionGoal::None,
12817                    reversed: selection.reversed,
12818                }
12819            })
12820            .collect::<Vec<_>>();
12821
12822        if !selected_larger_node {
12823            return; // don't put this call in the history
12824        }
12825
12826        // scroll based on transformation done to the last selection created by the user
12827        let (last_old, last_new) = old_selections
12828            .last()
12829            .zip(new_selections.last().cloned())
12830            .expect("old_selections isn't empty");
12831
12832        // revert selection
12833        let is_selection_reversed = {
12834            let should_newest_selection_be_reversed = last_old.start != last_new.start;
12835            new_selections.last_mut().expect("checked above").reversed =
12836                should_newest_selection_be_reversed;
12837            should_newest_selection_be_reversed
12838        };
12839
12840        if selected_larger_node {
12841            self.select_syntax_node_history.disable_clearing = true;
12842            self.change_selections(None, window, cx, |s| {
12843                s.select(new_selections.clone());
12844            });
12845            self.select_syntax_node_history.disable_clearing = false;
12846        }
12847
12848        let start_row = last_new.start.to_display_point(&display_map).row().0;
12849        let end_row = last_new.end.to_display_point(&display_map).row().0;
12850        let selection_height = end_row - start_row + 1;
12851        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
12852
12853        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
12854        let scroll_behavior = if fits_on_the_screen {
12855            self.request_autoscroll(Autoscroll::fit(), cx);
12856            SelectSyntaxNodeScrollBehavior::FitSelection
12857        } else if is_selection_reversed {
12858            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
12859            SelectSyntaxNodeScrollBehavior::CursorTop
12860        } else {
12861            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
12862            SelectSyntaxNodeScrollBehavior::CursorBottom
12863        };
12864
12865        self.select_syntax_node_history.push((
12866            old_selections,
12867            scroll_behavior,
12868            is_selection_reversed,
12869        ));
12870    }
12871
12872    pub fn select_smaller_syntax_node(
12873        &mut self,
12874        _: &SelectSmallerSyntaxNode,
12875        window: &mut Window,
12876        cx: &mut Context<Self>,
12877    ) {
12878        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12879
12880        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
12881            self.select_syntax_node_history.pop()
12882        {
12883            if let Some(selection) = selections.last_mut() {
12884                selection.reversed = is_selection_reversed;
12885            }
12886
12887            self.select_syntax_node_history.disable_clearing = true;
12888            self.change_selections(None, window, cx, |s| {
12889                s.select(selections.to_vec());
12890            });
12891            self.select_syntax_node_history.disable_clearing = false;
12892
12893            match scroll_behavior {
12894                SelectSyntaxNodeScrollBehavior::CursorTop => {
12895                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
12896                }
12897                SelectSyntaxNodeScrollBehavior::FitSelection => {
12898                    self.request_autoscroll(Autoscroll::fit(), cx);
12899                }
12900                SelectSyntaxNodeScrollBehavior::CursorBottom => {
12901                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
12902                }
12903            }
12904        }
12905    }
12906
12907    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
12908        if !EditorSettings::get_global(cx).gutter.runnables {
12909            self.clear_tasks();
12910            return Task::ready(());
12911        }
12912        let project = self.project.as_ref().map(Entity::downgrade);
12913        let task_sources = self.lsp_task_sources(cx);
12914        cx.spawn_in(window, async move |editor, cx| {
12915            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
12916            let Some(project) = project.and_then(|p| p.upgrade()) else {
12917                return;
12918            };
12919            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
12920                this.display_map.update(cx, |map, cx| map.snapshot(cx))
12921            }) else {
12922                return;
12923            };
12924
12925            let hide_runnables = project
12926                .update(cx, |project, cx| {
12927                    // Do not display any test indicators in non-dev server remote projects.
12928                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
12929                })
12930                .unwrap_or(true);
12931            if hide_runnables {
12932                return;
12933            }
12934            let new_rows =
12935                cx.background_spawn({
12936                    let snapshot = display_snapshot.clone();
12937                    async move {
12938                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
12939                    }
12940                })
12941                    .await;
12942            let Ok(lsp_tasks) =
12943                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
12944            else {
12945                return;
12946            };
12947            let lsp_tasks = lsp_tasks.await;
12948
12949            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
12950                lsp_tasks
12951                    .into_iter()
12952                    .flat_map(|(kind, tasks)| {
12953                        tasks.into_iter().filter_map(move |(location, task)| {
12954                            Some((kind.clone(), location?, task))
12955                        })
12956                    })
12957                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
12958                        let buffer = location.target.buffer;
12959                        let buffer_snapshot = buffer.read(cx).snapshot();
12960                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
12961                            |(excerpt_id, snapshot, _)| {
12962                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
12963                                    display_snapshot
12964                                        .buffer_snapshot
12965                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
12966                                } else {
12967                                    None
12968                                }
12969                            },
12970                        );
12971                        if let Some(offset) = offset {
12972                            let task_buffer_range =
12973                                location.target.range.to_point(&buffer_snapshot);
12974                            let context_buffer_range =
12975                                task_buffer_range.to_offset(&buffer_snapshot);
12976                            let context_range = BufferOffset(context_buffer_range.start)
12977                                ..BufferOffset(context_buffer_range.end);
12978
12979                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
12980                                .or_insert_with(|| RunnableTasks {
12981                                    templates: Vec::new(),
12982                                    offset,
12983                                    column: task_buffer_range.start.column,
12984                                    extra_variables: HashMap::default(),
12985                                    context_range,
12986                                })
12987                                .templates
12988                                .push((kind, task.original_task().clone()));
12989                        }
12990
12991                        acc
12992                    })
12993            }) else {
12994                return;
12995            };
12996
12997            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
12998            editor
12999                .update(cx, |editor, _| {
13000                    editor.clear_tasks();
13001                    for (key, mut value) in rows {
13002                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13003                            value.templates.extend(lsp_tasks.templates);
13004                        }
13005
13006                        editor.insert_tasks(key, value);
13007                    }
13008                    for (key, value) in lsp_tasks_by_rows {
13009                        editor.insert_tasks(key, value);
13010                    }
13011                })
13012                .ok();
13013        })
13014    }
13015    fn fetch_runnable_ranges(
13016        snapshot: &DisplaySnapshot,
13017        range: Range<Anchor>,
13018    ) -> Vec<language::RunnableRange> {
13019        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13020    }
13021
13022    fn runnable_rows(
13023        project: Entity<Project>,
13024        snapshot: DisplaySnapshot,
13025        runnable_ranges: Vec<RunnableRange>,
13026        mut cx: AsyncWindowContext,
13027    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13028        runnable_ranges
13029            .into_iter()
13030            .filter_map(|mut runnable| {
13031                let tasks = cx
13032                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13033                    .ok()?;
13034                if tasks.is_empty() {
13035                    return None;
13036                }
13037
13038                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13039
13040                let row = snapshot
13041                    .buffer_snapshot
13042                    .buffer_line_for_row(MultiBufferRow(point.row))?
13043                    .1
13044                    .start
13045                    .row;
13046
13047                let context_range =
13048                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13049                Some((
13050                    (runnable.buffer_id, row),
13051                    RunnableTasks {
13052                        templates: tasks,
13053                        offset: snapshot
13054                            .buffer_snapshot
13055                            .anchor_before(runnable.run_range.start),
13056                        context_range,
13057                        column: point.column,
13058                        extra_variables: runnable.extra_captures,
13059                    },
13060                ))
13061            })
13062            .collect()
13063    }
13064
13065    fn templates_with_tags(
13066        project: &Entity<Project>,
13067        runnable: &mut Runnable,
13068        cx: &mut App,
13069    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13070        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13071            let (worktree_id, file) = project
13072                .buffer_for_id(runnable.buffer, cx)
13073                .and_then(|buffer| buffer.read(cx).file())
13074                .map(|file| (file.worktree_id(cx), file.clone()))
13075                .unzip();
13076
13077            (
13078                project.task_store().read(cx).task_inventory().cloned(),
13079                worktree_id,
13080                file,
13081            )
13082        });
13083
13084        let mut templates_with_tags = mem::take(&mut runnable.tags)
13085            .into_iter()
13086            .flat_map(|RunnableTag(tag)| {
13087                inventory
13088                    .as_ref()
13089                    .into_iter()
13090                    .flat_map(|inventory| {
13091                        inventory.read(cx).list_tasks(
13092                            file.clone(),
13093                            Some(runnable.language.clone()),
13094                            worktree_id,
13095                            cx,
13096                        )
13097                    })
13098                    .filter(move |(_, template)| {
13099                        template.tags.iter().any(|source_tag| source_tag == &tag)
13100                    })
13101            })
13102            .sorted_by_key(|(kind, _)| kind.to_owned())
13103            .collect::<Vec<_>>();
13104        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13105            // Strongest source wins; if we have worktree tag binding, prefer that to
13106            // global and language bindings;
13107            // if we have a global binding, prefer that to language binding.
13108            let first_mismatch = templates_with_tags
13109                .iter()
13110                .position(|(tag_source, _)| tag_source != leading_tag_source);
13111            if let Some(index) = first_mismatch {
13112                templates_with_tags.truncate(index);
13113            }
13114        }
13115
13116        templates_with_tags
13117    }
13118
13119    pub fn move_to_enclosing_bracket(
13120        &mut self,
13121        _: &MoveToEnclosingBracket,
13122        window: &mut Window,
13123        cx: &mut Context<Self>,
13124    ) {
13125        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13126        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13127            s.move_offsets_with(|snapshot, selection| {
13128                let Some(enclosing_bracket_ranges) =
13129                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13130                else {
13131                    return;
13132                };
13133
13134                let mut best_length = usize::MAX;
13135                let mut best_inside = false;
13136                let mut best_in_bracket_range = false;
13137                let mut best_destination = None;
13138                for (open, close) in enclosing_bracket_ranges {
13139                    let close = close.to_inclusive();
13140                    let length = close.end() - open.start;
13141                    let inside = selection.start >= open.end && selection.end <= *close.start();
13142                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13143                        || close.contains(&selection.head());
13144
13145                    // If best is next to a bracket and current isn't, skip
13146                    if !in_bracket_range && best_in_bracket_range {
13147                        continue;
13148                    }
13149
13150                    // Prefer smaller lengths unless best is inside and current isn't
13151                    if length > best_length && (best_inside || !inside) {
13152                        continue;
13153                    }
13154
13155                    best_length = length;
13156                    best_inside = inside;
13157                    best_in_bracket_range = in_bracket_range;
13158                    best_destination = Some(
13159                        if close.contains(&selection.start) && close.contains(&selection.end) {
13160                            if inside { open.end } else { open.start }
13161                        } else if inside {
13162                            *close.start()
13163                        } else {
13164                            *close.end()
13165                        },
13166                    );
13167                }
13168
13169                if let Some(destination) = best_destination {
13170                    selection.collapse_to(destination, SelectionGoal::None);
13171                }
13172            })
13173        });
13174    }
13175
13176    pub fn undo_selection(
13177        &mut self,
13178        _: &UndoSelection,
13179        window: &mut Window,
13180        cx: &mut Context<Self>,
13181    ) {
13182        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13183        self.end_selection(window, cx);
13184        self.selection_history.mode = SelectionHistoryMode::Undoing;
13185        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13186            self.change_selections(None, window, cx, |s| {
13187                s.select_anchors(entry.selections.to_vec())
13188            });
13189            self.select_next_state = entry.select_next_state;
13190            self.select_prev_state = entry.select_prev_state;
13191            self.add_selections_state = entry.add_selections_state;
13192            self.request_autoscroll(Autoscroll::newest(), cx);
13193        }
13194        self.selection_history.mode = SelectionHistoryMode::Normal;
13195    }
13196
13197    pub fn redo_selection(
13198        &mut self,
13199        _: &RedoSelection,
13200        window: &mut Window,
13201        cx: &mut Context<Self>,
13202    ) {
13203        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13204        self.end_selection(window, cx);
13205        self.selection_history.mode = SelectionHistoryMode::Redoing;
13206        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13207            self.change_selections(None, window, cx, |s| {
13208                s.select_anchors(entry.selections.to_vec())
13209            });
13210            self.select_next_state = entry.select_next_state;
13211            self.select_prev_state = entry.select_prev_state;
13212            self.add_selections_state = entry.add_selections_state;
13213            self.request_autoscroll(Autoscroll::newest(), cx);
13214        }
13215        self.selection_history.mode = SelectionHistoryMode::Normal;
13216    }
13217
13218    pub fn expand_excerpts(
13219        &mut self,
13220        action: &ExpandExcerpts,
13221        _: &mut Window,
13222        cx: &mut Context<Self>,
13223    ) {
13224        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13225    }
13226
13227    pub fn expand_excerpts_down(
13228        &mut self,
13229        action: &ExpandExcerptsDown,
13230        _: &mut Window,
13231        cx: &mut Context<Self>,
13232    ) {
13233        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13234    }
13235
13236    pub fn expand_excerpts_up(
13237        &mut self,
13238        action: &ExpandExcerptsUp,
13239        _: &mut Window,
13240        cx: &mut Context<Self>,
13241    ) {
13242        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13243    }
13244
13245    pub fn expand_excerpts_for_direction(
13246        &mut self,
13247        lines: u32,
13248        direction: ExpandExcerptDirection,
13249
13250        cx: &mut Context<Self>,
13251    ) {
13252        let selections = self.selections.disjoint_anchors();
13253
13254        let lines = if lines == 0 {
13255            EditorSettings::get_global(cx).expand_excerpt_lines
13256        } else {
13257            lines
13258        };
13259
13260        self.buffer.update(cx, |buffer, cx| {
13261            let snapshot = buffer.snapshot(cx);
13262            let mut excerpt_ids = selections
13263                .iter()
13264                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13265                .collect::<Vec<_>>();
13266            excerpt_ids.sort();
13267            excerpt_ids.dedup();
13268            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13269        })
13270    }
13271
13272    pub fn expand_excerpt(
13273        &mut self,
13274        excerpt: ExcerptId,
13275        direction: ExpandExcerptDirection,
13276        window: &mut Window,
13277        cx: &mut Context<Self>,
13278    ) {
13279        let current_scroll_position = self.scroll_position(cx);
13280        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13281        let mut should_scroll_up = false;
13282
13283        if direction == ExpandExcerptDirection::Down {
13284            let multi_buffer = self.buffer.read(cx);
13285            let snapshot = multi_buffer.snapshot(cx);
13286            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13287                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13288                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13289                        let buffer_snapshot = buffer.read(cx).snapshot();
13290                        let excerpt_end_row =
13291                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13292                        let last_row = buffer_snapshot.max_point().row;
13293                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13294                        should_scroll_up = lines_below >= lines_to_expand;
13295                    }
13296                }
13297            }
13298        }
13299
13300        self.buffer.update(cx, |buffer, cx| {
13301            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13302        });
13303
13304        if should_scroll_up {
13305            let new_scroll_position =
13306                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13307            self.set_scroll_position(new_scroll_position, window, cx);
13308        }
13309    }
13310
13311    pub fn go_to_singleton_buffer_point(
13312        &mut self,
13313        point: Point,
13314        window: &mut Window,
13315        cx: &mut Context<Self>,
13316    ) {
13317        self.go_to_singleton_buffer_range(point..point, window, cx);
13318    }
13319
13320    pub fn go_to_singleton_buffer_range(
13321        &mut self,
13322        range: Range<Point>,
13323        window: &mut Window,
13324        cx: &mut Context<Self>,
13325    ) {
13326        let multibuffer = self.buffer().read(cx);
13327        let Some(buffer) = multibuffer.as_singleton() else {
13328            return;
13329        };
13330        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13331            return;
13332        };
13333        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13334            return;
13335        };
13336        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13337            s.select_anchor_ranges([start..end])
13338        });
13339    }
13340
13341    pub fn go_to_diagnostic(
13342        &mut self,
13343        _: &GoToDiagnostic,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) {
13347        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13348        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13349    }
13350
13351    pub fn go_to_prev_diagnostic(
13352        &mut self,
13353        _: &GoToPreviousDiagnostic,
13354        window: &mut Window,
13355        cx: &mut Context<Self>,
13356    ) {
13357        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13358        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13359    }
13360
13361    pub fn go_to_diagnostic_impl(
13362        &mut self,
13363        direction: Direction,
13364        window: &mut Window,
13365        cx: &mut Context<Self>,
13366    ) {
13367        let buffer = self.buffer.read(cx).snapshot(cx);
13368        let selection = self.selections.newest::<usize>(cx);
13369
13370        let mut active_group_id = None;
13371        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13372            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13373                active_group_id = Some(active_group.group_id);
13374            }
13375        }
13376
13377        fn filtered(
13378            snapshot: EditorSnapshot,
13379            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13380        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13381            diagnostics
13382                .filter(|entry| entry.range.start != entry.range.end)
13383                .filter(|entry| !entry.diagnostic.is_unnecessary)
13384                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13385        }
13386
13387        let snapshot = self.snapshot(window, cx);
13388        let before = filtered(
13389            snapshot.clone(),
13390            buffer
13391                .diagnostics_in_range(0..selection.start)
13392                .filter(|entry| entry.range.start <= selection.start),
13393        );
13394        let after = filtered(
13395            snapshot,
13396            buffer
13397                .diagnostics_in_range(selection.start..buffer.len())
13398                .filter(|entry| entry.range.start >= selection.start),
13399        );
13400
13401        let mut found: Option<DiagnosticEntry<usize>> = None;
13402        if direction == Direction::Prev {
13403            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13404            {
13405                for diagnostic in prev_diagnostics.into_iter().rev() {
13406                    if diagnostic.range.start != selection.start
13407                        || active_group_id
13408                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13409                    {
13410                        found = Some(diagnostic);
13411                        break 'outer;
13412                    }
13413                }
13414            }
13415        } else {
13416            for diagnostic in after.chain(before) {
13417                if diagnostic.range.start != selection.start
13418                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13419                {
13420                    found = Some(diagnostic);
13421                    break;
13422                }
13423            }
13424        }
13425        let Some(next_diagnostic) = found else {
13426            return;
13427        };
13428
13429        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13430            return;
13431        };
13432        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13433            s.select_ranges(vec![
13434                next_diagnostic.range.start..next_diagnostic.range.start,
13435            ])
13436        });
13437        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13438        self.refresh_inline_completion(false, true, window, cx);
13439    }
13440
13441    fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13442        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13443        let snapshot = self.snapshot(window, cx);
13444        let selection = self.selections.newest::<Point>(cx);
13445        self.go_to_hunk_before_or_after_position(
13446            &snapshot,
13447            selection.head(),
13448            Direction::Next,
13449            window,
13450            cx,
13451        );
13452    }
13453
13454    pub fn go_to_hunk_before_or_after_position(
13455        &mut self,
13456        snapshot: &EditorSnapshot,
13457        position: Point,
13458        direction: Direction,
13459        window: &mut Window,
13460        cx: &mut Context<Editor>,
13461    ) {
13462        let row = if direction == Direction::Next {
13463            self.hunk_after_position(snapshot, position)
13464                .map(|hunk| hunk.row_range.start)
13465        } else {
13466            self.hunk_before_position(snapshot, position)
13467        };
13468
13469        if let Some(row) = row {
13470            let destination = Point::new(row.0, 0);
13471            let autoscroll = Autoscroll::center();
13472
13473            self.unfold_ranges(&[destination..destination], false, false, cx);
13474            self.change_selections(Some(autoscroll), window, cx, |s| {
13475                s.select_ranges([destination..destination]);
13476            });
13477        }
13478    }
13479
13480    fn hunk_after_position(
13481        &mut self,
13482        snapshot: &EditorSnapshot,
13483        position: Point,
13484    ) -> Option<MultiBufferDiffHunk> {
13485        snapshot
13486            .buffer_snapshot
13487            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13488            .find(|hunk| hunk.row_range.start.0 > position.row)
13489            .or_else(|| {
13490                snapshot
13491                    .buffer_snapshot
13492                    .diff_hunks_in_range(Point::zero()..position)
13493                    .find(|hunk| hunk.row_range.end.0 < position.row)
13494            })
13495    }
13496
13497    fn go_to_prev_hunk(
13498        &mut self,
13499        _: &GoToPreviousHunk,
13500        window: &mut Window,
13501        cx: &mut Context<Self>,
13502    ) {
13503        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13504        let snapshot = self.snapshot(window, cx);
13505        let selection = self.selections.newest::<Point>(cx);
13506        self.go_to_hunk_before_or_after_position(
13507            &snapshot,
13508            selection.head(),
13509            Direction::Prev,
13510            window,
13511            cx,
13512        );
13513    }
13514
13515    fn hunk_before_position(
13516        &mut self,
13517        snapshot: &EditorSnapshot,
13518        position: Point,
13519    ) -> Option<MultiBufferRow> {
13520        snapshot
13521            .buffer_snapshot
13522            .diff_hunk_before(position)
13523            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
13524    }
13525
13526    fn go_to_next_change(
13527        &mut self,
13528        _: &GoToNextChange,
13529        window: &mut Window,
13530        cx: &mut Context<Self>,
13531    ) {
13532        if let Some(selections) = self
13533            .change_list
13534            .next_change(1, Direction::Next)
13535            .map(|s| s.to_vec())
13536        {
13537            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13538                let map = s.display_map();
13539                s.select_display_ranges(selections.iter().map(|a| {
13540                    let point = a.to_display_point(&map);
13541                    point..point
13542                }))
13543            })
13544        }
13545    }
13546
13547    fn go_to_previous_change(
13548        &mut self,
13549        _: &GoToPreviousChange,
13550        window: &mut Window,
13551        cx: &mut Context<Self>,
13552    ) {
13553        if let Some(selections) = self
13554            .change_list
13555            .next_change(1, Direction::Prev)
13556            .map(|s| s.to_vec())
13557        {
13558            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13559                let map = s.display_map();
13560                s.select_display_ranges(selections.iter().map(|a| {
13561                    let point = a.to_display_point(&map);
13562                    point..point
13563                }))
13564            })
13565        }
13566    }
13567
13568    fn go_to_line<T: 'static>(
13569        &mut self,
13570        position: Anchor,
13571        highlight_color: Option<Hsla>,
13572        window: &mut Window,
13573        cx: &mut Context<Self>,
13574    ) {
13575        let snapshot = self.snapshot(window, cx).display_snapshot;
13576        let position = position.to_point(&snapshot.buffer_snapshot);
13577        let start = snapshot
13578            .buffer_snapshot
13579            .clip_point(Point::new(position.row, 0), Bias::Left);
13580        let end = start + Point::new(1, 0);
13581        let start = snapshot.buffer_snapshot.anchor_before(start);
13582        let end = snapshot.buffer_snapshot.anchor_before(end);
13583
13584        self.highlight_rows::<T>(
13585            start..end,
13586            highlight_color
13587                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
13588            Default::default(),
13589            cx,
13590        );
13591        self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
13592    }
13593
13594    pub fn go_to_definition(
13595        &mut self,
13596        _: &GoToDefinition,
13597        window: &mut Window,
13598        cx: &mut Context<Self>,
13599    ) -> Task<Result<Navigated>> {
13600        let definition =
13601            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
13602        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
13603        cx.spawn_in(window, async move |editor, cx| {
13604            if definition.await? == Navigated::Yes {
13605                return Ok(Navigated::Yes);
13606            }
13607            match fallback_strategy {
13608                GoToDefinitionFallback::None => Ok(Navigated::No),
13609                GoToDefinitionFallback::FindAllReferences => {
13610                    match editor.update_in(cx, |editor, window, cx| {
13611                        editor.find_all_references(&FindAllReferences, window, cx)
13612                    })? {
13613                        Some(references) => references.await,
13614                        None => Ok(Navigated::No),
13615                    }
13616                }
13617            }
13618        })
13619    }
13620
13621    pub fn go_to_declaration(
13622        &mut self,
13623        _: &GoToDeclaration,
13624        window: &mut Window,
13625        cx: &mut Context<Self>,
13626    ) -> Task<Result<Navigated>> {
13627        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
13628    }
13629
13630    pub fn go_to_declaration_split(
13631        &mut self,
13632        _: &GoToDeclaration,
13633        window: &mut Window,
13634        cx: &mut Context<Self>,
13635    ) -> Task<Result<Navigated>> {
13636        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
13637    }
13638
13639    pub fn go_to_implementation(
13640        &mut self,
13641        _: &GoToImplementation,
13642        window: &mut Window,
13643        cx: &mut Context<Self>,
13644    ) -> Task<Result<Navigated>> {
13645        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
13646    }
13647
13648    pub fn go_to_implementation_split(
13649        &mut self,
13650        _: &GoToImplementationSplit,
13651        window: &mut Window,
13652        cx: &mut Context<Self>,
13653    ) -> Task<Result<Navigated>> {
13654        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
13655    }
13656
13657    pub fn go_to_type_definition(
13658        &mut self,
13659        _: &GoToTypeDefinition,
13660        window: &mut Window,
13661        cx: &mut Context<Self>,
13662    ) -> Task<Result<Navigated>> {
13663        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
13664    }
13665
13666    pub fn go_to_definition_split(
13667        &mut self,
13668        _: &GoToDefinitionSplit,
13669        window: &mut Window,
13670        cx: &mut Context<Self>,
13671    ) -> Task<Result<Navigated>> {
13672        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
13673    }
13674
13675    pub fn go_to_type_definition_split(
13676        &mut self,
13677        _: &GoToTypeDefinitionSplit,
13678        window: &mut Window,
13679        cx: &mut Context<Self>,
13680    ) -> Task<Result<Navigated>> {
13681        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
13682    }
13683
13684    fn go_to_definition_of_kind(
13685        &mut self,
13686        kind: GotoDefinitionKind,
13687        split: bool,
13688        window: &mut Window,
13689        cx: &mut Context<Self>,
13690    ) -> Task<Result<Navigated>> {
13691        let Some(provider) = self.semantics_provider.clone() else {
13692            return Task::ready(Ok(Navigated::No));
13693        };
13694        let head = self.selections.newest::<usize>(cx).head();
13695        let buffer = self.buffer.read(cx);
13696        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
13697            text_anchor
13698        } else {
13699            return Task::ready(Ok(Navigated::No));
13700        };
13701
13702        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
13703            return Task::ready(Ok(Navigated::No));
13704        };
13705
13706        cx.spawn_in(window, async move |editor, cx| {
13707            let definitions = definitions.await?;
13708            let navigated = editor
13709                .update_in(cx, |editor, window, cx| {
13710                    editor.navigate_to_hover_links(
13711                        Some(kind),
13712                        definitions
13713                            .into_iter()
13714                            .filter(|location| {
13715                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
13716                            })
13717                            .map(HoverLink::Text)
13718                            .collect::<Vec<_>>(),
13719                        split,
13720                        window,
13721                        cx,
13722                    )
13723                })?
13724                .await?;
13725            anyhow::Ok(navigated)
13726        })
13727    }
13728
13729    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
13730        let selection = self.selections.newest_anchor();
13731        let head = selection.head();
13732        let tail = selection.tail();
13733
13734        let Some((buffer, start_position)) =
13735            self.buffer.read(cx).text_anchor_for_position(head, cx)
13736        else {
13737            return;
13738        };
13739
13740        let end_position = if head != tail {
13741            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
13742                return;
13743            };
13744            Some(pos)
13745        } else {
13746            None
13747        };
13748
13749        let url_finder = cx.spawn_in(window, async move |editor, cx| {
13750            let url = if let Some(end_pos) = end_position {
13751                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
13752            } else {
13753                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
13754            };
13755
13756            if let Some(url) = url {
13757                editor.update(cx, |_, cx| {
13758                    cx.open_url(&url);
13759                })
13760            } else {
13761                Ok(())
13762            }
13763        });
13764
13765        url_finder.detach();
13766    }
13767
13768    pub fn open_selected_filename(
13769        &mut self,
13770        _: &OpenSelectedFilename,
13771        window: &mut Window,
13772        cx: &mut Context<Self>,
13773    ) {
13774        let Some(workspace) = self.workspace() else {
13775            return;
13776        };
13777
13778        let position = self.selections.newest_anchor().head();
13779
13780        let Some((buffer, buffer_position)) =
13781            self.buffer.read(cx).text_anchor_for_position(position, cx)
13782        else {
13783            return;
13784        };
13785
13786        let project = self.project.clone();
13787
13788        cx.spawn_in(window, async move |_, cx| {
13789            let result = find_file(&buffer, project, buffer_position, cx).await;
13790
13791            if let Some((_, path)) = result {
13792                workspace
13793                    .update_in(cx, |workspace, window, cx| {
13794                        workspace.open_resolved_path(path, window, cx)
13795                    })?
13796                    .await?;
13797            }
13798            anyhow::Ok(())
13799        })
13800        .detach();
13801    }
13802
13803    pub(crate) fn navigate_to_hover_links(
13804        &mut self,
13805        kind: Option<GotoDefinitionKind>,
13806        mut definitions: Vec<HoverLink>,
13807        split: bool,
13808        window: &mut Window,
13809        cx: &mut Context<Editor>,
13810    ) -> Task<Result<Navigated>> {
13811        // If there is one definition, just open it directly
13812        if definitions.len() == 1 {
13813            let definition = definitions.pop().unwrap();
13814
13815            enum TargetTaskResult {
13816                Location(Option<Location>),
13817                AlreadyNavigated,
13818            }
13819
13820            let target_task = match definition {
13821                HoverLink::Text(link) => {
13822                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
13823                }
13824                HoverLink::InlayHint(lsp_location, server_id) => {
13825                    let computation =
13826                        self.compute_target_location(lsp_location, server_id, window, cx);
13827                    cx.background_spawn(async move {
13828                        let location = computation.await?;
13829                        Ok(TargetTaskResult::Location(location))
13830                    })
13831                }
13832                HoverLink::Url(url) => {
13833                    cx.open_url(&url);
13834                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
13835                }
13836                HoverLink::File(path) => {
13837                    if let Some(workspace) = self.workspace() {
13838                        cx.spawn_in(window, async move |_, cx| {
13839                            workspace
13840                                .update_in(cx, |workspace, window, cx| {
13841                                    workspace.open_resolved_path(path, window, cx)
13842                                })?
13843                                .await
13844                                .map(|_| TargetTaskResult::AlreadyNavigated)
13845                        })
13846                    } else {
13847                        Task::ready(Ok(TargetTaskResult::Location(None)))
13848                    }
13849                }
13850            };
13851            cx.spawn_in(window, async move |editor, cx| {
13852                let target = match target_task.await.context("target resolution task")? {
13853                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
13854                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
13855                    TargetTaskResult::Location(Some(target)) => target,
13856                };
13857
13858                editor.update_in(cx, |editor, window, cx| {
13859                    let Some(workspace) = editor.workspace() else {
13860                        return Navigated::No;
13861                    };
13862                    let pane = workspace.read(cx).active_pane().clone();
13863
13864                    let range = target.range.to_point(target.buffer.read(cx));
13865                    let range = editor.range_for_match(&range);
13866                    let range = collapse_multiline_range(range);
13867
13868                    if !split
13869                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
13870                    {
13871                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
13872                    } else {
13873                        window.defer(cx, move |window, cx| {
13874                            let target_editor: Entity<Self> =
13875                                workspace.update(cx, |workspace, cx| {
13876                                    let pane = if split {
13877                                        workspace.adjacent_pane(window, cx)
13878                                    } else {
13879                                        workspace.active_pane().clone()
13880                                    };
13881
13882                                    workspace.open_project_item(
13883                                        pane,
13884                                        target.buffer.clone(),
13885                                        true,
13886                                        true,
13887                                        window,
13888                                        cx,
13889                                    )
13890                                });
13891                            target_editor.update(cx, |target_editor, cx| {
13892                                // When selecting a definition in a different buffer, disable the nav history
13893                                // to avoid creating a history entry at the previous cursor location.
13894                                pane.update(cx, |pane, _| pane.disable_history());
13895                                target_editor.go_to_singleton_buffer_range(range, window, cx);
13896                                pane.update(cx, |pane, _| pane.enable_history());
13897                            });
13898                        });
13899                    }
13900                    Navigated::Yes
13901                })
13902            })
13903        } else if !definitions.is_empty() {
13904            cx.spawn_in(window, async move |editor, cx| {
13905                let (title, location_tasks, workspace) = editor
13906                    .update_in(cx, |editor, window, cx| {
13907                        let tab_kind = match kind {
13908                            Some(GotoDefinitionKind::Implementation) => "Implementations",
13909                            _ => "Definitions",
13910                        };
13911                        let title = definitions
13912                            .iter()
13913                            .find_map(|definition| match definition {
13914                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
13915                                    let buffer = origin.buffer.read(cx);
13916                                    format!(
13917                                        "{} for {}",
13918                                        tab_kind,
13919                                        buffer
13920                                            .text_for_range(origin.range.clone())
13921                                            .collect::<String>()
13922                                    )
13923                                }),
13924                                HoverLink::InlayHint(_, _) => None,
13925                                HoverLink::Url(_) => None,
13926                                HoverLink::File(_) => None,
13927                            })
13928                            .unwrap_or(tab_kind.to_string());
13929                        let location_tasks = definitions
13930                            .into_iter()
13931                            .map(|definition| match definition {
13932                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
13933                                HoverLink::InlayHint(lsp_location, server_id) => editor
13934                                    .compute_target_location(lsp_location, server_id, window, cx),
13935                                HoverLink::Url(_) => Task::ready(Ok(None)),
13936                                HoverLink::File(_) => Task::ready(Ok(None)),
13937                            })
13938                            .collect::<Vec<_>>();
13939                        (title, location_tasks, editor.workspace().clone())
13940                    })
13941                    .context("location tasks preparation")?;
13942
13943                let locations = future::join_all(location_tasks)
13944                    .await
13945                    .into_iter()
13946                    .filter_map(|location| location.transpose())
13947                    .collect::<Result<_>>()
13948                    .context("location tasks")?;
13949
13950                let Some(workspace) = workspace else {
13951                    return Ok(Navigated::No);
13952                };
13953                let opened = workspace
13954                    .update_in(cx, |workspace, window, cx| {
13955                        Self::open_locations_in_multibuffer(
13956                            workspace,
13957                            locations,
13958                            title,
13959                            split,
13960                            MultibufferSelectionMode::First,
13961                            window,
13962                            cx,
13963                        )
13964                    })
13965                    .ok();
13966
13967                anyhow::Ok(Navigated::from_bool(opened.is_some()))
13968            })
13969        } else {
13970            Task::ready(Ok(Navigated::No))
13971        }
13972    }
13973
13974    fn compute_target_location(
13975        &self,
13976        lsp_location: lsp::Location,
13977        server_id: LanguageServerId,
13978        window: &mut Window,
13979        cx: &mut Context<Self>,
13980    ) -> Task<anyhow::Result<Option<Location>>> {
13981        let Some(project) = self.project.clone() else {
13982            return Task::ready(Ok(None));
13983        };
13984
13985        cx.spawn_in(window, async move |editor, cx| {
13986            let location_task = editor.update(cx, |_, cx| {
13987                project.update(cx, |project, cx| {
13988                    let language_server_name = project
13989                        .language_server_statuses(cx)
13990                        .find(|(id, _)| server_id == *id)
13991                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
13992                    language_server_name.map(|language_server_name| {
13993                        project.open_local_buffer_via_lsp(
13994                            lsp_location.uri.clone(),
13995                            server_id,
13996                            language_server_name,
13997                            cx,
13998                        )
13999                    })
14000                })
14001            })?;
14002            let location = match location_task {
14003                Some(task) => Some({
14004                    let target_buffer_handle = task.await.context("open local buffer")?;
14005                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14006                        let target_start = target_buffer
14007                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14008                        let target_end = target_buffer
14009                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14010                        target_buffer.anchor_after(target_start)
14011                            ..target_buffer.anchor_before(target_end)
14012                    })?;
14013                    Location {
14014                        buffer: target_buffer_handle,
14015                        range,
14016                    }
14017                }),
14018                None => None,
14019            };
14020            Ok(location)
14021        })
14022    }
14023
14024    pub fn find_all_references(
14025        &mut self,
14026        _: &FindAllReferences,
14027        window: &mut Window,
14028        cx: &mut Context<Self>,
14029    ) -> Option<Task<Result<Navigated>>> {
14030        let selection = self.selections.newest::<usize>(cx);
14031        let multi_buffer = self.buffer.read(cx);
14032        let head = selection.head();
14033
14034        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14035        let head_anchor = multi_buffer_snapshot.anchor_at(
14036            head,
14037            if head < selection.tail() {
14038                Bias::Right
14039            } else {
14040                Bias::Left
14041            },
14042        );
14043
14044        match self
14045            .find_all_references_task_sources
14046            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14047        {
14048            Ok(_) => {
14049                log::info!(
14050                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14051                );
14052                return None;
14053            }
14054            Err(i) => {
14055                self.find_all_references_task_sources.insert(i, head_anchor);
14056            }
14057        }
14058
14059        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14060        let workspace = self.workspace()?;
14061        let project = workspace.read(cx).project().clone();
14062        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14063        Some(cx.spawn_in(window, async move |editor, cx| {
14064            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14065                if let Ok(i) = editor
14066                    .find_all_references_task_sources
14067                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14068                {
14069                    editor.find_all_references_task_sources.remove(i);
14070                }
14071            });
14072
14073            let locations = references.await?;
14074            if locations.is_empty() {
14075                return anyhow::Ok(Navigated::No);
14076            }
14077
14078            workspace.update_in(cx, |workspace, window, cx| {
14079                let title = locations
14080                    .first()
14081                    .as_ref()
14082                    .map(|location| {
14083                        let buffer = location.buffer.read(cx);
14084                        format!(
14085                            "References to `{}`",
14086                            buffer
14087                                .text_for_range(location.range.clone())
14088                                .collect::<String>()
14089                        )
14090                    })
14091                    .unwrap();
14092                Self::open_locations_in_multibuffer(
14093                    workspace,
14094                    locations,
14095                    title,
14096                    false,
14097                    MultibufferSelectionMode::First,
14098                    window,
14099                    cx,
14100                );
14101                Navigated::Yes
14102            })
14103        }))
14104    }
14105
14106    /// Opens a multibuffer with the given project locations in it
14107    pub fn open_locations_in_multibuffer(
14108        workspace: &mut Workspace,
14109        mut locations: Vec<Location>,
14110        title: String,
14111        split: bool,
14112        multibuffer_selection_mode: MultibufferSelectionMode,
14113        window: &mut Window,
14114        cx: &mut Context<Workspace>,
14115    ) {
14116        // If there are multiple definitions, open them in a multibuffer
14117        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14118        let mut locations = locations.into_iter().peekable();
14119        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14120        let capability = workspace.project().read(cx).capability();
14121
14122        let excerpt_buffer = cx.new(|cx| {
14123            let mut multibuffer = MultiBuffer::new(capability);
14124            while let Some(location) = locations.next() {
14125                let buffer = location.buffer.read(cx);
14126                let mut ranges_for_buffer = Vec::new();
14127                let range = location.range.to_point(buffer);
14128                ranges_for_buffer.push(range.clone());
14129
14130                while let Some(next_location) = locations.peek() {
14131                    if next_location.buffer == location.buffer {
14132                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14133                        locations.next();
14134                    } else {
14135                        break;
14136                    }
14137                }
14138
14139                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14140                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14141                    PathKey::for_buffer(&location.buffer, cx),
14142                    location.buffer.clone(),
14143                    ranges_for_buffer,
14144                    DEFAULT_MULTIBUFFER_CONTEXT,
14145                    cx,
14146                );
14147                ranges.extend(new_ranges)
14148            }
14149
14150            multibuffer.with_title(title)
14151        });
14152
14153        let editor = cx.new(|cx| {
14154            Editor::for_multibuffer(
14155                excerpt_buffer,
14156                Some(workspace.project().clone()),
14157                window,
14158                cx,
14159            )
14160        });
14161        editor.update(cx, |editor, cx| {
14162            match multibuffer_selection_mode {
14163                MultibufferSelectionMode::First => {
14164                    if let Some(first_range) = ranges.first() {
14165                        editor.change_selections(None, window, cx, |selections| {
14166                            selections.clear_disjoint();
14167                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14168                        });
14169                    }
14170                    editor.highlight_background::<Self>(
14171                        &ranges,
14172                        |theme| theme.editor_highlighted_line_background,
14173                        cx,
14174                    );
14175                }
14176                MultibufferSelectionMode::All => {
14177                    editor.change_selections(None, window, cx, |selections| {
14178                        selections.clear_disjoint();
14179                        selections.select_anchor_ranges(ranges);
14180                    });
14181                }
14182            }
14183            editor.register_buffers_with_language_servers(cx);
14184        });
14185
14186        let item = Box::new(editor);
14187        let item_id = item.item_id();
14188
14189        if split {
14190            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14191        } else {
14192            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14193                let (preview_item_id, preview_item_idx) =
14194                    workspace.active_pane().update(cx, |pane, _| {
14195                        (pane.preview_item_id(), pane.preview_item_idx())
14196                    });
14197
14198                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14199
14200                if let Some(preview_item_id) = preview_item_id {
14201                    workspace.active_pane().update(cx, |pane, cx| {
14202                        pane.remove_item(preview_item_id, false, false, window, cx);
14203                    });
14204                }
14205            } else {
14206                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14207            }
14208        }
14209        workspace.active_pane().update(cx, |pane, cx| {
14210            pane.set_preview_item_id(Some(item_id), cx);
14211        });
14212    }
14213
14214    pub fn rename(
14215        &mut self,
14216        _: &Rename,
14217        window: &mut Window,
14218        cx: &mut Context<Self>,
14219    ) -> Option<Task<Result<()>>> {
14220        use language::ToOffset as _;
14221
14222        let provider = self.semantics_provider.clone()?;
14223        let selection = self.selections.newest_anchor().clone();
14224        let (cursor_buffer, cursor_buffer_position) = self
14225            .buffer
14226            .read(cx)
14227            .text_anchor_for_position(selection.head(), cx)?;
14228        let (tail_buffer, cursor_buffer_position_end) = self
14229            .buffer
14230            .read(cx)
14231            .text_anchor_for_position(selection.tail(), cx)?;
14232        if tail_buffer != cursor_buffer {
14233            return None;
14234        }
14235
14236        let snapshot = cursor_buffer.read(cx).snapshot();
14237        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14238        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14239        let prepare_rename = provider
14240            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14241            .unwrap_or_else(|| Task::ready(Ok(None)));
14242        drop(snapshot);
14243
14244        Some(cx.spawn_in(window, async move |this, cx| {
14245            let rename_range = if let Some(range) = prepare_rename.await? {
14246                Some(range)
14247            } else {
14248                this.update(cx, |this, cx| {
14249                    let buffer = this.buffer.read(cx).snapshot(cx);
14250                    let mut buffer_highlights = this
14251                        .document_highlights_for_position(selection.head(), &buffer)
14252                        .filter(|highlight| {
14253                            highlight.start.excerpt_id == selection.head().excerpt_id
14254                                && highlight.end.excerpt_id == selection.head().excerpt_id
14255                        });
14256                    buffer_highlights
14257                        .next()
14258                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14259                })?
14260            };
14261            if let Some(rename_range) = rename_range {
14262                this.update_in(cx, |this, window, cx| {
14263                    let snapshot = cursor_buffer.read(cx).snapshot();
14264                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14265                    let cursor_offset_in_rename_range =
14266                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14267                    let cursor_offset_in_rename_range_end =
14268                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14269
14270                    this.take_rename(false, window, cx);
14271                    let buffer = this.buffer.read(cx).read(cx);
14272                    let cursor_offset = selection.head().to_offset(&buffer);
14273                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14274                    let rename_end = rename_start + rename_buffer_range.len();
14275                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14276                    let mut old_highlight_id = None;
14277                    let old_name: Arc<str> = buffer
14278                        .chunks(rename_start..rename_end, true)
14279                        .map(|chunk| {
14280                            if old_highlight_id.is_none() {
14281                                old_highlight_id = chunk.syntax_highlight_id;
14282                            }
14283                            chunk.text
14284                        })
14285                        .collect::<String>()
14286                        .into();
14287
14288                    drop(buffer);
14289
14290                    // Position the selection in the rename editor so that it matches the current selection.
14291                    this.show_local_selections = false;
14292                    let rename_editor = cx.new(|cx| {
14293                        let mut editor = Editor::single_line(window, cx);
14294                        editor.buffer.update(cx, |buffer, cx| {
14295                            buffer.edit([(0..0, old_name.clone())], None, cx)
14296                        });
14297                        let rename_selection_range = match cursor_offset_in_rename_range
14298                            .cmp(&cursor_offset_in_rename_range_end)
14299                        {
14300                            Ordering::Equal => {
14301                                editor.select_all(&SelectAll, window, cx);
14302                                return editor;
14303                            }
14304                            Ordering::Less => {
14305                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14306                            }
14307                            Ordering::Greater => {
14308                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14309                            }
14310                        };
14311                        if rename_selection_range.end > old_name.len() {
14312                            editor.select_all(&SelectAll, window, cx);
14313                        } else {
14314                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14315                                s.select_ranges([rename_selection_range]);
14316                            });
14317                        }
14318                        editor
14319                    });
14320                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14321                        if e == &EditorEvent::Focused {
14322                            cx.emit(EditorEvent::FocusedIn)
14323                        }
14324                    })
14325                    .detach();
14326
14327                    let write_highlights =
14328                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14329                    let read_highlights =
14330                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14331                    let ranges = write_highlights
14332                        .iter()
14333                        .flat_map(|(_, ranges)| ranges.iter())
14334                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14335                        .cloned()
14336                        .collect();
14337
14338                    this.highlight_text::<Rename>(
14339                        ranges,
14340                        HighlightStyle {
14341                            fade_out: Some(0.6),
14342                            ..Default::default()
14343                        },
14344                        cx,
14345                    );
14346                    let rename_focus_handle = rename_editor.focus_handle(cx);
14347                    window.focus(&rename_focus_handle);
14348                    let block_id = this.insert_blocks(
14349                        [BlockProperties {
14350                            style: BlockStyle::Flex,
14351                            placement: BlockPlacement::Below(range.start),
14352                            height: Some(1),
14353                            render: Arc::new({
14354                                let rename_editor = rename_editor.clone();
14355                                move |cx: &mut BlockContext| {
14356                                    let mut text_style = cx.editor_style.text.clone();
14357                                    if let Some(highlight_style) = old_highlight_id
14358                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14359                                    {
14360                                        text_style = text_style.highlight(highlight_style);
14361                                    }
14362                                    div()
14363                                        .block_mouse_down()
14364                                        .pl(cx.anchor_x)
14365                                        .child(EditorElement::new(
14366                                            &rename_editor,
14367                                            EditorStyle {
14368                                                background: cx.theme().system().transparent,
14369                                                local_player: cx.editor_style.local_player,
14370                                                text: text_style,
14371                                                scrollbar_width: cx.editor_style.scrollbar_width,
14372                                                syntax: cx.editor_style.syntax.clone(),
14373                                                status: cx.editor_style.status.clone(),
14374                                                inlay_hints_style: HighlightStyle {
14375                                                    font_weight: Some(FontWeight::BOLD),
14376                                                    ..make_inlay_hints_style(cx.app)
14377                                                },
14378                                                inline_completion_styles: make_suggestion_styles(
14379                                                    cx.app,
14380                                                ),
14381                                                ..EditorStyle::default()
14382                                            },
14383                                        ))
14384                                        .into_any_element()
14385                                }
14386                            }),
14387                            priority: 0,
14388                        }],
14389                        Some(Autoscroll::fit()),
14390                        cx,
14391                    )[0];
14392                    this.pending_rename = Some(RenameState {
14393                        range,
14394                        old_name,
14395                        editor: rename_editor,
14396                        block_id,
14397                    });
14398                })?;
14399            }
14400
14401            Ok(())
14402        }))
14403    }
14404
14405    pub fn confirm_rename(
14406        &mut self,
14407        _: &ConfirmRename,
14408        window: &mut Window,
14409        cx: &mut Context<Self>,
14410    ) -> Option<Task<Result<()>>> {
14411        let rename = self.take_rename(false, window, cx)?;
14412        let workspace = self.workspace()?.downgrade();
14413        let (buffer, start) = self
14414            .buffer
14415            .read(cx)
14416            .text_anchor_for_position(rename.range.start, cx)?;
14417        let (end_buffer, _) = self
14418            .buffer
14419            .read(cx)
14420            .text_anchor_for_position(rename.range.end, cx)?;
14421        if buffer != end_buffer {
14422            return None;
14423        }
14424
14425        let old_name = rename.old_name;
14426        let new_name = rename.editor.read(cx).text(cx);
14427
14428        let rename = self.semantics_provider.as_ref()?.perform_rename(
14429            &buffer,
14430            start,
14431            new_name.clone(),
14432            cx,
14433        )?;
14434
14435        Some(cx.spawn_in(window, async move |editor, cx| {
14436            let project_transaction = rename.await?;
14437            Self::open_project_transaction(
14438                &editor,
14439                workspace,
14440                project_transaction,
14441                format!("Rename: {}{}", old_name, new_name),
14442                cx,
14443            )
14444            .await?;
14445
14446            editor.update(cx, |editor, cx| {
14447                editor.refresh_document_highlights(cx);
14448            })?;
14449            Ok(())
14450        }))
14451    }
14452
14453    fn take_rename(
14454        &mut self,
14455        moving_cursor: bool,
14456        window: &mut Window,
14457        cx: &mut Context<Self>,
14458    ) -> Option<RenameState> {
14459        let rename = self.pending_rename.take()?;
14460        if rename.editor.focus_handle(cx).is_focused(window) {
14461            window.focus(&self.focus_handle);
14462        }
14463
14464        self.remove_blocks(
14465            [rename.block_id].into_iter().collect(),
14466            Some(Autoscroll::fit()),
14467            cx,
14468        );
14469        self.clear_highlights::<Rename>(cx);
14470        self.show_local_selections = true;
14471
14472        if moving_cursor {
14473            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14474                editor.selections.newest::<usize>(cx).head()
14475            });
14476
14477            // Update the selection to match the position of the selection inside
14478            // the rename editor.
14479            let snapshot = self.buffer.read(cx).read(cx);
14480            let rename_range = rename.range.to_offset(&snapshot);
14481            let cursor_in_editor = snapshot
14482                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14483                .min(rename_range.end);
14484            drop(snapshot);
14485
14486            self.change_selections(None, window, cx, |s| {
14487                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14488            });
14489        } else {
14490            self.refresh_document_highlights(cx);
14491        }
14492
14493        Some(rename)
14494    }
14495
14496    pub fn pending_rename(&self) -> Option<&RenameState> {
14497        self.pending_rename.as_ref()
14498    }
14499
14500    fn format(
14501        &mut self,
14502        _: &Format,
14503        window: &mut Window,
14504        cx: &mut Context<Self>,
14505    ) -> Option<Task<Result<()>>> {
14506        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14507
14508        let project = match &self.project {
14509            Some(project) => project.clone(),
14510            None => return None,
14511        };
14512
14513        Some(self.perform_format(
14514            project,
14515            FormatTrigger::Manual,
14516            FormatTarget::Buffers,
14517            window,
14518            cx,
14519        ))
14520    }
14521
14522    fn format_selections(
14523        &mut self,
14524        _: &FormatSelections,
14525        window: &mut Window,
14526        cx: &mut Context<Self>,
14527    ) -> Option<Task<Result<()>>> {
14528        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14529
14530        let project = match &self.project {
14531            Some(project) => project.clone(),
14532            None => return None,
14533        };
14534
14535        let ranges = self
14536            .selections
14537            .all_adjusted(cx)
14538            .into_iter()
14539            .map(|selection| selection.range())
14540            .collect_vec();
14541
14542        Some(self.perform_format(
14543            project,
14544            FormatTrigger::Manual,
14545            FormatTarget::Ranges(ranges),
14546            window,
14547            cx,
14548        ))
14549    }
14550
14551    fn perform_format(
14552        &mut self,
14553        project: Entity<Project>,
14554        trigger: FormatTrigger,
14555        target: FormatTarget,
14556        window: &mut Window,
14557        cx: &mut Context<Self>,
14558    ) -> Task<Result<()>> {
14559        let buffer = self.buffer.clone();
14560        let (buffers, target) = match target {
14561            FormatTarget::Buffers => {
14562                let mut buffers = buffer.read(cx).all_buffers();
14563                if trigger == FormatTrigger::Save {
14564                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
14565                }
14566                (buffers, LspFormatTarget::Buffers)
14567            }
14568            FormatTarget::Ranges(selection_ranges) => {
14569                let multi_buffer = buffer.read(cx);
14570                let snapshot = multi_buffer.read(cx);
14571                let mut buffers = HashSet::default();
14572                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
14573                    BTreeMap::new();
14574                for selection_range in selection_ranges {
14575                    for (buffer, buffer_range, _) in
14576                        snapshot.range_to_buffer_ranges(selection_range)
14577                    {
14578                        let buffer_id = buffer.remote_id();
14579                        let start = buffer.anchor_before(buffer_range.start);
14580                        let end = buffer.anchor_after(buffer_range.end);
14581                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
14582                        buffer_id_to_ranges
14583                            .entry(buffer_id)
14584                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
14585                            .or_insert_with(|| vec![start..end]);
14586                    }
14587                }
14588                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
14589            }
14590        };
14591
14592        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
14593        let selections_prev = transaction_id_prev
14594            .and_then(|transaction_id_prev| {
14595                // default to selections as they were after the last edit, if we have them,
14596                // instead of how they are now.
14597                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
14598                // will take you back to where you made the last edit, instead of staying where you scrolled
14599                self.selection_history
14600                    .transaction(transaction_id_prev)
14601                    .map(|t| t.0.clone())
14602            })
14603            .unwrap_or_else(|| {
14604                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
14605                self.selections.disjoint_anchors()
14606            });
14607
14608        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
14609        let format = project.update(cx, |project, cx| {
14610            project.format(buffers, target, true, trigger, cx)
14611        });
14612
14613        cx.spawn_in(window, async move |editor, cx| {
14614            let transaction = futures::select_biased! {
14615                transaction = format.log_err().fuse() => transaction,
14616                () = timeout => {
14617                    log::warn!("timed out waiting for formatting");
14618                    None
14619                }
14620            };
14621
14622            buffer
14623                .update(cx, |buffer, cx| {
14624                    if let Some(transaction) = transaction {
14625                        if !buffer.is_singleton() {
14626                            buffer.push_transaction(&transaction.0, cx);
14627                        }
14628                    }
14629                    cx.notify();
14630                })
14631                .ok();
14632
14633            if let Some(transaction_id_now) =
14634                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
14635            {
14636                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
14637                if has_new_transaction {
14638                    _ = editor.update(cx, |editor, _| {
14639                        editor
14640                            .selection_history
14641                            .insert_transaction(transaction_id_now, selections_prev);
14642                    });
14643                }
14644            }
14645
14646            Ok(())
14647        })
14648    }
14649
14650    fn organize_imports(
14651        &mut self,
14652        _: &OrganizeImports,
14653        window: &mut Window,
14654        cx: &mut Context<Self>,
14655    ) -> Option<Task<Result<()>>> {
14656        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14657        let project = match &self.project {
14658            Some(project) => project.clone(),
14659            None => return None,
14660        };
14661        Some(self.perform_code_action_kind(
14662            project,
14663            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
14664            window,
14665            cx,
14666        ))
14667    }
14668
14669    fn perform_code_action_kind(
14670        &mut self,
14671        project: Entity<Project>,
14672        kind: CodeActionKind,
14673        window: &mut Window,
14674        cx: &mut Context<Self>,
14675    ) -> Task<Result<()>> {
14676        let buffer = self.buffer.clone();
14677        let buffers = buffer.read(cx).all_buffers();
14678        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
14679        let apply_action = project.update(cx, |project, cx| {
14680            project.apply_code_action_kind(buffers, kind, true, cx)
14681        });
14682        cx.spawn_in(window, async move |_, cx| {
14683            let transaction = futures::select_biased! {
14684                () = timeout => {
14685                    log::warn!("timed out waiting for executing code action");
14686                    None
14687                }
14688                transaction = apply_action.log_err().fuse() => transaction,
14689            };
14690            buffer
14691                .update(cx, |buffer, cx| {
14692                    // check if we need this
14693                    if let Some(transaction) = transaction {
14694                        if !buffer.is_singleton() {
14695                            buffer.push_transaction(&transaction.0, cx);
14696                        }
14697                    }
14698                    cx.notify();
14699                })
14700                .ok();
14701            Ok(())
14702        })
14703    }
14704
14705    fn restart_language_server(
14706        &mut self,
14707        _: &RestartLanguageServer,
14708        _: &mut Window,
14709        cx: &mut Context<Self>,
14710    ) {
14711        if let Some(project) = self.project.clone() {
14712            self.buffer.update(cx, |multi_buffer, cx| {
14713                project.update(cx, |project, cx| {
14714                    project.restart_language_servers_for_buffers(
14715                        multi_buffer.all_buffers().into_iter().collect(),
14716                        cx,
14717                    );
14718                });
14719            })
14720        }
14721    }
14722
14723    fn stop_language_server(
14724        &mut self,
14725        _: &StopLanguageServer,
14726        _: &mut Window,
14727        cx: &mut Context<Self>,
14728    ) {
14729        if let Some(project) = self.project.clone() {
14730            self.buffer.update(cx, |multi_buffer, cx| {
14731                project.update(cx, |project, cx| {
14732                    project.stop_language_servers_for_buffers(
14733                        multi_buffer.all_buffers().into_iter().collect(),
14734                        cx,
14735                    );
14736                    cx.emit(project::Event::RefreshInlayHints);
14737                });
14738            });
14739        }
14740    }
14741
14742    fn cancel_language_server_work(
14743        workspace: &mut Workspace,
14744        _: &actions::CancelLanguageServerWork,
14745        _: &mut Window,
14746        cx: &mut Context<Workspace>,
14747    ) {
14748        let project = workspace.project();
14749        let buffers = workspace
14750            .active_item(cx)
14751            .and_then(|item| item.act_as::<Editor>(cx))
14752            .map_or(HashSet::default(), |editor| {
14753                editor.read(cx).buffer.read(cx).all_buffers()
14754            });
14755        project.update(cx, |project, cx| {
14756            project.cancel_language_server_work_for_buffers(buffers, cx);
14757        });
14758    }
14759
14760    fn show_character_palette(
14761        &mut self,
14762        _: &ShowCharacterPalette,
14763        window: &mut Window,
14764        _: &mut Context<Self>,
14765    ) {
14766        window.show_character_palette();
14767    }
14768
14769    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
14770        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
14771            let buffer = self.buffer.read(cx).snapshot(cx);
14772            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
14773            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
14774            let is_valid = buffer
14775                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
14776                .any(|entry| {
14777                    entry.diagnostic.is_primary
14778                        && !entry.range.is_empty()
14779                        && entry.range.start == primary_range_start
14780                        && entry.diagnostic.message == active_diagnostics.active_message
14781                });
14782
14783            if !is_valid {
14784                self.dismiss_diagnostics(cx);
14785            }
14786        }
14787    }
14788
14789    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
14790        match &self.active_diagnostics {
14791            ActiveDiagnostic::Group(group) => Some(group),
14792            _ => None,
14793        }
14794    }
14795
14796    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
14797        self.dismiss_diagnostics(cx);
14798        self.active_diagnostics = ActiveDiagnostic::All;
14799    }
14800
14801    fn activate_diagnostics(
14802        &mut self,
14803        buffer_id: BufferId,
14804        diagnostic: DiagnosticEntry<usize>,
14805        window: &mut Window,
14806        cx: &mut Context<Self>,
14807    ) {
14808        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
14809            return;
14810        }
14811        self.dismiss_diagnostics(cx);
14812        let snapshot = self.snapshot(window, cx);
14813        let buffer = self.buffer.read(cx).snapshot(cx);
14814        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
14815            return;
14816        };
14817
14818        let diagnostic_group = buffer
14819            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
14820            .collect::<Vec<_>>();
14821
14822        let blocks =
14823            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
14824
14825        let blocks = self.display_map.update(cx, |display_map, cx| {
14826            display_map.insert_blocks(blocks, cx).into_iter().collect()
14827        });
14828        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
14829            active_range: buffer.anchor_before(diagnostic.range.start)
14830                ..buffer.anchor_after(diagnostic.range.end),
14831            active_message: diagnostic.diagnostic.message.clone(),
14832            group_id: diagnostic.diagnostic.group_id,
14833            blocks,
14834        });
14835        cx.notify();
14836    }
14837
14838    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
14839        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
14840            return;
14841        };
14842
14843        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
14844        if let ActiveDiagnostic::Group(group) = prev {
14845            self.display_map.update(cx, |display_map, cx| {
14846                display_map.remove_blocks(group.blocks, cx);
14847            });
14848            cx.notify();
14849        }
14850    }
14851
14852    /// Disable inline diagnostics rendering for this editor.
14853    pub fn disable_inline_diagnostics(&mut self) {
14854        self.inline_diagnostics_enabled = false;
14855        self.inline_diagnostics_update = Task::ready(());
14856        self.inline_diagnostics.clear();
14857    }
14858
14859    pub fn inline_diagnostics_enabled(&self) -> bool {
14860        self.inline_diagnostics_enabled
14861    }
14862
14863    pub fn show_inline_diagnostics(&self) -> bool {
14864        self.show_inline_diagnostics
14865    }
14866
14867    pub fn toggle_inline_diagnostics(
14868        &mut self,
14869        _: &ToggleInlineDiagnostics,
14870        window: &mut Window,
14871        cx: &mut Context<Editor>,
14872    ) {
14873        self.show_inline_diagnostics = !self.show_inline_diagnostics;
14874        self.refresh_inline_diagnostics(false, window, cx);
14875    }
14876
14877    fn refresh_inline_diagnostics(
14878        &mut self,
14879        debounce: bool,
14880        window: &mut Window,
14881        cx: &mut Context<Self>,
14882    ) {
14883        if !self.inline_diagnostics_enabled || !self.show_inline_diagnostics {
14884            self.inline_diagnostics_update = Task::ready(());
14885            self.inline_diagnostics.clear();
14886            return;
14887        }
14888
14889        let debounce_ms = ProjectSettings::get_global(cx)
14890            .diagnostics
14891            .inline
14892            .update_debounce_ms;
14893        let debounce = if debounce && debounce_ms > 0 {
14894            Some(Duration::from_millis(debounce_ms))
14895        } else {
14896            None
14897        };
14898        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
14899            let editor = editor.upgrade().unwrap();
14900
14901            if let Some(debounce) = debounce {
14902                cx.background_executor().timer(debounce).await;
14903            }
14904            let Some(snapshot) = editor
14905                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
14906                .ok()
14907            else {
14908                return;
14909            };
14910
14911            let new_inline_diagnostics = cx
14912                .background_spawn(async move {
14913                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
14914                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
14915                        let message = diagnostic_entry
14916                            .diagnostic
14917                            .message
14918                            .split_once('\n')
14919                            .map(|(line, _)| line)
14920                            .map(SharedString::new)
14921                            .unwrap_or_else(|| {
14922                                SharedString::from(diagnostic_entry.diagnostic.message)
14923                            });
14924                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
14925                        let (Ok(i) | Err(i)) = inline_diagnostics
14926                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
14927                        inline_diagnostics.insert(
14928                            i,
14929                            (
14930                                start_anchor,
14931                                InlineDiagnostic {
14932                                    message,
14933                                    group_id: diagnostic_entry.diagnostic.group_id,
14934                                    start: diagnostic_entry.range.start.to_point(&snapshot),
14935                                    is_primary: diagnostic_entry.diagnostic.is_primary,
14936                                    severity: diagnostic_entry.diagnostic.severity,
14937                                },
14938                            ),
14939                        );
14940                    }
14941                    inline_diagnostics
14942                })
14943                .await;
14944
14945            editor
14946                .update(cx, |editor, cx| {
14947                    editor.inline_diagnostics = new_inline_diagnostics;
14948                    cx.notify();
14949                })
14950                .ok();
14951        });
14952    }
14953
14954    pub fn set_selections_from_remote(
14955        &mut self,
14956        selections: Vec<Selection<Anchor>>,
14957        pending_selection: Option<Selection<Anchor>>,
14958        window: &mut Window,
14959        cx: &mut Context<Self>,
14960    ) {
14961        let old_cursor_position = self.selections.newest_anchor().head();
14962        self.selections.change_with(cx, |s| {
14963            s.select_anchors(selections);
14964            if let Some(pending_selection) = pending_selection {
14965                s.set_pending(pending_selection, SelectMode::Character);
14966            } else {
14967                s.clear_pending();
14968            }
14969        });
14970        self.selections_did_change(false, &old_cursor_position, true, window, cx);
14971    }
14972
14973    fn push_to_selection_history(&mut self) {
14974        self.selection_history.push(SelectionHistoryEntry {
14975            selections: self.selections.disjoint_anchors(),
14976            select_next_state: self.select_next_state.clone(),
14977            select_prev_state: self.select_prev_state.clone(),
14978            add_selections_state: self.add_selections_state.clone(),
14979        });
14980    }
14981
14982    pub fn transact(
14983        &mut self,
14984        window: &mut Window,
14985        cx: &mut Context<Self>,
14986        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
14987    ) -> Option<TransactionId> {
14988        self.start_transaction_at(Instant::now(), window, cx);
14989        update(self, window, cx);
14990        self.end_transaction_at(Instant::now(), cx)
14991    }
14992
14993    pub fn start_transaction_at(
14994        &mut self,
14995        now: Instant,
14996        window: &mut Window,
14997        cx: &mut Context<Self>,
14998    ) {
14999        self.end_selection(window, cx);
15000        if let Some(tx_id) = self
15001            .buffer
15002            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15003        {
15004            self.selection_history
15005                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15006            cx.emit(EditorEvent::TransactionBegun {
15007                transaction_id: tx_id,
15008            })
15009        }
15010    }
15011
15012    pub fn end_transaction_at(
15013        &mut self,
15014        now: Instant,
15015        cx: &mut Context<Self>,
15016    ) -> Option<TransactionId> {
15017        if let Some(transaction_id) = self
15018            .buffer
15019            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15020        {
15021            if let Some((_, end_selections)) =
15022                self.selection_history.transaction_mut(transaction_id)
15023            {
15024                *end_selections = Some(self.selections.disjoint_anchors());
15025            } else {
15026                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15027            }
15028
15029            cx.emit(EditorEvent::Edited { transaction_id });
15030            Some(transaction_id)
15031        } else {
15032            None
15033        }
15034    }
15035
15036    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15037        if self.selection_mark_mode {
15038            self.change_selections(None, window, cx, |s| {
15039                s.move_with(|_, sel| {
15040                    sel.collapse_to(sel.head(), SelectionGoal::None);
15041                });
15042            })
15043        }
15044        self.selection_mark_mode = true;
15045        cx.notify();
15046    }
15047
15048    pub fn swap_selection_ends(
15049        &mut self,
15050        _: &actions::SwapSelectionEnds,
15051        window: &mut Window,
15052        cx: &mut Context<Self>,
15053    ) {
15054        self.change_selections(None, window, cx, |s| {
15055            s.move_with(|_, sel| {
15056                if sel.start != sel.end {
15057                    sel.reversed = !sel.reversed
15058                }
15059            });
15060        });
15061        self.request_autoscroll(Autoscroll::newest(), cx);
15062        cx.notify();
15063    }
15064
15065    pub fn toggle_fold(
15066        &mut self,
15067        _: &actions::ToggleFold,
15068        window: &mut Window,
15069        cx: &mut Context<Self>,
15070    ) {
15071        if self.is_singleton(cx) {
15072            let selection = self.selections.newest::<Point>(cx);
15073
15074            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15075            let range = if selection.is_empty() {
15076                let point = selection.head().to_display_point(&display_map);
15077                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15078                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15079                    .to_point(&display_map);
15080                start..end
15081            } else {
15082                selection.range()
15083            };
15084            if display_map.folds_in_range(range).next().is_some() {
15085                self.unfold_lines(&Default::default(), window, cx)
15086            } else {
15087                self.fold(&Default::default(), window, cx)
15088            }
15089        } else {
15090            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15091            let buffer_ids: HashSet<_> = self
15092                .selections
15093                .disjoint_anchor_ranges()
15094                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15095                .collect();
15096
15097            let should_unfold = buffer_ids
15098                .iter()
15099                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15100
15101            for buffer_id in buffer_ids {
15102                if should_unfold {
15103                    self.unfold_buffer(buffer_id, cx);
15104                } else {
15105                    self.fold_buffer(buffer_id, cx);
15106                }
15107            }
15108        }
15109    }
15110
15111    pub fn toggle_fold_recursive(
15112        &mut self,
15113        _: &actions::ToggleFoldRecursive,
15114        window: &mut Window,
15115        cx: &mut Context<Self>,
15116    ) {
15117        let selection = self.selections.newest::<Point>(cx);
15118
15119        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15120        let range = if selection.is_empty() {
15121            let point = selection.head().to_display_point(&display_map);
15122            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15123            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15124                .to_point(&display_map);
15125            start..end
15126        } else {
15127            selection.range()
15128        };
15129        if display_map.folds_in_range(range).next().is_some() {
15130            self.unfold_recursive(&Default::default(), window, cx)
15131        } else {
15132            self.fold_recursive(&Default::default(), window, cx)
15133        }
15134    }
15135
15136    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15137        if self.is_singleton(cx) {
15138            let mut to_fold = Vec::new();
15139            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15140            let selections = self.selections.all_adjusted(cx);
15141
15142            for selection in selections {
15143                let range = selection.range().sorted();
15144                let buffer_start_row = range.start.row;
15145
15146                if range.start.row != range.end.row {
15147                    let mut found = false;
15148                    let mut row = range.start.row;
15149                    while row <= range.end.row {
15150                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15151                        {
15152                            found = true;
15153                            row = crease.range().end.row + 1;
15154                            to_fold.push(crease);
15155                        } else {
15156                            row += 1
15157                        }
15158                    }
15159                    if found {
15160                        continue;
15161                    }
15162                }
15163
15164                for row in (0..=range.start.row).rev() {
15165                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15166                        if crease.range().end.row >= buffer_start_row {
15167                            to_fold.push(crease);
15168                            if row <= range.start.row {
15169                                break;
15170                            }
15171                        }
15172                    }
15173                }
15174            }
15175
15176            self.fold_creases(to_fold, true, window, cx);
15177        } else {
15178            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15179            let buffer_ids = self
15180                .selections
15181                .disjoint_anchor_ranges()
15182                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15183                .collect::<HashSet<_>>();
15184            for buffer_id in buffer_ids {
15185                self.fold_buffer(buffer_id, cx);
15186            }
15187        }
15188    }
15189
15190    fn fold_at_level(
15191        &mut self,
15192        fold_at: &FoldAtLevel,
15193        window: &mut Window,
15194        cx: &mut Context<Self>,
15195    ) {
15196        if !self.buffer.read(cx).is_singleton() {
15197            return;
15198        }
15199
15200        let fold_at_level = fold_at.0;
15201        let snapshot = self.buffer.read(cx).snapshot(cx);
15202        let mut to_fold = Vec::new();
15203        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15204
15205        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15206            while start_row < end_row {
15207                match self
15208                    .snapshot(window, cx)
15209                    .crease_for_buffer_row(MultiBufferRow(start_row))
15210                {
15211                    Some(crease) => {
15212                        let nested_start_row = crease.range().start.row + 1;
15213                        let nested_end_row = crease.range().end.row;
15214
15215                        if current_level < fold_at_level {
15216                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15217                        } else if current_level == fold_at_level {
15218                            to_fold.push(crease);
15219                        }
15220
15221                        start_row = nested_end_row + 1;
15222                    }
15223                    None => start_row += 1,
15224                }
15225            }
15226        }
15227
15228        self.fold_creases(to_fold, true, window, cx);
15229    }
15230
15231    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15232        if self.buffer.read(cx).is_singleton() {
15233            let mut fold_ranges = Vec::new();
15234            let snapshot = self.buffer.read(cx).snapshot(cx);
15235
15236            for row in 0..snapshot.max_row().0 {
15237                if let Some(foldable_range) = self
15238                    .snapshot(window, cx)
15239                    .crease_for_buffer_row(MultiBufferRow(row))
15240                {
15241                    fold_ranges.push(foldable_range);
15242                }
15243            }
15244
15245            self.fold_creases(fold_ranges, true, window, cx);
15246        } else {
15247            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15248                editor
15249                    .update_in(cx, |editor, _, cx| {
15250                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15251                            editor.fold_buffer(buffer_id, cx);
15252                        }
15253                    })
15254                    .ok();
15255            });
15256        }
15257    }
15258
15259    pub fn fold_function_bodies(
15260        &mut self,
15261        _: &actions::FoldFunctionBodies,
15262        window: &mut Window,
15263        cx: &mut Context<Self>,
15264    ) {
15265        let snapshot = self.buffer.read(cx).snapshot(cx);
15266
15267        let ranges = snapshot
15268            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15269            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15270            .collect::<Vec<_>>();
15271
15272        let creases = ranges
15273            .into_iter()
15274            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15275            .collect();
15276
15277        self.fold_creases(creases, true, window, cx);
15278    }
15279
15280    pub fn fold_recursive(
15281        &mut self,
15282        _: &actions::FoldRecursive,
15283        window: &mut Window,
15284        cx: &mut Context<Self>,
15285    ) {
15286        let mut to_fold = Vec::new();
15287        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15288        let selections = self.selections.all_adjusted(cx);
15289
15290        for selection in selections {
15291            let range = selection.range().sorted();
15292            let buffer_start_row = range.start.row;
15293
15294            if range.start.row != range.end.row {
15295                let mut found = false;
15296                for row in range.start.row..=range.end.row {
15297                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15298                        found = true;
15299                        to_fold.push(crease);
15300                    }
15301                }
15302                if found {
15303                    continue;
15304                }
15305            }
15306
15307            for row in (0..=range.start.row).rev() {
15308                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15309                    if crease.range().end.row >= buffer_start_row {
15310                        to_fold.push(crease);
15311                    } else {
15312                        break;
15313                    }
15314                }
15315            }
15316        }
15317
15318        self.fold_creases(to_fold, true, window, cx);
15319    }
15320
15321    pub fn fold_at(
15322        &mut self,
15323        buffer_row: MultiBufferRow,
15324        window: &mut Window,
15325        cx: &mut Context<Self>,
15326    ) {
15327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15328
15329        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15330            let autoscroll = self
15331                .selections
15332                .all::<Point>(cx)
15333                .iter()
15334                .any(|selection| crease.range().overlaps(&selection.range()));
15335
15336            self.fold_creases(vec![crease], autoscroll, window, cx);
15337        }
15338    }
15339
15340    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15341        if self.is_singleton(cx) {
15342            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15343            let buffer = &display_map.buffer_snapshot;
15344            let selections = self.selections.all::<Point>(cx);
15345            let ranges = selections
15346                .iter()
15347                .map(|s| {
15348                    let range = s.display_range(&display_map).sorted();
15349                    let mut start = range.start.to_point(&display_map);
15350                    let mut end = range.end.to_point(&display_map);
15351                    start.column = 0;
15352                    end.column = buffer.line_len(MultiBufferRow(end.row));
15353                    start..end
15354                })
15355                .collect::<Vec<_>>();
15356
15357            self.unfold_ranges(&ranges, true, true, cx);
15358        } else {
15359            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15360            let buffer_ids = self
15361                .selections
15362                .disjoint_anchor_ranges()
15363                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15364                .collect::<HashSet<_>>();
15365            for buffer_id in buffer_ids {
15366                self.unfold_buffer(buffer_id, cx);
15367            }
15368        }
15369    }
15370
15371    pub fn unfold_recursive(
15372        &mut self,
15373        _: &UnfoldRecursive,
15374        _window: &mut Window,
15375        cx: &mut Context<Self>,
15376    ) {
15377        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15378        let selections = self.selections.all::<Point>(cx);
15379        let ranges = selections
15380            .iter()
15381            .map(|s| {
15382                let mut range = s.display_range(&display_map).sorted();
15383                *range.start.column_mut() = 0;
15384                *range.end.column_mut() = display_map.line_len(range.end.row());
15385                let start = range.start.to_point(&display_map);
15386                let end = range.end.to_point(&display_map);
15387                start..end
15388            })
15389            .collect::<Vec<_>>();
15390
15391        self.unfold_ranges(&ranges, true, true, cx);
15392    }
15393
15394    pub fn unfold_at(
15395        &mut self,
15396        buffer_row: MultiBufferRow,
15397        _window: &mut Window,
15398        cx: &mut Context<Self>,
15399    ) {
15400        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15401
15402        let intersection_range = Point::new(buffer_row.0, 0)
15403            ..Point::new(
15404                buffer_row.0,
15405                display_map.buffer_snapshot.line_len(buffer_row),
15406            );
15407
15408        let autoscroll = self
15409            .selections
15410            .all::<Point>(cx)
15411            .iter()
15412            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15413
15414        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15415    }
15416
15417    pub fn unfold_all(
15418        &mut self,
15419        _: &actions::UnfoldAll,
15420        _window: &mut Window,
15421        cx: &mut Context<Self>,
15422    ) {
15423        if self.buffer.read(cx).is_singleton() {
15424            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15425            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15426        } else {
15427            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15428                editor
15429                    .update(cx, |editor, cx| {
15430                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15431                            editor.unfold_buffer(buffer_id, cx);
15432                        }
15433                    })
15434                    .ok();
15435            });
15436        }
15437    }
15438
15439    pub fn fold_selected_ranges(
15440        &mut self,
15441        _: &FoldSelectedRanges,
15442        window: &mut Window,
15443        cx: &mut Context<Self>,
15444    ) {
15445        let selections = self.selections.all_adjusted(cx);
15446        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15447        let ranges = selections
15448            .into_iter()
15449            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15450            .collect::<Vec<_>>();
15451        self.fold_creases(ranges, true, window, cx);
15452    }
15453
15454    pub fn fold_ranges<T: ToOffset + Clone>(
15455        &mut self,
15456        ranges: Vec<Range<T>>,
15457        auto_scroll: bool,
15458        window: &mut Window,
15459        cx: &mut Context<Self>,
15460    ) {
15461        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15462        let ranges = ranges
15463            .into_iter()
15464            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
15465            .collect::<Vec<_>>();
15466        self.fold_creases(ranges, auto_scroll, window, cx);
15467    }
15468
15469    pub fn fold_creases<T: ToOffset + Clone>(
15470        &mut self,
15471        creases: Vec<Crease<T>>,
15472        auto_scroll: bool,
15473        _window: &mut Window,
15474        cx: &mut Context<Self>,
15475    ) {
15476        if creases.is_empty() {
15477            return;
15478        }
15479
15480        let mut buffers_affected = HashSet::default();
15481        let multi_buffer = self.buffer().read(cx);
15482        for crease in &creases {
15483            if let Some((_, buffer, _)) =
15484                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
15485            {
15486                buffers_affected.insert(buffer.read(cx).remote_id());
15487            };
15488        }
15489
15490        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
15491
15492        if auto_scroll {
15493            self.request_autoscroll(Autoscroll::fit(), cx);
15494        }
15495
15496        cx.notify();
15497
15498        self.scrollbar_marker_state.dirty = true;
15499        self.folds_did_change(cx);
15500    }
15501
15502    /// Removes any folds whose ranges intersect any of the given ranges.
15503    pub fn unfold_ranges<T: ToOffset + Clone>(
15504        &mut self,
15505        ranges: &[Range<T>],
15506        inclusive: bool,
15507        auto_scroll: bool,
15508        cx: &mut Context<Self>,
15509    ) {
15510        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
15511            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
15512        });
15513        self.folds_did_change(cx);
15514    }
15515
15516    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15517        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
15518            return;
15519        }
15520        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
15521        self.display_map.update(cx, |display_map, cx| {
15522            display_map.fold_buffers([buffer_id], cx)
15523        });
15524        cx.emit(EditorEvent::BufferFoldToggled {
15525            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
15526            folded: true,
15527        });
15528        cx.notify();
15529    }
15530
15531    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15532        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
15533            return;
15534        }
15535        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
15536        self.display_map.update(cx, |display_map, cx| {
15537            display_map.unfold_buffers([buffer_id], cx);
15538        });
15539        cx.emit(EditorEvent::BufferFoldToggled {
15540            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
15541            folded: false,
15542        });
15543        cx.notify();
15544    }
15545
15546    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
15547        self.display_map.read(cx).is_buffer_folded(buffer)
15548    }
15549
15550    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
15551        self.display_map.read(cx).folded_buffers()
15552    }
15553
15554    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15555        self.display_map.update(cx, |display_map, cx| {
15556            display_map.disable_header_for_buffer(buffer_id, cx);
15557        });
15558        cx.notify();
15559    }
15560
15561    /// Removes any folds with the given ranges.
15562    pub fn remove_folds_with_type<T: ToOffset + Clone>(
15563        &mut self,
15564        ranges: &[Range<T>],
15565        type_id: TypeId,
15566        auto_scroll: bool,
15567        cx: &mut Context<Self>,
15568    ) {
15569        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
15570            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
15571        });
15572        self.folds_did_change(cx);
15573    }
15574
15575    fn remove_folds_with<T: ToOffset + Clone>(
15576        &mut self,
15577        ranges: &[Range<T>],
15578        auto_scroll: bool,
15579        cx: &mut Context<Self>,
15580        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
15581    ) {
15582        if ranges.is_empty() {
15583            return;
15584        }
15585
15586        let mut buffers_affected = HashSet::default();
15587        let multi_buffer = self.buffer().read(cx);
15588        for range in ranges {
15589            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
15590                buffers_affected.insert(buffer.read(cx).remote_id());
15591            };
15592        }
15593
15594        self.display_map.update(cx, update);
15595
15596        if auto_scroll {
15597            self.request_autoscroll(Autoscroll::fit(), cx);
15598        }
15599
15600        cx.notify();
15601        self.scrollbar_marker_state.dirty = true;
15602        self.active_indent_guides_state.dirty = true;
15603    }
15604
15605    pub fn update_fold_widths(
15606        &mut self,
15607        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
15608        cx: &mut Context<Self>,
15609    ) -> bool {
15610        self.display_map
15611            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
15612    }
15613
15614    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
15615        self.display_map.read(cx).fold_placeholder.clone()
15616    }
15617
15618    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
15619        self.buffer.update(cx, |buffer, cx| {
15620            buffer.set_all_diff_hunks_expanded(cx);
15621        });
15622    }
15623
15624    pub fn expand_all_diff_hunks(
15625        &mut self,
15626        _: &ExpandAllDiffHunks,
15627        _window: &mut Window,
15628        cx: &mut Context<Self>,
15629    ) {
15630        self.buffer.update(cx, |buffer, cx| {
15631            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
15632        });
15633    }
15634
15635    pub fn toggle_selected_diff_hunks(
15636        &mut self,
15637        _: &ToggleSelectedDiffHunks,
15638        _window: &mut Window,
15639        cx: &mut Context<Self>,
15640    ) {
15641        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
15642        self.toggle_diff_hunks_in_ranges(ranges, cx);
15643    }
15644
15645    pub fn diff_hunks_in_ranges<'a>(
15646        &'a self,
15647        ranges: &'a [Range<Anchor>],
15648        buffer: &'a MultiBufferSnapshot,
15649    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
15650        ranges.iter().flat_map(move |range| {
15651            let end_excerpt_id = range.end.excerpt_id;
15652            let range = range.to_point(buffer);
15653            let mut peek_end = range.end;
15654            if range.end.row < buffer.max_row().0 {
15655                peek_end = Point::new(range.end.row + 1, 0);
15656            }
15657            buffer
15658                .diff_hunks_in_range(range.start..peek_end)
15659                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
15660        })
15661    }
15662
15663    pub fn has_stageable_diff_hunks_in_ranges(
15664        &self,
15665        ranges: &[Range<Anchor>],
15666        snapshot: &MultiBufferSnapshot,
15667    ) -> bool {
15668        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
15669        hunks.any(|hunk| hunk.status().has_secondary_hunk())
15670    }
15671
15672    pub fn toggle_staged_selected_diff_hunks(
15673        &mut self,
15674        _: &::git::ToggleStaged,
15675        _: &mut Window,
15676        cx: &mut Context<Self>,
15677    ) {
15678        let snapshot = self.buffer.read(cx).snapshot(cx);
15679        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
15680        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
15681        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
15682    }
15683
15684    pub fn set_render_diff_hunk_controls(
15685        &mut self,
15686        render_diff_hunk_controls: RenderDiffHunkControlsFn,
15687        cx: &mut Context<Self>,
15688    ) {
15689        self.render_diff_hunk_controls = render_diff_hunk_controls;
15690        cx.notify();
15691    }
15692
15693    pub fn stage_and_next(
15694        &mut self,
15695        _: &::git::StageAndNext,
15696        window: &mut Window,
15697        cx: &mut Context<Self>,
15698    ) {
15699        self.do_stage_or_unstage_and_next(true, window, cx);
15700    }
15701
15702    pub fn unstage_and_next(
15703        &mut self,
15704        _: &::git::UnstageAndNext,
15705        window: &mut Window,
15706        cx: &mut Context<Self>,
15707    ) {
15708        self.do_stage_or_unstage_and_next(false, window, cx);
15709    }
15710
15711    pub fn stage_or_unstage_diff_hunks(
15712        &mut self,
15713        stage: bool,
15714        ranges: Vec<Range<Anchor>>,
15715        cx: &mut Context<Self>,
15716    ) {
15717        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
15718        cx.spawn(async move |this, cx| {
15719            task.await?;
15720            this.update(cx, |this, cx| {
15721                let snapshot = this.buffer.read(cx).snapshot(cx);
15722                let chunk_by = this
15723                    .diff_hunks_in_ranges(&ranges, &snapshot)
15724                    .chunk_by(|hunk| hunk.buffer_id);
15725                for (buffer_id, hunks) in &chunk_by {
15726                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
15727                }
15728            })
15729        })
15730        .detach_and_log_err(cx);
15731    }
15732
15733    fn save_buffers_for_ranges_if_needed(
15734        &mut self,
15735        ranges: &[Range<Anchor>],
15736        cx: &mut Context<Editor>,
15737    ) -> Task<Result<()>> {
15738        let multibuffer = self.buffer.read(cx);
15739        let snapshot = multibuffer.read(cx);
15740        let buffer_ids: HashSet<_> = ranges
15741            .iter()
15742            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
15743            .collect();
15744        drop(snapshot);
15745
15746        let mut buffers = HashSet::default();
15747        for buffer_id in buffer_ids {
15748            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
15749                let buffer = buffer_entity.read(cx);
15750                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
15751                {
15752                    buffers.insert(buffer_entity);
15753                }
15754            }
15755        }
15756
15757        if let Some(project) = &self.project {
15758            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
15759        } else {
15760            Task::ready(Ok(()))
15761        }
15762    }
15763
15764    fn do_stage_or_unstage_and_next(
15765        &mut self,
15766        stage: bool,
15767        window: &mut Window,
15768        cx: &mut Context<Self>,
15769    ) {
15770        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
15771
15772        if ranges.iter().any(|range| range.start != range.end) {
15773            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
15774            return;
15775        }
15776
15777        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
15778        let snapshot = self.snapshot(window, cx);
15779        let position = self.selections.newest::<Point>(cx).head();
15780        let mut row = snapshot
15781            .buffer_snapshot
15782            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15783            .find(|hunk| hunk.row_range.start.0 > position.row)
15784            .map(|hunk| hunk.row_range.start);
15785
15786        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
15787        // Outside of the project diff editor, wrap around to the beginning.
15788        if !all_diff_hunks_expanded {
15789            row = row.or_else(|| {
15790                snapshot
15791                    .buffer_snapshot
15792                    .diff_hunks_in_range(Point::zero()..position)
15793                    .find(|hunk| hunk.row_range.end.0 < position.row)
15794                    .map(|hunk| hunk.row_range.start)
15795            });
15796        }
15797
15798        if let Some(row) = row {
15799            let destination = Point::new(row.0, 0);
15800            let autoscroll = Autoscroll::center();
15801
15802            self.unfold_ranges(&[destination..destination], false, false, cx);
15803            self.change_selections(Some(autoscroll), window, cx, |s| {
15804                s.select_ranges([destination..destination]);
15805            });
15806        }
15807    }
15808
15809    fn do_stage_or_unstage(
15810        &self,
15811        stage: bool,
15812        buffer_id: BufferId,
15813        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
15814        cx: &mut App,
15815    ) -> Option<()> {
15816        let project = self.project.as_ref()?;
15817        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
15818        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
15819        let buffer_snapshot = buffer.read(cx).snapshot();
15820        let file_exists = buffer_snapshot
15821            .file()
15822            .is_some_and(|file| file.disk_state().exists());
15823        diff.update(cx, |diff, cx| {
15824            diff.stage_or_unstage_hunks(
15825                stage,
15826                &hunks
15827                    .map(|hunk| buffer_diff::DiffHunk {
15828                        buffer_range: hunk.buffer_range,
15829                        diff_base_byte_range: hunk.diff_base_byte_range,
15830                        secondary_status: hunk.secondary_status,
15831                        range: Point::zero()..Point::zero(), // unused
15832                    })
15833                    .collect::<Vec<_>>(),
15834                &buffer_snapshot,
15835                file_exists,
15836                cx,
15837            )
15838        });
15839        None
15840    }
15841
15842    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
15843        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
15844        self.buffer
15845            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
15846    }
15847
15848    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
15849        self.buffer.update(cx, |buffer, cx| {
15850            let ranges = vec![Anchor::min()..Anchor::max()];
15851            if !buffer.all_diff_hunks_expanded()
15852                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
15853            {
15854                buffer.collapse_diff_hunks(ranges, cx);
15855                true
15856            } else {
15857                false
15858            }
15859        })
15860    }
15861
15862    fn toggle_diff_hunks_in_ranges(
15863        &mut self,
15864        ranges: Vec<Range<Anchor>>,
15865        cx: &mut Context<Editor>,
15866    ) {
15867        self.buffer.update(cx, |buffer, cx| {
15868            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
15869            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
15870        })
15871    }
15872
15873    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
15874        self.buffer.update(cx, |buffer, cx| {
15875            let snapshot = buffer.snapshot(cx);
15876            let excerpt_id = range.end.excerpt_id;
15877            let point_range = range.to_point(&snapshot);
15878            let expand = !buffer.single_hunk_is_expanded(range, cx);
15879            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
15880        })
15881    }
15882
15883    pub(crate) fn apply_all_diff_hunks(
15884        &mut self,
15885        _: &ApplyAllDiffHunks,
15886        window: &mut Window,
15887        cx: &mut Context<Self>,
15888    ) {
15889        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15890
15891        let buffers = self.buffer.read(cx).all_buffers();
15892        for branch_buffer in buffers {
15893            branch_buffer.update(cx, |branch_buffer, cx| {
15894                branch_buffer.merge_into_base(Vec::new(), cx);
15895            });
15896        }
15897
15898        if let Some(project) = self.project.clone() {
15899            self.save(true, project, window, cx).detach_and_log_err(cx);
15900        }
15901    }
15902
15903    pub(crate) fn apply_selected_diff_hunks(
15904        &mut self,
15905        _: &ApplyDiffHunk,
15906        window: &mut Window,
15907        cx: &mut Context<Self>,
15908    ) {
15909        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15910        let snapshot = self.snapshot(window, cx);
15911        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
15912        let mut ranges_by_buffer = HashMap::default();
15913        self.transact(window, cx, |editor, _window, cx| {
15914            for hunk in hunks {
15915                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
15916                    ranges_by_buffer
15917                        .entry(buffer.clone())
15918                        .or_insert_with(Vec::new)
15919                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
15920                }
15921            }
15922
15923            for (buffer, ranges) in ranges_by_buffer {
15924                buffer.update(cx, |buffer, cx| {
15925                    buffer.merge_into_base(ranges, cx);
15926                });
15927            }
15928        });
15929
15930        if let Some(project) = self.project.clone() {
15931            self.save(true, project, window, cx).detach_and_log_err(cx);
15932        }
15933    }
15934
15935    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
15936        if hovered != self.gutter_hovered {
15937            self.gutter_hovered = hovered;
15938            cx.notify();
15939        }
15940    }
15941
15942    pub fn insert_blocks(
15943        &mut self,
15944        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
15945        autoscroll: Option<Autoscroll>,
15946        cx: &mut Context<Self>,
15947    ) -> Vec<CustomBlockId> {
15948        let blocks = self
15949            .display_map
15950            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
15951        if let Some(autoscroll) = autoscroll {
15952            self.request_autoscroll(autoscroll, cx);
15953        }
15954        cx.notify();
15955        blocks
15956    }
15957
15958    pub fn resize_blocks(
15959        &mut self,
15960        heights: HashMap<CustomBlockId, u32>,
15961        autoscroll: Option<Autoscroll>,
15962        cx: &mut Context<Self>,
15963    ) {
15964        self.display_map
15965            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
15966        if let Some(autoscroll) = autoscroll {
15967            self.request_autoscroll(autoscroll, cx);
15968        }
15969        cx.notify();
15970    }
15971
15972    pub fn replace_blocks(
15973        &mut self,
15974        renderers: HashMap<CustomBlockId, RenderBlock>,
15975        autoscroll: Option<Autoscroll>,
15976        cx: &mut Context<Self>,
15977    ) {
15978        self.display_map
15979            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
15980        if let Some(autoscroll) = autoscroll {
15981            self.request_autoscroll(autoscroll, cx);
15982        }
15983        cx.notify();
15984    }
15985
15986    pub fn remove_blocks(
15987        &mut self,
15988        block_ids: HashSet<CustomBlockId>,
15989        autoscroll: Option<Autoscroll>,
15990        cx: &mut Context<Self>,
15991    ) {
15992        self.display_map.update(cx, |display_map, cx| {
15993            display_map.remove_blocks(block_ids, cx)
15994        });
15995        if let Some(autoscroll) = autoscroll {
15996            self.request_autoscroll(autoscroll, cx);
15997        }
15998        cx.notify();
15999    }
16000
16001    pub fn row_for_block(
16002        &self,
16003        block_id: CustomBlockId,
16004        cx: &mut Context<Self>,
16005    ) -> Option<DisplayRow> {
16006        self.display_map
16007            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16008    }
16009
16010    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16011        self.focused_block = Some(focused_block);
16012    }
16013
16014    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16015        self.focused_block.take()
16016    }
16017
16018    pub fn insert_creases(
16019        &mut self,
16020        creases: impl IntoIterator<Item = Crease<Anchor>>,
16021        cx: &mut Context<Self>,
16022    ) -> Vec<CreaseId> {
16023        self.display_map
16024            .update(cx, |map, cx| map.insert_creases(creases, cx))
16025    }
16026
16027    pub fn remove_creases(
16028        &mut self,
16029        ids: impl IntoIterator<Item = CreaseId>,
16030        cx: &mut Context<Self>,
16031    ) {
16032        self.display_map
16033            .update(cx, |map, cx| map.remove_creases(ids, cx));
16034    }
16035
16036    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16037        self.display_map
16038            .update(cx, |map, cx| map.snapshot(cx))
16039            .longest_row()
16040    }
16041
16042    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16043        self.display_map
16044            .update(cx, |map, cx| map.snapshot(cx))
16045            .max_point()
16046    }
16047
16048    pub fn text(&self, cx: &App) -> String {
16049        self.buffer.read(cx).read(cx).text()
16050    }
16051
16052    pub fn is_empty(&self, cx: &App) -> bool {
16053        self.buffer.read(cx).read(cx).is_empty()
16054    }
16055
16056    pub fn text_option(&self, cx: &App) -> Option<String> {
16057        let text = self.text(cx);
16058        let text = text.trim();
16059
16060        if text.is_empty() {
16061            return None;
16062        }
16063
16064        Some(text.to_string())
16065    }
16066
16067    pub fn set_text(
16068        &mut self,
16069        text: impl Into<Arc<str>>,
16070        window: &mut Window,
16071        cx: &mut Context<Self>,
16072    ) {
16073        self.transact(window, cx, |this, _, cx| {
16074            this.buffer
16075                .read(cx)
16076                .as_singleton()
16077                .expect("you can only call set_text on editors for singleton buffers")
16078                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16079        });
16080    }
16081
16082    pub fn display_text(&self, cx: &mut App) -> String {
16083        self.display_map
16084            .update(cx, |map, cx| map.snapshot(cx))
16085            .text()
16086    }
16087
16088    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16089        let mut wrap_guides = smallvec::smallvec![];
16090
16091        if self.show_wrap_guides == Some(false) {
16092            return wrap_guides;
16093        }
16094
16095        let settings = self.buffer.read(cx).language_settings(cx);
16096        if settings.show_wrap_guides {
16097            match self.soft_wrap_mode(cx) {
16098                SoftWrap::Column(soft_wrap) => {
16099                    wrap_guides.push((soft_wrap as usize, true));
16100                }
16101                SoftWrap::Bounded(soft_wrap) => {
16102                    wrap_guides.push((soft_wrap as usize, true));
16103                }
16104                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16105            }
16106            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16107        }
16108
16109        wrap_guides
16110    }
16111
16112    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16113        let settings = self.buffer.read(cx).language_settings(cx);
16114        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16115        match mode {
16116            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16117                SoftWrap::None
16118            }
16119            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16120            language_settings::SoftWrap::PreferredLineLength => {
16121                SoftWrap::Column(settings.preferred_line_length)
16122            }
16123            language_settings::SoftWrap::Bounded => {
16124                SoftWrap::Bounded(settings.preferred_line_length)
16125            }
16126        }
16127    }
16128
16129    pub fn set_soft_wrap_mode(
16130        &mut self,
16131        mode: language_settings::SoftWrap,
16132
16133        cx: &mut Context<Self>,
16134    ) {
16135        self.soft_wrap_mode_override = Some(mode);
16136        cx.notify();
16137    }
16138
16139    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16140        self.hard_wrap = hard_wrap;
16141        cx.notify();
16142    }
16143
16144    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16145        self.text_style_refinement = Some(style);
16146    }
16147
16148    /// called by the Element so we know what style we were most recently rendered with.
16149    pub(crate) fn set_style(
16150        &mut self,
16151        style: EditorStyle,
16152        window: &mut Window,
16153        cx: &mut Context<Self>,
16154    ) {
16155        let rem_size = window.rem_size();
16156        self.display_map.update(cx, |map, cx| {
16157            map.set_font(
16158                style.text.font(),
16159                style.text.font_size.to_pixels(rem_size),
16160                cx,
16161            )
16162        });
16163        self.style = Some(style);
16164    }
16165
16166    pub fn style(&self) -> Option<&EditorStyle> {
16167        self.style.as_ref()
16168    }
16169
16170    // Called by the element. This method is not designed to be called outside of the editor
16171    // element's layout code because it does not notify when rewrapping is computed synchronously.
16172    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16173        self.display_map
16174            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16175    }
16176
16177    pub fn set_soft_wrap(&mut self) {
16178        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16179    }
16180
16181    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16182        if self.soft_wrap_mode_override.is_some() {
16183            self.soft_wrap_mode_override.take();
16184        } else {
16185            let soft_wrap = match self.soft_wrap_mode(cx) {
16186                SoftWrap::GitDiff => return,
16187                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16188                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16189                    language_settings::SoftWrap::None
16190                }
16191            };
16192            self.soft_wrap_mode_override = Some(soft_wrap);
16193        }
16194        cx.notify();
16195    }
16196
16197    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16198        let Some(workspace) = self.workspace() else {
16199            return;
16200        };
16201        let fs = workspace.read(cx).app_state().fs.clone();
16202        let current_show = TabBarSettings::get_global(cx).show;
16203        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16204            setting.show = Some(!current_show);
16205        });
16206    }
16207
16208    pub fn toggle_indent_guides(
16209        &mut self,
16210        _: &ToggleIndentGuides,
16211        _: &mut Window,
16212        cx: &mut Context<Self>,
16213    ) {
16214        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16215            self.buffer
16216                .read(cx)
16217                .language_settings(cx)
16218                .indent_guides
16219                .enabled
16220        });
16221        self.show_indent_guides = Some(!currently_enabled);
16222        cx.notify();
16223    }
16224
16225    fn should_show_indent_guides(&self) -> Option<bool> {
16226        self.show_indent_guides
16227    }
16228
16229    pub fn toggle_line_numbers(
16230        &mut self,
16231        _: &ToggleLineNumbers,
16232        _: &mut Window,
16233        cx: &mut Context<Self>,
16234    ) {
16235        let mut editor_settings = EditorSettings::get_global(cx).clone();
16236        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16237        EditorSettings::override_global(editor_settings, cx);
16238    }
16239
16240    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16241        if let Some(show_line_numbers) = self.show_line_numbers {
16242            return show_line_numbers;
16243        }
16244        EditorSettings::get_global(cx).gutter.line_numbers
16245    }
16246
16247    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16248        self.use_relative_line_numbers
16249            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16250    }
16251
16252    pub fn toggle_relative_line_numbers(
16253        &mut self,
16254        _: &ToggleRelativeLineNumbers,
16255        _: &mut Window,
16256        cx: &mut Context<Self>,
16257    ) {
16258        let is_relative = self.should_use_relative_line_numbers(cx);
16259        self.set_relative_line_number(Some(!is_relative), cx)
16260    }
16261
16262    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16263        self.use_relative_line_numbers = is_relative;
16264        cx.notify();
16265    }
16266
16267    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16268        self.show_gutter = show_gutter;
16269        cx.notify();
16270    }
16271
16272    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16273        self.show_scrollbars = show_scrollbars;
16274        cx.notify();
16275    }
16276
16277    pub fn disable_scrolling(&mut self, cx: &mut Context<Self>) {
16278        self.disable_scrolling = true;
16279        cx.notify();
16280    }
16281
16282    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16283        self.show_line_numbers = Some(show_line_numbers);
16284        cx.notify();
16285    }
16286
16287    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16288        self.disable_expand_excerpt_buttons = true;
16289        cx.notify();
16290    }
16291
16292    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16293        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16294        cx.notify();
16295    }
16296
16297    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16298        self.show_code_actions = Some(show_code_actions);
16299        cx.notify();
16300    }
16301
16302    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16303        self.show_runnables = Some(show_runnables);
16304        cx.notify();
16305    }
16306
16307    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16308        self.show_breakpoints = Some(show_breakpoints);
16309        cx.notify();
16310    }
16311
16312    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16313        if self.display_map.read(cx).masked != masked {
16314            self.display_map.update(cx, |map, _| map.masked = masked);
16315        }
16316        cx.notify()
16317    }
16318
16319    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16320        self.show_wrap_guides = Some(show_wrap_guides);
16321        cx.notify();
16322    }
16323
16324    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16325        self.show_indent_guides = Some(show_indent_guides);
16326        cx.notify();
16327    }
16328
16329    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16330        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16331            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16332                if let Some(dir) = file.abs_path(cx).parent() {
16333                    return Some(dir.to_owned());
16334                }
16335            }
16336
16337            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16338                return Some(project_path.path.to_path_buf());
16339            }
16340        }
16341
16342        None
16343    }
16344
16345    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16346        self.active_excerpt(cx)?
16347            .1
16348            .read(cx)
16349            .file()
16350            .and_then(|f| f.as_local())
16351    }
16352
16353    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16354        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16355            let buffer = buffer.read(cx);
16356            if let Some(project_path) = buffer.project_path(cx) {
16357                let project = self.project.as_ref()?.read(cx);
16358                project.absolute_path(&project_path, cx)
16359            } else {
16360                buffer
16361                    .file()
16362                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16363            }
16364        })
16365    }
16366
16367    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16368        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16369            let project_path = buffer.read(cx).project_path(cx)?;
16370            let project = self.project.as_ref()?.read(cx);
16371            let entry = project.entry_for_path(&project_path, cx)?;
16372            let path = entry.path.to_path_buf();
16373            Some(path)
16374        })
16375    }
16376
16377    pub fn reveal_in_finder(
16378        &mut self,
16379        _: &RevealInFileManager,
16380        _window: &mut Window,
16381        cx: &mut Context<Self>,
16382    ) {
16383        if let Some(target) = self.target_file(cx) {
16384            cx.reveal_path(&target.abs_path(cx));
16385        }
16386    }
16387
16388    pub fn copy_path(
16389        &mut self,
16390        _: &zed_actions::workspace::CopyPath,
16391        _window: &mut Window,
16392        cx: &mut Context<Self>,
16393    ) {
16394        if let Some(path) = self.target_file_abs_path(cx) {
16395            if let Some(path) = path.to_str() {
16396                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16397            }
16398        }
16399    }
16400
16401    pub fn copy_relative_path(
16402        &mut self,
16403        _: &zed_actions::workspace::CopyRelativePath,
16404        _window: &mut Window,
16405        cx: &mut Context<Self>,
16406    ) {
16407        if let Some(path) = self.target_file_path(cx) {
16408            if let Some(path) = path.to_str() {
16409                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16410            }
16411        }
16412    }
16413
16414    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
16415        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
16416            buffer.read(cx).project_path(cx)
16417        } else {
16418            None
16419        }
16420    }
16421
16422    // Returns true if the editor handled a go-to-line request
16423    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
16424        maybe!({
16425            let breakpoint_store = self.breakpoint_store.as_ref()?;
16426
16427            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
16428            else {
16429                self.clear_row_highlights::<DebugCurrentRowHighlight>();
16430                return None;
16431            };
16432
16433            let position = active_stack_frame.position;
16434            let buffer_id = position.buffer_id?;
16435            let snapshot = self
16436                .project
16437                .as_ref()?
16438                .read(cx)
16439                .buffer_for_id(buffer_id, cx)?
16440                .read(cx)
16441                .snapshot();
16442
16443            let mut handled = false;
16444            for (id, ExcerptRange { context, .. }) in
16445                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
16446            {
16447                if context.start.cmp(&position, &snapshot).is_ge()
16448                    || context.end.cmp(&position, &snapshot).is_lt()
16449                {
16450                    continue;
16451                }
16452                let snapshot = self.buffer.read(cx).snapshot(cx);
16453                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
16454
16455                handled = true;
16456                self.clear_row_highlights::<DebugCurrentRowHighlight>();
16457                self.go_to_line::<DebugCurrentRowHighlight>(
16458                    multibuffer_anchor,
16459                    Some(cx.theme().colors().editor_debugger_active_line_background),
16460                    window,
16461                    cx,
16462                );
16463
16464                cx.notify();
16465            }
16466
16467            handled.then_some(())
16468        })
16469        .is_some()
16470    }
16471
16472    pub fn copy_file_name_without_extension(
16473        &mut self,
16474        _: &CopyFileNameWithoutExtension,
16475        _: &mut Window,
16476        cx: &mut Context<Self>,
16477    ) {
16478        if let Some(file) = self.target_file(cx) {
16479            if let Some(file_stem) = file.path().file_stem() {
16480                if let Some(name) = file_stem.to_str() {
16481                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
16482                }
16483            }
16484        }
16485    }
16486
16487    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
16488        if let Some(file) = self.target_file(cx) {
16489            if let Some(file_name) = file.path().file_name() {
16490                if let Some(name) = file_name.to_str() {
16491                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
16492                }
16493            }
16494        }
16495    }
16496
16497    pub fn toggle_git_blame(
16498        &mut self,
16499        _: &::git::Blame,
16500        window: &mut Window,
16501        cx: &mut Context<Self>,
16502    ) {
16503        self.show_git_blame_gutter = !self.show_git_blame_gutter;
16504
16505        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
16506            self.start_git_blame(true, window, cx);
16507        }
16508
16509        cx.notify();
16510    }
16511
16512    pub fn toggle_git_blame_inline(
16513        &mut self,
16514        _: &ToggleGitBlameInline,
16515        window: &mut Window,
16516        cx: &mut Context<Self>,
16517    ) {
16518        self.toggle_git_blame_inline_internal(true, window, cx);
16519        cx.notify();
16520    }
16521
16522    pub fn open_git_blame_commit(
16523        &mut self,
16524        _: &OpenGitBlameCommit,
16525        window: &mut Window,
16526        cx: &mut Context<Self>,
16527    ) {
16528        self.open_git_blame_commit_internal(window, cx);
16529    }
16530
16531    fn open_git_blame_commit_internal(
16532        &mut self,
16533        window: &mut Window,
16534        cx: &mut Context<Self>,
16535    ) -> Option<()> {
16536        let blame = self.blame.as_ref()?;
16537        let snapshot = self.snapshot(window, cx);
16538        let cursor = self.selections.newest::<Point>(cx).head();
16539        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
16540        let blame_entry = blame
16541            .update(cx, |blame, cx| {
16542                blame
16543                    .blame_for_rows(
16544                        &[RowInfo {
16545                            buffer_id: Some(buffer.remote_id()),
16546                            buffer_row: Some(point.row),
16547                            ..Default::default()
16548                        }],
16549                        cx,
16550                    )
16551                    .next()
16552            })
16553            .flatten()?;
16554        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
16555        let repo = blame.read(cx).repository(cx)?;
16556        let workspace = self.workspace()?.downgrade();
16557        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
16558        None
16559    }
16560
16561    pub fn git_blame_inline_enabled(&self) -> bool {
16562        self.git_blame_inline_enabled
16563    }
16564
16565    pub fn toggle_selection_menu(
16566        &mut self,
16567        _: &ToggleSelectionMenu,
16568        _: &mut Window,
16569        cx: &mut Context<Self>,
16570    ) {
16571        self.show_selection_menu = self
16572            .show_selection_menu
16573            .map(|show_selections_menu| !show_selections_menu)
16574            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
16575
16576        cx.notify();
16577    }
16578
16579    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
16580        self.show_selection_menu
16581            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
16582    }
16583
16584    fn start_git_blame(
16585        &mut self,
16586        user_triggered: bool,
16587        window: &mut Window,
16588        cx: &mut Context<Self>,
16589    ) {
16590        if let Some(project) = self.project.as_ref() {
16591            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
16592                return;
16593            };
16594
16595            if buffer.read(cx).file().is_none() {
16596                return;
16597            }
16598
16599            let focused = self.focus_handle(cx).contains_focused(window, cx);
16600
16601            let project = project.clone();
16602            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
16603            self.blame_subscription =
16604                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
16605            self.blame = Some(blame);
16606        }
16607    }
16608
16609    fn toggle_git_blame_inline_internal(
16610        &mut self,
16611        user_triggered: bool,
16612        window: &mut Window,
16613        cx: &mut Context<Self>,
16614    ) {
16615        if self.git_blame_inline_enabled {
16616            self.git_blame_inline_enabled = false;
16617            self.show_git_blame_inline = false;
16618            self.show_git_blame_inline_delay_task.take();
16619        } else {
16620            self.git_blame_inline_enabled = true;
16621            self.start_git_blame_inline(user_triggered, window, cx);
16622        }
16623
16624        cx.notify();
16625    }
16626
16627    fn start_git_blame_inline(
16628        &mut self,
16629        user_triggered: bool,
16630        window: &mut Window,
16631        cx: &mut Context<Self>,
16632    ) {
16633        self.start_git_blame(user_triggered, window, cx);
16634
16635        if ProjectSettings::get_global(cx)
16636            .git
16637            .inline_blame_delay()
16638            .is_some()
16639        {
16640            self.start_inline_blame_timer(window, cx);
16641        } else {
16642            self.show_git_blame_inline = true
16643        }
16644    }
16645
16646    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
16647        self.blame.as_ref()
16648    }
16649
16650    pub fn show_git_blame_gutter(&self) -> bool {
16651        self.show_git_blame_gutter
16652    }
16653
16654    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
16655        self.show_git_blame_gutter && self.has_blame_entries(cx)
16656    }
16657
16658    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
16659        self.show_git_blame_inline
16660            && (self.focus_handle.is_focused(window)
16661                || self
16662                    .git_blame_inline_tooltip
16663                    .as_ref()
16664                    .and_then(|t| t.upgrade())
16665                    .is_some())
16666            && !self.newest_selection_head_on_empty_line(cx)
16667            && self.has_blame_entries(cx)
16668    }
16669
16670    fn has_blame_entries(&self, cx: &App) -> bool {
16671        self.blame()
16672            .map_or(false, |blame| blame.read(cx).has_generated_entries())
16673    }
16674
16675    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
16676        let cursor_anchor = self.selections.newest_anchor().head();
16677
16678        let snapshot = self.buffer.read(cx).snapshot(cx);
16679        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
16680
16681        snapshot.line_len(buffer_row) == 0
16682    }
16683
16684    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
16685        let buffer_and_selection = maybe!({
16686            let selection = self.selections.newest::<Point>(cx);
16687            let selection_range = selection.range();
16688
16689            let multi_buffer = self.buffer().read(cx);
16690            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16691            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
16692
16693            let (buffer, range, _) = if selection.reversed {
16694                buffer_ranges.first()
16695            } else {
16696                buffer_ranges.last()
16697            }?;
16698
16699            let selection = text::ToPoint::to_point(&range.start, &buffer).row
16700                ..text::ToPoint::to_point(&range.end, &buffer).row;
16701            Some((
16702                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
16703                selection,
16704            ))
16705        });
16706
16707        let Some((buffer, selection)) = buffer_and_selection else {
16708            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
16709        };
16710
16711        let Some(project) = self.project.as_ref() else {
16712            return Task::ready(Err(anyhow!("editor does not have project")));
16713        };
16714
16715        project.update(cx, |project, cx| {
16716            project.get_permalink_to_line(&buffer, selection, cx)
16717        })
16718    }
16719
16720    pub fn copy_permalink_to_line(
16721        &mut self,
16722        _: &CopyPermalinkToLine,
16723        window: &mut Window,
16724        cx: &mut Context<Self>,
16725    ) {
16726        let permalink_task = self.get_permalink_to_line(cx);
16727        let workspace = self.workspace();
16728
16729        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
16730            Ok(permalink) => {
16731                cx.update(|_, cx| {
16732                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
16733                })
16734                .ok();
16735            }
16736            Err(err) => {
16737                let message = format!("Failed to copy permalink: {err}");
16738
16739                Err::<(), anyhow::Error>(err).log_err();
16740
16741                if let Some(workspace) = workspace {
16742                    workspace
16743                        .update_in(cx, |workspace, _, cx| {
16744                            struct CopyPermalinkToLine;
16745
16746                            workspace.show_toast(
16747                                Toast::new(
16748                                    NotificationId::unique::<CopyPermalinkToLine>(),
16749                                    message,
16750                                ),
16751                                cx,
16752                            )
16753                        })
16754                        .ok();
16755                }
16756            }
16757        })
16758        .detach();
16759    }
16760
16761    pub fn copy_file_location(
16762        &mut self,
16763        _: &CopyFileLocation,
16764        _: &mut Window,
16765        cx: &mut Context<Self>,
16766    ) {
16767        let selection = self.selections.newest::<Point>(cx).start.row + 1;
16768        if let Some(file) = self.target_file(cx) {
16769            if let Some(path) = file.path().to_str() {
16770                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
16771            }
16772        }
16773    }
16774
16775    pub fn open_permalink_to_line(
16776        &mut self,
16777        _: &OpenPermalinkToLine,
16778        window: &mut Window,
16779        cx: &mut Context<Self>,
16780    ) {
16781        let permalink_task = self.get_permalink_to_line(cx);
16782        let workspace = self.workspace();
16783
16784        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
16785            Ok(permalink) => {
16786                cx.update(|_, cx| {
16787                    cx.open_url(permalink.as_ref());
16788                })
16789                .ok();
16790            }
16791            Err(err) => {
16792                let message = format!("Failed to open permalink: {err}");
16793
16794                Err::<(), anyhow::Error>(err).log_err();
16795
16796                if let Some(workspace) = workspace {
16797                    workspace
16798                        .update(cx, |workspace, cx| {
16799                            struct OpenPermalinkToLine;
16800
16801                            workspace.show_toast(
16802                                Toast::new(
16803                                    NotificationId::unique::<OpenPermalinkToLine>(),
16804                                    message,
16805                                ),
16806                                cx,
16807                            )
16808                        })
16809                        .ok();
16810                }
16811            }
16812        })
16813        .detach();
16814    }
16815
16816    pub fn insert_uuid_v4(
16817        &mut self,
16818        _: &InsertUuidV4,
16819        window: &mut Window,
16820        cx: &mut Context<Self>,
16821    ) {
16822        self.insert_uuid(UuidVersion::V4, window, cx);
16823    }
16824
16825    pub fn insert_uuid_v7(
16826        &mut self,
16827        _: &InsertUuidV7,
16828        window: &mut Window,
16829        cx: &mut Context<Self>,
16830    ) {
16831        self.insert_uuid(UuidVersion::V7, window, cx);
16832    }
16833
16834    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
16835        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16836        self.transact(window, cx, |this, window, cx| {
16837            let edits = this
16838                .selections
16839                .all::<Point>(cx)
16840                .into_iter()
16841                .map(|selection| {
16842                    let uuid = match version {
16843                        UuidVersion::V4 => uuid::Uuid::new_v4(),
16844                        UuidVersion::V7 => uuid::Uuid::now_v7(),
16845                    };
16846
16847                    (selection.range(), uuid.to_string())
16848                });
16849            this.edit(edits, cx);
16850            this.refresh_inline_completion(true, false, window, cx);
16851        });
16852    }
16853
16854    pub fn open_selections_in_multibuffer(
16855        &mut self,
16856        _: &OpenSelectionsInMultibuffer,
16857        window: &mut Window,
16858        cx: &mut Context<Self>,
16859    ) {
16860        let multibuffer = self.buffer.read(cx);
16861
16862        let Some(buffer) = multibuffer.as_singleton() else {
16863            return;
16864        };
16865
16866        let Some(workspace) = self.workspace() else {
16867            return;
16868        };
16869
16870        let locations = self
16871            .selections
16872            .disjoint_anchors()
16873            .iter()
16874            .map(|range| Location {
16875                buffer: buffer.clone(),
16876                range: range.start.text_anchor..range.end.text_anchor,
16877            })
16878            .collect::<Vec<_>>();
16879
16880        let title = multibuffer.title(cx).to_string();
16881
16882        cx.spawn_in(window, async move |_, cx| {
16883            workspace.update_in(cx, |workspace, window, cx| {
16884                Self::open_locations_in_multibuffer(
16885                    workspace,
16886                    locations,
16887                    format!("Selections for '{title}'"),
16888                    false,
16889                    MultibufferSelectionMode::All,
16890                    window,
16891                    cx,
16892                );
16893            })
16894        })
16895        .detach();
16896    }
16897
16898    /// Adds a row highlight for the given range. If a row has multiple highlights, the
16899    /// last highlight added will be used.
16900    ///
16901    /// If the range ends at the beginning of a line, then that line will not be highlighted.
16902    pub fn highlight_rows<T: 'static>(
16903        &mut self,
16904        range: Range<Anchor>,
16905        color: Hsla,
16906        options: RowHighlightOptions,
16907        cx: &mut Context<Self>,
16908    ) {
16909        let snapshot = self.buffer().read(cx).snapshot(cx);
16910        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
16911        let ix = row_highlights.binary_search_by(|highlight| {
16912            Ordering::Equal
16913                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
16914                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
16915        });
16916
16917        if let Err(mut ix) = ix {
16918            let index = post_inc(&mut self.highlight_order);
16919
16920            // If this range intersects with the preceding highlight, then merge it with
16921            // the preceding highlight. Otherwise insert a new highlight.
16922            let mut merged = false;
16923            if ix > 0 {
16924                let prev_highlight = &mut row_highlights[ix - 1];
16925                if prev_highlight
16926                    .range
16927                    .end
16928                    .cmp(&range.start, &snapshot)
16929                    .is_ge()
16930                {
16931                    ix -= 1;
16932                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
16933                        prev_highlight.range.end = range.end;
16934                    }
16935                    merged = true;
16936                    prev_highlight.index = index;
16937                    prev_highlight.color = color;
16938                    prev_highlight.options = options;
16939                }
16940            }
16941
16942            if !merged {
16943                row_highlights.insert(
16944                    ix,
16945                    RowHighlight {
16946                        range: range.clone(),
16947                        index,
16948                        color,
16949                        options,
16950                        type_id: TypeId::of::<T>(),
16951                    },
16952                );
16953            }
16954
16955            // If any of the following highlights intersect with this one, merge them.
16956            while let Some(next_highlight) = row_highlights.get(ix + 1) {
16957                let highlight = &row_highlights[ix];
16958                if next_highlight
16959                    .range
16960                    .start
16961                    .cmp(&highlight.range.end, &snapshot)
16962                    .is_le()
16963                {
16964                    if next_highlight
16965                        .range
16966                        .end
16967                        .cmp(&highlight.range.end, &snapshot)
16968                        .is_gt()
16969                    {
16970                        row_highlights[ix].range.end = next_highlight.range.end;
16971                    }
16972                    row_highlights.remove(ix + 1);
16973                } else {
16974                    break;
16975                }
16976            }
16977        }
16978    }
16979
16980    /// Remove any highlighted row ranges of the given type that intersect the
16981    /// given ranges.
16982    pub fn remove_highlighted_rows<T: 'static>(
16983        &mut self,
16984        ranges_to_remove: Vec<Range<Anchor>>,
16985        cx: &mut Context<Self>,
16986    ) {
16987        let snapshot = self.buffer().read(cx).snapshot(cx);
16988        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
16989        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
16990        row_highlights.retain(|highlight| {
16991            while let Some(range_to_remove) = ranges_to_remove.peek() {
16992                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
16993                    Ordering::Less | Ordering::Equal => {
16994                        ranges_to_remove.next();
16995                    }
16996                    Ordering::Greater => {
16997                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
16998                            Ordering::Less | Ordering::Equal => {
16999                                return false;
17000                            }
17001                            Ordering::Greater => break,
17002                        }
17003                    }
17004                }
17005            }
17006
17007            true
17008        })
17009    }
17010
17011    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17012    pub fn clear_row_highlights<T: 'static>(&mut self) {
17013        self.highlighted_rows.remove(&TypeId::of::<T>());
17014    }
17015
17016    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17017    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17018        self.highlighted_rows
17019            .get(&TypeId::of::<T>())
17020            .map_or(&[] as &[_], |vec| vec.as_slice())
17021            .iter()
17022            .map(|highlight| (highlight.range.clone(), highlight.color))
17023    }
17024
17025    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17026    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17027    /// Allows to ignore certain kinds of highlights.
17028    pub fn highlighted_display_rows(
17029        &self,
17030        window: &mut Window,
17031        cx: &mut App,
17032    ) -> BTreeMap<DisplayRow, LineHighlight> {
17033        let snapshot = self.snapshot(window, cx);
17034        let mut used_highlight_orders = HashMap::default();
17035        self.highlighted_rows
17036            .iter()
17037            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17038            .fold(
17039                BTreeMap::<DisplayRow, LineHighlight>::new(),
17040                |mut unique_rows, highlight| {
17041                    let start = highlight.range.start.to_display_point(&snapshot);
17042                    let end = highlight.range.end.to_display_point(&snapshot);
17043                    let start_row = start.row().0;
17044                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17045                        && end.column() == 0
17046                    {
17047                        end.row().0.saturating_sub(1)
17048                    } else {
17049                        end.row().0
17050                    };
17051                    for row in start_row..=end_row {
17052                        let used_index =
17053                            used_highlight_orders.entry(row).or_insert(highlight.index);
17054                        if highlight.index >= *used_index {
17055                            *used_index = highlight.index;
17056                            unique_rows.insert(
17057                                DisplayRow(row),
17058                                LineHighlight {
17059                                    include_gutter: highlight.options.include_gutter,
17060                                    border: None,
17061                                    background: highlight.color.into(),
17062                                    type_id: Some(highlight.type_id),
17063                                },
17064                            );
17065                        }
17066                    }
17067                    unique_rows
17068                },
17069            )
17070    }
17071
17072    pub fn highlighted_display_row_for_autoscroll(
17073        &self,
17074        snapshot: &DisplaySnapshot,
17075    ) -> Option<DisplayRow> {
17076        self.highlighted_rows
17077            .values()
17078            .flat_map(|highlighted_rows| highlighted_rows.iter())
17079            .filter_map(|highlight| {
17080                if highlight.options.autoscroll {
17081                    Some(highlight.range.start.to_display_point(snapshot).row())
17082                } else {
17083                    None
17084                }
17085            })
17086            .min()
17087    }
17088
17089    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17090        self.highlight_background::<SearchWithinRange>(
17091            ranges,
17092            |colors| colors.editor_document_highlight_read_background,
17093            cx,
17094        )
17095    }
17096
17097    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17098        self.breadcrumb_header = Some(new_header);
17099    }
17100
17101    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17102        self.clear_background_highlights::<SearchWithinRange>(cx);
17103    }
17104
17105    pub fn highlight_background<T: 'static>(
17106        &mut self,
17107        ranges: &[Range<Anchor>],
17108        color_fetcher: fn(&ThemeColors) -> Hsla,
17109        cx: &mut Context<Self>,
17110    ) {
17111        self.background_highlights
17112            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17113        self.scrollbar_marker_state.dirty = true;
17114        cx.notify();
17115    }
17116
17117    pub fn clear_background_highlights<T: 'static>(
17118        &mut self,
17119        cx: &mut Context<Self>,
17120    ) -> Option<BackgroundHighlight> {
17121        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17122        if !text_highlights.1.is_empty() {
17123            self.scrollbar_marker_state.dirty = true;
17124            cx.notify();
17125        }
17126        Some(text_highlights)
17127    }
17128
17129    pub fn highlight_gutter<T: 'static>(
17130        &mut self,
17131        ranges: &[Range<Anchor>],
17132        color_fetcher: fn(&App) -> Hsla,
17133        cx: &mut Context<Self>,
17134    ) {
17135        self.gutter_highlights
17136            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17137        cx.notify();
17138    }
17139
17140    pub fn clear_gutter_highlights<T: 'static>(
17141        &mut self,
17142        cx: &mut Context<Self>,
17143    ) -> Option<GutterHighlight> {
17144        cx.notify();
17145        self.gutter_highlights.remove(&TypeId::of::<T>())
17146    }
17147
17148    #[cfg(feature = "test-support")]
17149    pub fn all_text_background_highlights(
17150        &self,
17151        window: &mut Window,
17152        cx: &mut Context<Self>,
17153    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17154        let snapshot = self.snapshot(window, cx);
17155        let buffer = &snapshot.buffer_snapshot;
17156        let start = buffer.anchor_before(0);
17157        let end = buffer.anchor_after(buffer.len());
17158        let theme = cx.theme().colors();
17159        self.background_highlights_in_range(start..end, &snapshot, theme)
17160    }
17161
17162    #[cfg(feature = "test-support")]
17163    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17164        let snapshot = self.buffer().read(cx).snapshot(cx);
17165
17166        let highlights = self
17167            .background_highlights
17168            .get(&TypeId::of::<items::BufferSearchHighlights>());
17169
17170        if let Some((_color, ranges)) = highlights {
17171            ranges
17172                .iter()
17173                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17174                .collect_vec()
17175        } else {
17176            vec![]
17177        }
17178    }
17179
17180    fn document_highlights_for_position<'a>(
17181        &'a self,
17182        position: Anchor,
17183        buffer: &'a MultiBufferSnapshot,
17184    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17185        let read_highlights = self
17186            .background_highlights
17187            .get(&TypeId::of::<DocumentHighlightRead>())
17188            .map(|h| &h.1);
17189        let write_highlights = self
17190            .background_highlights
17191            .get(&TypeId::of::<DocumentHighlightWrite>())
17192            .map(|h| &h.1);
17193        let left_position = position.bias_left(buffer);
17194        let right_position = position.bias_right(buffer);
17195        read_highlights
17196            .into_iter()
17197            .chain(write_highlights)
17198            .flat_map(move |ranges| {
17199                let start_ix = match ranges.binary_search_by(|probe| {
17200                    let cmp = probe.end.cmp(&left_position, buffer);
17201                    if cmp.is_ge() {
17202                        Ordering::Greater
17203                    } else {
17204                        Ordering::Less
17205                    }
17206                }) {
17207                    Ok(i) | Err(i) => i,
17208                };
17209
17210                ranges[start_ix..]
17211                    .iter()
17212                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17213            })
17214    }
17215
17216    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17217        self.background_highlights
17218            .get(&TypeId::of::<T>())
17219            .map_or(false, |(_, highlights)| !highlights.is_empty())
17220    }
17221
17222    pub fn background_highlights_in_range(
17223        &self,
17224        search_range: Range<Anchor>,
17225        display_snapshot: &DisplaySnapshot,
17226        theme: &ThemeColors,
17227    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17228        let mut results = Vec::new();
17229        for (color_fetcher, ranges) in self.background_highlights.values() {
17230            let color = color_fetcher(theme);
17231            let start_ix = match ranges.binary_search_by(|probe| {
17232                let cmp = probe
17233                    .end
17234                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17235                if cmp.is_gt() {
17236                    Ordering::Greater
17237                } else {
17238                    Ordering::Less
17239                }
17240            }) {
17241                Ok(i) | Err(i) => i,
17242            };
17243            for range in &ranges[start_ix..] {
17244                if range
17245                    .start
17246                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17247                    .is_ge()
17248                {
17249                    break;
17250                }
17251
17252                let start = range.start.to_display_point(display_snapshot);
17253                let end = range.end.to_display_point(display_snapshot);
17254                results.push((start..end, color))
17255            }
17256        }
17257        results
17258    }
17259
17260    pub fn background_highlight_row_ranges<T: 'static>(
17261        &self,
17262        search_range: Range<Anchor>,
17263        display_snapshot: &DisplaySnapshot,
17264        count: usize,
17265    ) -> Vec<RangeInclusive<DisplayPoint>> {
17266        let mut results = Vec::new();
17267        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17268            return vec![];
17269        };
17270
17271        let start_ix = match ranges.binary_search_by(|probe| {
17272            let cmp = probe
17273                .end
17274                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17275            if cmp.is_gt() {
17276                Ordering::Greater
17277            } else {
17278                Ordering::Less
17279            }
17280        }) {
17281            Ok(i) | Err(i) => i,
17282        };
17283        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17284            if let (Some(start_display), Some(end_display)) = (start, end) {
17285                results.push(
17286                    start_display.to_display_point(display_snapshot)
17287                        ..=end_display.to_display_point(display_snapshot),
17288                );
17289            }
17290        };
17291        let mut start_row: Option<Point> = None;
17292        let mut end_row: Option<Point> = None;
17293        if ranges.len() > count {
17294            return Vec::new();
17295        }
17296        for range in &ranges[start_ix..] {
17297            if range
17298                .start
17299                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17300                .is_ge()
17301            {
17302                break;
17303            }
17304            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17305            if let Some(current_row) = &end_row {
17306                if end.row == current_row.row {
17307                    continue;
17308                }
17309            }
17310            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17311            if start_row.is_none() {
17312                assert_eq!(end_row, None);
17313                start_row = Some(start);
17314                end_row = Some(end);
17315                continue;
17316            }
17317            if let Some(current_end) = end_row.as_mut() {
17318                if start.row > current_end.row + 1 {
17319                    push_region(start_row, end_row);
17320                    start_row = Some(start);
17321                    end_row = Some(end);
17322                } else {
17323                    // Merge two hunks.
17324                    *current_end = end;
17325                }
17326            } else {
17327                unreachable!();
17328            }
17329        }
17330        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17331        push_region(start_row, end_row);
17332        results
17333    }
17334
17335    pub fn gutter_highlights_in_range(
17336        &self,
17337        search_range: Range<Anchor>,
17338        display_snapshot: &DisplaySnapshot,
17339        cx: &App,
17340    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17341        let mut results = Vec::new();
17342        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17343            let color = color_fetcher(cx);
17344            let start_ix = match ranges.binary_search_by(|probe| {
17345                let cmp = probe
17346                    .end
17347                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17348                if cmp.is_gt() {
17349                    Ordering::Greater
17350                } else {
17351                    Ordering::Less
17352                }
17353            }) {
17354                Ok(i) | Err(i) => i,
17355            };
17356            for range in &ranges[start_ix..] {
17357                if range
17358                    .start
17359                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17360                    .is_ge()
17361                {
17362                    break;
17363                }
17364
17365                let start = range.start.to_display_point(display_snapshot);
17366                let end = range.end.to_display_point(display_snapshot);
17367                results.push((start..end, color))
17368            }
17369        }
17370        results
17371    }
17372
17373    /// Get the text ranges corresponding to the redaction query
17374    pub fn redacted_ranges(
17375        &self,
17376        search_range: Range<Anchor>,
17377        display_snapshot: &DisplaySnapshot,
17378        cx: &App,
17379    ) -> Vec<Range<DisplayPoint>> {
17380        display_snapshot
17381            .buffer_snapshot
17382            .redacted_ranges(search_range, |file| {
17383                if let Some(file) = file {
17384                    file.is_private()
17385                        && EditorSettings::get(
17386                            Some(SettingsLocation {
17387                                worktree_id: file.worktree_id(cx),
17388                                path: file.path().as_ref(),
17389                            }),
17390                            cx,
17391                        )
17392                        .redact_private_values
17393                } else {
17394                    false
17395                }
17396            })
17397            .map(|range| {
17398                range.start.to_display_point(display_snapshot)
17399                    ..range.end.to_display_point(display_snapshot)
17400            })
17401            .collect()
17402    }
17403
17404    pub fn highlight_text<T: 'static>(
17405        &mut self,
17406        ranges: Vec<Range<Anchor>>,
17407        style: HighlightStyle,
17408        cx: &mut Context<Self>,
17409    ) {
17410        self.display_map.update(cx, |map, _| {
17411            map.highlight_text(TypeId::of::<T>(), ranges, style)
17412        });
17413        cx.notify();
17414    }
17415
17416    pub(crate) fn highlight_inlays<T: 'static>(
17417        &mut self,
17418        highlights: Vec<InlayHighlight>,
17419        style: HighlightStyle,
17420        cx: &mut Context<Self>,
17421    ) {
17422        self.display_map.update(cx, |map, _| {
17423            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
17424        });
17425        cx.notify();
17426    }
17427
17428    pub fn text_highlights<'a, T: 'static>(
17429        &'a self,
17430        cx: &'a App,
17431    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
17432        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
17433    }
17434
17435    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
17436        let cleared = self
17437            .display_map
17438            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
17439        if cleared {
17440            cx.notify();
17441        }
17442    }
17443
17444    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
17445        (self.read_only(cx) || self.blink_manager.read(cx).visible())
17446            && self.focus_handle.is_focused(window)
17447    }
17448
17449    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
17450        self.show_cursor_when_unfocused = is_enabled;
17451        cx.notify();
17452    }
17453
17454    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
17455        cx.notify();
17456    }
17457
17458    fn on_debug_session_event(
17459        &mut self,
17460        _session: Entity<Session>,
17461        event: &SessionEvent,
17462        cx: &mut Context<Self>,
17463    ) {
17464        match event {
17465            SessionEvent::InvalidateInlineValue => {
17466                self.refresh_inline_values(cx);
17467            }
17468            _ => {}
17469        }
17470    }
17471
17472    fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
17473        let Some(project) = self.project.clone() else {
17474            return;
17475        };
17476        let Some(buffer) = self.buffer.read(cx).as_singleton() else {
17477            return;
17478        };
17479        if !self.inline_value_cache.enabled {
17480            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
17481            self.splice_inlays(&inlays, Vec::new(), cx);
17482            return;
17483        }
17484
17485        let current_execution_position = self
17486            .highlighted_rows
17487            .get(&TypeId::of::<DebugCurrentRowHighlight>())
17488            .and_then(|lines| lines.last().map(|line| line.range.start));
17489
17490        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
17491            let snapshot = editor
17492                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17493                .ok()?;
17494
17495            let inline_values = editor
17496                .update(cx, |_, cx| {
17497                    let Some(current_execution_position) = current_execution_position else {
17498                        return Some(Task::ready(Ok(Vec::new())));
17499                    };
17500
17501                    // todo(debugger) when introducing multi buffer inline values check execution position's buffer id to make sure the text
17502                    // anchor is in the same buffer
17503                    let range =
17504                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
17505                    project.inline_values(buffer, range, cx)
17506                })
17507                .ok()
17508                .flatten()?
17509                .await
17510                .context("refreshing debugger inlays")
17511                .log_err()?;
17512
17513            let (excerpt_id, buffer_id) = snapshot
17514                .excerpts()
17515                .next()
17516                .map(|excerpt| (excerpt.0, excerpt.1.remote_id()))?;
17517            editor
17518                .update(cx, |editor, cx| {
17519                    let new_inlays = inline_values
17520                        .into_iter()
17521                        .map(|debugger_value| {
17522                            Inlay::debugger_hint(
17523                                post_inc(&mut editor.next_inlay_id),
17524                                Anchor::in_buffer(excerpt_id, buffer_id, debugger_value.position),
17525                                debugger_value.text(),
17526                            )
17527                        })
17528                        .collect::<Vec<_>>();
17529                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
17530                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
17531
17532                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
17533                })
17534                .ok()?;
17535            Some(())
17536        });
17537    }
17538
17539    fn on_buffer_event(
17540        &mut self,
17541        multibuffer: &Entity<MultiBuffer>,
17542        event: &multi_buffer::Event,
17543        window: &mut Window,
17544        cx: &mut Context<Self>,
17545    ) {
17546        match event {
17547            multi_buffer::Event::Edited {
17548                singleton_buffer_edited,
17549                edited_buffer: buffer_edited,
17550            } => {
17551                self.scrollbar_marker_state.dirty = true;
17552                self.active_indent_guides_state.dirty = true;
17553                self.refresh_active_diagnostics(cx);
17554                self.refresh_code_actions(window, cx);
17555                if self.has_active_inline_completion() {
17556                    self.update_visible_inline_completion(window, cx);
17557                }
17558                if let Some(buffer) = buffer_edited {
17559                    let buffer_id = buffer.read(cx).remote_id();
17560                    if !self.registered_buffers.contains_key(&buffer_id) {
17561                        if let Some(project) = self.project.as_ref() {
17562                            project.update(cx, |project, cx| {
17563                                self.registered_buffers.insert(
17564                                    buffer_id,
17565                                    project.register_buffer_with_language_servers(&buffer, cx),
17566                                );
17567                            })
17568                        }
17569                    }
17570                }
17571                cx.emit(EditorEvent::BufferEdited);
17572                cx.emit(SearchEvent::MatchesInvalidated);
17573                if *singleton_buffer_edited {
17574                    if let Some(project) = &self.project {
17575                        #[allow(clippy::mutable_key_type)]
17576                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
17577                            multibuffer
17578                                .all_buffers()
17579                                .into_iter()
17580                                .filter_map(|buffer| {
17581                                    buffer.update(cx, |buffer, cx| {
17582                                        let language = buffer.language()?;
17583                                        let should_discard = project.update(cx, |project, cx| {
17584                                            project.is_local()
17585                                                && !project.has_language_servers_for(buffer, cx)
17586                                        });
17587                                        should_discard.not().then_some(language.clone())
17588                                    })
17589                                })
17590                                .collect::<HashSet<_>>()
17591                        });
17592                        if !languages_affected.is_empty() {
17593                            self.refresh_inlay_hints(
17594                                InlayHintRefreshReason::BufferEdited(languages_affected),
17595                                cx,
17596                            );
17597                        }
17598                    }
17599                }
17600
17601                let Some(project) = &self.project else { return };
17602                let (telemetry, is_via_ssh) = {
17603                    let project = project.read(cx);
17604                    let telemetry = project.client().telemetry().clone();
17605                    let is_via_ssh = project.is_via_ssh();
17606                    (telemetry, is_via_ssh)
17607                };
17608                refresh_linked_ranges(self, window, cx);
17609                telemetry.log_edit_event("editor", is_via_ssh);
17610            }
17611            multi_buffer::Event::ExcerptsAdded {
17612                buffer,
17613                predecessor,
17614                excerpts,
17615            } => {
17616                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17617                let buffer_id = buffer.read(cx).remote_id();
17618                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
17619                    if let Some(project) = &self.project {
17620                        get_uncommitted_diff_for_buffer(
17621                            project,
17622                            [buffer.clone()],
17623                            self.buffer.clone(),
17624                            cx,
17625                        )
17626                        .detach();
17627                    }
17628                }
17629                cx.emit(EditorEvent::ExcerptsAdded {
17630                    buffer: buffer.clone(),
17631                    predecessor: *predecessor,
17632                    excerpts: excerpts.clone(),
17633                });
17634                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17635            }
17636            multi_buffer::Event::ExcerptsRemoved {
17637                ids,
17638                removed_buffer_ids,
17639            } => {
17640                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
17641                let buffer = self.buffer.read(cx);
17642                self.registered_buffers
17643                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
17644                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
17645                cx.emit(EditorEvent::ExcerptsRemoved {
17646                    ids: ids.clone(),
17647                    removed_buffer_ids: removed_buffer_ids.clone(),
17648                })
17649            }
17650            multi_buffer::Event::ExcerptsEdited {
17651                excerpt_ids,
17652                buffer_ids,
17653            } => {
17654                self.display_map.update(cx, |map, cx| {
17655                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
17656                });
17657                cx.emit(EditorEvent::ExcerptsEdited {
17658                    ids: excerpt_ids.clone(),
17659                })
17660            }
17661            multi_buffer::Event::ExcerptsExpanded { ids } => {
17662                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17663                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
17664            }
17665            multi_buffer::Event::Reparsed(buffer_id) => {
17666                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17667                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
17668
17669                cx.emit(EditorEvent::Reparsed(*buffer_id));
17670            }
17671            multi_buffer::Event::DiffHunksToggled => {
17672                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17673            }
17674            multi_buffer::Event::LanguageChanged(buffer_id) => {
17675                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
17676                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
17677                cx.emit(EditorEvent::Reparsed(*buffer_id));
17678                cx.notify();
17679            }
17680            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
17681            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
17682            multi_buffer::Event::FileHandleChanged
17683            | multi_buffer::Event::Reloaded
17684            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
17685            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
17686            multi_buffer::Event::DiagnosticsUpdated => {
17687                self.refresh_active_diagnostics(cx);
17688                self.refresh_inline_diagnostics(true, window, cx);
17689                self.scrollbar_marker_state.dirty = true;
17690                cx.notify();
17691            }
17692            _ => {}
17693        };
17694    }
17695
17696    fn on_display_map_changed(
17697        &mut self,
17698        _: Entity<DisplayMap>,
17699        _: &mut Window,
17700        cx: &mut Context<Self>,
17701    ) {
17702        cx.notify();
17703    }
17704
17705    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17706        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17707        self.update_edit_prediction_settings(cx);
17708        self.refresh_inline_completion(true, false, window, cx);
17709        self.refresh_inlay_hints(
17710            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
17711                self.selections.newest_anchor().head(),
17712                &self.buffer.read(cx).snapshot(cx),
17713                cx,
17714            )),
17715            cx,
17716        );
17717
17718        let old_cursor_shape = self.cursor_shape;
17719
17720        {
17721            let editor_settings = EditorSettings::get_global(cx);
17722            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
17723            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
17724            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
17725            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
17726        }
17727
17728        if old_cursor_shape != self.cursor_shape {
17729            cx.emit(EditorEvent::CursorShapeChanged);
17730        }
17731
17732        let project_settings = ProjectSettings::get_global(cx);
17733        self.serialize_dirty_buffers = project_settings.session.restore_unsaved_buffers;
17734
17735        if self.mode.is_full() {
17736            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
17737            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
17738            if self.show_inline_diagnostics != show_inline_diagnostics {
17739                self.show_inline_diagnostics = show_inline_diagnostics;
17740                self.refresh_inline_diagnostics(false, window, cx);
17741            }
17742
17743            if self.git_blame_inline_enabled != inline_blame_enabled {
17744                self.toggle_git_blame_inline_internal(false, window, cx);
17745            }
17746        }
17747
17748        cx.notify();
17749    }
17750
17751    pub fn set_searchable(&mut self, searchable: bool) {
17752        self.searchable = searchable;
17753    }
17754
17755    pub fn searchable(&self) -> bool {
17756        self.searchable
17757    }
17758
17759    fn open_proposed_changes_editor(
17760        &mut self,
17761        _: &OpenProposedChangesEditor,
17762        window: &mut Window,
17763        cx: &mut Context<Self>,
17764    ) {
17765        let Some(workspace) = self.workspace() else {
17766            cx.propagate();
17767            return;
17768        };
17769
17770        let selections = self.selections.all::<usize>(cx);
17771        let multi_buffer = self.buffer.read(cx);
17772        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17773        let mut new_selections_by_buffer = HashMap::default();
17774        for selection in selections {
17775            for (buffer, range, _) in
17776                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
17777            {
17778                let mut range = range.to_point(buffer);
17779                range.start.column = 0;
17780                range.end.column = buffer.line_len(range.end.row);
17781                new_selections_by_buffer
17782                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
17783                    .or_insert(Vec::new())
17784                    .push(range)
17785            }
17786        }
17787
17788        let proposed_changes_buffers = new_selections_by_buffer
17789            .into_iter()
17790            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
17791            .collect::<Vec<_>>();
17792        let proposed_changes_editor = cx.new(|cx| {
17793            ProposedChangesEditor::new(
17794                "Proposed changes",
17795                proposed_changes_buffers,
17796                self.project.clone(),
17797                window,
17798                cx,
17799            )
17800        });
17801
17802        window.defer(cx, move |window, cx| {
17803            workspace.update(cx, |workspace, cx| {
17804                workspace.active_pane().update(cx, |pane, cx| {
17805                    pane.add_item(
17806                        Box::new(proposed_changes_editor),
17807                        true,
17808                        true,
17809                        None,
17810                        window,
17811                        cx,
17812                    );
17813                });
17814            });
17815        });
17816    }
17817
17818    pub fn open_excerpts_in_split(
17819        &mut self,
17820        _: &OpenExcerptsSplit,
17821        window: &mut Window,
17822        cx: &mut Context<Self>,
17823    ) {
17824        self.open_excerpts_common(None, true, window, cx)
17825    }
17826
17827    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
17828        self.open_excerpts_common(None, false, window, cx)
17829    }
17830
17831    fn open_excerpts_common(
17832        &mut self,
17833        jump_data: Option<JumpData>,
17834        split: bool,
17835        window: &mut Window,
17836        cx: &mut Context<Self>,
17837    ) {
17838        let Some(workspace) = self.workspace() else {
17839            cx.propagate();
17840            return;
17841        };
17842
17843        if self.buffer.read(cx).is_singleton() {
17844            cx.propagate();
17845            return;
17846        }
17847
17848        let mut new_selections_by_buffer = HashMap::default();
17849        match &jump_data {
17850            Some(JumpData::MultiBufferPoint {
17851                excerpt_id,
17852                position,
17853                anchor,
17854                line_offset_from_top,
17855            }) => {
17856                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17857                if let Some(buffer) = multi_buffer_snapshot
17858                    .buffer_id_for_excerpt(*excerpt_id)
17859                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
17860                {
17861                    let buffer_snapshot = buffer.read(cx).snapshot();
17862                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
17863                        language::ToPoint::to_point(anchor, &buffer_snapshot)
17864                    } else {
17865                        buffer_snapshot.clip_point(*position, Bias::Left)
17866                    };
17867                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
17868                    new_selections_by_buffer.insert(
17869                        buffer,
17870                        (
17871                            vec![jump_to_offset..jump_to_offset],
17872                            Some(*line_offset_from_top),
17873                        ),
17874                    );
17875                }
17876            }
17877            Some(JumpData::MultiBufferRow {
17878                row,
17879                line_offset_from_top,
17880            }) => {
17881                let point = MultiBufferPoint::new(row.0, 0);
17882                if let Some((buffer, buffer_point, _)) =
17883                    self.buffer.read(cx).point_to_buffer_point(point, cx)
17884                {
17885                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
17886                    new_selections_by_buffer
17887                        .entry(buffer)
17888                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
17889                        .0
17890                        .push(buffer_offset..buffer_offset)
17891                }
17892            }
17893            None => {
17894                let selections = self.selections.all::<usize>(cx);
17895                let multi_buffer = self.buffer.read(cx);
17896                for selection in selections {
17897                    for (snapshot, range, _, anchor) in multi_buffer
17898                        .snapshot(cx)
17899                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
17900                    {
17901                        if let Some(anchor) = anchor {
17902                            // selection is in a deleted hunk
17903                            let Some(buffer_id) = anchor.buffer_id else {
17904                                continue;
17905                            };
17906                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
17907                                continue;
17908                            };
17909                            let offset = text::ToOffset::to_offset(
17910                                &anchor.text_anchor,
17911                                &buffer_handle.read(cx).snapshot(),
17912                            );
17913                            let range = offset..offset;
17914                            new_selections_by_buffer
17915                                .entry(buffer_handle)
17916                                .or_insert((Vec::new(), None))
17917                                .0
17918                                .push(range)
17919                        } else {
17920                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
17921                            else {
17922                                continue;
17923                            };
17924                            new_selections_by_buffer
17925                                .entry(buffer_handle)
17926                                .or_insert((Vec::new(), None))
17927                                .0
17928                                .push(range)
17929                        }
17930                    }
17931                }
17932            }
17933        }
17934
17935        new_selections_by_buffer
17936            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
17937
17938        if new_selections_by_buffer.is_empty() {
17939            return;
17940        }
17941
17942        // We defer the pane interaction because we ourselves are a workspace item
17943        // and activating a new item causes the pane to call a method on us reentrantly,
17944        // which panics if we're on the stack.
17945        window.defer(cx, move |window, cx| {
17946            workspace.update(cx, |workspace, cx| {
17947                let pane = if split {
17948                    workspace.adjacent_pane(window, cx)
17949                } else {
17950                    workspace.active_pane().clone()
17951                };
17952
17953                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
17954                    let editor = buffer
17955                        .read(cx)
17956                        .file()
17957                        .is_none()
17958                        .then(|| {
17959                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
17960                            // so `workspace.open_project_item` will never find them, always opening a new editor.
17961                            // Instead, we try to activate the existing editor in the pane first.
17962                            let (editor, pane_item_index) =
17963                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
17964                                    let editor = item.downcast::<Editor>()?;
17965                                    let singleton_buffer =
17966                                        editor.read(cx).buffer().read(cx).as_singleton()?;
17967                                    if singleton_buffer == buffer {
17968                                        Some((editor, i))
17969                                    } else {
17970                                        None
17971                                    }
17972                                })?;
17973                            pane.update(cx, |pane, cx| {
17974                                pane.activate_item(pane_item_index, true, true, window, cx)
17975                            });
17976                            Some(editor)
17977                        })
17978                        .flatten()
17979                        .unwrap_or_else(|| {
17980                            workspace.open_project_item::<Self>(
17981                                pane.clone(),
17982                                buffer,
17983                                true,
17984                                true,
17985                                window,
17986                                cx,
17987                            )
17988                        });
17989
17990                    editor.update(cx, |editor, cx| {
17991                        let autoscroll = match scroll_offset {
17992                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
17993                            None => Autoscroll::newest(),
17994                        };
17995                        let nav_history = editor.nav_history.take();
17996                        editor.change_selections(Some(autoscroll), window, cx, |s| {
17997                            s.select_ranges(ranges);
17998                        });
17999                        editor.nav_history = nav_history;
18000                    });
18001                }
18002            })
18003        });
18004    }
18005
18006    // For now, don't allow opening excerpts in buffers that aren't backed by
18007    // regular project files.
18008    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18009        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18010    }
18011
18012    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18013        let snapshot = self.buffer.read(cx).read(cx);
18014        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18015        Some(
18016            ranges
18017                .iter()
18018                .map(move |range| {
18019                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18020                })
18021                .collect(),
18022        )
18023    }
18024
18025    fn selection_replacement_ranges(
18026        &self,
18027        range: Range<OffsetUtf16>,
18028        cx: &mut App,
18029    ) -> Vec<Range<OffsetUtf16>> {
18030        let selections = self.selections.all::<OffsetUtf16>(cx);
18031        let newest_selection = selections
18032            .iter()
18033            .max_by_key(|selection| selection.id)
18034            .unwrap();
18035        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18036        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18037        let snapshot = self.buffer.read(cx).read(cx);
18038        selections
18039            .into_iter()
18040            .map(|mut selection| {
18041                selection.start.0 =
18042                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18043                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18044                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18045                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18046            })
18047            .collect()
18048    }
18049
18050    fn report_editor_event(
18051        &self,
18052        event_type: &'static str,
18053        file_extension: Option<String>,
18054        cx: &App,
18055    ) {
18056        if cfg!(any(test, feature = "test-support")) {
18057            return;
18058        }
18059
18060        let Some(project) = &self.project else { return };
18061
18062        // If None, we are in a file without an extension
18063        let file = self
18064            .buffer
18065            .read(cx)
18066            .as_singleton()
18067            .and_then(|b| b.read(cx).file());
18068        let file_extension = file_extension.or(file
18069            .as_ref()
18070            .and_then(|file| Path::new(file.file_name(cx)).extension())
18071            .and_then(|e| e.to_str())
18072            .map(|a| a.to_string()));
18073
18074        let vim_mode = vim_enabled(cx);
18075
18076        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18077        let copilot_enabled = edit_predictions_provider
18078            == language::language_settings::EditPredictionProvider::Copilot;
18079        let copilot_enabled_for_language = self
18080            .buffer
18081            .read(cx)
18082            .language_settings(cx)
18083            .show_edit_predictions;
18084
18085        let project = project.read(cx);
18086        telemetry::event!(
18087            event_type,
18088            file_extension,
18089            vim_mode,
18090            copilot_enabled,
18091            copilot_enabled_for_language,
18092            edit_predictions_provider,
18093            is_via_ssh = project.is_via_ssh(),
18094        );
18095    }
18096
18097    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18098    /// with each line being an array of {text, highlight} objects.
18099    fn copy_highlight_json(
18100        &mut self,
18101        _: &CopyHighlightJson,
18102        window: &mut Window,
18103        cx: &mut Context<Self>,
18104    ) {
18105        #[derive(Serialize)]
18106        struct Chunk<'a> {
18107            text: String,
18108            highlight: Option<&'a str>,
18109        }
18110
18111        let snapshot = self.buffer.read(cx).snapshot(cx);
18112        let range = self
18113            .selected_text_range(false, window, cx)
18114            .and_then(|selection| {
18115                if selection.range.is_empty() {
18116                    None
18117                } else {
18118                    Some(selection.range)
18119                }
18120            })
18121            .unwrap_or_else(|| 0..snapshot.len());
18122
18123        let chunks = snapshot.chunks(range, true);
18124        let mut lines = Vec::new();
18125        let mut line: VecDeque<Chunk> = VecDeque::new();
18126
18127        let Some(style) = self.style.as_ref() else {
18128            return;
18129        };
18130
18131        for chunk in chunks {
18132            let highlight = chunk
18133                .syntax_highlight_id
18134                .and_then(|id| id.name(&style.syntax));
18135            let mut chunk_lines = chunk.text.split('\n').peekable();
18136            while let Some(text) = chunk_lines.next() {
18137                let mut merged_with_last_token = false;
18138                if let Some(last_token) = line.back_mut() {
18139                    if last_token.highlight == highlight {
18140                        last_token.text.push_str(text);
18141                        merged_with_last_token = true;
18142                    }
18143                }
18144
18145                if !merged_with_last_token {
18146                    line.push_back(Chunk {
18147                        text: text.into(),
18148                        highlight,
18149                    });
18150                }
18151
18152                if chunk_lines.peek().is_some() {
18153                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18154                        line.pop_front();
18155                    }
18156                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18157                        line.pop_back();
18158                    }
18159
18160                    lines.push(mem::take(&mut line));
18161                }
18162            }
18163        }
18164
18165        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18166            return;
18167        };
18168        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18169    }
18170
18171    pub fn open_context_menu(
18172        &mut self,
18173        _: &OpenContextMenu,
18174        window: &mut Window,
18175        cx: &mut Context<Self>,
18176    ) {
18177        self.request_autoscroll(Autoscroll::newest(), cx);
18178        let position = self.selections.newest_display(cx).start;
18179        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18180    }
18181
18182    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18183        &self.inlay_hint_cache
18184    }
18185
18186    pub fn replay_insert_event(
18187        &mut self,
18188        text: &str,
18189        relative_utf16_range: Option<Range<isize>>,
18190        window: &mut Window,
18191        cx: &mut Context<Self>,
18192    ) {
18193        if !self.input_enabled {
18194            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18195            return;
18196        }
18197        if let Some(relative_utf16_range) = relative_utf16_range {
18198            let selections = self.selections.all::<OffsetUtf16>(cx);
18199            self.change_selections(None, window, cx, |s| {
18200                let new_ranges = selections.into_iter().map(|range| {
18201                    let start = OffsetUtf16(
18202                        range
18203                            .head()
18204                            .0
18205                            .saturating_add_signed(relative_utf16_range.start),
18206                    );
18207                    let end = OffsetUtf16(
18208                        range
18209                            .head()
18210                            .0
18211                            .saturating_add_signed(relative_utf16_range.end),
18212                    );
18213                    start..end
18214                });
18215                s.select_ranges(new_ranges);
18216            });
18217        }
18218
18219        self.handle_input(text, window, cx);
18220    }
18221
18222    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18223        let Some(provider) = self.semantics_provider.as_ref() else {
18224            return false;
18225        };
18226
18227        let mut supports = false;
18228        self.buffer().update(cx, |this, cx| {
18229            this.for_each_buffer(|buffer| {
18230                supports |= provider.supports_inlay_hints(buffer, cx);
18231            });
18232        });
18233
18234        supports
18235    }
18236
18237    pub fn is_focused(&self, window: &Window) -> bool {
18238        self.focus_handle.is_focused(window)
18239    }
18240
18241    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18242        cx.emit(EditorEvent::Focused);
18243
18244        if let Some(descendant) = self
18245            .last_focused_descendant
18246            .take()
18247            .and_then(|descendant| descendant.upgrade())
18248        {
18249            window.focus(&descendant);
18250        } else {
18251            if let Some(blame) = self.blame.as_ref() {
18252                blame.update(cx, GitBlame::focus)
18253            }
18254
18255            self.blink_manager.update(cx, BlinkManager::enable);
18256            self.show_cursor_names(window, cx);
18257            self.buffer.update(cx, |buffer, cx| {
18258                buffer.finalize_last_transaction(cx);
18259                if self.leader_peer_id.is_none() {
18260                    buffer.set_active_selections(
18261                        &self.selections.disjoint_anchors(),
18262                        self.selections.line_mode,
18263                        self.cursor_shape,
18264                        cx,
18265                    );
18266                }
18267            });
18268        }
18269    }
18270
18271    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18272        cx.emit(EditorEvent::FocusedIn)
18273    }
18274
18275    fn handle_focus_out(
18276        &mut self,
18277        event: FocusOutEvent,
18278        _window: &mut Window,
18279        cx: &mut Context<Self>,
18280    ) {
18281        if event.blurred != self.focus_handle {
18282            self.last_focused_descendant = Some(event.blurred);
18283        }
18284        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18285    }
18286
18287    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18288        self.blink_manager.update(cx, BlinkManager::disable);
18289        self.buffer
18290            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18291
18292        if let Some(blame) = self.blame.as_ref() {
18293            blame.update(cx, GitBlame::blur)
18294        }
18295        if !self.hover_state.focused(window, cx) {
18296            hide_hover(self, cx);
18297        }
18298        if !self
18299            .context_menu
18300            .borrow()
18301            .as_ref()
18302            .is_some_and(|context_menu| context_menu.focused(window, cx))
18303        {
18304            self.hide_context_menu(window, cx);
18305        }
18306        self.discard_inline_completion(false, cx);
18307        cx.emit(EditorEvent::Blurred);
18308        cx.notify();
18309    }
18310
18311    pub fn register_action<A: Action>(
18312        &mut self,
18313        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
18314    ) -> Subscription {
18315        let id = self.next_editor_action_id.post_inc();
18316        let listener = Arc::new(listener);
18317        self.editor_actions.borrow_mut().insert(
18318            id,
18319            Box::new(move |window, _| {
18320                let listener = listener.clone();
18321                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
18322                    let action = action.downcast_ref().unwrap();
18323                    if phase == DispatchPhase::Bubble {
18324                        listener(action, window, cx)
18325                    }
18326                })
18327            }),
18328        );
18329
18330        let editor_actions = self.editor_actions.clone();
18331        Subscription::new(move || {
18332            editor_actions.borrow_mut().remove(&id);
18333        })
18334    }
18335
18336    pub fn file_header_size(&self) -> u32 {
18337        FILE_HEADER_HEIGHT
18338    }
18339
18340    pub fn restore(
18341        &mut self,
18342        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
18343        window: &mut Window,
18344        cx: &mut Context<Self>,
18345    ) {
18346        let workspace = self.workspace();
18347        let project = self.project.as_ref();
18348        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
18349            let mut tasks = Vec::new();
18350            for (buffer_id, changes) in revert_changes {
18351                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
18352                    buffer.update(cx, |buffer, cx| {
18353                        buffer.edit(
18354                            changes
18355                                .into_iter()
18356                                .map(|(range, text)| (range, text.to_string())),
18357                            None,
18358                            cx,
18359                        );
18360                    });
18361
18362                    if let Some(project) =
18363                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
18364                    {
18365                        project.update(cx, |project, cx| {
18366                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
18367                        })
18368                    }
18369                }
18370            }
18371            tasks
18372        });
18373        cx.spawn_in(window, async move |_, cx| {
18374            for (buffer, task) in save_tasks {
18375                let result = task.await;
18376                if result.is_err() {
18377                    let Some(path) = buffer
18378                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
18379                        .ok()
18380                    else {
18381                        continue;
18382                    };
18383                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
18384                        let Some(task) = cx
18385                            .update_window_entity(&workspace, |workspace, window, cx| {
18386                                workspace
18387                                    .open_path_preview(path, None, false, false, false, window, cx)
18388                            })
18389                            .ok()
18390                        else {
18391                            continue;
18392                        };
18393                        task.await.log_err();
18394                    }
18395                }
18396            }
18397        })
18398        .detach();
18399        self.change_selections(None, window, cx, |selections| selections.refresh());
18400    }
18401
18402    pub fn to_pixel_point(
18403        &self,
18404        source: multi_buffer::Anchor,
18405        editor_snapshot: &EditorSnapshot,
18406        window: &mut Window,
18407    ) -> Option<gpui::Point<Pixels>> {
18408        let source_point = source.to_display_point(editor_snapshot);
18409        self.display_to_pixel_point(source_point, editor_snapshot, window)
18410    }
18411
18412    pub fn display_to_pixel_point(
18413        &self,
18414        source: DisplayPoint,
18415        editor_snapshot: &EditorSnapshot,
18416        window: &mut Window,
18417    ) -> Option<gpui::Point<Pixels>> {
18418        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
18419        let text_layout_details = self.text_layout_details(window);
18420        let scroll_top = text_layout_details
18421            .scroll_anchor
18422            .scroll_position(editor_snapshot)
18423            .y;
18424
18425        if source.row().as_f32() < scroll_top.floor() {
18426            return None;
18427        }
18428        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
18429        let source_y = line_height * (source.row().as_f32() - scroll_top);
18430        Some(gpui::Point::new(source_x, source_y))
18431    }
18432
18433    pub fn has_visible_completions_menu(&self) -> bool {
18434        !self.edit_prediction_preview_is_active()
18435            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
18436                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
18437            })
18438    }
18439
18440    pub fn register_addon<T: Addon>(&mut self, instance: T) {
18441        self.addons
18442            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
18443    }
18444
18445    pub fn unregister_addon<T: Addon>(&mut self) {
18446        self.addons.remove(&std::any::TypeId::of::<T>());
18447    }
18448
18449    pub fn addon<T: Addon>(&self) -> Option<&T> {
18450        let type_id = std::any::TypeId::of::<T>();
18451        self.addons
18452            .get(&type_id)
18453            .and_then(|item| item.to_any().downcast_ref::<T>())
18454    }
18455
18456    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
18457        let type_id = std::any::TypeId::of::<T>();
18458        self.addons
18459            .get_mut(&type_id)
18460            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
18461    }
18462
18463    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
18464        let text_layout_details = self.text_layout_details(window);
18465        let style = &text_layout_details.editor_style;
18466        let font_id = window.text_system().resolve_font(&style.text.font());
18467        let font_size = style.text.font_size.to_pixels(window.rem_size());
18468        let line_height = style.text.line_height_in_pixels(window.rem_size());
18469        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
18470
18471        gpui::Size::new(em_width, line_height)
18472    }
18473
18474    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
18475        self.load_diff_task.clone()
18476    }
18477
18478    fn read_metadata_from_db(
18479        &mut self,
18480        item_id: u64,
18481        workspace_id: WorkspaceId,
18482        window: &mut Window,
18483        cx: &mut Context<Editor>,
18484    ) {
18485        if self.is_singleton(cx)
18486            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
18487        {
18488            let buffer_snapshot = OnceCell::new();
18489
18490            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
18491                if !folds.is_empty() {
18492                    let snapshot =
18493                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
18494                    self.fold_ranges(
18495                        folds
18496                            .into_iter()
18497                            .map(|(start, end)| {
18498                                snapshot.clip_offset(start, Bias::Left)
18499                                    ..snapshot.clip_offset(end, Bias::Right)
18500                            })
18501                            .collect(),
18502                        false,
18503                        window,
18504                        cx,
18505                    );
18506                }
18507            }
18508
18509            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
18510                if !selections.is_empty() {
18511                    let snapshot =
18512                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
18513                    self.change_selections(None, window, cx, |s| {
18514                        s.select_ranges(selections.into_iter().map(|(start, end)| {
18515                            snapshot.clip_offset(start, Bias::Left)
18516                                ..snapshot.clip_offset(end, Bias::Right)
18517                        }));
18518                    });
18519                }
18520            };
18521        }
18522
18523        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
18524    }
18525}
18526
18527fn vim_enabled(cx: &App) -> bool {
18528    cx.global::<SettingsStore>()
18529        .raw_user_settings()
18530        .get("vim_mode")
18531        == Some(&serde_json::Value::Bool(true))
18532}
18533
18534// Consider user intent and default settings
18535fn choose_completion_range(
18536    completion: &Completion,
18537    intent: CompletionIntent,
18538    buffer: &Entity<Buffer>,
18539    cx: &mut Context<Editor>,
18540) -> Range<usize> {
18541    fn should_replace(
18542        completion: &Completion,
18543        insert_range: &Range<text::Anchor>,
18544        intent: CompletionIntent,
18545        completion_mode_setting: LspInsertMode,
18546        buffer: &Buffer,
18547    ) -> bool {
18548        // specific actions take precedence over settings
18549        match intent {
18550            CompletionIntent::CompleteWithInsert => return false,
18551            CompletionIntent::CompleteWithReplace => return true,
18552            CompletionIntent::Complete | CompletionIntent::Compose => {}
18553        }
18554
18555        match completion_mode_setting {
18556            LspInsertMode::Insert => false,
18557            LspInsertMode::Replace => true,
18558            LspInsertMode::ReplaceSubsequence => {
18559                let mut text_to_replace = buffer.chars_for_range(
18560                    buffer.anchor_before(completion.replace_range.start)
18561                        ..buffer.anchor_after(completion.replace_range.end),
18562                );
18563                let mut completion_text = completion.new_text.chars();
18564
18565                // is `text_to_replace` a subsequence of `completion_text`
18566                text_to_replace
18567                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
18568            }
18569            LspInsertMode::ReplaceSuffix => {
18570                let range_after_cursor = insert_range.end..completion.replace_range.end;
18571
18572                let text_after_cursor = buffer
18573                    .text_for_range(
18574                        buffer.anchor_before(range_after_cursor.start)
18575                            ..buffer.anchor_after(range_after_cursor.end),
18576                    )
18577                    .collect::<String>();
18578                completion.new_text.ends_with(&text_after_cursor)
18579            }
18580        }
18581    }
18582
18583    let buffer = buffer.read(cx);
18584
18585    if let CompletionSource::Lsp {
18586        insert_range: Some(insert_range),
18587        ..
18588    } = &completion.source
18589    {
18590        let completion_mode_setting =
18591            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
18592                .completions
18593                .lsp_insert_mode;
18594
18595        if !should_replace(
18596            completion,
18597            &insert_range,
18598            intent,
18599            completion_mode_setting,
18600            buffer,
18601        ) {
18602            return insert_range.to_offset(buffer);
18603        }
18604    }
18605
18606    completion.replace_range.to_offset(buffer)
18607}
18608
18609fn insert_extra_newline_brackets(
18610    buffer: &MultiBufferSnapshot,
18611    range: Range<usize>,
18612    language: &language::LanguageScope,
18613) -> bool {
18614    let leading_whitespace_len = buffer
18615        .reversed_chars_at(range.start)
18616        .take_while(|c| c.is_whitespace() && *c != '\n')
18617        .map(|c| c.len_utf8())
18618        .sum::<usize>();
18619    let trailing_whitespace_len = buffer
18620        .chars_at(range.end)
18621        .take_while(|c| c.is_whitespace() && *c != '\n')
18622        .map(|c| c.len_utf8())
18623        .sum::<usize>();
18624    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
18625
18626    language.brackets().any(|(pair, enabled)| {
18627        let pair_start = pair.start.trim_end();
18628        let pair_end = pair.end.trim_start();
18629
18630        enabled
18631            && pair.newline
18632            && buffer.contains_str_at(range.end, pair_end)
18633            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
18634    })
18635}
18636
18637fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
18638    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
18639        [(buffer, range, _)] => (*buffer, range.clone()),
18640        _ => return false,
18641    };
18642    let pair = {
18643        let mut result: Option<BracketMatch> = None;
18644
18645        for pair in buffer
18646            .all_bracket_ranges(range.clone())
18647            .filter(move |pair| {
18648                pair.open_range.start <= range.start && pair.close_range.end >= range.end
18649            })
18650        {
18651            let len = pair.close_range.end - pair.open_range.start;
18652
18653            if let Some(existing) = &result {
18654                let existing_len = existing.close_range.end - existing.open_range.start;
18655                if len > existing_len {
18656                    continue;
18657                }
18658            }
18659
18660            result = Some(pair);
18661        }
18662
18663        result
18664    };
18665    let Some(pair) = pair else {
18666        return false;
18667    };
18668    pair.newline_only
18669        && buffer
18670            .chars_for_range(pair.open_range.end..range.start)
18671            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
18672            .all(|c| c.is_whitespace() && c != '\n')
18673}
18674
18675fn get_uncommitted_diff_for_buffer(
18676    project: &Entity<Project>,
18677    buffers: impl IntoIterator<Item = Entity<Buffer>>,
18678    buffer: Entity<MultiBuffer>,
18679    cx: &mut App,
18680) -> Task<()> {
18681    let mut tasks = Vec::new();
18682    project.update(cx, |project, cx| {
18683        for buffer in buffers {
18684            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
18685                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
18686            }
18687        }
18688    });
18689    cx.spawn(async move |cx| {
18690        let diffs = future::join_all(tasks).await;
18691        buffer
18692            .update(cx, |buffer, cx| {
18693                for diff in diffs.into_iter().flatten() {
18694                    buffer.add_diff(diff, cx);
18695                }
18696            })
18697            .ok();
18698    })
18699}
18700
18701fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
18702    let tab_size = tab_size.get() as usize;
18703    let mut width = offset;
18704
18705    for ch in text.chars() {
18706        width += if ch == '\t' {
18707            tab_size - (width % tab_size)
18708        } else {
18709            1
18710        };
18711    }
18712
18713    width - offset
18714}
18715
18716#[cfg(test)]
18717mod tests {
18718    use super::*;
18719
18720    #[test]
18721    fn test_string_size_with_expanded_tabs() {
18722        let nz = |val| NonZeroU32::new(val).unwrap();
18723        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
18724        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
18725        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
18726        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
18727        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
18728        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
18729        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
18730        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
18731    }
18732}
18733
18734/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
18735struct WordBreakingTokenizer<'a> {
18736    input: &'a str,
18737}
18738
18739impl<'a> WordBreakingTokenizer<'a> {
18740    fn new(input: &'a str) -> Self {
18741        Self { input }
18742    }
18743}
18744
18745fn is_char_ideographic(ch: char) -> bool {
18746    use unicode_script::Script::*;
18747    use unicode_script::UnicodeScript;
18748    matches!(ch.script(), Han | Tangut | Yi)
18749}
18750
18751fn is_grapheme_ideographic(text: &str) -> bool {
18752    text.chars().any(is_char_ideographic)
18753}
18754
18755fn is_grapheme_whitespace(text: &str) -> bool {
18756    text.chars().any(|x| x.is_whitespace())
18757}
18758
18759fn should_stay_with_preceding_ideograph(text: &str) -> bool {
18760    text.chars().next().map_or(false, |ch| {
18761        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
18762    })
18763}
18764
18765#[derive(PartialEq, Eq, Debug, Clone, Copy)]
18766enum WordBreakToken<'a> {
18767    Word { token: &'a str, grapheme_len: usize },
18768    InlineWhitespace { token: &'a str, grapheme_len: usize },
18769    Newline,
18770}
18771
18772impl<'a> Iterator for WordBreakingTokenizer<'a> {
18773    /// Yields a span, the count of graphemes in the token, and whether it was
18774    /// whitespace. Note that it also breaks at word boundaries.
18775    type Item = WordBreakToken<'a>;
18776
18777    fn next(&mut self) -> Option<Self::Item> {
18778        use unicode_segmentation::UnicodeSegmentation;
18779        if self.input.is_empty() {
18780            return None;
18781        }
18782
18783        let mut iter = self.input.graphemes(true).peekable();
18784        let mut offset = 0;
18785        let mut grapheme_len = 0;
18786        if let Some(first_grapheme) = iter.next() {
18787            let is_newline = first_grapheme == "\n";
18788            let is_whitespace = is_grapheme_whitespace(first_grapheme);
18789            offset += first_grapheme.len();
18790            grapheme_len += 1;
18791            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
18792                if let Some(grapheme) = iter.peek().copied() {
18793                    if should_stay_with_preceding_ideograph(grapheme) {
18794                        offset += grapheme.len();
18795                        grapheme_len += 1;
18796                    }
18797                }
18798            } else {
18799                let mut words = self.input[offset..].split_word_bound_indices().peekable();
18800                let mut next_word_bound = words.peek().copied();
18801                if next_word_bound.map_or(false, |(i, _)| i == 0) {
18802                    next_word_bound = words.next();
18803                }
18804                while let Some(grapheme) = iter.peek().copied() {
18805                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
18806                        break;
18807                    };
18808                    if is_grapheme_whitespace(grapheme) != is_whitespace
18809                        || (grapheme == "\n") != is_newline
18810                    {
18811                        break;
18812                    };
18813                    offset += grapheme.len();
18814                    grapheme_len += 1;
18815                    iter.next();
18816                }
18817            }
18818            let token = &self.input[..offset];
18819            self.input = &self.input[offset..];
18820            if token == "\n" {
18821                Some(WordBreakToken::Newline)
18822            } else if is_whitespace {
18823                Some(WordBreakToken::InlineWhitespace {
18824                    token,
18825                    grapheme_len,
18826                })
18827            } else {
18828                Some(WordBreakToken::Word {
18829                    token,
18830                    grapheme_len,
18831                })
18832            }
18833        } else {
18834            None
18835        }
18836    }
18837}
18838
18839#[test]
18840fn test_word_breaking_tokenizer() {
18841    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
18842        ("", &[]),
18843        ("  ", &[whitespace("  ", 2)]),
18844        ("Ʒ", &[word("Ʒ", 1)]),
18845        ("Ǽ", &[word("Ǽ", 1)]),
18846        ("", &[word("", 1)]),
18847        ("⋑⋑", &[word("⋑⋑", 2)]),
18848        (
18849            "原理,进而",
18850            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
18851        ),
18852        (
18853            "hello world",
18854            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
18855        ),
18856        (
18857            "hello, world",
18858            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
18859        ),
18860        (
18861            "  hello world",
18862            &[
18863                whitespace("  ", 2),
18864                word("hello", 5),
18865                whitespace(" ", 1),
18866                word("world", 5),
18867            ],
18868        ),
18869        (
18870            "这是什么 \n 钢笔",
18871            &[
18872                word("", 1),
18873                word("", 1),
18874                word("", 1),
18875                word("", 1),
18876                whitespace(" ", 1),
18877                newline(),
18878                whitespace(" ", 1),
18879                word("", 1),
18880                word("", 1),
18881            ],
18882        ),
18883        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
18884    ];
18885
18886    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
18887        WordBreakToken::Word {
18888            token,
18889            grapheme_len,
18890        }
18891    }
18892
18893    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
18894        WordBreakToken::InlineWhitespace {
18895            token,
18896            grapheme_len,
18897        }
18898    }
18899
18900    fn newline() -> WordBreakToken<'static> {
18901        WordBreakToken::Newline
18902    }
18903
18904    for (input, result) in tests {
18905        assert_eq!(
18906            WordBreakingTokenizer::new(input)
18907                .collect::<Vec<_>>()
18908                .as_slice(),
18909            *result,
18910        );
18911    }
18912}
18913
18914fn wrap_with_prefix(
18915    line_prefix: String,
18916    unwrapped_text: String,
18917    wrap_column: usize,
18918    tab_size: NonZeroU32,
18919    preserve_existing_whitespace: bool,
18920) -> String {
18921    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
18922    let mut wrapped_text = String::new();
18923    let mut current_line = line_prefix.clone();
18924
18925    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
18926    let mut current_line_len = line_prefix_len;
18927    let mut in_whitespace = false;
18928    for token in tokenizer {
18929        let have_preceding_whitespace = in_whitespace;
18930        match token {
18931            WordBreakToken::Word {
18932                token,
18933                grapheme_len,
18934            } => {
18935                in_whitespace = false;
18936                if current_line_len + grapheme_len > wrap_column
18937                    && current_line_len != line_prefix_len
18938                {
18939                    wrapped_text.push_str(current_line.trim_end());
18940                    wrapped_text.push('\n');
18941                    current_line.truncate(line_prefix.len());
18942                    current_line_len = line_prefix_len;
18943                }
18944                current_line.push_str(token);
18945                current_line_len += grapheme_len;
18946            }
18947            WordBreakToken::InlineWhitespace {
18948                mut token,
18949                mut grapheme_len,
18950            } => {
18951                in_whitespace = true;
18952                if have_preceding_whitespace && !preserve_existing_whitespace {
18953                    continue;
18954                }
18955                if !preserve_existing_whitespace {
18956                    token = " ";
18957                    grapheme_len = 1;
18958                }
18959                if current_line_len + grapheme_len > wrap_column {
18960                    wrapped_text.push_str(current_line.trim_end());
18961                    wrapped_text.push('\n');
18962                    current_line.truncate(line_prefix.len());
18963                    current_line_len = line_prefix_len;
18964                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
18965                    current_line.push_str(token);
18966                    current_line_len += grapheme_len;
18967                }
18968            }
18969            WordBreakToken::Newline => {
18970                in_whitespace = true;
18971                if preserve_existing_whitespace {
18972                    wrapped_text.push_str(current_line.trim_end());
18973                    wrapped_text.push('\n');
18974                    current_line.truncate(line_prefix.len());
18975                    current_line_len = line_prefix_len;
18976                } else if have_preceding_whitespace {
18977                    continue;
18978                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
18979                {
18980                    wrapped_text.push_str(current_line.trim_end());
18981                    wrapped_text.push('\n');
18982                    current_line.truncate(line_prefix.len());
18983                    current_line_len = line_prefix_len;
18984                } else if current_line_len != line_prefix_len {
18985                    current_line.push(' ');
18986                    current_line_len += 1;
18987                }
18988            }
18989        }
18990    }
18991
18992    if !current_line.is_empty() {
18993        wrapped_text.push_str(&current_line);
18994    }
18995    wrapped_text
18996}
18997
18998#[test]
18999fn test_wrap_with_prefix() {
19000    assert_eq!(
19001        wrap_with_prefix(
19002            "# ".to_string(),
19003            "abcdefg".to_string(),
19004            4,
19005            NonZeroU32::new(4).unwrap(),
19006            false,
19007        ),
19008        "# abcdefg"
19009    );
19010    assert_eq!(
19011        wrap_with_prefix(
19012            "".to_string(),
19013            "\thello world".to_string(),
19014            8,
19015            NonZeroU32::new(4).unwrap(),
19016            false,
19017        ),
19018        "hello\nworld"
19019    );
19020    assert_eq!(
19021        wrap_with_prefix(
19022            "// ".to_string(),
19023            "xx \nyy zz aa bb cc".to_string(),
19024            12,
19025            NonZeroU32::new(4).unwrap(),
19026            false,
19027        ),
19028        "// xx yy zz\n// aa bb cc"
19029    );
19030    assert_eq!(
19031        wrap_with_prefix(
19032            String::new(),
19033            "这是什么 \n 钢笔".to_string(),
19034            3,
19035            NonZeroU32::new(4).unwrap(),
19036            false,
19037        ),
19038        "这是什\n么 钢\n"
19039    );
19040}
19041
19042pub trait CollaborationHub {
19043    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19044    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19045    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19046}
19047
19048impl CollaborationHub for Entity<Project> {
19049    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19050        self.read(cx).collaborators()
19051    }
19052
19053    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19054        self.read(cx).user_store().read(cx).participant_indices()
19055    }
19056
19057    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19058        let this = self.read(cx);
19059        let user_ids = this.collaborators().values().map(|c| c.user_id);
19060        this.user_store().read_with(cx, |user_store, cx| {
19061            user_store.participant_names(user_ids, cx)
19062        })
19063    }
19064}
19065
19066pub trait SemanticsProvider {
19067    fn hover(
19068        &self,
19069        buffer: &Entity<Buffer>,
19070        position: text::Anchor,
19071        cx: &mut App,
19072    ) -> Option<Task<Vec<project::Hover>>>;
19073
19074    fn inline_values(
19075        &self,
19076        buffer_handle: Entity<Buffer>,
19077        range: Range<text::Anchor>,
19078        cx: &mut App,
19079    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19080
19081    fn inlay_hints(
19082        &self,
19083        buffer_handle: Entity<Buffer>,
19084        range: Range<text::Anchor>,
19085        cx: &mut App,
19086    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19087
19088    fn resolve_inlay_hint(
19089        &self,
19090        hint: InlayHint,
19091        buffer_handle: Entity<Buffer>,
19092        server_id: LanguageServerId,
19093        cx: &mut App,
19094    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19095
19096    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19097
19098    fn document_highlights(
19099        &self,
19100        buffer: &Entity<Buffer>,
19101        position: text::Anchor,
19102        cx: &mut App,
19103    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19104
19105    fn definitions(
19106        &self,
19107        buffer: &Entity<Buffer>,
19108        position: text::Anchor,
19109        kind: GotoDefinitionKind,
19110        cx: &mut App,
19111    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19112
19113    fn range_for_rename(
19114        &self,
19115        buffer: &Entity<Buffer>,
19116        position: text::Anchor,
19117        cx: &mut App,
19118    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19119
19120    fn perform_rename(
19121        &self,
19122        buffer: &Entity<Buffer>,
19123        position: text::Anchor,
19124        new_name: String,
19125        cx: &mut App,
19126    ) -> Option<Task<Result<ProjectTransaction>>>;
19127}
19128
19129pub trait CompletionProvider {
19130    fn completions(
19131        &self,
19132        excerpt_id: ExcerptId,
19133        buffer: &Entity<Buffer>,
19134        buffer_position: text::Anchor,
19135        trigger: CompletionContext,
19136        window: &mut Window,
19137        cx: &mut Context<Editor>,
19138    ) -> Task<Result<Option<Vec<Completion>>>>;
19139
19140    fn resolve_completions(
19141        &self,
19142        buffer: Entity<Buffer>,
19143        completion_indices: Vec<usize>,
19144        completions: Rc<RefCell<Box<[Completion]>>>,
19145        cx: &mut Context<Editor>,
19146    ) -> Task<Result<bool>>;
19147
19148    fn apply_additional_edits_for_completion(
19149        &self,
19150        _buffer: Entity<Buffer>,
19151        _completions: Rc<RefCell<Box<[Completion]>>>,
19152        _completion_index: usize,
19153        _push_to_history: bool,
19154        _cx: &mut Context<Editor>,
19155    ) -> Task<Result<Option<language::Transaction>>> {
19156        Task::ready(Ok(None))
19157    }
19158
19159    fn is_completion_trigger(
19160        &self,
19161        buffer: &Entity<Buffer>,
19162        position: language::Anchor,
19163        text: &str,
19164        trigger_in_words: bool,
19165        cx: &mut Context<Editor>,
19166    ) -> bool;
19167
19168    fn sort_completions(&self) -> bool {
19169        true
19170    }
19171
19172    fn filter_completions(&self) -> bool {
19173        true
19174    }
19175}
19176
19177pub trait CodeActionProvider {
19178    fn id(&self) -> Arc<str>;
19179
19180    fn code_actions(
19181        &self,
19182        buffer: &Entity<Buffer>,
19183        range: Range<text::Anchor>,
19184        window: &mut Window,
19185        cx: &mut App,
19186    ) -> Task<Result<Vec<CodeAction>>>;
19187
19188    fn apply_code_action(
19189        &self,
19190        buffer_handle: Entity<Buffer>,
19191        action: CodeAction,
19192        excerpt_id: ExcerptId,
19193        push_to_history: bool,
19194        window: &mut Window,
19195        cx: &mut App,
19196    ) -> Task<Result<ProjectTransaction>>;
19197}
19198
19199impl CodeActionProvider for Entity<Project> {
19200    fn id(&self) -> Arc<str> {
19201        "project".into()
19202    }
19203
19204    fn code_actions(
19205        &self,
19206        buffer: &Entity<Buffer>,
19207        range: Range<text::Anchor>,
19208        _window: &mut Window,
19209        cx: &mut App,
19210    ) -> Task<Result<Vec<CodeAction>>> {
19211        self.update(cx, |project, cx| {
19212            let code_lens = project.code_lens(buffer, range.clone(), cx);
19213            let code_actions = project.code_actions(buffer, range, None, cx);
19214            cx.background_spawn(async move {
19215                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19216                Ok(code_lens
19217                    .context("code lens fetch")?
19218                    .into_iter()
19219                    .chain(code_actions.context("code action fetch")?)
19220                    .collect())
19221            })
19222        })
19223    }
19224
19225    fn apply_code_action(
19226        &self,
19227        buffer_handle: Entity<Buffer>,
19228        action: CodeAction,
19229        _excerpt_id: ExcerptId,
19230        push_to_history: bool,
19231        _window: &mut Window,
19232        cx: &mut App,
19233    ) -> Task<Result<ProjectTransaction>> {
19234        self.update(cx, |project, cx| {
19235            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19236        })
19237    }
19238}
19239
19240fn snippet_completions(
19241    project: &Project,
19242    buffer: &Entity<Buffer>,
19243    buffer_position: text::Anchor,
19244    cx: &mut App,
19245) -> Task<Result<Vec<Completion>>> {
19246    let languages = buffer.read(cx).languages_at(buffer_position);
19247    let snippet_store = project.snippets().read(cx);
19248
19249    let scopes: Vec<_> = languages
19250        .iter()
19251        .filter_map(|language| {
19252            let language_name = language.lsp_id();
19253            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19254
19255            if snippets.is_empty() {
19256                None
19257            } else {
19258                Some((language.default_scope(), snippets))
19259            }
19260        })
19261        .collect();
19262
19263    if scopes.is_empty() {
19264        return Task::ready(Ok(vec![]));
19265    }
19266
19267    let snapshot = buffer.read(cx).text_snapshot();
19268    let chars: String = snapshot
19269        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19270        .collect();
19271    let executor = cx.background_executor().clone();
19272
19273    cx.background_spawn(async move {
19274        let mut all_results: Vec<Completion> = Vec::new();
19275        for (scope, snippets) in scopes.into_iter() {
19276            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19277            let mut last_word = chars
19278                .chars()
19279                .take_while(|c| classifier.is_word(*c))
19280                .collect::<String>();
19281            last_word = last_word.chars().rev().collect();
19282
19283            if last_word.is_empty() {
19284                return Ok(vec![]);
19285            }
19286
19287            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19288            let to_lsp = |point: &text::Anchor| {
19289                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19290                point_to_lsp(end)
19291            };
19292            let lsp_end = to_lsp(&buffer_position);
19293
19294            let candidates = snippets
19295                .iter()
19296                .enumerate()
19297                .flat_map(|(ix, snippet)| {
19298                    snippet
19299                        .prefix
19300                        .iter()
19301                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19302                })
19303                .collect::<Vec<StringMatchCandidate>>();
19304
19305            let mut matches = fuzzy::match_strings(
19306                &candidates,
19307                &last_word,
19308                last_word.chars().any(|c| c.is_uppercase()),
19309                100,
19310                &Default::default(),
19311                executor.clone(),
19312            )
19313            .await;
19314
19315            // Remove all candidates where the query's start does not match the start of any word in the candidate
19316            if let Some(query_start) = last_word.chars().next() {
19317                matches.retain(|string_match| {
19318                    split_words(&string_match.string).any(|word| {
19319                        // Check that the first codepoint of the word as lowercase matches the first
19320                        // codepoint of the query as lowercase
19321                        word.chars()
19322                            .flat_map(|codepoint| codepoint.to_lowercase())
19323                            .zip(query_start.to_lowercase())
19324                            .all(|(word_cp, query_cp)| word_cp == query_cp)
19325                    })
19326                });
19327            }
19328
19329            let matched_strings = matches
19330                .into_iter()
19331                .map(|m| m.string)
19332                .collect::<HashSet<_>>();
19333
19334            let mut result: Vec<Completion> = snippets
19335                .iter()
19336                .filter_map(|snippet| {
19337                    let matching_prefix = snippet
19338                        .prefix
19339                        .iter()
19340                        .find(|prefix| matched_strings.contains(*prefix))?;
19341                    let start = as_offset - last_word.len();
19342                    let start = snapshot.anchor_before(start);
19343                    let range = start..buffer_position;
19344                    let lsp_start = to_lsp(&start);
19345                    let lsp_range = lsp::Range {
19346                        start: lsp_start,
19347                        end: lsp_end,
19348                    };
19349                    Some(Completion {
19350                        replace_range: range,
19351                        new_text: snippet.body.clone(),
19352                        source: CompletionSource::Lsp {
19353                            insert_range: None,
19354                            server_id: LanguageServerId(usize::MAX),
19355                            resolved: true,
19356                            lsp_completion: Box::new(lsp::CompletionItem {
19357                                label: snippet.prefix.first().unwrap().clone(),
19358                                kind: Some(CompletionItemKind::SNIPPET),
19359                                label_details: snippet.description.as_ref().map(|description| {
19360                                    lsp::CompletionItemLabelDetails {
19361                                        detail: Some(description.clone()),
19362                                        description: None,
19363                                    }
19364                                }),
19365                                insert_text_format: Some(InsertTextFormat::SNIPPET),
19366                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
19367                                    lsp::InsertReplaceEdit {
19368                                        new_text: snippet.body.clone(),
19369                                        insert: lsp_range,
19370                                        replace: lsp_range,
19371                                    },
19372                                )),
19373                                filter_text: Some(snippet.body.clone()),
19374                                sort_text: Some(char::MAX.to_string()),
19375                                ..lsp::CompletionItem::default()
19376                            }),
19377                            lsp_defaults: None,
19378                        },
19379                        label: CodeLabel {
19380                            text: matching_prefix.clone(),
19381                            runs: Vec::new(),
19382                            filter_range: 0..matching_prefix.len(),
19383                        },
19384                        icon_path: None,
19385                        documentation: snippet.description.clone().map(|description| {
19386                            CompletionDocumentation::SingleLine(description.into())
19387                        }),
19388                        insert_text_mode: None,
19389                        confirm: None,
19390                    })
19391                })
19392                .collect();
19393
19394            all_results.append(&mut result);
19395        }
19396
19397        Ok(all_results)
19398    })
19399}
19400
19401impl CompletionProvider for Entity<Project> {
19402    fn completions(
19403        &self,
19404        _excerpt_id: ExcerptId,
19405        buffer: &Entity<Buffer>,
19406        buffer_position: text::Anchor,
19407        options: CompletionContext,
19408        _window: &mut Window,
19409        cx: &mut Context<Editor>,
19410    ) -> Task<Result<Option<Vec<Completion>>>> {
19411        self.update(cx, |project, cx| {
19412            let snippets = snippet_completions(project, buffer, buffer_position, cx);
19413            let project_completions = project.completions(buffer, buffer_position, options, cx);
19414            cx.background_spawn(async move {
19415                let snippets_completions = snippets.await?;
19416                match project_completions.await? {
19417                    Some(mut completions) => {
19418                        completions.extend(snippets_completions);
19419                        Ok(Some(completions))
19420                    }
19421                    None => {
19422                        if snippets_completions.is_empty() {
19423                            Ok(None)
19424                        } else {
19425                            Ok(Some(snippets_completions))
19426                        }
19427                    }
19428                }
19429            })
19430        })
19431    }
19432
19433    fn resolve_completions(
19434        &self,
19435        buffer: Entity<Buffer>,
19436        completion_indices: Vec<usize>,
19437        completions: Rc<RefCell<Box<[Completion]>>>,
19438        cx: &mut Context<Editor>,
19439    ) -> Task<Result<bool>> {
19440        self.update(cx, |project, cx| {
19441            project.lsp_store().update(cx, |lsp_store, cx| {
19442                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
19443            })
19444        })
19445    }
19446
19447    fn apply_additional_edits_for_completion(
19448        &self,
19449        buffer: Entity<Buffer>,
19450        completions: Rc<RefCell<Box<[Completion]>>>,
19451        completion_index: usize,
19452        push_to_history: bool,
19453        cx: &mut Context<Editor>,
19454    ) -> Task<Result<Option<language::Transaction>>> {
19455        self.update(cx, |project, cx| {
19456            project.lsp_store().update(cx, |lsp_store, cx| {
19457                lsp_store.apply_additional_edits_for_completion(
19458                    buffer,
19459                    completions,
19460                    completion_index,
19461                    push_to_history,
19462                    cx,
19463                )
19464            })
19465        })
19466    }
19467
19468    fn is_completion_trigger(
19469        &self,
19470        buffer: &Entity<Buffer>,
19471        position: language::Anchor,
19472        text: &str,
19473        trigger_in_words: bool,
19474        cx: &mut Context<Editor>,
19475    ) -> bool {
19476        let mut chars = text.chars();
19477        let char = if let Some(char) = chars.next() {
19478            char
19479        } else {
19480            return false;
19481        };
19482        if chars.next().is_some() {
19483            return false;
19484        }
19485
19486        let buffer = buffer.read(cx);
19487        let snapshot = buffer.snapshot();
19488        if !snapshot.settings_at(position, cx).show_completions_on_input {
19489            return false;
19490        }
19491        let classifier = snapshot.char_classifier_at(position).for_completion(true);
19492        if trigger_in_words && classifier.is_word(char) {
19493            return true;
19494        }
19495
19496        buffer.completion_triggers().contains(text)
19497    }
19498}
19499
19500impl SemanticsProvider for Entity<Project> {
19501    fn hover(
19502        &self,
19503        buffer: &Entity<Buffer>,
19504        position: text::Anchor,
19505        cx: &mut App,
19506    ) -> Option<Task<Vec<project::Hover>>> {
19507        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
19508    }
19509
19510    fn document_highlights(
19511        &self,
19512        buffer: &Entity<Buffer>,
19513        position: text::Anchor,
19514        cx: &mut App,
19515    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
19516        Some(self.update(cx, |project, cx| {
19517            project.document_highlights(buffer, position, cx)
19518        }))
19519    }
19520
19521    fn definitions(
19522        &self,
19523        buffer: &Entity<Buffer>,
19524        position: text::Anchor,
19525        kind: GotoDefinitionKind,
19526        cx: &mut App,
19527    ) -> Option<Task<Result<Vec<LocationLink>>>> {
19528        Some(self.update(cx, |project, cx| match kind {
19529            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
19530            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
19531            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
19532            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
19533        }))
19534    }
19535
19536    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
19537        // TODO: make this work for remote projects
19538        self.update(cx, |project, cx| {
19539            if project
19540                .active_debug_session(cx)
19541                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
19542            {
19543                return true;
19544            }
19545
19546            buffer.update(cx, |buffer, cx| {
19547                project.any_language_server_supports_inlay_hints(buffer, cx)
19548            })
19549        })
19550    }
19551
19552    fn inline_values(
19553        &self,
19554        buffer_handle: Entity<Buffer>,
19555        range: Range<text::Anchor>,
19556        cx: &mut App,
19557    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
19558        self.update(cx, |project, cx| {
19559            let (session, active_stack_frame) = project.active_debug_session(cx)?;
19560
19561            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
19562        })
19563    }
19564
19565    fn inlay_hints(
19566        &self,
19567        buffer_handle: Entity<Buffer>,
19568        range: Range<text::Anchor>,
19569        cx: &mut App,
19570    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
19571        Some(self.update(cx, |project, cx| {
19572            project.inlay_hints(buffer_handle, range, cx)
19573        }))
19574    }
19575
19576    fn resolve_inlay_hint(
19577        &self,
19578        hint: InlayHint,
19579        buffer_handle: Entity<Buffer>,
19580        server_id: LanguageServerId,
19581        cx: &mut App,
19582    ) -> Option<Task<anyhow::Result<InlayHint>>> {
19583        Some(self.update(cx, |project, cx| {
19584            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
19585        }))
19586    }
19587
19588    fn range_for_rename(
19589        &self,
19590        buffer: &Entity<Buffer>,
19591        position: text::Anchor,
19592        cx: &mut App,
19593    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
19594        Some(self.update(cx, |project, cx| {
19595            let buffer = buffer.clone();
19596            let task = project.prepare_rename(buffer.clone(), position, cx);
19597            cx.spawn(async move |_, cx| {
19598                Ok(match task.await? {
19599                    PrepareRenameResponse::Success(range) => Some(range),
19600                    PrepareRenameResponse::InvalidPosition => None,
19601                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
19602                        // Fallback on using TreeSitter info to determine identifier range
19603                        buffer.update(cx, |buffer, _| {
19604                            let snapshot = buffer.snapshot();
19605                            let (range, kind) = snapshot.surrounding_word(position);
19606                            if kind != Some(CharKind::Word) {
19607                                return None;
19608                            }
19609                            Some(
19610                                snapshot.anchor_before(range.start)
19611                                    ..snapshot.anchor_after(range.end),
19612                            )
19613                        })?
19614                    }
19615                })
19616            })
19617        }))
19618    }
19619
19620    fn perform_rename(
19621        &self,
19622        buffer: &Entity<Buffer>,
19623        position: text::Anchor,
19624        new_name: String,
19625        cx: &mut App,
19626    ) -> Option<Task<Result<ProjectTransaction>>> {
19627        Some(self.update(cx, |project, cx| {
19628            project.perform_rename(buffer.clone(), position, new_name, cx)
19629        }))
19630    }
19631}
19632
19633fn inlay_hint_settings(
19634    location: Anchor,
19635    snapshot: &MultiBufferSnapshot,
19636    cx: &mut Context<Editor>,
19637) -> InlayHintSettings {
19638    let file = snapshot.file_at(location);
19639    let language = snapshot.language_at(location).map(|l| l.name());
19640    language_settings(language, file, cx).inlay_hints
19641}
19642
19643fn consume_contiguous_rows(
19644    contiguous_row_selections: &mut Vec<Selection<Point>>,
19645    selection: &Selection<Point>,
19646    display_map: &DisplaySnapshot,
19647    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
19648) -> (MultiBufferRow, MultiBufferRow) {
19649    contiguous_row_selections.push(selection.clone());
19650    let start_row = MultiBufferRow(selection.start.row);
19651    let mut end_row = ending_row(selection, display_map);
19652
19653    while let Some(next_selection) = selections.peek() {
19654        if next_selection.start.row <= end_row.0 {
19655            end_row = ending_row(next_selection, display_map);
19656            contiguous_row_selections.push(selections.next().unwrap().clone());
19657        } else {
19658            break;
19659        }
19660    }
19661    (start_row, end_row)
19662}
19663
19664fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
19665    if next_selection.end.column > 0 || next_selection.is_empty() {
19666        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
19667    } else {
19668        MultiBufferRow(next_selection.end.row)
19669    }
19670}
19671
19672impl EditorSnapshot {
19673    pub fn remote_selections_in_range<'a>(
19674        &'a self,
19675        range: &'a Range<Anchor>,
19676        collaboration_hub: &dyn CollaborationHub,
19677        cx: &'a App,
19678    ) -> impl 'a + Iterator<Item = RemoteSelection> {
19679        let participant_names = collaboration_hub.user_names(cx);
19680        let participant_indices = collaboration_hub.user_participant_indices(cx);
19681        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
19682        let collaborators_by_replica_id = collaborators_by_peer_id
19683            .iter()
19684            .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
19685            .collect::<HashMap<_, _>>();
19686        self.buffer_snapshot
19687            .selections_in_range(range, false)
19688            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
19689                let collaborator = collaborators_by_replica_id.get(&replica_id)?;
19690                let participant_index = participant_indices.get(&collaborator.user_id).copied();
19691                let user_name = participant_names.get(&collaborator.user_id).cloned();
19692                Some(RemoteSelection {
19693                    replica_id,
19694                    selection,
19695                    cursor_shape,
19696                    line_mode,
19697                    participant_index,
19698                    peer_id: collaborator.peer_id,
19699                    user_name,
19700                })
19701            })
19702    }
19703
19704    pub fn hunks_for_ranges(
19705        &self,
19706        ranges: impl IntoIterator<Item = Range<Point>>,
19707    ) -> Vec<MultiBufferDiffHunk> {
19708        let mut hunks = Vec::new();
19709        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
19710            HashMap::default();
19711        for query_range in ranges {
19712            let query_rows =
19713                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
19714            for hunk in self.buffer_snapshot.diff_hunks_in_range(
19715                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
19716            ) {
19717                // Include deleted hunks that are adjacent to the query range, because
19718                // otherwise they would be missed.
19719                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
19720                if hunk.status().is_deleted() {
19721                    intersects_range |= hunk.row_range.start == query_rows.end;
19722                    intersects_range |= hunk.row_range.end == query_rows.start;
19723                }
19724                if intersects_range {
19725                    if !processed_buffer_rows
19726                        .entry(hunk.buffer_id)
19727                        .or_default()
19728                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
19729                    {
19730                        continue;
19731                    }
19732                    hunks.push(hunk);
19733                }
19734            }
19735        }
19736
19737        hunks
19738    }
19739
19740    fn display_diff_hunks_for_rows<'a>(
19741        &'a self,
19742        display_rows: Range<DisplayRow>,
19743        folded_buffers: &'a HashSet<BufferId>,
19744    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
19745        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
19746        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
19747
19748        self.buffer_snapshot
19749            .diff_hunks_in_range(buffer_start..buffer_end)
19750            .filter_map(|hunk| {
19751                if folded_buffers.contains(&hunk.buffer_id) {
19752                    return None;
19753                }
19754
19755                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
19756                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
19757
19758                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
19759                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
19760
19761                let display_hunk = if hunk_display_start.column() != 0 {
19762                    DisplayDiffHunk::Folded {
19763                        display_row: hunk_display_start.row(),
19764                    }
19765                } else {
19766                    let mut end_row = hunk_display_end.row();
19767                    if hunk_display_end.column() > 0 {
19768                        end_row.0 += 1;
19769                    }
19770                    let is_created_file = hunk.is_created_file();
19771                    DisplayDiffHunk::Unfolded {
19772                        status: hunk.status(),
19773                        diff_base_byte_range: hunk.diff_base_byte_range,
19774                        display_row_range: hunk_display_start.row()..end_row,
19775                        multi_buffer_range: Anchor::range_in_buffer(
19776                            hunk.excerpt_id,
19777                            hunk.buffer_id,
19778                            hunk.buffer_range,
19779                        ),
19780                        is_created_file,
19781                    }
19782                };
19783
19784                Some(display_hunk)
19785            })
19786    }
19787
19788    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
19789        self.display_snapshot.buffer_snapshot.language_at(position)
19790    }
19791
19792    pub fn is_focused(&self) -> bool {
19793        self.is_focused
19794    }
19795
19796    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
19797        self.placeholder_text.as_ref()
19798    }
19799
19800    pub fn scroll_position(&self) -> gpui::Point<f32> {
19801        self.scroll_anchor.scroll_position(&self.display_snapshot)
19802    }
19803
19804    fn gutter_dimensions(
19805        &self,
19806        font_id: FontId,
19807        font_size: Pixels,
19808        max_line_number_width: Pixels,
19809        cx: &App,
19810    ) -> Option<GutterDimensions> {
19811        if !self.show_gutter {
19812            return None;
19813        }
19814
19815        let descent = cx.text_system().descent(font_id, font_size);
19816        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
19817        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
19818
19819        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
19820            matches!(
19821                ProjectSettings::get_global(cx).git.git_gutter,
19822                Some(GitGutterSetting::TrackedFiles)
19823            )
19824        });
19825        let gutter_settings = EditorSettings::get_global(cx).gutter;
19826        let show_line_numbers = self
19827            .show_line_numbers
19828            .unwrap_or(gutter_settings.line_numbers);
19829        let line_gutter_width = if show_line_numbers {
19830            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
19831            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
19832            max_line_number_width.max(min_width_for_number_on_gutter)
19833        } else {
19834            0.0.into()
19835        };
19836
19837        let show_code_actions = self
19838            .show_code_actions
19839            .unwrap_or(gutter_settings.code_actions);
19840
19841        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
19842        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
19843
19844        let git_blame_entries_width =
19845            self.git_blame_gutter_max_author_length
19846                .map(|max_author_length| {
19847                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19848                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
19849
19850                    /// The number of characters to dedicate to gaps and margins.
19851                    const SPACING_WIDTH: usize = 4;
19852
19853                    let max_char_count = max_author_length.min(renderer.max_author_length())
19854                        + ::git::SHORT_SHA_LENGTH
19855                        + MAX_RELATIVE_TIMESTAMP.len()
19856                        + SPACING_WIDTH;
19857
19858                    em_advance * max_char_count
19859                });
19860
19861        let is_singleton = self.buffer_snapshot.is_singleton();
19862
19863        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
19864        left_padding += if !is_singleton {
19865            em_width * 4.0
19866        } else if show_code_actions || show_runnables || show_breakpoints {
19867            em_width * 3.0
19868        } else if show_git_gutter && show_line_numbers {
19869            em_width * 2.0
19870        } else if show_git_gutter || show_line_numbers {
19871            em_width
19872        } else {
19873            px(0.)
19874        };
19875
19876        let shows_folds = is_singleton && gutter_settings.folds;
19877
19878        let right_padding = if shows_folds && show_line_numbers {
19879            em_width * 4.0
19880        } else if shows_folds || (!is_singleton && show_line_numbers) {
19881            em_width * 3.0
19882        } else if show_line_numbers {
19883            em_width
19884        } else {
19885            px(0.)
19886        };
19887
19888        Some(GutterDimensions {
19889            left_padding,
19890            right_padding,
19891            width: line_gutter_width + left_padding + right_padding,
19892            margin: -descent,
19893            git_blame_entries_width,
19894        })
19895    }
19896
19897    pub fn render_crease_toggle(
19898        &self,
19899        buffer_row: MultiBufferRow,
19900        row_contains_cursor: bool,
19901        editor: Entity<Editor>,
19902        window: &mut Window,
19903        cx: &mut App,
19904    ) -> Option<AnyElement> {
19905        let folded = self.is_line_folded(buffer_row);
19906        let mut is_foldable = false;
19907
19908        if let Some(crease) = self
19909            .crease_snapshot
19910            .query_row(buffer_row, &self.buffer_snapshot)
19911        {
19912            is_foldable = true;
19913            match crease {
19914                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
19915                    if let Some(render_toggle) = render_toggle {
19916                        let toggle_callback =
19917                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
19918                                if folded {
19919                                    editor.update(cx, |editor, cx| {
19920                                        editor.fold_at(buffer_row, window, cx)
19921                                    });
19922                                } else {
19923                                    editor.update(cx, |editor, cx| {
19924                                        editor.unfold_at(buffer_row, window, cx)
19925                                    });
19926                                }
19927                            });
19928                        return Some((render_toggle)(
19929                            buffer_row,
19930                            folded,
19931                            toggle_callback,
19932                            window,
19933                            cx,
19934                        ));
19935                    }
19936                }
19937            }
19938        }
19939
19940        is_foldable |= self.starts_indent(buffer_row);
19941
19942        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
19943            Some(
19944                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
19945                    .toggle_state(folded)
19946                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
19947                        if folded {
19948                            this.unfold_at(buffer_row, window, cx);
19949                        } else {
19950                            this.fold_at(buffer_row, window, cx);
19951                        }
19952                    }))
19953                    .into_any_element(),
19954            )
19955        } else {
19956            None
19957        }
19958    }
19959
19960    pub fn render_crease_trailer(
19961        &self,
19962        buffer_row: MultiBufferRow,
19963        window: &mut Window,
19964        cx: &mut App,
19965    ) -> Option<AnyElement> {
19966        let folded = self.is_line_folded(buffer_row);
19967        if let Crease::Inline { render_trailer, .. } = self
19968            .crease_snapshot
19969            .query_row(buffer_row, &self.buffer_snapshot)?
19970        {
19971            let render_trailer = render_trailer.as_ref()?;
19972            Some(render_trailer(buffer_row, folded, window, cx))
19973        } else {
19974            None
19975        }
19976    }
19977}
19978
19979impl Deref for EditorSnapshot {
19980    type Target = DisplaySnapshot;
19981
19982    fn deref(&self) -> &Self::Target {
19983        &self.display_snapshot
19984    }
19985}
19986
19987#[derive(Clone, Debug, PartialEq, Eq)]
19988pub enum EditorEvent {
19989    InputIgnored {
19990        text: Arc<str>,
19991    },
19992    InputHandled {
19993        utf16_range_to_replace: Option<Range<isize>>,
19994        text: Arc<str>,
19995    },
19996    ExcerptsAdded {
19997        buffer: Entity<Buffer>,
19998        predecessor: ExcerptId,
19999        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20000    },
20001    ExcerptsRemoved {
20002        ids: Vec<ExcerptId>,
20003        removed_buffer_ids: Vec<BufferId>,
20004    },
20005    BufferFoldToggled {
20006        ids: Vec<ExcerptId>,
20007        folded: bool,
20008    },
20009    ExcerptsEdited {
20010        ids: Vec<ExcerptId>,
20011    },
20012    ExcerptsExpanded {
20013        ids: Vec<ExcerptId>,
20014    },
20015    BufferEdited,
20016    Edited {
20017        transaction_id: clock::Lamport,
20018    },
20019    Reparsed(BufferId),
20020    Focused,
20021    FocusedIn,
20022    Blurred,
20023    DirtyChanged,
20024    Saved,
20025    TitleChanged,
20026    DiffBaseChanged,
20027    SelectionsChanged {
20028        local: bool,
20029    },
20030    ScrollPositionChanged {
20031        local: bool,
20032        autoscroll: bool,
20033    },
20034    Closed,
20035    TransactionUndone {
20036        transaction_id: clock::Lamport,
20037    },
20038    TransactionBegun {
20039        transaction_id: clock::Lamport,
20040    },
20041    Reloaded,
20042    CursorShapeChanged,
20043    PushedToNavHistory {
20044        anchor: Anchor,
20045        is_deactivate: bool,
20046    },
20047}
20048
20049impl EventEmitter<EditorEvent> for Editor {}
20050
20051impl Focusable for Editor {
20052    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20053        self.focus_handle.clone()
20054    }
20055}
20056
20057impl Render for Editor {
20058    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20059        let settings = ThemeSettings::get_global(cx);
20060
20061        let mut text_style = match self.mode {
20062            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20063                color: cx.theme().colors().editor_foreground,
20064                font_family: settings.ui_font.family.clone(),
20065                font_features: settings.ui_font.features.clone(),
20066                font_fallbacks: settings.ui_font.fallbacks.clone(),
20067                font_size: rems(0.875).into(),
20068                font_weight: settings.ui_font.weight,
20069                line_height: relative(settings.buffer_line_height.value()),
20070                ..Default::default()
20071            },
20072            EditorMode::Full { .. } => TextStyle {
20073                color: cx.theme().colors().editor_foreground,
20074                font_family: settings.buffer_font.family.clone(),
20075                font_features: settings.buffer_font.features.clone(),
20076                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20077                font_size: settings.buffer_font_size(cx).into(),
20078                font_weight: settings.buffer_font.weight,
20079                line_height: relative(settings.buffer_line_height.value()),
20080                ..Default::default()
20081            },
20082        };
20083        if let Some(text_style_refinement) = &self.text_style_refinement {
20084            text_style.refine(text_style_refinement)
20085        }
20086
20087        let background = match self.mode {
20088            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20089            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20090            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20091        };
20092
20093        EditorElement::new(
20094            &cx.entity(),
20095            EditorStyle {
20096                background,
20097                local_player: cx.theme().players().local(),
20098                text: text_style,
20099                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20100                syntax: cx.theme().syntax().clone(),
20101                status: cx.theme().status().clone(),
20102                inlay_hints_style: make_inlay_hints_style(cx),
20103                inline_completion_styles: make_suggestion_styles(cx),
20104                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20105            },
20106        )
20107    }
20108}
20109
20110impl EntityInputHandler for Editor {
20111    fn text_for_range(
20112        &mut self,
20113        range_utf16: Range<usize>,
20114        adjusted_range: &mut Option<Range<usize>>,
20115        _: &mut Window,
20116        cx: &mut Context<Self>,
20117    ) -> Option<String> {
20118        let snapshot = self.buffer.read(cx).read(cx);
20119        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20120        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20121        if (start.0..end.0) != range_utf16 {
20122            adjusted_range.replace(start.0..end.0);
20123        }
20124        Some(snapshot.text_for_range(start..end).collect())
20125    }
20126
20127    fn selected_text_range(
20128        &mut self,
20129        ignore_disabled_input: bool,
20130        _: &mut Window,
20131        cx: &mut Context<Self>,
20132    ) -> Option<UTF16Selection> {
20133        // Prevent the IME menu from appearing when holding down an alphabetic key
20134        // while input is disabled.
20135        if !ignore_disabled_input && !self.input_enabled {
20136            return None;
20137        }
20138
20139        let selection = self.selections.newest::<OffsetUtf16>(cx);
20140        let range = selection.range();
20141
20142        Some(UTF16Selection {
20143            range: range.start.0..range.end.0,
20144            reversed: selection.reversed,
20145        })
20146    }
20147
20148    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20149        let snapshot = self.buffer.read(cx).read(cx);
20150        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20151        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20152    }
20153
20154    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20155        self.clear_highlights::<InputComposition>(cx);
20156        self.ime_transaction.take();
20157    }
20158
20159    fn replace_text_in_range(
20160        &mut self,
20161        range_utf16: Option<Range<usize>>,
20162        text: &str,
20163        window: &mut Window,
20164        cx: &mut Context<Self>,
20165    ) {
20166        if !self.input_enabled {
20167            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20168            return;
20169        }
20170
20171        self.transact(window, cx, |this, window, cx| {
20172            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20173                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20174                Some(this.selection_replacement_ranges(range_utf16, cx))
20175            } else {
20176                this.marked_text_ranges(cx)
20177            };
20178
20179            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20180                let newest_selection_id = this.selections.newest_anchor().id;
20181                this.selections
20182                    .all::<OffsetUtf16>(cx)
20183                    .iter()
20184                    .zip(ranges_to_replace.iter())
20185                    .find_map(|(selection, range)| {
20186                        if selection.id == newest_selection_id {
20187                            Some(
20188                                (range.start.0 as isize - selection.head().0 as isize)
20189                                    ..(range.end.0 as isize - selection.head().0 as isize),
20190                            )
20191                        } else {
20192                            None
20193                        }
20194                    })
20195            });
20196
20197            cx.emit(EditorEvent::InputHandled {
20198                utf16_range_to_replace: range_to_replace,
20199                text: text.into(),
20200            });
20201
20202            if let Some(new_selected_ranges) = new_selected_ranges {
20203                this.change_selections(None, window, cx, |selections| {
20204                    selections.select_ranges(new_selected_ranges)
20205                });
20206                this.backspace(&Default::default(), window, cx);
20207            }
20208
20209            this.handle_input(text, window, cx);
20210        });
20211
20212        if let Some(transaction) = self.ime_transaction {
20213            self.buffer.update(cx, |buffer, cx| {
20214                buffer.group_until_transaction(transaction, cx);
20215            });
20216        }
20217
20218        self.unmark_text(window, cx);
20219    }
20220
20221    fn replace_and_mark_text_in_range(
20222        &mut self,
20223        range_utf16: Option<Range<usize>>,
20224        text: &str,
20225        new_selected_range_utf16: Option<Range<usize>>,
20226        window: &mut Window,
20227        cx: &mut Context<Self>,
20228    ) {
20229        if !self.input_enabled {
20230            return;
20231        }
20232
20233        let transaction = self.transact(window, cx, |this, window, cx| {
20234            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20235                let snapshot = this.buffer.read(cx).read(cx);
20236                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20237                    for marked_range in &mut marked_ranges {
20238                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20239                        marked_range.start.0 += relative_range_utf16.start;
20240                        marked_range.start =
20241                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20242                        marked_range.end =
20243                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20244                    }
20245                }
20246                Some(marked_ranges)
20247            } else if let Some(range_utf16) = range_utf16 {
20248                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20249                Some(this.selection_replacement_ranges(range_utf16, cx))
20250            } else {
20251                None
20252            };
20253
20254            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20255                let newest_selection_id = this.selections.newest_anchor().id;
20256                this.selections
20257                    .all::<OffsetUtf16>(cx)
20258                    .iter()
20259                    .zip(ranges_to_replace.iter())
20260                    .find_map(|(selection, range)| {
20261                        if selection.id == newest_selection_id {
20262                            Some(
20263                                (range.start.0 as isize - selection.head().0 as isize)
20264                                    ..(range.end.0 as isize - selection.head().0 as isize),
20265                            )
20266                        } else {
20267                            None
20268                        }
20269                    })
20270            });
20271
20272            cx.emit(EditorEvent::InputHandled {
20273                utf16_range_to_replace: range_to_replace,
20274                text: text.into(),
20275            });
20276
20277            if let Some(ranges) = ranges_to_replace {
20278                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20279            }
20280
20281            let marked_ranges = {
20282                let snapshot = this.buffer.read(cx).read(cx);
20283                this.selections
20284                    .disjoint_anchors()
20285                    .iter()
20286                    .map(|selection| {
20287                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20288                    })
20289                    .collect::<Vec<_>>()
20290            };
20291
20292            if text.is_empty() {
20293                this.unmark_text(window, cx);
20294            } else {
20295                this.highlight_text::<InputComposition>(
20296                    marked_ranges.clone(),
20297                    HighlightStyle {
20298                        underline: Some(UnderlineStyle {
20299                            thickness: px(1.),
20300                            color: None,
20301                            wavy: false,
20302                        }),
20303                        ..Default::default()
20304                    },
20305                    cx,
20306                );
20307            }
20308
20309            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
20310            let use_autoclose = this.use_autoclose;
20311            let use_auto_surround = this.use_auto_surround;
20312            this.set_use_autoclose(false);
20313            this.set_use_auto_surround(false);
20314            this.handle_input(text, window, cx);
20315            this.set_use_autoclose(use_autoclose);
20316            this.set_use_auto_surround(use_auto_surround);
20317
20318            if let Some(new_selected_range) = new_selected_range_utf16 {
20319                let snapshot = this.buffer.read(cx).read(cx);
20320                let new_selected_ranges = marked_ranges
20321                    .into_iter()
20322                    .map(|marked_range| {
20323                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
20324                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
20325                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
20326                        snapshot.clip_offset_utf16(new_start, Bias::Left)
20327                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
20328                    })
20329                    .collect::<Vec<_>>();
20330
20331                drop(snapshot);
20332                this.change_selections(None, window, cx, |selections| {
20333                    selections.select_ranges(new_selected_ranges)
20334                });
20335            }
20336        });
20337
20338        self.ime_transaction = self.ime_transaction.or(transaction);
20339        if let Some(transaction) = self.ime_transaction {
20340            self.buffer.update(cx, |buffer, cx| {
20341                buffer.group_until_transaction(transaction, cx);
20342            });
20343        }
20344
20345        if self.text_highlights::<InputComposition>(cx).is_none() {
20346            self.ime_transaction.take();
20347        }
20348    }
20349
20350    fn bounds_for_range(
20351        &mut self,
20352        range_utf16: Range<usize>,
20353        element_bounds: gpui::Bounds<Pixels>,
20354        window: &mut Window,
20355        cx: &mut Context<Self>,
20356    ) -> Option<gpui::Bounds<Pixels>> {
20357        let text_layout_details = self.text_layout_details(window);
20358        let gpui::Size {
20359            width: em_width,
20360            height: line_height,
20361        } = self.character_size(window);
20362
20363        let snapshot = self.snapshot(window, cx);
20364        let scroll_position = snapshot.scroll_position();
20365        let scroll_left = scroll_position.x * em_width;
20366
20367        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
20368        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
20369            + self.gutter_dimensions.width
20370            + self.gutter_dimensions.margin;
20371        let y = line_height * (start.row().as_f32() - scroll_position.y);
20372
20373        Some(Bounds {
20374            origin: element_bounds.origin + point(x, y),
20375            size: size(em_width, line_height),
20376        })
20377    }
20378
20379    fn character_index_for_point(
20380        &mut self,
20381        point: gpui::Point<Pixels>,
20382        _window: &mut Window,
20383        _cx: &mut Context<Self>,
20384    ) -> Option<usize> {
20385        let position_map = self.last_position_map.as_ref()?;
20386        if !position_map.text_hitbox.contains(&point) {
20387            return None;
20388        }
20389        let display_point = position_map.point_for_position(point).previous_valid;
20390        let anchor = position_map
20391            .snapshot
20392            .display_point_to_anchor(display_point, Bias::Left);
20393        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
20394        Some(utf16_offset.0)
20395    }
20396}
20397
20398trait SelectionExt {
20399    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
20400    fn spanned_rows(
20401        &self,
20402        include_end_if_at_line_start: bool,
20403        map: &DisplaySnapshot,
20404    ) -> Range<MultiBufferRow>;
20405}
20406
20407impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
20408    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
20409        let start = self
20410            .start
20411            .to_point(&map.buffer_snapshot)
20412            .to_display_point(map);
20413        let end = self
20414            .end
20415            .to_point(&map.buffer_snapshot)
20416            .to_display_point(map);
20417        if self.reversed {
20418            end..start
20419        } else {
20420            start..end
20421        }
20422    }
20423
20424    fn spanned_rows(
20425        &self,
20426        include_end_if_at_line_start: bool,
20427        map: &DisplaySnapshot,
20428    ) -> Range<MultiBufferRow> {
20429        let start = self.start.to_point(&map.buffer_snapshot);
20430        let mut end = self.end.to_point(&map.buffer_snapshot);
20431        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
20432            end.row -= 1;
20433        }
20434
20435        let buffer_start = map.prev_line_boundary(start).0;
20436        let buffer_end = map.next_line_boundary(end).0;
20437        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
20438    }
20439}
20440
20441impl<T: InvalidationRegion> InvalidationStack<T> {
20442    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
20443    where
20444        S: Clone + ToOffset,
20445    {
20446        while let Some(region) = self.last() {
20447            let all_selections_inside_invalidation_ranges =
20448                if selections.len() == region.ranges().len() {
20449                    selections
20450                        .iter()
20451                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
20452                        .all(|(selection, invalidation_range)| {
20453                            let head = selection.head().to_offset(buffer);
20454                            invalidation_range.start <= head && invalidation_range.end >= head
20455                        })
20456                } else {
20457                    false
20458                };
20459
20460            if all_selections_inside_invalidation_ranges {
20461                break;
20462            } else {
20463                self.pop();
20464            }
20465        }
20466    }
20467}
20468
20469impl<T> Default for InvalidationStack<T> {
20470    fn default() -> Self {
20471        Self(Default::default())
20472    }
20473}
20474
20475impl<T> Deref for InvalidationStack<T> {
20476    type Target = Vec<T>;
20477
20478    fn deref(&self) -> &Self::Target {
20479        &self.0
20480    }
20481}
20482
20483impl<T> DerefMut for InvalidationStack<T> {
20484    fn deref_mut(&mut self) -> &mut Self::Target {
20485        &mut self.0
20486    }
20487}
20488
20489impl InvalidationRegion for SnippetState {
20490    fn ranges(&self) -> &[Range<Anchor>] {
20491        &self.ranges[self.active_index]
20492    }
20493}
20494
20495fn inline_completion_edit_text(
20496    current_snapshot: &BufferSnapshot,
20497    edits: &[(Range<Anchor>, String)],
20498    edit_preview: &EditPreview,
20499    include_deletions: bool,
20500    cx: &App,
20501) -> HighlightedText {
20502    let edits = edits
20503        .iter()
20504        .map(|(anchor, text)| {
20505            (
20506                anchor.start.text_anchor..anchor.end.text_anchor,
20507                text.clone(),
20508            )
20509        })
20510        .collect::<Vec<_>>();
20511
20512    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
20513}
20514
20515pub fn diagnostic_style(severity: DiagnosticSeverity, colors: &StatusColors) -> Hsla {
20516    match severity {
20517        DiagnosticSeverity::ERROR => colors.error,
20518        DiagnosticSeverity::WARNING => colors.warning,
20519        DiagnosticSeverity::INFORMATION => colors.info,
20520        DiagnosticSeverity::HINT => colors.info,
20521        _ => colors.ignored,
20522    }
20523}
20524
20525pub fn styled_runs_for_code_label<'a>(
20526    label: &'a CodeLabel,
20527    syntax_theme: &'a theme::SyntaxTheme,
20528) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
20529    let fade_out = HighlightStyle {
20530        fade_out: Some(0.35),
20531        ..Default::default()
20532    };
20533
20534    let mut prev_end = label.filter_range.end;
20535    label
20536        .runs
20537        .iter()
20538        .enumerate()
20539        .flat_map(move |(ix, (range, highlight_id))| {
20540            let style = if let Some(style) = highlight_id.style(syntax_theme) {
20541                style
20542            } else {
20543                return Default::default();
20544            };
20545            let mut muted_style = style;
20546            muted_style.highlight(fade_out);
20547
20548            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
20549            if range.start >= label.filter_range.end {
20550                if range.start > prev_end {
20551                    runs.push((prev_end..range.start, fade_out));
20552                }
20553                runs.push((range.clone(), muted_style));
20554            } else if range.end <= label.filter_range.end {
20555                runs.push((range.clone(), style));
20556            } else {
20557                runs.push((range.start..label.filter_range.end, style));
20558                runs.push((label.filter_range.end..range.end, muted_style));
20559            }
20560            prev_end = cmp::max(prev_end, range.end);
20561
20562            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
20563                runs.push((prev_end..label.text.len(), fade_out));
20564            }
20565
20566            runs
20567        })
20568}
20569
20570pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
20571    let mut prev_index = 0;
20572    let mut prev_codepoint: Option<char> = None;
20573    text.char_indices()
20574        .chain([(text.len(), '\0')])
20575        .filter_map(move |(index, codepoint)| {
20576            let prev_codepoint = prev_codepoint.replace(codepoint)?;
20577            let is_boundary = index == text.len()
20578                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
20579                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
20580            if is_boundary {
20581                let chunk = &text[prev_index..index];
20582                prev_index = index;
20583                Some(chunk)
20584            } else {
20585                None
20586            }
20587        })
20588}
20589
20590pub trait RangeToAnchorExt: Sized {
20591    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
20592
20593    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
20594        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
20595        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
20596    }
20597}
20598
20599impl<T: ToOffset> RangeToAnchorExt for Range<T> {
20600    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
20601        let start_offset = self.start.to_offset(snapshot);
20602        let end_offset = self.end.to_offset(snapshot);
20603        if start_offset == end_offset {
20604            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
20605        } else {
20606            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
20607        }
20608    }
20609}
20610
20611pub trait RowExt {
20612    fn as_f32(&self) -> f32;
20613
20614    fn next_row(&self) -> Self;
20615
20616    fn previous_row(&self) -> Self;
20617
20618    fn minus(&self, other: Self) -> u32;
20619}
20620
20621impl RowExt for DisplayRow {
20622    fn as_f32(&self) -> f32 {
20623        self.0 as f32
20624    }
20625
20626    fn next_row(&self) -> Self {
20627        Self(self.0 + 1)
20628    }
20629
20630    fn previous_row(&self) -> Self {
20631        Self(self.0.saturating_sub(1))
20632    }
20633
20634    fn minus(&self, other: Self) -> u32 {
20635        self.0 - other.0
20636    }
20637}
20638
20639impl RowExt for MultiBufferRow {
20640    fn as_f32(&self) -> f32 {
20641        self.0 as f32
20642    }
20643
20644    fn next_row(&self) -> Self {
20645        Self(self.0 + 1)
20646    }
20647
20648    fn previous_row(&self) -> Self {
20649        Self(self.0.saturating_sub(1))
20650    }
20651
20652    fn minus(&self, other: Self) -> u32 {
20653        self.0 - other.0
20654    }
20655}
20656
20657trait RowRangeExt {
20658    type Row;
20659
20660    fn len(&self) -> usize;
20661
20662    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
20663}
20664
20665impl RowRangeExt for Range<MultiBufferRow> {
20666    type Row = MultiBufferRow;
20667
20668    fn len(&self) -> usize {
20669        (self.end.0 - self.start.0) as usize
20670    }
20671
20672    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
20673        (self.start.0..self.end.0).map(MultiBufferRow)
20674    }
20675}
20676
20677impl RowRangeExt for Range<DisplayRow> {
20678    type Row = DisplayRow;
20679
20680    fn len(&self) -> usize {
20681        (self.end.0 - self.start.0) as usize
20682    }
20683
20684    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
20685        (self.start.0..self.end.0).map(DisplayRow)
20686    }
20687}
20688
20689/// If select range has more than one line, we
20690/// just point the cursor to range.start.
20691fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
20692    if range.start.row == range.end.row {
20693        range
20694    } else {
20695        range.start..range.start
20696    }
20697}
20698pub struct KillRing(ClipboardItem);
20699impl Global for KillRing {}
20700
20701const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
20702
20703enum BreakpointPromptEditAction {
20704    Log,
20705    Condition,
20706    HitCondition,
20707}
20708
20709struct BreakpointPromptEditor {
20710    pub(crate) prompt: Entity<Editor>,
20711    editor: WeakEntity<Editor>,
20712    breakpoint_anchor: Anchor,
20713    breakpoint: Breakpoint,
20714    edit_action: BreakpointPromptEditAction,
20715    block_ids: HashSet<CustomBlockId>,
20716    gutter_dimensions: Arc<Mutex<GutterDimensions>>,
20717    _subscriptions: Vec<Subscription>,
20718}
20719
20720impl BreakpointPromptEditor {
20721    const MAX_LINES: u8 = 4;
20722
20723    fn new(
20724        editor: WeakEntity<Editor>,
20725        breakpoint_anchor: Anchor,
20726        breakpoint: Breakpoint,
20727        edit_action: BreakpointPromptEditAction,
20728        window: &mut Window,
20729        cx: &mut Context<Self>,
20730    ) -> Self {
20731        let base_text = match edit_action {
20732            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
20733            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
20734            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
20735        }
20736        .map(|msg| msg.to_string())
20737        .unwrap_or_default();
20738
20739        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
20740        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
20741
20742        let prompt = cx.new(|cx| {
20743            let mut prompt = Editor::new(
20744                EditorMode::AutoHeight {
20745                    max_lines: Self::MAX_LINES as usize,
20746                },
20747                buffer,
20748                None,
20749                window,
20750                cx,
20751            );
20752            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
20753            prompt.set_show_cursor_when_unfocused(false, cx);
20754            prompt.set_placeholder_text(
20755                match edit_action {
20756                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
20757                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
20758                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
20759                },
20760                cx,
20761            );
20762
20763            prompt
20764        });
20765
20766        Self {
20767            prompt,
20768            editor,
20769            breakpoint_anchor,
20770            breakpoint,
20771            edit_action,
20772            gutter_dimensions: Arc::new(Mutex::new(GutterDimensions::default())),
20773            block_ids: Default::default(),
20774            _subscriptions: vec![],
20775        }
20776    }
20777
20778    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
20779        self.block_ids.extend(block_ids)
20780    }
20781
20782    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
20783        if let Some(editor) = self.editor.upgrade() {
20784            let message = self
20785                .prompt
20786                .read(cx)
20787                .buffer
20788                .read(cx)
20789                .as_singleton()
20790                .expect("A multi buffer in breakpoint prompt isn't possible")
20791                .read(cx)
20792                .as_rope()
20793                .to_string();
20794
20795            editor.update(cx, |editor, cx| {
20796                editor.edit_breakpoint_at_anchor(
20797                    self.breakpoint_anchor,
20798                    self.breakpoint.clone(),
20799                    match self.edit_action {
20800                        BreakpointPromptEditAction::Log => {
20801                            BreakpointEditAction::EditLogMessage(message.into())
20802                        }
20803                        BreakpointPromptEditAction::Condition => {
20804                            BreakpointEditAction::EditCondition(message.into())
20805                        }
20806                        BreakpointPromptEditAction::HitCondition => {
20807                            BreakpointEditAction::EditHitCondition(message.into())
20808                        }
20809                    },
20810                    cx,
20811                );
20812
20813                editor.remove_blocks(self.block_ids.clone(), None, cx);
20814                cx.focus_self(window);
20815            });
20816        }
20817    }
20818
20819    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
20820        self.editor
20821            .update(cx, |editor, cx| {
20822                editor.remove_blocks(self.block_ids.clone(), None, cx);
20823                window.focus(&editor.focus_handle);
20824            })
20825            .log_err();
20826    }
20827
20828    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
20829        let settings = ThemeSettings::get_global(cx);
20830        let text_style = TextStyle {
20831            color: if self.prompt.read(cx).read_only(cx) {
20832                cx.theme().colors().text_disabled
20833            } else {
20834                cx.theme().colors().text
20835            },
20836            font_family: settings.buffer_font.family.clone(),
20837            font_fallbacks: settings.buffer_font.fallbacks.clone(),
20838            font_size: settings.buffer_font_size(cx).into(),
20839            font_weight: settings.buffer_font.weight,
20840            line_height: relative(settings.buffer_line_height.value()),
20841            ..Default::default()
20842        };
20843        EditorElement::new(
20844            &self.prompt,
20845            EditorStyle {
20846                background: cx.theme().colors().editor_background,
20847                local_player: cx.theme().players().local(),
20848                text: text_style,
20849                ..Default::default()
20850            },
20851        )
20852    }
20853}
20854
20855impl Render for BreakpointPromptEditor {
20856    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20857        let gutter_dimensions = *self.gutter_dimensions.lock();
20858        h_flex()
20859            .key_context("Editor")
20860            .bg(cx.theme().colors().editor_background)
20861            .border_y_1()
20862            .border_color(cx.theme().status().info_border)
20863            .size_full()
20864            .py(window.line_height() / 2.5)
20865            .on_action(cx.listener(Self::confirm))
20866            .on_action(cx.listener(Self::cancel))
20867            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
20868            .child(div().flex_1().child(self.render_prompt_editor(cx)))
20869    }
20870}
20871
20872impl Focusable for BreakpointPromptEditor {
20873    fn focus_handle(&self, cx: &App) -> FocusHandle {
20874        self.prompt.focus_handle(cx)
20875    }
20876}
20877
20878fn all_edits_insertions_or_deletions(
20879    edits: &Vec<(Range<Anchor>, String)>,
20880    snapshot: &MultiBufferSnapshot,
20881) -> bool {
20882    let mut all_insertions = true;
20883    let mut all_deletions = true;
20884
20885    for (range, new_text) in edits.iter() {
20886        let range_is_empty = range.to_offset(&snapshot).is_empty();
20887        let text_is_empty = new_text.is_empty();
20888
20889        if range_is_empty != text_is_empty {
20890            if range_is_empty {
20891                all_deletions = false;
20892            } else {
20893                all_insertions = false;
20894            }
20895        } else {
20896            return false;
20897        }
20898
20899        if !all_insertions && !all_deletions {
20900            return false;
20901        }
20902    }
20903    all_insertions || all_deletions
20904}
20905
20906struct MissingEditPredictionKeybindingTooltip;
20907
20908impl Render for MissingEditPredictionKeybindingTooltip {
20909    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20910        ui::tooltip_container(window, cx, |container, _, cx| {
20911            container
20912                .flex_shrink_0()
20913                .max_w_80()
20914                .min_h(rems_from_px(124.))
20915                .justify_between()
20916                .child(
20917                    v_flex()
20918                        .flex_1()
20919                        .text_ui_sm(cx)
20920                        .child(Label::new("Conflict with Accept Keybinding"))
20921                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
20922                )
20923                .child(
20924                    h_flex()
20925                        .pb_1()
20926                        .gap_1()
20927                        .items_end()
20928                        .w_full()
20929                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
20930                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
20931                        }))
20932                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
20933                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
20934                        })),
20935                )
20936        })
20937    }
20938}
20939
20940#[derive(Debug, Clone, Copy, PartialEq)]
20941pub struct LineHighlight {
20942    pub background: Background,
20943    pub border: Option<gpui::Hsla>,
20944    pub include_gutter: bool,
20945    pub type_id: Option<TypeId>,
20946}
20947
20948fn render_diff_hunk_controls(
20949    row: u32,
20950    status: &DiffHunkStatus,
20951    hunk_range: Range<Anchor>,
20952    is_created_file: bool,
20953    line_height: Pixels,
20954    editor: &Entity<Editor>,
20955    _window: &mut Window,
20956    cx: &mut App,
20957) -> AnyElement {
20958    h_flex()
20959        .h(line_height)
20960        .mr_1()
20961        .gap_1()
20962        .px_0p5()
20963        .pb_1()
20964        .border_x_1()
20965        .border_b_1()
20966        .border_color(cx.theme().colors().border_variant)
20967        .rounded_b_lg()
20968        .bg(cx.theme().colors().editor_background)
20969        .gap_1()
20970        .occlude()
20971        .shadow_md()
20972        .child(if status.has_secondary_hunk() {
20973            Button::new(("stage", row as u64), "Stage")
20974                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
20975                .tooltip({
20976                    let focus_handle = editor.focus_handle(cx);
20977                    move |window, cx| {
20978                        Tooltip::for_action_in(
20979                            "Stage Hunk",
20980                            &::git::ToggleStaged,
20981                            &focus_handle,
20982                            window,
20983                            cx,
20984                        )
20985                    }
20986                })
20987                .on_click({
20988                    let editor = editor.clone();
20989                    move |_event, _window, cx| {
20990                        editor.update(cx, |editor, cx| {
20991                            editor.stage_or_unstage_diff_hunks(
20992                                true,
20993                                vec![hunk_range.start..hunk_range.start],
20994                                cx,
20995                            );
20996                        });
20997                    }
20998                })
20999        } else {
21000            Button::new(("unstage", row as u64), "Unstage")
21001                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21002                .tooltip({
21003                    let focus_handle = editor.focus_handle(cx);
21004                    move |window, cx| {
21005                        Tooltip::for_action_in(
21006                            "Unstage Hunk",
21007                            &::git::ToggleStaged,
21008                            &focus_handle,
21009                            window,
21010                            cx,
21011                        )
21012                    }
21013                })
21014                .on_click({
21015                    let editor = editor.clone();
21016                    move |_event, _window, cx| {
21017                        editor.update(cx, |editor, cx| {
21018                            editor.stage_or_unstage_diff_hunks(
21019                                false,
21020                                vec![hunk_range.start..hunk_range.start],
21021                                cx,
21022                            );
21023                        });
21024                    }
21025                })
21026        })
21027        .child(
21028            Button::new(("restore", row as u64), "Restore")
21029                .tooltip({
21030                    let focus_handle = editor.focus_handle(cx);
21031                    move |window, cx| {
21032                        Tooltip::for_action_in(
21033                            "Restore Hunk",
21034                            &::git::Restore,
21035                            &focus_handle,
21036                            window,
21037                            cx,
21038                        )
21039                    }
21040                })
21041                .on_click({
21042                    let editor = editor.clone();
21043                    move |_event, window, cx| {
21044                        editor.update(cx, |editor, cx| {
21045                            let snapshot = editor.snapshot(window, cx);
21046                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21047                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21048                        });
21049                    }
21050                })
21051                .disabled(is_created_file),
21052        )
21053        .when(
21054            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21055            |el| {
21056                el.child(
21057                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21058                        .shape(IconButtonShape::Square)
21059                        .icon_size(IconSize::Small)
21060                        // .disabled(!has_multiple_hunks)
21061                        .tooltip({
21062                            let focus_handle = editor.focus_handle(cx);
21063                            move |window, cx| {
21064                                Tooltip::for_action_in(
21065                                    "Next Hunk",
21066                                    &GoToHunk,
21067                                    &focus_handle,
21068                                    window,
21069                                    cx,
21070                                )
21071                            }
21072                        })
21073                        .on_click({
21074                            let editor = editor.clone();
21075                            move |_event, window, cx| {
21076                                editor.update(cx, |editor, cx| {
21077                                    let snapshot = editor.snapshot(window, cx);
21078                                    let position =
21079                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21080                                    editor.go_to_hunk_before_or_after_position(
21081                                        &snapshot,
21082                                        position,
21083                                        Direction::Next,
21084                                        window,
21085                                        cx,
21086                                    );
21087                                    editor.expand_selected_diff_hunks(cx);
21088                                });
21089                            }
21090                        }),
21091                )
21092                .child(
21093                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21094                        .shape(IconButtonShape::Square)
21095                        .icon_size(IconSize::Small)
21096                        // .disabled(!has_multiple_hunks)
21097                        .tooltip({
21098                            let focus_handle = editor.focus_handle(cx);
21099                            move |window, cx| {
21100                                Tooltip::for_action_in(
21101                                    "Previous Hunk",
21102                                    &GoToPreviousHunk,
21103                                    &focus_handle,
21104                                    window,
21105                                    cx,
21106                                )
21107                            }
21108                        })
21109                        .on_click({
21110                            let editor = editor.clone();
21111                            move |_event, window, cx| {
21112                                editor.update(cx, |editor, cx| {
21113                                    let snapshot = editor.snapshot(window, cx);
21114                                    let point =
21115                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21116                                    editor.go_to_hunk_before_or_after_position(
21117                                        &snapshot,
21118                                        point,
21119                                        Direction::Prev,
21120                                        window,
21121                                        cx,
21122                                    );
21123                                    editor.expand_selected_diff_hunks(cx);
21124                                });
21125                            }
21126                        }),
21127                )
21128            },
21129        )
21130        .into_any_element()
21131}