editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   55use aho_corasick::AhoCorasick;
   56use anyhow::{Context as _, Result, anyhow};
   57use blink_manager::BlinkManager;
   58use buffer_diff::DiffHunkStatus;
   59use client::{Collaborator, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82use lsp_colors::LspColorData;
   83
   84use ::git::blame::BlameEntry;
   85use ::git::{Restore, blame::ParsedCommitMessage};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use git::blame::{GitBlame, GlobalBlameRenderer};
   91use gpui::{
   92    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   93    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   94    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   95    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   96    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   97    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   98    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   99    div, point, prelude::*, pulsating_between, px, relative, size,
  100};
  101use highlight_matching_bracket::refresh_matching_bracket_highlights;
  102use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  103pub use hover_popover::hover_markdown_style;
  104use hover_popover::{HoverState, hide_hover};
  105use indent_guides::ActiveIndentGuidesState;
  106use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  107pub use inline_completion::Direction;
  108use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  109pub use items::MAX_TAB_TITLE_LEN;
  110use itertools::Itertools;
  111use language::{
  112    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  113    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  114    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  115    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, ProjectPath,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    git_store::{GitStoreEvent, RepositoryEvent},
  137    project_settings::DiagnosticSeverity,
  138};
  139
  140pub use git::blame::BlameRenderer;
  141pub use proposed_changes_editor::{
  142    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  143};
  144use std::{cell::OnceCell, iter::Peekable, ops::Not};
  145use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  146
  147pub use lsp::CompletionContext;
  148use lsp::{
  149    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  150    LanguageServerId, LanguageServerName,
  151};
  152
  153use language::BufferSnapshot;
  154pub use lsp_ext::lsp_tasks;
  155use movement::TextLayoutDetails;
  156pub use multi_buffer::{
  157    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  158    RowInfo, ToOffset, ToPoint,
  159};
  160use multi_buffer::{
  161    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  162    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  163};
  164use parking_lot::Mutex;
  165use project::{
  166    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  167    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  168    TaskSourceKind,
  169    debugger::breakpoint_store::Breakpoint,
  170    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  171    project_settings::{GitGutterSetting, ProjectSettings},
  172};
  173use rand::prelude::*;
  174use rpc::{ErrorExt, proto::*};
  175use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  176use selections_collection::{
  177    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  178};
  179use serde::{Deserialize, Serialize};
  180use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  181use smallvec::{SmallVec, smallvec};
  182use snippet::Snippet;
  183use std::sync::Arc;
  184use std::{
  185    any::TypeId,
  186    borrow::Cow,
  187    cell::RefCell,
  188    cmp::{self, Ordering, Reverse},
  189    mem,
  190    num::NonZeroU32,
  191    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  192    path::{Path, PathBuf},
  193    rc::Rc,
  194    time::{Duration, Instant},
  195};
  196pub use sum_tree::Bias;
  197use sum_tree::TreeMap;
  198use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  199use theme::{
  200    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  201    observe_buffer_font_size_adjustment,
  202};
  203use ui::{
  204    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  205    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  206};
  207use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  208use workspace::{
  209    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  210    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  211    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  212    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  213    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  214    searchable::SearchEvent,
  215};
  216
  217use crate::{
  218    code_context_menus::CompletionsMenuSource,
  219    hover_links::{find_url, find_url_from_range},
  220};
  221use crate::{
  222    editor_settings::MultiCursorModifier,
  223    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  224};
  225
  226pub const FILE_HEADER_HEIGHT: u32 = 2;
  227pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  228pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  229const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  230const MAX_LINE_LEN: usize = 1024;
  231const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  232const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  233pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  234#[doc(hidden)]
  235pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  236const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  237
  238pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  241
  242pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  243pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  244pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  245
  246pub type RenderDiffHunkControlsFn = Arc<
  247    dyn Fn(
  248        u32,
  249        &DiffHunkStatus,
  250        Range<Anchor>,
  251        bool,
  252        Pixels,
  253        &Entity<Editor>,
  254        &mut Window,
  255        &mut App,
  256    ) -> AnyElement,
  257>;
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    DebuggerValue(usize),
  279    // LSP
  280    Hint(usize),
  281    Color(usize),
  282}
  283
  284impl InlayId {
  285    fn id(&self) -> usize {
  286        match self {
  287            Self::InlineCompletion(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289            Self::Hint(id) => *id,
  290            Self::Color(id) => *id,
  291        }
  292    }
  293}
  294
  295pub enum ActiveDebugLine {}
  296pub enum DebugStackFrameLine {}
  297enum DocumentHighlightRead {}
  298enum DocumentHighlightWrite {}
  299enum InputComposition {}
  300pub enum PendingInput {}
  301enum SelectedTextHighlight {}
  302
  303pub enum ConflictsOuter {}
  304pub enum ConflictsOurs {}
  305pub enum ConflictsTheirs {}
  306pub enum ConflictsOursMarker {}
  307pub enum ConflictsTheirsMarker {}
  308
  309#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  310pub enum Navigated {
  311    Yes,
  312    No,
  313}
  314
  315impl Navigated {
  316    pub fn from_bool(yes: bool) -> Navigated {
  317        if yes { Navigated::Yes } else { Navigated::No }
  318    }
  319}
  320
  321#[derive(Debug, Clone, PartialEq, Eq)]
  322enum DisplayDiffHunk {
  323    Folded {
  324        display_row: DisplayRow,
  325    },
  326    Unfolded {
  327        is_created_file: bool,
  328        diff_base_byte_range: Range<usize>,
  329        display_row_range: Range<DisplayRow>,
  330        multi_buffer_range: Range<Anchor>,
  331        status: DiffHunkStatus,
  332    },
  333}
  334
  335pub enum HideMouseCursorOrigin {
  336    TypingAction,
  337    MovementAction,
  338}
  339
  340pub fn init_settings(cx: &mut App) {
  341    EditorSettings::register(cx);
  342}
  343
  344pub fn init(cx: &mut App) {
  345    init_settings(cx);
  346
  347    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  348
  349    workspace::register_project_item::<Editor>(cx);
  350    workspace::FollowableViewRegistry::register::<Editor>(cx);
  351    workspace::register_serializable_item::<Editor>(cx);
  352
  353    cx.observe_new(
  354        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  355            workspace.register_action(Editor::new_file);
  356            workspace.register_action(Editor::new_file_vertical);
  357            workspace.register_action(Editor::new_file_horizontal);
  358            workspace.register_action(Editor::cancel_language_server_work);
  359        },
  360    )
  361    .detach();
  362
  363    cx.on_action(move |_: &workspace::NewFile, cx| {
  364        let app_state = workspace::AppState::global(cx);
  365        if let Some(app_state) = app_state.upgrade() {
  366            workspace::open_new(
  367                Default::default(),
  368                app_state,
  369                cx,
  370                |workspace, window, cx| {
  371                    Editor::new_file(workspace, &Default::default(), window, cx)
  372                },
  373            )
  374            .detach();
  375        }
  376    });
  377    cx.on_action(move |_: &workspace::NewWindow, cx| {
  378        let app_state = workspace::AppState::global(cx);
  379        if let Some(app_state) = app_state.upgrade() {
  380            workspace::open_new(
  381                Default::default(),
  382                app_state,
  383                cx,
  384                |workspace, window, cx| {
  385                    cx.activate(true);
  386                    Editor::new_file(workspace, &Default::default(), window, cx)
  387                },
  388            )
  389            .detach();
  390        }
  391    });
  392}
  393
  394pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  395    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  396}
  397
  398pub trait DiagnosticRenderer {
  399    fn render_group(
  400        &self,
  401        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  402        buffer_id: BufferId,
  403        snapshot: EditorSnapshot,
  404        editor: WeakEntity<Editor>,
  405        cx: &mut App,
  406    ) -> Vec<BlockProperties<Anchor>>;
  407
  408    fn render_hover(
  409        &self,
  410        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  411        range: Range<Point>,
  412        buffer_id: BufferId,
  413        cx: &mut App,
  414    ) -> Option<Entity<markdown::Markdown>>;
  415
  416    fn open_link(
  417        &self,
  418        editor: &mut Editor,
  419        link: SharedString,
  420        window: &mut Window,
  421        cx: &mut Context<Editor>,
  422    );
  423}
  424
  425pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  426
  427impl GlobalDiagnosticRenderer {
  428    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  429        cx.try_global::<Self>().map(|g| g.0.clone())
  430    }
  431}
  432
  433impl gpui::Global for GlobalDiagnosticRenderer {}
  434pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  435    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  436}
  437
  438pub struct SearchWithinRange;
  439
  440trait InvalidationRegion {
  441    fn ranges(&self) -> &[Range<Anchor>];
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum SelectPhase {
  446    Begin {
  447        position: DisplayPoint,
  448        add: bool,
  449        click_count: usize,
  450    },
  451    BeginColumnar {
  452        position: DisplayPoint,
  453        reset: bool,
  454        mode: ColumnarMode,
  455        goal_column: u32,
  456    },
  457    Extend {
  458        position: DisplayPoint,
  459        click_count: usize,
  460    },
  461    Update {
  462        position: DisplayPoint,
  463        goal_column: u32,
  464        scroll_delta: gpui::Point<f32>,
  465    },
  466    End,
  467}
  468
  469#[derive(Clone, Debug, PartialEq)]
  470pub enum ColumnarMode {
  471    FromMouse,
  472    FromSelection,
  473}
  474
  475#[derive(Clone, Debug)]
  476pub enum SelectMode {
  477    Character,
  478    Word(Range<Anchor>),
  479    Line(Range<Anchor>),
  480    All,
  481}
  482
  483#[derive(Clone, PartialEq, Eq, Debug)]
  484pub enum EditorMode {
  485    SingleLine {
  486        auto_width: bool,
  487    },
  488    AutoHeight {
  489        min_lines: usize,
  490        max_lines: Option<usize>,
  491    },
  492    Full {
  493        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  494        scale_ui_elements_with_buffer_font_size: bool,
  495        /// When set to `true`, the editor will render a background for the active line.
  496        show_active_line_background: bool,
  497        /// When set to `true`, the editor's height will be determined by its content.
  498        sized_by_content: bool,
  499    },
  500    Minimap {
  501        parent: WeakEntity<Editor>,
  502    },
  503}
  504
  505impl EditorMode {
  506    pub fn full() -> Self {
  507        Self::Full {
  508            scale_ui_elements_with_buffer_font_size: true,
  509            show_active_line_background: true,
  510            sized_by_content: false,
  511        }
  512    }
  513
  514    #[inline]
  515    pub fn is_full(&self) -> bool {
  516        matches!(self, Self::Full { .. })
  517    }
  518
  519    #[inline]
  520    pub fn is_single_line(&self) -> bool {
  521        matches!(self, Self::SingleLine { .. })
  522    }
  523
  524    #[inline]
  525    fn is_minimap(&self) -> bool {
  526        matches!(self, Self::Minimap { .. })
  527    }
  528}
  529
  530#[derive(Copy, Clone, Debug)]
  531pub enum SoftWrap {
  532    /// Prefer not to wrap at all.
  533    ///
  534    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  535    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  536    GitDiff,
  537    /// Prefer a single line generally, unless an overly long line is encountered.
  538    None,
  539    /// Soft wrap lines that exceed the editor width.
  540    EditorWidth,
  541    /// Soft wrap lines at the preferred line length.
  542    Column(u32),
  543    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  544    Bounded(u32),
  545}
  546
  547#[derive(Clone)]
  548pub struct EditorStyle {
  549    pub background: Hsla,
  550    pub border: Hsla,
  551    pub local_player: PlayerColor,
  552    pub text: TextStyle,
  553    pub scrollbar_width: Pixels,
  554    pub syntax: Arc<SyntaxTheme>,
  555    pub status: StatusColors,
  556    pub inlay_hints_style: HighlightStyle,
  557    pub inline_completion_styles: InlineCompletionStyles,
  558    pub unnecessary_code_fade: f32,
  559    pub show_underlines: bool,
  560}
  561
  562impl Default for EditorStyle {
  563    fn default() -> Self {
  564        Self {
  565            background: Hsla::default(),
  566            border: Hsla::default(),
  567            local_player: PlayerColor::default(),
  568            text: TextStyle::default(),
  569            scrollbar_width: Pixels::default(),
  570            syntax: Default::default(),
  571            // HACK: Status colors don't have a real default.
  572            // We should look into removing the status colors from the editor
  573            // style and retrieve them directly from the theme.
  574            status: StatusColors::dark(),
  575            inlay_hints_style: HighlightStyle::default(),
  576            inline_completion_styles: InlineCompletionStyles {
  577                insertion: HighlightStyle::default(),
  578                whitespace: HighlightStyle::default(),
  579            },
  580            unnecessary_code_fade: Default::default(),
  581            show_underlines: true,
  582        }
  583    }
  584}
  585
  586pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  587    let show_background = language_settings::language_settings(None, None, cx)
  588        .inlay_hints
  589        .show_background;
  590
  591    HighlightStyle {
  592        color: Some(cx.theme().status().hint),
  593        background_color: show_background.then(|| cx.theme().status().hint_background),
  594        ..HighlightStyle::default()
  595    }
  596}
  597
  598pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  599    InlineCompletionStyles {
  600        insertion: HighlightStyle {
  601            color: Some(cx.theme().status().predictive),
  602            ..HighlightStyle::default()
  603        },
  604        whitespace: HighlightStyle {
  605            background_color: Some(cx.theme().status().created_background),
  606            ..HighlightStyle::default()
  607        },
  608    }
  609}
  610
  611type CompletionId = usize;
  612
  613pub(crate) enum EditDisplayMode {
  614    TabAccept,
  615    DiffPopover,
  616    Inline,
  617}
  618
  619enum InlineCompletion {
  620    Edit {
  621        edits: Vec<(Range<Anchor>, String)>,
  622        edit_preview: Option<EditPreview>,
  623        display_mode: EditDisplayMode,
  624        snapshot: BufferSnapshot,
  625    },
  626    Move {
  627        target: Anchor,
  628        snapshot: BufferSnapshot,
  629    },
  630}
  631
  632struct InlineCompletionState {
  633    inlay_ids: Vec<InlayId>,
  634    completion: InlineCompletion,
  635    completion_id: Option<SharedString>,
  636    invalidation_range: Range<Anchor>,
  637}
  638
  639enum EditPredictionSettings {
  640    Disabled,
  641    Enabled {
  642        show_in_menu: bool,
  643        preview_requires_modifier: bool,
  644    },
  645}
  646
  647enum InlineCompletionHighlight {}
  648
  649#[derive(Debug, Clone)]
  650struct InlineDiagnostic {
  651    message: SharedString,
  652    group_id: usize,
  653    is_primary: bool,
  654    start: Point,
  655    severity: lsp::DiagnosticSeverity,
  656}
  657
  658pub enum MenuInlineCompletionsPolicy {
  659    Never,
  660    ByProvider,
  661}
  662
  663pub enum EditPredictionPreview {
  664    /// Modifier is not pressed
  665    Inactive { released_too_fast: bool },
  666    /// Modifier pressed
  667    Active {
  668        since: Instant,
  669        previous_scroll_position: Option<ScrollAnchor>,
  670    },
  671}
  672
  673impl EditPredictionPreview {
  674    pub fn released_too_fast(&self) -> bool {
  675        match self {
  676            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  677            EditPredictionPreview::Active { .. } => false,
  678        }
  679    }
  680
  681    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  682        if let EditPredictionPreview::Active {
  683            previous_scroll_position,
  684            ..
  685        } = self
  686        {
  687            *previous_scroll_position = scroll_position;
  688        }
  689    }
  690}
  691
  692pub struct ContextMenuOptions {
  693    pub min_entries_visible: usize,
  694    pub max_entries_visible: usize,
  695    pub placement: Option<ContextMenuPlacement>,
  696}
  697
  698#[derive(Debug, Clone, PartialEq, Eq)]
  699pub enum ContextMenuPlacement {
  700    Above,
  701    Below,
  702}
  703
  704#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  705struct EditorActionId(usize);
  706
  707impl EditorActionId {
  708    pub fn post_inc(&mut self) -> Self {
  709        let answer = self.0;
  710
  711        *self = Self(answer + 1);
  712
  713        Self(answer)
  714    }
  715}
  716
  717// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  718// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  719
  720type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  721type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  722
  723#[derive(Default)]
  724struct ScrollbarMarkerState {
  725    scrollbar_size: Size<Pixels>,
  726    dirty: bool,
  727    markers: Arc<[PaintQuad]>,
  728    pending_refresh: Option<Task<Result<()>>>,
  729}
  730
  731impl ScrollbarMarkerState {
  732    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  733        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  734    }
  735}
  736
  737#[derive(Clone, Copy, PartialEq, Eq)]
  738pub enum MinimapVisibility {
  739    Disabled,
  740    Enabled {
  741        /// The configuration currently present in the users settings.
  742        setting_configuration: bool,
  743        /// Whether to override the currently set visibility from the users setting.
  744        toggle_override: bool,
  745    },
  746}
  747
  748impl MinimapVisibility {
  749    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  750        if mode.is_full() {
  751            Self::Enabled {
  752                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  753                toggle_override: false,
  754            }
  755        } else {
  756            Self::Disabled
  757        }
  758    }
  759
  760    fn hidden(&self) -> Self {
  761        match *self {
  762            Self::Enabled {
  763                setting_configuration,
  764                ..
  765            } => Self::Enabled {
  766                setting_configuration,
  767                toggle_override: setting_configuration,
  768            },
  769            Self::Disabled => Self::Disabled,
  770        }
  771    }
  772
  773    fn disabled(&self) -> bool {
  774        match *self {
  775            Self::Disabled => true,
  776            _ => false,
  777        }
  778    }
  779
  780    fn settings_visibility(&self) -> bool {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => setting_configuration,
  786            _ => false,
  787        }
  788    }
  789
  790    fn visible(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                toggle_override,
  795            } => setting_configuration ^ toggle_override,
  796            _ => false,
  797        }
  798    }
  799
  800    fn toggle_visibility(&self) -> Self {
  801        match *self {
  802            Self::Enabled {
  803                toggle_override,
  804                setting_configuration,
  805            } => Self::Enabled {
  806                setting_configuration,
  807                toggle_override: !toggle_override,
  808            },
  809            Self::Disabled => Self::Disabled,
  810        }
  811    }
  812}
  813
  814#[derive(Clone, Debug)]
  815struct RunnableTasks {
  816    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  817    offset: multi_buffer::Anchor,
  818    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  819    column: u32,
  820    // Values of all named captures, including those starting with '_'
  821    extra_variables: HashMap<String, String>,
  822    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  823    context_range: Range<BufferOffset>,
  824}
  825
  826impl RunnableTasks {
  827    fn resolve<'a>(
  828        &'a self,
  829        cx: &'a task::TaskContext,
  830    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  831        self.templates.iter().filter_map(|(kind, template)| {
  832            template
  833                .resolve_task(&kind.to_id_base(), cx)
  834                .map(|task| (kind.clone(), task))
  835        })
  836    }
  837}
  838
  839#[derive(Clone)]
  840pub struct ResolvedTasks {
  841    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  842    position: Anchor,
  843}
  844
  845#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  846struct BufferOffset(usize);
  847
  848// Addons allow storing per-editor state in other crates (e.g. Vim)
  849pub trait Addon: 'static {
  850    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  851
  852    fn render_buffer_header_controls(
  853        &self,
  854        _: &ExcerptInfo,
  855        _: &Window,
  856        _: &App,
  857    ) -> Option<AnyElement> {
  858        None
  859    }
  860
  861    fn to_any(&self) -> &dyn std::any::Any;
  862
  863    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  864        None
  865    }
  866}
  867
  868/// A set of caret positions, registered when the editor was edited.
  869pub struct ChangeList {
  870    changes: Vec<Vec<Anchor>>,
  871    /// Currently "selected" change.
  872    position: Option<usize>,
  873}
  874
  875impl ChangeList {
  876    pub fn new() -> Self {
  877        Self {
  878            changes: Vec::new(),
  879            position: None,
  880        }
  881    }
  882
  883    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  884    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  885    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  886        if self.changes.is_empty() {
  887            return None;
  888        }
  889
  890        let prev = self.position.unwrap_or(self.changes.len());
  891        let next = if direction == Direction::Prev {
  892            prev.saturating_sub(count)
  893        } else {
  894            (prev + count).min(self.changes.len() - 1)
  895        };
  896        self.position = Some(next);
  897        self.changes.get(next).map(|anchors| anchors.as_slice())
  898    }
  899
  900    /// Adds a new change to the list, resetting the change list position.
  901    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  902        self.position.take();
  903        if pop_state {
  904            self.changes.pop();
  905        }
  906        self.changes.push(new_positions.clone());
  907    }
  908
  909    pub fn last(&self) -> Option<&[Anchor]> {
  910        self.changes.last().map(|anchors| anchors.as_slice())
  911    }
  912}
  913
  914#[derive(Clone)]
  915struct InlineBlamePopoverState {
  916    scroll_handle: ScrollHandle,
  917    commit_message: Option<ParsedCommitMessage>,
  918    markdown: Entity<Markdown>,
  919}
  920
  921struct InlineBlamePopover {
  922    position: gpui::Point<Pixels>,
  923    hide_task: Option<Task<()>>,
  924    popover_bounds: Option<Bounds<Pixels>>,
  925    popover_state: InlineBlamePopoverState,
  926}
  927
  928enum SelectionDragState {
  929    /// State when no drag related activity is detected.
  930    None,
  931    /// State when the mouse is down on a selection that is about to be dragged.
  932    ReadyToDrag {
  933        selection: Selection<Anchor>,
  934        click_position: gpui::Point<Pixels>,
  935        mouse_down_time: Instant,
  936    },
  937    /// State when the mouse is dragging the selection in the editor.
  938    Dragging {
  939        selection: Selection<Anchor>,
  940        drop_cursor: Selection<Anchor>,
  941        hide_drop_cursor: bool,
  942    },
  943}
  944
  945enum ColumnarSelectionState {
  946    FromMouse {
  947        selection_tail: Anchor,
  948        display_point: Option<DisplayPoint>,
  949    },
  950    FromSelection {
  951        selection_tail: Anchor,
  952    },
  953}
  954
  955/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  956/// a breakpoint on them.
  957#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  958struct PhantomBreakpointIndicator {
  959    display_row: DisplayRow,
  960    /// There's a small debounce between hovering over the line and showing the indicator.
  961    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  962    is_active: bool,
  963    collides_with_existing_breakpoint: bool,
  964}
  965
  966/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  967///
  968/// See the [module level documentation](self) for more information.
  969pub struct Editor {
  970    focus_handle: FocusHandle,
  971    last_focused_descendant: Option<WeakFocusHandle>,
  972    /// The text buffer being edited
  973    buffer: Entity<MultiBuffer>,
  974    /// Map of how text in the buffer should be displayed.
  975    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  976    pub display_map: Entity<DisplayMap>,
  977    pub selections: SelectionsCollection,
  978    pub scroll_manager: ScrollManager,
  979    /// When inline assist editors are linked, they all render cursors because
  980    /// typing enters text into each of them, even the ones that aren't focused.
  981    pub(crate) show_cursor_when_unfocused: bool,
  982    columnar_selection_state: Option<ColumnarSelectionState>,
  983    add_selections_state: Option<AddSelectionsState>,
  984    select_next_state: Option<SelectNextState>,
  985    select_prev_state: Option<SelectNextState>,
  986    selection_history: SelectionHistory,
  987    defer_selection_effects: bool,
  988    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  989    autoclose_regions: Vec<AutocloseRegion>,
  990    snippet_stack: InvalidationStack<SnippetState>,
  991    select_syntax_node_history: SelectSyntaxNodeHistory,
  992    ime_transaction: Option<TransactionId>,
  993    pub diagnostics_max_severity: DiagnosticSeverity,
  994    active_diagnostics: ActiveDiagnostic,
  995    show_inline_diagnostics: bool,
  996    inline_diagnostics_update: Task<()>,
  997    inline_diagnostics_enabled: bool,
  998    diagnostics_enabled: bool,
  999    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1000    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1001    hard_wrap: Option<usize>,
 1002
 1003    // TODO: make this a access method
 1004    pub project: Option<Entity<Project>>,
 1005    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1006    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1007    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1008    blink_manager: Entity<BlinkManager>,
 1009    show_cursor_names: bool,
 1010    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1011    pub show_local_selections: bool,
 1012    mode: EditorMode,
 1013    show_breadcrumbs: bool,
 1014    show_gutter: bool,
 1015    show_scrollbars: ScrollbarAxes,
 1016    minimap_visibility: MinimapVisibility,
 1017    offset_content: bool,
 1018    disable_expand_excerpt_buttons: bool,
 1019    show_line_numbers: Option<bool>,
 1020    use_relative_line_numbers: Option<bool>,
 1021    show_git_diff_gutter: Option<bool>,
 1022    show_code_actions: Option<bool>,
 1023    show_runnables: Option<bool>,
 1024    show_breakpoints: Option<bool>,
 1025    show_wrap_guides: Option<bool>,
 1026    show_indent_guides: Option<bool>,
 1027    placeholder_text: Option<Arc<str>>,
 1028    highlight_order: usize,
 1029    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1030    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1031    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1032    scrollbar_marker_state: ScrollbarMarkerState,
 1033    active_indent_guides_state: ActiveIndentGuidesState,
 1034    nav_history: Option<ItemNavHistory>,
 1035    context_menu: RefCell<Option<CodeContextMenu>>,
 1036    context_menu_options: Option<ContextMenuOptions>,
 1037    mouse_context_menu: Option<MouseContextMenu>,
 1038    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1039    inline_blame_popover: Option<InlineBlamePopover>,
 1040    inline_blame_popover_show_task: Option<Task<()>>,
 1041    signature_help_state: SignatureHelpState,
 1042    auto_signature_help: Option<bool>,
 1043    find_all_references_task_sources: Vec<Anchor>,
 1044    next_completion_id: CompletionId,
 1045    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1046    code_actions_task: Option<Task<Result<()>>>,
 1047    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1048    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1049    document_highlights_task: Option<Task<()>>,
 1050    linked_editing_range_task: Option<Task<Option<()>>>,
 1051    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1052    pending_rename: Option<RenameState>,
 1053    searchable: bool,
 1054    cursor_shape: CursorShape,
 1055    current_line_highlight: Option<CurrentLineHighlight>,
 1056    collapse_matches: bool,
 1057    autoindent_mode: Option<AutoindentMode>,
 1058    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1059    input_enabled: bool,
 1060    use_modal_editing: bool,
 1061    read_only: bool,
 1062    leader_id: Option<CollaboratorId>,
 1063    remote_id: Option<ViewId>,
 1064    pub hover_state: HoverState,
 1065    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1066    gutter_hovered: bool,
 1067    hovered_link_state: Option<HoveredLinkState>,
 1068    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1069    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1070    active_inline_completion: Option<InlineCompletionState>,
 1071    /// Used to prevent flickering as the user types while the menu is open
 1072    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1073    edit_prediction_settings: EditPredictionSettings,
 1074    inline_completions_hidden_for_vim_mode: bool,
 1075    show_inline_completions_override: Option<bool>,
 1076    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1077    edit_prediction_preview: EditPredictionPreview,
 1078    edit_prediction_indent_conflict: bool,
 1079    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1080    inlay_hint_cache: InlayHintCache,
 1081    next_inlay_id: usize,
 1082    _subscriptions: Vec<Subscription>,
 1083    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1084    gutter_dimensions: GutterDimensions,
 1085    style: Option<EditorStyle>,
 1086    text_style_refinement: Option<TextStyleRefinement>,
 1087    next_editor_action_id: EditorActionId,
 1088    editor_actions: Rc<
 1089        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1090    >,
 1091    use_autoclose: bool,
 1092    use_auto_surround: bool,
 1093    auto_replace_emoji_shortcode: bool,
 1094    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1095    show_git_blame_gutter: bool,
 1096    show_git_blame_inline: bool,
 1097    show_git_blame_inline_delay_task: Option<Task<()>>,
 1098    git_blame_inline_enabled: bool,
 1099    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1100    serialize_dirty_buffers: bool,
 1101    show_selection_menu: Option<bool>,
 1102    blame: Option<Entity<GitBlame>>,
 1103    blame_subscription: Option<Subscription>,
 1104    custom_context_menu: Option<
 1105        Box<
 1106            dyn 'static
 1107                + Fn(
 1108                    &mut Self,
 1109                    DisplayPoint,
 1110                    &mut Window,
 1111                    &mut Context<Self>,
 1112                ) -> Option<Entity<ui::ContextMenu>>,
 1113        >,
 1114    >,
 1115    last_bounds: Option<Bounds<Pixels>>,
 1116    last_position_map: Option<Rc<PositionMap>>,
 1117    expect_bounds_change: Option<Bounds<Pixels>>,
 1118    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1119    tasks_update_task: Option<Task<()>>,
 1120    breakpoint_store: Option<Entity<BreakpointStore>>,
 1121    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1122    hovered_diff_hunk_row: Option<DisplayRow>,
 1123    pull_diagnostics_task: Task<()>,
 1124    in_project_search: bool,
 1125    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1126    breadcrumb_header: Option<String>,
 1127    focused_block: Option<FocusedBlock>,
 1128    next_scroll_position: NextScrollCursorCenterTopBottom,
 1129    addons: HashMap<TypeId, Box<dyn Addon>>,
 1130    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1131    load_diff_task: Option<Shared<Task<()>>>,
 1132    /// Whether we are temporarily displaying a diff other than git's
 1133    temporary_diff_override: bool,
 1134    selection_mark_mode: bool,
 1135    toggle_fold_multiple_buffers: Task<()>,
 1136    _scroll_cursor_center_top_bottom_task: Task<()>,
 1137    serialize_selections: Task<()>,
 1138    serialize_folds: Task<()>,
 1139    mouse_cursor_hidden: bool,
 1140    minimap: Option<Entity<Self>>,
 1141    hide_mouse_mode: HideMouseMode,
 1142    pub change_list: ChangeList,
 1143    inline_value_cache: InlineValueCache,
 1144    selection_drag_state: SelectionDragState,
 1145    drag_and_drop_selection_enabled: bool,
 1146    next_color_inlay_id: usize,
 1147    colors: Option<LspColorData>,
 1148    folding_newlines: Task<()>,
 1149}
 1150
 1151#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1152enum NextScrollCursorCenterTopBottom {
 1153    #[default]
 1154    Center,
 1155    Top,
 1156    Bottom,
 1157}
 1158
 1159impl NextScrollCursorCenterTopBottom {
 1160    fn next(&self) -> Self {
 1161        match self {
 1162            Self::Center => Self::Top,
 1163            Self::Top => Self::Bottom,
 1164            Self::Bottom => Self::Center,
 1165        }
 1166    }
 1167}
 1168
 1169#[derive(Clone)]
 1170pub struct EditorSnapshot {
 1171    pub mode: EditorMode,
 1172    show_gutter: bool,
 1173    show_line_numbers: Option<bool>,
 1174    show_git_diff_gutter: Option<bool>,
 1175    show_code_actions: Option<bool>,
 1176    show_runnables: Option<bool>,
 1177    show_breakpoints: Option<bool>,
 1178    git_blame_gutter_max_author_length: Option<usize>,
 1179    pub display_snapshot: DisplaySnapshot,
 1180    pub placeholder_text: Option<Arc<str>>,
 1181    is_focused: bool,
 1182    scroll_anchor: ScrollAnchor,
 1183    ongoing_scroll: OngoingScroll,
 1184    current_line_highlight: CurrentLineHighlight,
 1185    gutter_hovered: bool,
 1186}
 1187
 1188#[derive(Default, Debug, Clone, Copy)]
 1189pub struct GutterDimensions {
 1190    pub left_padding: Pixels,
 1191    pub right_padding: Pixels,
 1192    pub width: Pixels,
 1193    pub margin: Pixels,
 1194    pub git_blame_entries_width: Option<Pixels>,
 1195}
 1196
 1197impl GutterDimensions {
 1198    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1199        Self {
 1200            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1201            ..Default::default()
 1202        }
 1203    }
 1204
 1205    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1206        -cx.text_system().descent(font_id, font_size)
 1207    }
 1208    /// The full width of the space taken up by the gutter.
 1209    pub fn full_width(&self) -> Pixels {
 1210        self.margin + self.width
 1211    }
 1212
 1213    /// The width of the space reserved for the fold indicators,
 1214    /// use alongside 'justify_end' and `gutter_width` to
 1215    /// right align content with the line numbers
 1216    pub fn fold_area_width(&self) -> Pixels {
 1217        self.margin + self.right_padding
 1218    }
 1219}
 1220
 1221struct CharacterDimensions {
 1222    em_width: Pixels,
 1223    em_advance: Pixels,
 1224    line_height: Pixels,
 1225}
 1226
 1227#[derive(Debug)]
 1228pub struct RemoteSelection {
 1229    pub replica_id: ReplicaId,
 1230    pub selection: Selection<Anchor>,
 1231    pub cursor_shape: CursorShape,
 1232    pub collaborator_id: CollaboratorId,
 1233    pub line_mode: bool,
 1234    pub user_name: Option<SharedString>,
 1235    pub color: PlayerColor,
 1236}
 1237
 1238#[derive(Clone, Debug)]
 1239struct SelectionHistoryEntry {
 1240    selections: Arc<[Selection<Anchor>]>,
 1241    select_next_state: Option<SelectNextState>,
 1242    select_prev_state: Option<SelectNextState>,
 1243    add_selections_state: Option<AddSelectionsState>,
 1244}
 1245
 1246#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1247enum SelectionHistoryMode {
 1248    Normal,
 1249    Undoing,
 1250    Redoing,
 1251    Skipping,
 1252}
 1253
 1254#[derive(Clone, PartialEq, Eq, Hash)]
 1255struct HoveredCursor {
 1256    replica_id: u16,
 1257    selection_id: usize,
 1258}
 1259
 1260impl Default for SelectionHistoryMode {
 1261    fn default() -> Self {
 1262        Self::Normal
 1263    }
 1264}
 1265
 1266#[derive(Debug)]
 1267/// SelectionEffects controls the side-effects of updating the selection.
 1268///
 1269/// The default behaviour does "what you mostly want":
 1270/// - it pushes to the nav history if the cursor moved by >10 lines
 1271/// - it re-triggers completion requests
 1272/// - it scrolls to fit
 1273///
 1274/// You might want to modify these behaviours. For example when doing a "jump"
 1275/// like go to definition, we always want to add to nav history; but when scrolling
 1276/// in vim mode we never do.
 1277///
 1278/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1279/// move.
 1280pub struct SelectionEffects {
 1281    nav_history: Option<bool>,
 1282    completions: bool,
 1283    scroll: Option<Autoscroll>,
 1284}
 1285
 1286impl Default for SelectionEffects {
 1287    fn default() -> Self {
 1288        Self {
 1289            nav_history: None,
 1290            completions: true,
 1291            scroll: Some(Autoscroll::fit()),
 1292        }
 1293    }
 1294}
 1295impl SelectionEffects {
 1296    pub fn scroll(scroll: Autoscroll) -> Self {
 1297        Self {
 1298            scroll: Some(scroll),
 1299            ..Default::default()
 1300        }
 1301    }
 1302
 1303    pub fn no_scroll() -> Self {
 1304        Self {
 1305            scroll: None,
 1306            ..Default::default()
 1307        }
 1308    }
 1309
 1310    pub fn completions(self, completions: bool) -> Self {
 1311        Self {
 1312            completions,
 1313            ..self
 1314        }
 1315    }
 1316
 1317    pub fn nav_history(self, nav_history: bool) -> Self {
 1318        Self {
 1319            nav_history: Some(nav_history),
 1320            ..self
 1321        }
 1322    }
 1323}
 1324
 1325struct DeferredSelectionEffectsState {
 1326    changed: bool,
 1327    effects: SelectionEffects,
 1328    old_cursor_position: Anchor,
 1329    history_entry: SelectionHistoryEntry,
 1330}
 1331
 1332#[derive(Default)]
 1333struct SelectionHistory {
 1334    #[allow(clippy::type_complexity)]
 1335    selections_by_transaction:
 1336        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1337    mode: SelectionHistoryMode,
 1338    undo_stack: VecDeque<SelectionHistoryEntry>,
 1339    redo_stack: VecDeque<SelectionHistoryEntry>,
 1340}
 1341
 1342impl SelectionHistory {
 1343    #[track_caller]
 1344    fn insert_transaction(
 1345        &mut self,
 1346        transaction_id: TransactionId,
 1347        selections: Arc<[Selection<Anchor>]>,
 1348    ) {
 1349        if selections.is_empty() {
 1350            log::error!(
 1351                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1352                std::panic::Location::caller()
 1353            );
 1354            return;
 1355        }
 1356        self.selections_by_transaction
 1357            .insert(transaction_id, (selections, None));
 1358    }
 1359
 1360    #[allow(clippy::type_complexity)]
 1361    fn transaction(
 1362        &self,
 1363        transaction_id: TransactionId,
 1364    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1365        self.selections_by_transaction.get(&transaction_id)
 1366    }
 1367
 1368    #[allow(clippy::type_complexity)]
 1369    fn transaction_mut(
 1370        &mut self,
 1371        transaction_id: TransactionId,
 1372    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1373        self.selections_by_transaction.get_mut(&transaction_id)
 1374    }
 1375
 1376    fn push(&mut self, entry: SelectionHistoryEntry) {
 1377        if !entry.selections.is_empty() {
 1378            match self.mode {
 1379                SelectionHistoryMode::Normal => {
 1380                    self.push_undo(entry);
 1381                    self.redo_stack.clear();
 1382                }
 1383                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1384                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1385                SelectionHistoryMode::Skipping => {}
 1386            }
 1387        }
 1388    }
 1389
 1390    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1391        if self
 1392            .undo_stack
 1393            .back()
 1394            .map_or(true, |e| e.selections != entry.selections)
 1395        {
 1396            self.undo_stack.push_back(entry);
 1397            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1398                self.undo_stack.pop_front();
 1399            }
 1400        }
 1401    }
 1402
 1403    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1404        if self
 1405            .redo_stack
 1406            .back()
 1407            .map_or(true, |e| e.selections != entry.selections)
 1408        {
 1409            self.redo_stack.push_back(entry);
 1410            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1411                self.redo_stack.pop_front();
 1412            }
 1413        }
 1414    }
 1415}
 1416
 1417#[derive(Clone, Copy)]
 1418pub struct RowHighlightOptions {
 1419    pub autoscroll: bool,
 1420    pub include_gutter: bool,
 1421}
 1422
 1423impl Default for RowHighlightOptions {
 1424    fn default() -> Self {
 1425        Self {
 1426            autoscroll: Default::default(),
 1427            include_gutter: true,
 1428        }
 1429    }
 1430}
 1431
 1432struct RowHighlight {
 1433    index: usize,
 1434    range: Range<Anchor>,
 1435    color: Hsla,
 1436    options: RowHighlightOptions,
 1437    type_id: TypeId,
 1438}
 1439
 1440#[derive(Clone, Debug)]
 1441struct AddSelectionsState {
 1442    groups: Vec<AddSelectionsGroup>,
 1443}
 1444
 1445#[derive(Clone, Debug)]
 1446struct AddSelectionsGroup {
 1447    above: bool,
 1448    stack: Vec<usize>,
 1449}
 1450
 1451#[derive(Clone)]
 1452struct SelectNextState {
 1453    query: AhoCorasick,
 1454    wordwise: bool,
 1455    done: bool,
 1456}
 1457
 1458impl std::fmt::Debug for SelectNextState {
 1459    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1460        f.debug_struct(std::any::type_name::<Self>())
 1461            .field("wordwise", &self.wordwise)
 1462            .field("done", &self.done)
 1463            .finish()
 1464    }
 1465}
 1466
 1467#[derive(Debug)]
 1468struct AutocloseRegion {
 1469    selection_id: usize,
 1470    range: Range<Anchor>,
 1471    pair: BracketPair,
 1472}
 1473
 1474#[derive(Debug)]
 1475struct SnippetState {
 1476    ranges: Vec<Vec<Range<Anchor>>>,
 1477    active_index: usize,
 1478    choices: Vec<Option<Vec<String>>>,
 1479}
 1480
 1481#[doc(hidden)]
 1482pub struct RenameState {
 1483    pub range: Range<Anchor>,
 1484    pub old_name: Arc<str>,
 1485    pub editor: Entity<Editor>,
 1486    block_id: CustomBlockId,
 1487}
 1488
 1489struct InvalidationStack<T>(Vec<T>);
 1490
 1491struct RegisteredInlineCompletionProvider {
 1492    provider: Arc<dyn InlineCompletionProviderHandle>,
 1493    _subscription: Subscription,
 1494}
 1495
 1496#[derive(Debug, PartialEq, Eq)]
 1497pub struct ActiveDiagnosticGroup {
 1498    pub active_range: Range<Anchor>,
 1499    pub active_message: String,
 1500    pub group_id: usize,
 1501    pub blocks: HashSet<CustomBlockId>,
 1502}
 1503
 1504#[derive(Debug, PartialEq, Eq)]
 1505
 1506pub(crate) enum ActiveDiagnostic {
 1507    None,
 1508    All,
 1509    Group(ActiveDiagnosticGroup),
 1510}
 1511
 1512#[derive(Serialize, Deserialize, Clone, Debug)]
 1513pub struct ClipboardSelection {
 1514    /// The number of bytes in this selection.
 1515    pub len: usize,
 1516    /// Whether this was a full-line selection.
 1517    pub is_entire_line: bool,
 1518    /// The indentation of the first line when this content was originally copied.
 1519    pub first_line_indent: u32,
 1520}
 1521
 1522// selections, scroll behavior, was newest selection reversed
 1523type SelectSyntaxNodeHistoryState = (
 1524    Box<[Selection<usize>]>,
 1525    SelectSyntaxNodeScrollBehavior,
 1526    bool,
 1527);
 1528
 1529#[derive(Default)]
 1530struct SelectSyntaxNodeHistory {
 1531    stack: Vec<SelectSyntaxNodeHistoryState>,
 1532    // disable temporarily to allow changing selections without losing the stack
 1533    pub disable_clearing: bool,
 1534}
 1535
 1536impl SelectSyntaxNodeHistory {
 1537    pub fn try_clear(&mut self) {
 1538        if !self.disable_clearing {
 1539            self.stack.clear();
 1540        }
 1541    }
 1542
 1543    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1544        self.stack.push(selection);
 1545    }
 1546
 1547    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1548        self.stack.pop()
 1549    }
 1550}
 1551
 1552enum SelectSyntaxNodeScrollBehavior {
 1553    CursorTop,
 1554    FitSelection,
 1555    CursorBottom,
 1556}
 1557
 1558#[derive(Debug)]
 1559pub(crate) struct NavigationData {
 1560    cursor_anchor: Anchor,
 1561    cursor_position: Point,
 1562    scroll_anchor: ScrollAnchor,
 1563    scroll_top_row: u32,
 1564}
 1565
 1566#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1567pub enum GotoDefinitionKind {
 1568    Symbol,
 1569    Declaration,
 1570    Type,
 1571    Implementation,
 1572}
 1573
 1574#[derive(Debug, Clone)]
 1575enum InlayHintRefreshReason {
 1576    ModifiersChanged(bool),
 1577    Toggle(bool),
 1578    SettingsChange(InlayHintSettings),
 1579    NewLinesShown,
 1580    BufferEdited(HashSet<Arc<Language>>),
 1581    RefreshRequested,
 1582    ExcerptsRemoved(Vec<ExcerptId>),
 1583}
 1584
 1585impl InlayHintRefreshReason {
 1586    fn description(&self) -> &'static str {
 1587        match self {
 1588            Self::ModifiersChanged(_) => "modifiers changed",
 1589            Self::Toggle(_) => "toggle",
 1590            Self::SettingsChange(_) => "settings change",
 1591            Self::NewLinesShown => "new lines shown",
 1592            Self::BufferEdited(_) => "buffer edited",
 1593            Self::RefreshRequested => "refresh requested",
 1594            Self::ExcerptsRemoved(_) => "excerpts removed",
 1595        }
 1596    }
 1597}
 1598
 1599pub enum FormatTarget {
 1600    Buffers(HashSet<Entity<Buffer>>),
 1601    Ranges(Vec<Range<MultiBufferPoint>>),
 1602}
 1603
 1604pub(crate) struct FocusedBlock {
 1605    id: BlockId,
 1606    focus_handle: WeakFocusHandle,
 1607}
 1608
 1609#[derive(Clone)]
 1610enum JumpData {
 1611    MultiBufferRow {
 1612        row: MultiBufferRow,
 1613        line_offset_from_top: u32,
 1614    },
 1615    MultiBufferPoint {
 1616        excerpt_id: ExcerptId,
 1617        position: Point,
 1618        anchor: text::Anchor,
 1619        line_offset_from_top: u32,
 1620    },
 1621}
 1622
 1623pub enum MultibufferSelectionMode {
 1624    First,
 1625    All,
 1626}
 1627
 1628#[derive(Clone, Copy, Debug, Default)]
 1629pub struct RewrapOptions {
 1630    pub override_language_settings: bool,
 1631    pub preserve_existing_whitespace: bool,
 1632}
 1633
 1634impl Editor {
 1635    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1636        let buffer = cx.new(|cx| Buffer::local("", cx));
 1637        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1638        Self::new(
 1639            EditorMode::SingleLine { auto_width: false },
 1640            buffer,
 1641            None,
 1642            window,
 1643            cx,
 1644        )
 1645    }
 1646
 1647    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1648        let buffer = cx.new(|cx| Buffer::local("", cx));
 1649        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1650        Self::new(EditorMode::full(), buffer, None, window, cx)
 1651    }
 1652
 1653    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1654        let buffer = cx.new(|cx| Buffer::local("", cx));
 1655        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1656        Self::new(
 1657            EditorMode::SingleLine { auto_width: true },
 1658            buffer,
 1659            None,
 1660            window,
 1661            cx,
 1662        )
 1663    }
 1664
 1665    pub fn auto_height(
 1666        min_lines: usize,
 1667        max_lines: usize,
 1668        window: &mut Window,
 1669        cx: &mut Context<Self>,
 1670    ) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(
 1674            EditorMode::AutoHeight {
 1675                min_lines,
 1676                max_lines: Some(max_lines),
 1677            },
 1678            buffer,
 1679            None,
 1680            window,
 1681            cx,
 1682        )
 1683    }
 1684
 1685    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1686    /// The editor grows as tall as needed to fit its content.
 1687    pub fn auto_height_unbounded(
 1688        min_lines: usize,
 1689        window: &mut Window,
 1690        cx: &mut Context<Self>,
 1691    ) -> Self {
 1692        let buffer = cx.new(|cx| Buffer::local("", cx));
 1693        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1694        Self::new(
 1695            EditorMode::AutoHeight {
 1696                min_lines,
 1697                max_lines: None,
 1698            },
 1699            buffer,
 1700            None,
 1701            window,
 1702            cx,
 1703        )
 1704    }
 1705
 1706    pub fn for_buffer(
 1707        buffer: Entity<Buffer>,
 1708        project: Option<Entity<Project>>,
 1709        window: &mut Window,
 1710        cx: &mut Context<Self>,
 1711    ) -> Self {
 1712        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1713        Self::new(EditorMode::full(), buffer, project, window, cx)
 1714    }
 1715
 1716    pub fn for_multibuffer(
 1717        buffer: Entity<MultiBuffer>,
 1718        project: Option<Entity<Project>>,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        Self::new(EditorMode::full(), buffer, project, window, cx)
 1723    }
 1724
 1725    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1726        let mut clone = Self::new(
 1727            self.mode.clone(),
 1728            self.buffer.clone(),
 1729            self.project.clone(),
 1730            window,
 1731            cx,
 1732        );
 1733        self.display_map.update(cx, |display_map, cx| {
 1734            let snapshot = display_map.snapshot(cx);
 1735            clone.display_map.update(cx, |display_map, cx| {
 1736                display_map.set_state(&snapshot, cx);
 1737            });
 1738        });
 1739        clone.folds_did_change(cx);
 1740        clone.selections.clone_state(&self.selections);
 1741        clone.scroll_manager.clone_state(&self.scroll_manager);
 1742        clone.searchable = self.searchable;
 1743        clone.read_only = self.read_only;
 1744        clone
 1745    }
 1746
 1747    pub fn new(
 1748        mode: EditorMode,
 1749        buffer: Entity<MultiBuffer>,
 1750        project: Option<Entity<Project>>,
 1751        window: &mut Window,
 1752        cx: &mut Context<Self>,
 1753    ) -> Self {
 1754        Editor::new_internal(mode, buffer, project, None, window, cx)
 1755    }
 1756
 1757    fn new_internal(
 1758        mode: EditorMode,
 1759        buffer: Entity<MultiBuffer>,
 1760        project: Option<Entity<Project>>,
 1761        display_map: Option<Entity<DisplayMap>>,
 1762        window: &mut Window,
 1763        cx: &mut Context<Self>,
 1764    ) -> Self {
 1765        debug_assert!(
 1766            display_map.is_none() || mode.is_minimap(),
 1767            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1768        );
 1769
 1770        let full_mode = mode.is_full();
 1771        let diagnostics_max_severity = if full_mode {
 1772            EditorSettings::get_global(cx)
 1773                .diagnostics_max_severity
 1774                .unwrap_or(DiagnosticSeverity::Hint)
 1775        } else {
 1776            DiagnosticSeverity::Off
 1777        };
 1778        let style = window.text_style();
 1779        let font_size = style.font_size.to_pixels(window.rem_size());
 1780        let editor = cx.entity().downgrade();
 1781        let fold_placeholder = FoldPlaceholder {
 1782            constrain_width: true,
 1783            render: Arc::new(move |fold_id, fold_range, cx| {
 1784                let editor = editor.clone();
 1785                div()
 1786                    .id(fold_id)
 1787                    .bg(cx.theme().colors().ghost_element_background)
 1788                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1789                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1790                    .rounded_xs()
 1791                    .size_full()
 1792                    .cursor_pointer()
 1793                    .child("")
 1794                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1795                    .on_click(move |_, _window, cx| {
 1796                        editor
 1797                            .update(cx, |editor, cx| {
 1798                                editor.unfold_ranges(
 1799                                    &[fold_range.start..fold_range.end],
 1800                                    true,
 1801                                    false,
 1802                                    cx,
 1803                                );
 1804                                cx.stop_propagation();
 1805                            })
 1806                            .ok();
 1807                    })
 1808                    .into_any()
 1809            }),
 1810            merge_adjacent: true,
 1811            ..FoldPlaceholder::default()
 1812        };
 1813        let display_map = display_map.unwrap_or_else(|| {
 1814            cx.new(|cx| {
 1815                DisplayMap::new(
 1816                    buffer.clone(),
 1817                    style.font(),
 1818                    font_size,
 1819                    None,
 1820                    FILE_HEADER_HEIGHT,
 1821                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1822                    fold_placeholder,
 1823                    diagnostics_max_severity,
 1824                    cx,
 1825                )
 1826            })
 1827        });
 1828
 1829        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1830
 1831        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1832
 1833        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1834            .then(|| language_settings::SoftWrap::None);
 1835
 1836        let mut project_subscriptions = Vec::new();
 1837        if mode.is_full() {
 1838            if let Some(project) = project.as_ref() {
 1839                project_subscriptions.push(cx.subscribe_in(
 1840                    project,
 1841                    window,
 1842                    |editor, _, event, window, cx| match event {
 1843                        project::Event::RefreshCodeLens => {
 1844                            // we always query lens with actions, without storing them, always refreshing them
 1845                        }
 1846                        project::Event::RefreshInlayHints => {
 1847                            editor
 1848                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1849                        }
 1850                        project::Event::LanguageServerAdded(..)
 1851                        | project::Event::LanguageServerRemoved(..) => {
 1852                            if editor.tasks_update_task.is_none() {
 1853                                editor.tasks_update_task =
 1854                                    Some(editor.refresh_runnables(window, cx));
 1855                            }
 1856                            editor.update_lsp_data(true, None, window, cx);
 1857                        }
 1858                        project::Event::SnippetEdit(id, snippet_edits) => {
 1859                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1860                                let focus_handle = editor.focus_handle(cx);
 1861                                if focus_handle.is_focused(window) {
 1862                                    let snapshot = buffer.read(cx).snapshot();
 1863                                    for (range, snippet) in snippet_edits {
 1864                                        let editor_range =
 1865                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1866                                        editor
 1867                                            .insert_snippet(
 1868                                                &[editor_range],
 1869                                                snippet.clone(),
 1870                                                window,
 1871                                                cx,
 1872                                            )
 1873                                            .ok();
 1874                                    }
 1875                                }
 1876                            }
 1877                        }
 1878                        _ => {}
 1879                    },
 1880                ));
 1881                if let Some(task_inventory) = project
 1882                    .read(cx)
 1883                    .task_store()
 1884                    .read(cx)
 1885                    .task_inventory()
 1886                    .cloned()
 1887                {
 1888                    project_subscriptions.push(cx.observe_in(
 1889                        &task_inventory,
 1890                        window,
 1891                        |editor, _, window, cx| {
 1892                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1893                        },
 1894                    ));
 1895                };
 1896
 1897                project_subscriptions.push(cx.subscribe_in(
 1898                    &project.read(cx).breakpoint_store(),
 1899                    window,
 1900                    |editor, _, event, window, cx| match event {
 1901                        BreakpointStoreEvent::ClearDebugLines => {
 1902                            editor.clear_row_highlights::<ActiveDebugLine>();
 1903                            editor.refresh_inline_values(cx);
 1904                        }
 1905                        BreakpointStoreEvent::SetDebugLine => {
 1906                            if editor.go_to_active_debug_line(window, cx) {
 1907                                cx.stop_propagation();
 1908                            }
 1909
 1910                            editor.refresh_inline_values(cx);
 1911                        }
 1912                        _ => {}
 1913                    },
 1914                ));
 1915                let git_store = project.read(cx).git_store().clone();
 1916                let project = project.clone();
 1917                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1918                    match event {
 1919                        GitStoreEvent::RepositoryUpdated(
 1920                            _,
 1921                            RepositoryEvent::Updated {
 1922                                new_instance: true, ..
 1923                            },
 1924                            _,
 1925                        ) => {
 1926                            this.load_diff_task = Some(
 1927                                update_uncommitted_diff_for_buffer(
 1928                                    cx.entity(),
 1929                                    &project,
 1930                                    this.buffer.read(cx).all_buffers(),
 1931                                    this.buffer.clone(),
 1932                                    cx,
 1933                                )
 1934                                .shared(),
 1935                            );
 1936                        }
 1937                        _ => {}
 1938                    }
 1939                }));
 1940            }
 1941        }
 1942
 1943        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1944
 1945        let inlay_hint_settings =
 1946            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1947        let focus_handle = cx.focus_handle();
 1948        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1949            .detach();
 1950        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1951            .detach();
 1952        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1953            .detach();
 1954        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1955            .detach();
 1956        cx.observe_pending_input(window, Self::observe_pending_input)
 1957            .detach();
 1958
 1959        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1960            Some(false)
 1961        } else {
 1962            None
 1963        };
 1964
 1965        let breakpoint_store = match (&mode, project.as_ref()) {
 1966            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1967            _ => None,
 1968        };
 1969
 1970        let mut code_action_providers = Vec::new();
 1971        let mut load_uncommitted_diff = None;
 1972        if let Some(project) = project.clone() {
 1973            load_uncommitted_diff = Some(
 1974                update_uncommitted_diff_for_buffer(
 1975                    cx.entity(),
 1976                    &project,
 1977                    buffer.read(cx).all_buffers(),
 1978                    buffer.clone(),
 1979                    cx,
 1980                )
 1981                .shared(),
 1982            );
 1983            code_action_providers.push(Rc::new(project) as Rc<_>);
 1984        }
 1985
 1986        let mut editor = Self {
 1987            focus_handle,
 1988            show_cursor_when_unfocused: false,
 1989            last_focused_descendant: None,
 1990            buffer: buffer.clone(),
 1991            display_map: display_map.clone(),
 1992            selections,
 1993            scroll_manager: ScrollManager::new(cx),
 1994            columnar_selection_state: None,
 1995            add_selections_state: None,
 1996            select_next_state: None,
 1997            select_prev_state: None,
 1998            selection_history: SelectionHistory::default(),
 1999            defer_selection_effects: false,
 2000            deferred_selection_effects_state: None,
 2001            autoclose_regions: Vec::new(),
 2002            snippet_stack: InvalidationStack::default(),
 2003            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2004            ime_transaction: None,
 2005            active_diagnostics: ActiveDiagnostic::None,
 2006            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2007            inline_diagnostics_update: Task::ready(()),
 2008            inline_diagnostics: Vec::new(),
 2009            soft_wrap_mode_override,
 2010            diagnostics_max_severity,
 2011            hard_wrap: None,
 2012            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2013            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2014            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2015            project,
 2016            blink_manager: blink_manager.clone(),
 2017            show_local_selections: true,
 2018            show_scrollbars: ScrollbarAxes {
 2019                horizontal: full_mode,
 2020                vertical: full_mode,
 2021            },
 2022            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2023            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2024            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2025            show_gutter: mode.is_full(),
 2026            show_line_numbers: None,
 2027            use_relative_line_numbers: None,
 2028            disable_expand_excerpt_buttons: false,
 2029            show_git_diff_gutter: None,
 2030            show_code_actions: None,
 2031            show_runnables: None,
 2032            show_breakpoints: None,
 2033            show_wrap_guides: None,
 2034            show_indent_guides,
 2035            placeholder_text: None,
 2036            highlight_order: 0,
 2037            highlighted_rows: HashMap::default(),
 2038            background_highlights: TreeMap::default(),
 2039            gutter_highlights: TreeMap::default(),
 2040            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2041            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2042            nav_history: None,
 2043            context_menu: RefCell::new(None),
 2044            context_menu_options: None,
 2045            mouse_context_menu: None,
 2046            completion_tasks: Vec::new(),
 2047            inline_blame_popover: None,
 2048            inline_blame_popover_show_task: None,
 2049            signature_help_state: SignatureHelpState::default(),
 2050            auto_signature_help: None,
 2051            find_all_references_task_sources: Vec::new(),
 2052            next_completion_id: 0,
 2053            next_inlay_id: 0,
 2054            code_action_providers,
 2055            available_code_actions: None,
 2056            code_actions_task: None,
 2057            quick_selection_highlight_task: None,
 2058            debounced_selection_highlight_task: None,
 2059            document_highlights_task: None,
 2060            linked_editing_range_task: None,
 2061            pending_rename: None,
 2062            searchable: true,
 2063            cursor_shape: EditorSettings::get_global(cx)
 2064                .cursor_shape
 2065                .unwrap_or_default(),
 2066            current_line_highlight: None,
 2067            autoindent_mode: Some(AutoindentMode::EachLine),
 2068            collapse_matches: false,
 2069            workspace: None,
 2070            input_enabled: true,
 2071            use_modal_editing: mode.is_full(),
 2072            read_only: mode.is_minimap(),
 2073            use_autoclose: true,
 2074            use_auto_surround: true,
 2075            auto_replace_emoji_shortcode: false,
 2076            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2077            leader_id: None,
 2078            remote_id: None,
 2079            hover_state: HoverState::default(),
 2080            pending_mouse_down: None,
 2081            hovered_link_state: None,
 2082            edit_prediction_provider: None,
 2083            active_inline_completion: None,
 2084            stale_inline_completion_in_menu: None,
 2085            edit_prediction_preview: EditPredictionPreview::Inactive {
 2086                released_too_fast: false,
 2087            },
 2088            inline_diagnostics_enabled: mode.is_full(),
 2089            diagnostics_enabled: mode.is_full(),
 2090            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2091            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2092
 2093            gutter_hovered: false,
 2094            pixel_position_of_newest_cursor: None,
 2095            last_bounds: None,
 2096            last_position_map: None,
 2097            expect_bounds_change: None,
 2098            gutter_dimensions: GutterDimensions::default(),
 2099            style: None,
 2100            show_cursor_names: false,
 2101            hovered_cursors: HashMap::default(),
 2102            next_editor_action_id: EditorActionId::default(),
 2103            editor_actions: Rc::default(),
 2104            inline_completions_hidden_for_vim_mode: false,
 2105            show_inline_completions_override: None,
 2106            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2107            edit_prediction_settings: EditPredictionSettings::Disabled,
 2108            edit_prediction_indent_conflict: false,
 2109            edit_prediction_requires_modifier_in_indent_conflict: true,
 2110            custom_context_menu: None,
 2111            show_git_blame_gutter: false,
 2112            show_git_blame_inline: false,
 2113            show_selection_menu: None,
 2114            show_git_blame_inline_delay_task: None,
 2115            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2116            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2117            serialize_dirty_buffers: !mode.is_minimap()
 2118                && ProjectSettings::get_global(cx)
 2119                    .session
 2120                    .restore_unsaved_buffers,
 2121            blame: None,
 2122            blame_subscription: None,
 2123            tasks: BTreeMap::default(),
 2124
 2125            breakpoint_store,
 2126            gutter_breakpoint_indicator: (None, None),
 2127            hovered_diff_hunk_row: None,
 2128            _subscriptions: vec![
 2129                cx.observe(&buffer, Self::on_buffer_changed),
 2130                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2131                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2132                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2133                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2134                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2135                cx.observe_window_activation(window, |editor, window, cx| {
 2136                    let active = window.is_window_active();
 2137                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2138                        if active {
 2139                            blink_manager.enable(cx);
 2140                        } else {
 2141                            blink_manager.disable(cx);
 2142                        }
 2143                    });
 2144                    if active {
 2145                        editor.show_mouse_cursor(cx);
 2146                    }
 2147                }),
 2148            ],
 2149            tasks_update_task: None,
 2150            pull_diagnostics_task: Task::ready(()),
 2151            colors: None,
 2152            next_color_inlay_id: 0,
 2153            linked_edit_ranges: Default::default(),
 2154            in_project_search: false,
 2155            previous_search_ranges: None,
 2156            breadcrumb_header: None,
 2157            focused_block: None,
 2158            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2159            addons: HashMap::default(),
 2160            registered_buffers: HashMap::default(),
 2161            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2162            selection_mark_mode: false,
 2163            toggle_fold_multiple_buffers: Task::ready(()),
 2164            serialize_selections: Task::ready(()),
 2165            serialize_folds: Task::ready(()),
 2166            text_style_refinement: None,
 2167            load_diff_task: load_uncommitted_diff,
 2168            temporary_diff_override: false,
 2169            mouse_cursor_hidden: false,
 2170            minimap: None,
 2171            hide_mouse_mode: EditorSettings::get_global(cx)
 2172                .hide_mouse
 2173                .unwrap_or_default(),
 2174            change_list: ChangeList::new(),
 2175            mode,
 2176            selection_drag_state: SelectionDragState::None,
 2177            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2178            folding_newlines: Task::ready(()),
 2179        };
 2180        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2181            editor
 2182                ._subscriptions
 2183                .push(cx.observe(breakpoints, |_, _, cx| {
 2184                    cx.notify();
 2185                }));
 2186        }
 2187        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2188        editor._subscriptions.extend(project_subscriptions);
 2189
 2190        editor._subscriptions.push(cx.subscribe_in(
 2191            &cx.entity(),
 2192            window,
 2193            |editor, _, e: &EditorEvent, window, cx| match e {
 2194                EditorEvent::ScrollPositionChanged { local, .. } => {
 2195                    if *local {
 2196                        let new_anchor = editor.scroll_manager.anchor();
 2197                        let snapshot = editor.snapshot(window, cx);
 2198                        editor.update_restoration_data(cx, move |data| {
 2199                            data.scroll_position = (
 2200                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2201                                new_anchor.offset,
 2202                            );
 2203                        });
 2204                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2205                        editor.inline_blame_popover.take();
 2206                    }
 2207                }
 2208                EditorEvent::Edited { .. } => {
 2209                    if !vim_enabled(cx) {
 2210                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2211                        let pop_state = editor
 2212                            .change_list
 2213                            .last()
 2214                            .map(|previous| {
 2215                                previous.len() == selections.len()
 2216                                    && previous.iter().enumerate().all(|(ix, p)| {
 2217                                        p.to_display_point(&map).row()
 2218                                            == selections[ix].head().row()
 2219                                    })
 2220                            })
 2221                            .unwrap_or(false);
 2222                        let new_positions = selections
 2223                            .into_iter()
 2224                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2225                            .collect();
 2226                        editor
 2227                            .change_list
 2228                            .push_to_change_list(pop_state, new_positions);
 2229                    }
 2230                }
 2231                _ => (),
 2232            },
 2233        ));
 2234
 2235        if let Some(dap_store) = editor
 2236            .project
 2237            .as_ref()
 2238            .map(|project| project.read(cx).dap_store())
 2239        {
 2240            let weak_editor = cx.weak_entity();
 2241
 2242            editor
 2243                ._subscriptions
 2244                .push(
 2245                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2246                        let session_entity = cx.entity();
 2247                        weak_editor
 2248                            .update(cx, |editor, cx| {
 2249                                editor._subscriptions.push(
 2250                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2251                                );
 2252                            })
 2253                            .ok();
 2254                    }),
 2255                );
 2256
 2257            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2258                editor
 2259                    ._subscriptions
 2260                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2261            }
 2262        }
 2263
 2264        // skip adding the initial selection to selection history
 2265        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2266        editor.end_selection(window, cx);
 2267        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2268
 2269        editor.scroll_manager.show_scrollbars(window, cx);
 2270        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2271
 2272        if full_mode {
 2273            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2274            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2275
 2276            if editor.git_blame_inline_enabled {
 2277                editor.start_git_blame_inline(false, window, cx);
 2278            }
 2279
 2280            editor.go_to_active_debug_line(window, cx);
 2281
 2282            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2283                if let Some(project) = editor.project.as_ref() {
 2284                    let handle = project.update(cx, |project, cx| {
 2285                        project.register_buffer_with_language_servers(&buffer, cx)
 2286                    });
 2287                    editor
 2288                        .registered_buffers
 2289                        .insert(buffer.read(cx).remote_id(), handle);
 2290                }
 2291            }
 2292
 2293            editor.minimap =
 2294                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2295            editor.colors = Some(LspColorData::new(cx));
 2296            editor.update_lsp_data(false, None, window, cx);
 2297        }
 2298
 2299        editor.report_editor_event("Editor Opened", None, cx);
 2300        editor
 2301    }
 2302
 2303    pub fn deploy_mouse_context_menu(
 2304        &mut self,
 2305        position: gpui::Point<Pixels>,
 2306        context_menu: Entity<ContextMenu>,
 2307        window: &mut Window,
 2308        cx: &mut Context<Self>,
 2309    ) {
 2310        self.mouse_context_menu = Some(MouseContextMenu::new(
 2311            self,
 2312            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2313            context_menu,
 2314            window,
 2315            cx,
 2316        ));
 2317    }
 2318
 2319    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2320        self.mouse_context_menu
 2321            .as_ref()
 2322            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2323    }
 2324
 2325    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2326        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2327    }
 2328
 2329    fn key_context_internal(
 2330        &self,
 2331        has_active_edit_prediction: bool,
 2332        window: &Window,
 2333        cx: &App,
 2334    ) -> KeyContext {
 2335        let mut key_context = KeyContext::new_with_defaults();
 2336        key_context.add("Editor");
 2337        let mode = match self.mode {
 2338            EditorMode::SingleLine { .. } => "single_line",
 2339            EditorMode::AutoHeight { .. } => "auto_height",
 2340            EditorMode::Minimap { .. } => "minimap",
 2341            EditorMode::Full { .. } => "full",
 2342        };
 2343
 2344        if EditorSettings::jupyter_enabled(cx) {
 2345            key_context.add("jupyter");
 2346        }
 2347
 2348        key_context.set("mode", mode);
 2349        if self.pending_rename.is_some() {
 2350            key_context.add("renaming");
 2351        }
 2352
 2353        match self.context_menu.borrow().as_ref() {
 2354            Some(CodeContextMenu::Completions(_)) => {
 2355                key_context.add("menu");
 2356                key_context.add("showing_completions");
 2357            }
 2358            Some(CodeContextMenu::CodeActions(_)) => {
 2359                key_context.add("menu");
 2360                key_context.add("showing_code_actions")
 2361            }
 2362            None => {}
 2363        }
 2364
 2365        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2366        if !self.focus_handle(cx).contains_focused(window, cx)
 2367            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2368        {
 2369            for addon in self.addons.values() {
 2370                addon.extend_key_context(&mut key_context, cx)
 2371            }
 2372        }
 2373
 2374        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2375            if let Some(extension) = singleton_buffer
 2376                .read(cx)
 2377                .file()
 2378                .and_then(|file| file.path().extension()?.to_str())
 2379            {
 2380                key_context.set("extension", extension.to_string());
 2381            }
 2382        } else {
 2383            key_context.add("multibuffer");
 2384        }
 2385
 2386        if has_active_edit_prediction {
 2387            if self.edit_prediction_in_conflict() {
 2388                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2389            } else {
 2390                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2391                key_context.add("copilot_suggestion");
 2392            }
 2393        }
 2394
 2395        if self.selection_mark_mode {
 2396            key_context.add("selection_mode");
 2397        }
 2398
 2399        key_context
 2400    }
 2401
 2402    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2403        if self.mouse_cursor_hidden {
 2404            self.mouse_cursor_hidden = false;
 2405            cx.notify();
 2406        }
 2407    }
 2408
 2409    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2410        let hide_mouse_cursor = match origin {
 2411            HideMouseCursorOrigin::TypingAction => {
 2412                matches!(
 2413                    self.hide_mouse_mode,
 2414                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2415                )
 2416            }
 2417            HideMouseCursorOrigin::MovementAction => {
 2418                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2419            }
 2420        };
 2421        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2422            self.mouse_cursor_hidden = hide_mouse_cursor;
 2423            cx.notify();
 2424        }
 2425    }
 2426
 2427    pub fn edit_prediction_in_conflict(&self) -> bool {
 2428        if !self.show_edit_predictions_in_menu() {
 2429            return false;
 2430        }
 2431
 2432        let showing_completions = self
 2433            .context_menu
 2434            .borrow()
 2435            .as_ref()
 2436            .map_or(false, |context| {
 2437                matches!(context, CodeContextMenu::Completions(_))
 2438            });
 2439
 2440        showing_completions
 2441            || self.edit_prediction_requires_modifier()
 2442            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2443            // bindings to insert tab characters.
 2444            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2445    }
 2446
 2447    pub fn accept_edit_prediction_keybind(
 2448        &self,
 2449        accept_partial: bool,
 2450        window: &Window,
 2451        cx: &App,
 2452    ) -> AcceptEditPredictionBinding {
 2453        let key_context = self.key_context_internal(true, window, cx);
 2454        let in_conflict = self.edit_prediction_in_conflict();
 2455
 2456        let bindings = if accept_partial {
 2457            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2458        } else {
 2459            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2460        };
 2461
 2462        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2463        // just the first one.
 2464        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2465            !in_conflict
 2466                || binding
 2467                    .keystrokes()
 2468                    .first()
 2469                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2470        }))
 2471    }
 2472
 2473    pub fn new_file(
 2474        workspace: &mut Workspace,
 2475        _: &workspace::NewFile,
 2476        window: &mut Window,
 2477        cx: &mut Context<Workspace>,
 2478    ) {
 2479        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2480            "Failed to create buffer",
 2481            window,
 2482            cx,
 2483            |e, _, _| match e.error_code() {
 2484                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2485                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2486                e.error_tag("required").unwrap_or("the latest version")
 2487            )),
 2488                _ => None,
 2489            },
 2490        );
 2491    }
 2492
 2493    pub fn new_in_workspace(
 2494        workspace: &mut Workspace,
 2495        window: &mut Window,
 2496        cx: &mut Context<Workspace>,
 2497    ) -> Task<Result<Entity<Editor>>> {
 2498        let project = workspace.project().clone();
 2499        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2500
 2501        cx.spawn_in(window, async move |workspace, cx| {
 2502            let buffer = create.await?;
 2503            workspace.update_in(cx, |workspace, window, cx| {
 2504                let editor =
 2505                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2506                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2507                editor
 2508            })
 2509        })
 2510    }
 2511
 2512    fn new_file_vertical(
 2513        workspace: &mut Workspace,
 2514        _: &workspace::NewFileSplitVertical,
 2515        window: &mut Window,
 2516        cx: &mut Context<Workspace>,
 2517    ) {
 2518        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2519    }
 2520
 2521    fn new_file_horizontal(
 2522        workspace: &mut Workspace,
 2523        _: &workspace::NewFileSplitHorizontal,
 2524        window: &mut Window,
 2525        cx: &mut Context<Workspace>,
 2526    ) {
 2527        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2528    }
 2529
 2530    fn new_file_in_direction(
 2531        workspace: &mut Workspace,
 2532        direction: SplitDirection,
 2533        window: &mut Window,
 2534        cx: &mut Context<Workspace>,
 2535    ) {
 2536        let project = workspace.project().clone();
 2537        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2538
 2539        cx.spawn_in(window, async move |workspace, cx| {
 2540            let buffer = create.await?;
 2541            workspace.update_in(cx, move |workspace, window, cx| {
 2542                workspace.split_item(
 2543                    direction,
 2544                    Box::new(
 2545                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2546                    ),
 2547                    window,
 2548                    cx,
 2549                )
 2550            })?;
 2551            anyhow::Ok(())
 2552        })
 2553        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2554            match e.error_code() {
 2555                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2556                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2557                e.error_tag("required").unwrap_or("the latest version")
 2558            )),
 2559                _ => None,
 2560            }
 2561        });
 2562    }
 2563
 2564    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2565        self.leader_id
 2566    }
 2567
 2568    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2569        &self.buffer
 2570    }
 2571
 2572    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2573        self.workspace.as_ref()?.0.upgrade()
 2574    }
 2575
 2576    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2577        self.buffer().read(cx).title(cx)
 2578    }
 2579
 2580    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2581        let git_blame_gutter_max_author_length = self
 2582            .render_git_blame_gutter(cx)
 2583            .then(|| {
 2584                if let Some(blame) = self.blame.as_ref() {
 2585                    let max_author_length =
 2586                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2587                    Some(max_author_length)
 2588                } else {
 2589                    None
 2590                }
 2591            })
 2592            .flatten();
 2593
 2594        EditorSnapshot {
 2595            mode: self.mode.clone(),
 2596            show_gutter: self.show_gutter,
 2597            show_line_numbers: self.show_line_numbers,
 2598            show_git_diff_gutter: self.show_git_diff_gutter,
 2599            show_code_actions: self.show_code_actions,
 2600            show_runnables: self.show_runnables,
 2601            show_breakpoints: self.show_breakpoints,
 2602            git_blame_gutter_max_author_length,
 2603            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2604            scroll_anchor: self.scroll_manager.anchor(),
 2605            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2606            placeholder_text: self.placeholder_text.clone(),
 2607            is_focused: self.focus_handle.is_focused(window),
 2608            current_line_highlight: self
 2609                .current_line_highlight
 2610                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2611            gutter_hovered: self.gutter_hovered,
 2612        }
 2613    }
 2614
 2615    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2616        self.buffer.read(cx).language_at(point, cx)
 2617    }
 2618
 2619    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2620        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2621    }
 2622
 2623    pub fn active_excerpt(
 2624        &self,
 2625        cx: &App,
 2626    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2627        self.buffer
 2628            .read(cx)
 2629            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2630    }
 2631
 2632    pub fn mode(&self) -> &EditorMode {
 2633        &self.mode
 2634    }
 2635
 2636    pub fn set_mode(&mut self, mode: EditorMode) {
 2637        self.mode = mode;
 2638    }
 2639
 2640    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2641        self.collaboration_hub.as_deref()
 2642    }
 2643
 2644    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2645        self.collaboration_hub = Some(hub);
 2646    }
 2647
 2648    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2649        self.in_project_search = in_project_search;
 2650    }
 2651
 2652    pub fn set_custom_context_menu(
 2653        &mut self,
 2654        f: impl 'static
 2655        + Fn(
 2656            &mut Self,
 2657            DisplayPoint,
 2658            &mut Window,
 2659            &mut Context<Self>,
 2660        ) -> Option<Entity<ui::ContextMenu>>,
 2661    ) {
 2662        self.custom_context_menu = Some(Box::new(f))
 2663    }
 2664
 2665    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2666        self.completion_provider = provider;
 2667    }
 2668
 2669    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2670        self.semantics_provider.clone()
 2671    }
 2672
 2673    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2674        self.semantics_provider = provider;
 2675    }
 2676
 2677    pub fn set_edit_prediction_provider<T>(
 2678        &mut self,
 2679        provider: Option<Entity<T>>,
 2680        window: &mut Window,
 2681        cx: &mut Context<Self>,
 2682    ) where
 2683        T: EditPredictionProvider,
 2684    {
 2685        self.edit_prediction_provider =
 2686            provider.map(|provider| RegisteredInlineCompletionProvider {
 2687                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2688                    if this.focus_handle.is_focused(window) {
 2689                        this.update_visible_inline_completion(window, cx);
 2690                    }
 2691                }),
 2692                provider: Arc::new(provider),
 2693            });
 2694        self.update_edit_prediction_settings(cx);
 2695        self.refresh_inline_completion(false, false, window, cx);
 2696    }
 2697
 2698    pub fn placeholder_text(&self) -> Option<&str> {
 2699        self.placeholder_text.as_deref()
 2700    }
 2701
 2702    pub fn set_placeholder_text(
 2703        &mut self,
 2704        placeholder_text: impl Into<Arc<str>>,
 2705        cx: &mut Context<Self>,
 2706    ) {
 2707        let placeholder_text = Some(placeholder_text.into());
 2708        if self.placeholder_text != placeholder_text {
 2709            self.placeholder_text = placeholder_text;
 2710            cx.notify();
 2711        }
 2712    }
 2713
 2714    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2715        self.cursor_shape = cursor_shape;
 2716
 2717        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2718        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2719
 2720        cx.notify();
 2721    }
 2722
 2723    pub fn set_current_line_highlight(
 2724        &mut self,
 2725        current_line_highlight: Option<CurrentLineHighlight>,
 2726    ) {
 2727        self.current_line_highlight = current_line_highlight;
 2728    }
 2729
 2730    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2731        self.collapse_matches = collapse_matches;
 2732    }
 2733
 2734    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2735        let buffers = self.buffer.read(cx).all_buffers();
 2736        let Some(project) = self.project.as_ref() else {
 2737            return;
 2738        };
 2739        project.update(cx, |project, cx| {
 2740            for buffer in buffers {
 2741                self.registered_buffers
 2742                    .entry(buffer.read(cx).remote_id())
 2743                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2744            }
 2745        })
 2746    }
 2747
 2748    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2749        if self.collapse_matches {
 2750            return range.start..range.start;
 2751        }
 2752        range.clone()
 2753    }
 2754
 2755    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2756        if self.display_map.read(cx).clip_at_line_ends != clip {
 2757            self.display_map
 2758                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2759        }
 2760    }
 2761
 2762    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2763        self.input_enabled = input_enabled;
 2764    }
 2765
 2766    pub fn set_inline_completions_hidden_for_vim_mode(
 2767        &mut self,
 2768        hidden: bool,
 2769        window: &mut Window,
 2770        cx: &mut Context<Self>,
 2771    ) {
 2772        if hidden != self.inline_completions_hidden_for_vim_mode {
 2773            self.inline_completions_hidden_for_vim_mode = hidden;
 2774            if hidden {
 2775                self.update_visible_inline_completion(window, cx);
 2776            } else {
 2777                self.refresh_inline_completion(true, false, window, cx);
 2778            }
 2779        }
 2780    }
 2781
 2782    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2783        self.menu_inline_completions_policy = value;
 2784    }
 2785
 2786    pub fn set_autoindent(&mut self, autoindent: bool) {
 2787        if autoindent {
 2788            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2789        } else {
 2790            self.autoindent_mode = None;
 2791        }
 2792    }
 2793
 2794    pub fn read_only(&self, cx: &App) -> bool {
 2795        self.read_only || self.buffer.read(cx).read_only()
 2796    }
 2797
 2798    pub fn set_read_only(&mut self, read_only: bool) {
 2799        self.read_only = read_only;
 2800    }
 2801
 2802    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2803        self.use_autoclose = autoclose;
 2804    }
 2805
 2806    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2807        self.use_auto_surround = auto_surround;
 2808    }
 2809
 2810    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2811        self.auto_replace_emoji_shortcode = auto_replace;
 2812    }
 2813
 2814    pub fn toggle_edit_predictions(
 2815        &mut self,
 2816        _: &ToggleEditPrediction,
 2817        window: &mut Window,
 2818        cx: &mut Context<Self>,
 2819    ) {
 2820        if self.show_inline_completions_override.is_some() {
 2821            self.set_show_edit_predictions(None, window, cx);
 2822        } else {
 2823            let show_edit_predictions = !self.edit_predictions_enabled();
 2824            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2825        }
 2826    }
 2827
 2828    pub fn set_show_edit_predictions(
 2829        &mut self,
 2830        show_edit_predictions: Option<bool>,
 2831        window: &mut Window,
 2832        cx: &mut Context<Self>,
 2833    ) {
 2834        self.show_inline_completions_override = show_edit_predictions;
 2835        self.update_edit_prediction_settings(cx);
 2836
 2837        if let Some(false) = show_edit_predictions {
 2838            self.discard_inline_completion(false, cx);
 2839        } else {
 2840            self.refresh_inline_completion(false, true, window, cx);
 2841        }
 2842    }
 2843
 2844    fn inline_completions_disabled_in_scope(
 2845        &self,
 2846        buffer: &Entity<Buffer>,
 2847        buffer_position: language::Anchor,
 2848        cx: &App,
 2849    ) -> bool {
 2850        let snapshot = buffer.read(cx).snapshot();
 2851        let settings = snapshot.settings_at(buffer_position, cx);
 2852
 2853        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2854            return false;
 2855        };
 2856
 2857        scope.override_name().map_or(false, |scope_name| {
 2858            settings
 2859                .edit_predictions_disabled_in
 2860                .iter()
 2861                .any(|s| s == scope_name)
 2862        })
 2863    }
 2864
 2865    pub fn set_use_modal_editing(&mut self, to: bool) {
 2866        self.use_modal_editing = to;
 2867    }
 2868
 2869    pub fn use_modal_editing(&self) -> bool {
 2870        self.use_modal_editing
 2871    }
 2872
 2873    fn selections_did_change(
 2874        &mut self,
 2875        local: bool,
 2876        old_cursor_position: &Anchor,
 2877        effects: SelectionEffects,
 2878        window: &mut Window,
 2879        cx: &mut Context<Self>,
 2880    ) {
 2881        window.invalidate_character_coordinates();
 2882
 2883        // Copy selections to primary selection buffer
 2884        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2885        if local {
 2886            let selections = self.selections.all::<usize>(cx);
 2887            let buffer_handle = self.buffer.read(cx).read(cx);
 2888
 2889            let mut text = String::new();
 2890            for (index, selection) in selections.iter().enumerate() {
 2891                let text_for_selection = buffer_handle
 2892                    .text_for_range(selection.start..selection.end)
 2893                    .collect::<String>();
 2894
 2895                text.push_str(&text_for_selection);
 2896                if index != selections.len() - 1 {
 2897                    text.push('\n');
 2898                }
 2899            }
 2900
 2901            if !text.is_empty() {
 2902                cx.write_to_primary(ClipboardItem::new_string(text));
 2903            }
 2904        }
 2905
 2906        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2907            self.buffer.update(cx, |buffer, cx| {
 2908                buffer.set_active_selections(
 2909                    &self.selections.disjoint_anchors(),
 2910                    self.selections.line_mode,
 2911                    self.cursor_shape,
 2912                    cx,
 2913                )
 2914            });
 2915        }
 2916        let display_map = self
 2917            .display_map
 2918            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2919        let buffer = &display_map.buffer_snapshot;
 2920        if self.selections.count() == 1 {
 2921            self.add_selections_state = None;
 2922        }
 2923        self.select_next_state = None;
 2924        self.select_prev_state = None;
 2925        self.select_syntax_node_history.try_clear();
 2926        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2927        self.snippet_stack
 2928            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2929        self.take_rename(false, window, cx);
 2930
 2931        let newest_selection = self.selections.newest_anchor();
 2932        let new_cursor_position = newest_selection.head();
 2933        let selection_start = newest_selection.start;
 2934
 2935        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2936            self.push_to_nav_history(
 2937                *old_cursor_position,
 2938                Some(new_cursor_position.to_point(buffer)),
 2939                false,
 2940                effects.nav_history == Some(true),
 2941                cx,
 2942            );
 2943        }
 2944
 2945        if local {
 2946            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2947                if !self.registered_buffers.contains_key(&buffer_id) {
 2948                    if let Some(project) = self.project.as_ref() {
 2949                        project.update(cx, |project, cx| {
 2950                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2951                                return;
 2952                            };
 2953                            self.registered_buffers.insert(
 2954                                buffer_id,
 2955                                project.register_buffer_with_language_servers(&buffer, cx),
 2956                            );
 2957                        })
 2958                    }
 2959                }
 2960            }
 2961
 2962            let mut context_menu = self.context_menu.borrow_mut();
 2963            let completion_menu = match context_menu.as_ref() {
 2964                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2965                Some(CodeContextMenu::CodeActions(_)) => {
 2966                    *context_menu = None;
 2967                    None
 2968                }
 2969                None => None,
 2970            };
 2971            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2972            drop(context_menu);
 2973
 2974            if effects.completions {
 2975                if let Some(completion_position) = completion_position {
 2976                    let start_offset = selection_start.to_offset(buffer);
 2977                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2978                    let continue_showing = if position_matches {
 2979                        if self.snippet_stack.is_empty() {
 2980                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2981                        } else {
 2982                            // Snippet choices can be shown even when the cursor is in whitespace.
 2983                            // Dismissing the menu with actions like backspace is handled by
 2984                            // invalidation regions.
 2985                            true
 2986                        }
 2987                    } else {
 2988                        false
 2989                    };
 2990
 2991                    if continue_showing {
 2992                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2993                    } else {
 2994                        self.hide_context_menu(window, cx);
 2995                    }
 2996                }
 2997            }
 2998
 2999            hide_hover(self, cx);
 3000
 3001            if old_cursor_position.to_display_point(&display_map).row()
 3002                != new_cursor_position.to_display_point(&display_map).row()
 3003            {
 3004                self.available_code_actions.take();
 3005            }
 3006            self.refresh_code_actions(window, cx);
 3007            self.refresh_document_highlights(cx);
 3008            self.refresh_selected_text_highlights(false, window, cx);
 3009            refresh_matching_bracket_highlights(self, window, cx);
 3010            self.update_visible_inline_completion(window, cx);
 3011            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3012            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3013            self.inline_blame_popover.take();
 3014            if self.git_blame_inline_enabled {
 3015                self.start_inline_blame_timer(window, cx);
 3016            }
 3017        }
 3018
 3019        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3020        cx.emit(EditorEvent::SelectionsChanged { local });
 3021
 3022        let selections = &self.selections.disjoint;
 3023        if selections.len() == 1 {
 3024            cx.emit(SearchEvent::ActiveMatchChanged)
 3025        }
 3026        if local {
 3027            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3028                let inmemory_selections = selections
 3029                    .iter()
 3030                    .map(|s| {
 3031                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3032                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3033                    })
 3034                    .collect();
 3035                self.update_restoration_data(cx, |data| {
 3036                    data.selections = inmemory_selections;
 3037                });
 3038
 3039                if WorkspaceSettings::get(None, cx).restore_on_startup
 3040                    != RestoreOnStartupBehavior::None
 3041                {
 3042                    if let Some(workspace_id) =
 3043                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3044                    {
 3045                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3046                        let selections = selections.clone();
 3047                        let background_executor = cx.background_executor().clone();
 3048                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3049                        self.serialize_selections = cx.background_spawn(async move {
 3050                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3051                            let db_selections = selections
 3052                                .iter()
 3053                                .map(|selection| {
 3054                                    (
 3055                                        selection.start.to_offset(&snapshot),
 3056                                        selection.end.to_offset(&snapshot),
 3057                                    )
 3058                                })
 3059                                .collect();
 3060
 3061                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3062                                .await
 3063                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3064                                .log_err();
 3065                        });
 3066                    }
 3067                }
 3068            }
 3069        }
 3070
 3071        cx.notify();
 3072    }
 3073
 3074    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3075        use text::ToOffset as _;
 3076        use text::ToPoint as _;
 3077
 3078        if self.mode.is_minimap()
 3079            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3080        {
 3081            return;
 3082        }
 3083
 3084        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3085            return;
 3086        };
 3087
 3088        let snapshot = singleton.read(cx).snapshot();
 3089        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3090            let display_snapshot = display_map.snapshot(cx);
 3091
 3092            display_snapshot
 3093                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3094                .map(|fold| {
 3095                    fold.range.start.text_anchor.to_point(&snapshot)
 3096                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3097                })
 3098                .collect()
 3099        });
 3100        self.update_restoration_data(cx, |data| {
 3101            data.folds = inmemory_folds;
 3102        });
 3103
 3104        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3105            return;
 3106        };
 3107        let background_executor = cx.background_executor().clone();
 3108        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3109        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3110            display_map
 3111                .snapshot(cx)
 3112                .folds_in_range(0..snapshot.len())
 3113                .map(|fold| {
 3114                    (
 3115                        fold.range.start.text_anchor.to_offset(&snapshot),
 3116                        fold.range.end.text_anchor.to_offset(&snapshot),
 3117                    )
 3118                })
 3119                .collect()
 3120        });
 3121        self.serialize_folds = cx.background_spawn(async move {
 3122            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3123            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3124                .await
 3125                .with_context(|| {
 3126                    format!(
 3127                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3128                    )
 3129                })
 3130                .log_err();
 3131        });
 3132    }
 3133
 3134    pub fn sync_selections(
 3135        &mut self,
 3136        other: Entity<Editor>,
 3137        cx: &mut Context<Self>,
 3138    ) -> gpui::Subscription {
 3139        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3140        self.selections.change_with(cx, |selections| {
 3141            selections.select_anchors(other_selections);
 3142        });
 3143
 3144        let other_subscription =
 3145            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3146                EditorEvent::SelectionsChanged { local: true } => {
 3147                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3148                    if other_selections.is_empty() {
 3149                        return;
 3150                    }
 3151                    this.selections.change_with(cx, |selections| {
 3152                        selections.select_anchors(other_selections);
 3153                    });
 3154                }
 3155                _ => {}
 3156            });
 3157
 3158        let this_subscription =
 3159            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3160                EditorEvent::SelectionsChanged { local: true } => {
 3161                    let these_selections = this.selections.disjoint.to_vec();
 3162                    if these_selections.is_empty() {
 3163                        return;
 3164                    }
 3165                    other.update(cx, |other_editor, cx| {
 3166                        other_editor.selections.change_with(cx, |selections| {
 3167                            selections.select_anchors(these_selections);
 3168                        })
 3169                    });
 3170                }
 3171                _ => {}
 3172            });
 3173
 3174        Subscription::join(other_subscription, this_subscription)
 3175    }
 3176
 3177    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3178    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3179    /// effects of selection change occur at the end of the transaction.
 3180    pub fn change_selections<R>(
 3181        &mut self,
 3182        effects: SelectionEffects,
 3183        window: &mut Window,
 3184        cx: &mut Context<Self>,
 3185        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3186    ) -> R {
 3187        if let Some(state) = &mut self.deferred_selection_effects_state {
 3188            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3189            state.effects.completions = effects.completions;
 3190            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3191            let (changed, result) = self.selections.change_with(cx, change);
 3192            state.changed |= changed;
 3193            return result;
 3194        }
 3195        let mut state = DeferredSelectionEffectsState {
 3196            changed: false,
 3197            effects,
 3198            old_cursor_position: self.selections.newest_anchor().head(),
 3199            history_entry: SelectionHistoryEntry {
 3200                selections: self.selections.disjoint_anchors(),
 3201                select_next_state: self.select_next_state.clone(),
 3202                select_prev_state: self.select_prev_state.clone(),
 3203                add_selections_state: self.add_selections_state.clone(),
 3204            },
 3205        };
 3206        let (changed, result) = self.selections.change_with(cx, change);
 3207        state.changed = state.changed || changed;
 3208        if self.defer_selection_effects {
 3209            self.deferred_selection_effects_state = Some(state);
 3210        } else {
 3211            self.apply_selection_effects(state, window, cx);
 3212        }
 3213        result
 3214    }
 3215
 3216    /// Defers the effects of selection change, so that the effects of multiple calls to
 3217    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3218    /// to selection history and the state of popovers based on selection position aren't
 3219    /// erroneously updated.
 3220    pub fn with_selection_effects_deferred<R>(
 3221        &mut self,
 3222        window: &mut Window,
 3223        cx: &mut Context<Self>,
 3224        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3225    ) -> R {
 3226        let already_deferred = self.defer_selection_effects;
 3227        self.defer_selection_effects = true;
 3228        let result = update(self, window, cx);
 3229        if !already_deferred {
 3230            self.defer_selection_effects = false;
 3231            if let Some(state) = self.deferred_selection_effects_state.take() {
 3232                self.apply_selection_effects(state, window, cx);
 3233            }
 3234        }
 3235        result
 3236    }
 3237
 3238    fn apply_selection_effects(
 3239        &mut self,
 3240        state: DeferredSelectionEffectsState,
 3241        window: &mut Window,
 3242        cx: &mut Context<Self>,
 3243    ) {
 3244        if state.changed {
 3245            self.selection_history.push(state.history_entry);
 3246
 3247            if let Some(autoscroll) = state.effects.scroll {
 3248                self.request_autoscroll(autoscroll, cx);
 3249            }
 3250
 3251            let old_cursor_position = &state.old_cursor_position;
 3252
 3253            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3254
 3255            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3256                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3257            }
 3258        }
 3259    }
 3260
 3261    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3262    where
 3263        I: IntoIterator<Item = (Range<S>, T)>,
 3264        S: ToOffset,
 3265        T: Into<Arc<str>>,
 3266    {
 3267        if self.read_only(cx) {
 3268            return;
 3269        }
 3270
 3271        self.buffer
 3272            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3273    }
 3274
 3275    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3276    where
 3277        I: IntoIterator<Item = (Range<S>, T)>,
 3278        S: ToOffset,
 3279        T: Into<Arc<str>>,
 3280    {
 3281        if self.read_only(cx) {
 3282            return;
 3283        }
 3284
 3285        self.buffer.update(cx, |buffer, cx| {
 3286            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3287        });
 3288    }
 3289
 3290    pub fn edit_with_block_indent<I, S, T>(
 3291        &mut self,
 3292        edits: I,
 3293        original_indent_columns: Vec<Option<u32>>,
 3294        cx: &mut Context<Self>,
 3295    ) where
 3296        I: IntoIterator<Item = (Range<S>, T)>,
 3297        S: ToOffset,
 3298        T: Into<Arc<str>>,
 3299    {
 3300        if self.read_only(cx) {
 3301            return;
 3302        }
 3303
 3304        self.buffer.update(cx, |buffer, cx| {
 3305            buffer.edit(
 3306                edits,
 3307                Some(AutoindentMode::Block {
 3308                    original_indent_columns,
 3309                }),
 3310                cx,
 3311            )
 3312        });
 3313    }
 3314
 3315    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3316        self.hide_context_menu(window, cx);
 3317
 3318        match phase {
 3319            SelectPhase::Begin {
 3320                position,
 3321                add,
 3322                click_count,
 3323            } => self.begin_selection(position, add, click_count, window, cx),
 3324            SelectPhase::BeginColumnar {
 3325                position,
 3326                goal_column,
 3327                reset,
 3328                mode,
 3329            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3330            SelectPhase::Extend {
 3331                position,
 3332                click_count,
 3333            } => self.extend_selection(position, click_count, window, cx),
 3334            SelectPhase::Update {
 3335                position,
 3336                goal_column,
 3337                scroll_delta,
 3338            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3339            SelectPhase::End => self.end_selection(window, cx),
 3340        }
 3341    }
 3342
 3343    fn extend_selection(
 3344        &mut self,
 3345        position: DisplayPoint,
 3346        click_count: usize,
 3347        window: &mut Window,
 3348        cx: &mut Context<Self>,
 3349    ) {
 3350        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3351        let tail = self.selections.newest::<usize>(cx).tail();
 3352        self.begin_selection(position, false, click_count, window, cx);
 3353
 3354        let position = position.to_offset(&display_map, Bias::Left);
 3355        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3356
 3357        let mut pending_selection = self
 3358            .selections
 3359            .pending_anchor()
 3360            .expect("extend_selection not called with pending selection");
 3361        if position >= tail {
 3362            pending_selection.start = tail_anchor;
 3363        } else {
 3364            pending_selection.end = tail_anchor;
 3365            pending_selection.reversed = true;
 3366        }
 3367
 3368        let mut pending_mode = self.selections.pending_mode().unwrap();
 3369        match &mut pending_mode {
 3370            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3371            _ => {}
 3372        }
 3373
 3374        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3375            SelectionEffects::scroll(Autoscroll::fit())
 3376        } else {
 3377            SelectionEffects::no_scroll()
 3378        };
 3379
 3380        self.change_selections(effects, window, cx, |s| {
 3381            s.set_pending(pending_selection, pending_mode)
 3382        });
 3383    }
 3384
 3385    fn begin_selection(
 3386        &mut self,
 3387        position: DisplayPoint,
 3388        add: bool,
 3389        click_count: usize,
 3390        window: &mut Window,
 3391        cx: &mut Context<Self>,
 3392    ) {
 3393        if !self.focus_handle.is_focused(window) {
 3394            self.last_focused_descendant = None;
 3395            window.focus(&self.focus_handle);
 3396        }
 3397
 3398        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3399        let buffer = &display_map.buffer_snapshot;
 3400        let position = display_map.clip_point(position, Bias::Left);
 3401
 3402        let start;
 3403        let end;
 3404        let mode;
 3405        let mut auto_scroll;
 3406        match click_count {
 3407            1 => {
 3408                start = buffer.anchor_before(position.to_point(&display_map));
 3409                end = start;
 3410                mode = SelectMode::Character;
 3411                auto_scroll = true;
 3412            }
 3413            2 => {
 3414                let position = display_map
 3415                    .clip_point(position, Bias::Left)
 3416                    .to_offset(&display_map, Bias::Left);
 3417                let (range, _) = buffer.surrounding_word(position, false);
 3418                start = buffer.anchor_before(range.start);
 3419                end = buffer.anchor_before(range.end);
 3420                mode = SelectMode::Word(start..end);
 3421                auto_scroll = true;
 3422            }
 3423            3 => {
 3424                let position = display_map
 3425                    .clip_point(position, Bias::Left)
 3426                    .to_point(&display_map);
 3427                let line_start = display_map.prev_line_boundary(position).0;
 3428                let next_line_start = buffer.clip_point(
 3429                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3430                    Bias::Left,
 3431                );
 3432                start = buffer.anchor_before(line_start);
 3433                end = buffer.anchor_before(next_line_start);
 3434                mode = SelectMode::Line(start..end);
 3435                auto_scroll = true;
 3436            }
 3437            _ => {
 3438                start = buffer.anchor_before(0);
 3439                end = buffer.anchor_before(buffer.len());
 3440                mode = SelectMode::All;
 3441                auto_scroll = false;
 3442            }
 3443        }
 3444        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3445
 3446        let point_to_delete: Option<usize> = {
 3447            let selected_points: Vec<Selection<Point>> =
 3448                self.selections.disjoint_in_range(start..end, cx);
 3449
 3450            if !add || click_count > 1 {
 3451                None
 3452            } else if !selected_points.is_empty() {
 3453                Some(selected_points[0].id)
 3454            } else {
 3455                let clicked_point_already_selected =
 3456                    self.selections.disjoint.iter().find(|selection| {
 3457                        selection.start.to_point(buffer) == start.to_point(buffer)
 3458                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3459                    });
 3460
 3461                clicked_point_already_selected.map(|selection| selection.id)
 3462            }
 3463        };
 3464
 3465        let selections_count = self.selections.count();
 3466        let effects = if auto_scroll {
 3467            SelectionEffects::default()
 3468        } else {
 3469            SelectionEffects::no_scroll()
 3470        };
 3471
 3472        self.change_selections(effects, window, cx, |s| {
 3473            if let Some(point_to_delete) = point_to_delete {
 3474                s.delete(point_to_delete);
 3475
 3476                if selections_count == 1 {
 3477                    s.set_pending_anchor_range(start..end, mode);
 3478                }
 3479            } else {
 3480                if !add {
 3481                    s.clear_disjoint();
 3482                }
 3483
 3484                s.set_pending_anchor_range(start..end, mode);
 3485            }
 3486        });
 3487    }
 3488
 3489    fn begin_columnar_selection(
 3490        &mut self,
 3491        position: DisplayPoint,
 3492        goal_column: u32,
 3493        reset: bool,
 3494        mode: ColumnarMode,
 3495        window: &mut Window,
 3496        cx: &mut Context<Self>,
 3497    ) {
 3498        if !self.focus_handle.is_focused(window) {
 3499            self.last_focused_descendant = None;
 3500            window.focus(&self.focus_handle);
 3501        }
 3502
 3503        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3504
 3505        if reset {
 3506            let pointer_position = display_map
 3507                .buffer_snapshot
 3508                .anchor_before(position.to_point(&display_map));
 3509
 3510            self.change_selections(
 3511                SelectionEffects::scroll(Autoscroll::newest()),
 3512                window,
 3513                cx,
 3514                |s| {
 3515                    s.clear_disjoint();
 3516                    s.set_pending_anchor_range(
 3517                        pointer_position..pointer_position,
 3518                        SelectMode::Character,
 3519                    );
 3520                },
 3521            );
 3522        };
 3523
 3524        let tail = self.selections.newest::<Point>(cx).tail();
 3525        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3526        self.columnar_selection_state = match mode {
 3527            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3528                selection_tail: selection_anchor,
 3529                display_point: if reset {
 3530                    if position.column() != goal_column {
 3531                        Some(DisplayPoint::new(position.row(), goal_column))
 3532                    } else {
 3533                        None
 3534                    }
 3535                } else {
 3536                    None
 3537                },
 3538            }),
 3539            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3540                selection_tail: selection_anchor,
 3541            }),
 3542        };
 3543
 3544        if !reset {
 3545            self.select_columns(position, goal_column, &display_map, window, cx);
 3546        }
 3547    }
 3548
 3549    fn update_selection(
 3550        &mut self,
 3551        position: DisplayPoint,
 3552        goal_column: u32,
 3553        scroll_delta: gpui::Point<f32>,
 3554        window: &mut Window,
 3555        cx: &mut Context<Self>,
 3556    ) {
 3557        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3558
 3559        if self.columnar_selection_state.is_some() {
 3560            self.select_columns(position, goal_column, &display_map, window, cx);
 3561        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3562            let buffer = &display_map.buffer_snapshot;
 3563            let head;
 3564            let tail;
 3565            let mode = self.selections.pending_mode().unwrap();
 3566            match &mode {
 3567                SelectMode::Character => {
 3568                    head = position.to_point(&display_map);
 3569                    tail = pending.tail().to_point(buffer);
 3570                }
 3571                SelectMode::Word(original_range) => {
 3572                    let offset = display_map
 3573                        .clip_point(position, Bias::Left)
 3574                        .to_offset(&display_map, Bias::Left);
 3575                    let original_range = original_range.to_offset(buffer);
 3576
 3577                    let head_offset = if buffer.is_inside_word(offset, false)
 3578                        || original_range.contains(&offset)
 3579                    {
 3580                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3581                        if word_range.start < original_range.start {
 3582                            word_range.start
 3583                        } else {
 3584                            word_range.end
 3585                        }
 3586                    } else {
 3587                        offset
 3588                    };
 3589
 3590                    head = head_offset.to_point(buffer);
 3591                    if head_offset <= original_range.start {
 3592                        tail = original_range.end.to_point(buffer);
 3593                    } else {
 3594                        tail = original_range.start.to_point(buffer);
 3595                    }
 3596                }
 3597                SelectMode::Line(original_range) => {
 3598                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3599
 3600                    let position = display_map
 3601                        .clip_point(position, Bias::Left)
 3602                        .to_point(&display_map);
 3603                    let line_start = display_map.prev_line_boundary(position).0;
 3604                    let next_line_start = buffer.clip_point(
 3605                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3606                        Bias::Left,
 3607                    );
 3608
 3609                    if line_start < original_range.start {
 3610                        head = line_start
 3611                    } else {
 3612                        head = next_line_start
 3613                    }
 3614
 3615                    if head <= original_range.start {
 3616                        tail = original_range.end;
 3617                    } else {
 3618                        tail = original_range.start;
 3619                    }
 3620                }
 3621                SelectMode::All => {
 3622                    return;
 3623                }
 3624            };
 3625
 3626            if head < tail {
 3627                pending.start = buffer.anchor_before(head);
 3628                pending.end = buffer.anchor_before(tail);
 3629                pending.reversed = true;
 3630            } else {
 3631                pending.start = buffer.anchor_before(tail);
 3632                pending.end = buffer.anchor_before(head);
 3633                pending.reversed = false;
 3634            }
 3635
 3636            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3637                s.set_pending(pending, mode);
 3638            });
 3639        } else {
 3640            log::error!("update_selection dispatched with no pending selection");
 3641            return;
 3642        }
 3643
 3644        self.apply_scroll_delta(scroll_delta, window, cx);
 3645        cx.notify();
 3646    }
 3647
 3648    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3649        self.columnar_selection_state.take();
 3650        if self.selections.pending_anchor().is_some() {
 3651            let selections = self.selections.all::<usize>(cx);
 3652            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3653                s.select(selections);
 3654                s.clear_pending();
 3655            });
 3656        }
 3657    }
 3658
 3659    fn select_columns(
 3660        &mut self,
 3661        head: DisplayPoint,
 3662        goal_column: u32,
 3663        display_map: &DisplaySnapshot,
 3664        window: &mut Window,
 3665        cx: &mut Context<Self>,
 3666    ) {
 3667        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3668            return;
 3669        };
 3670
 3671        let tail = match columnar_state {
 3672            ColumnarSelectionState::FromMouse {
 3673                selection_tail,
 3674                display_point,
 3675            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3676            ColumnarSelectionState::FromSelection { selection_tail } => {
 3677                selection_tail.to_display_point(&display_map)
 3678            }
 3679        };
 3680
 3681        let start_row = cmp::min(tail.row(), head.row());
 3682        let end_row = cmp::max(tail.row(), head.row());
 3683        let start_column = cmp::min(tail.column(), goal_column);
 3684        let end_column = cmp::max(tail.column(), goal_column);
 3685        let reversed = start_column < tail.column();
 3686
 3687        let selection_ranges = (start_row.0..=end_row.0)
 3688            .map(DisplayRow)
 3689            .filter_map(|row| {
 3690                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3691                    || start_column <= display_map.line_len(row))
 3692                    && !display_map.is_block_line(row)
 3693                {
 3694                    let start = display_map
 3695                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3696                        .to_point(display_map);
 3697                    let end = display_map
 3698                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3699                        .to_point(display_map);
 3700                    if reversed {
 3701                        Some(end..start)
 3702                    } else {
 3703                        Some(start..end)
 3704                    }
 3705                } else {
 3706                    None
 3707                }
 3708            })
 3709            .collect::<Vec<_>>();
 3710
 3711        let ranges = match columnar_state {
 3712            ColumnarSelectionState::FromMouse { .. } => {
 3713                let mut non_empty_ranges = selection_ranges
 3714                    .iter()
 3715                    .filter(|selection_range| selection_range.start != selection_range.end)
 3716                    .peekable();
 3717                if non_empty_ranges.peek().is_some() {
 3718                    non_empty_ranges.cloned().collect()
 3719                } else {
 3720                    selection_ranges
 3721                }
 3722            }
 3723            _ => selection_ranges,
 3724        };
 3725
 3726        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3727            s.select_ranges(ranges);
 3728        });
 3729        cx.notify();
 3730    }
 3731
 3732    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3733        self.selections
 3734            .all_adjusted(cx)
 3735            .iter()
 3736            .any(|selection| !selection.is_empty())
 3737    }
 3738
 3739    pub fn has_pending_nonempty_selection(&self) -> bool {
 3740        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3741            Some(Selection { start, end, .. }) => start != end,
 3742            None => false,
 3743        };
 3744
 3745        pending_nonempty_selection
 3746            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3747    }
 3748
 3749    pub fn has_pending_selection(&self) -> bool {
 3750        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3751    }
 3752
 3753    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3754        self.selection_mark_mode = false;
 3755        self.selection_drag_state = SelectionDragState::None;
 3756
 3757        if self.clear_expanded_diff_hunks(cx) {
 3758            cx.notify();
 3759            return;
 3760        }
 3761        if self.dismiss_menus_and_popups(true, window, cx) {
 3762            return;
 3763        }
 3764
 3765        if self.mode.is_full()
 3766            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3767        {
 3768            return;
 3769        }
 3770
 3771        cx.propagate();
 3772    }
 3773
 3774    pub fn dismiss_menus_and_popups(
 3775        &mut self,
 3776        is_user_requested: bool,
 3777        window: &mut Window,
 3778        cx: &mut Context<Self>,
 3779    ) -> bool {
 3780        if self.take_rename(false, window, cx).is_some() {
 3781            return true;
 3782        }
 3783
 3784        if hide_hover(self, cx) {
 3785            return true;
 3786        }
 3787
 3788        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3789            return true;
 3790        }
 3791
 3792        if self.hide_context_menu(window, cx).is_some() {
 3793            return true;
 3794        }
 3795
 3796        if self.mouse_context_menu.take().is_some() {
 3797            return true;
 3798        }
 3799
 3800        if is_user_requested && self.discard_inline_completion(true, cx) {
 3801            return true;
 3802        }
 3803
 3804        if self.snippet_stack.pop().is_some() {
 3805            return true;
 3806        }
 3807
 3808        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3809            self.dismiss_diagnostics(cx);
 3810            return true;
 3811        }
 3812
 3813        false
 3814    }
 3815
 3816    fn linked_editing_ranges_for(
 3817        &self,
 3818        selection: Range<text::Anchor>,
 3819        cx: &App,
 3820    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3821        if self.linked_edit_ranges.is_empty() {
 3822            return None;
 3823        }
 3824        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3825            selection.end.buffer_id.and_then(|end_buffer_id| {
 3826                if selection.start.buffer_id != Some(end_buffer_id) {
 3827                    return None;
 3828                }
 3829                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3830                let snapshot = buffer.read(cx).snapshot();
 3831                self.linked_edit_ranges
 3832                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3833                    .map(|ranges| (ranges, snapshot, buffer))
 3834            })?;
 3835        use text::ToOffset as TO;
 3836        // find offset from the start of current range to current cursor position
 3837        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3838
 3839        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3840        let start_difference = start_offset - start_byte_offset;
 3841        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3842        let end_difference = end_offset - start_byte_offset;
 3843        // Current range has associated linked ranges.
 3844        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3845        for range in linked_ranges.iter() {
 3846            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3847            let end_offset = start_offset + end_difference;
 3848            let start_offset = start_offset + start_difference;
 3849            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3850                continue;
 3851            }
 3852            if self.selections.disjoint_anchor_ranges().any(|s| {
 3853                if s.start.buffer_id != selection.start.buffer_id
 3854                    || s.end.buffer_id != selection.end.buffer_id
 3855                {
 3856                    return false;
 3857                }
 3858                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3859                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3860            }) {
 3861                continue;
 3862            }
 3863            let start = buffer_snapshot.anchor_after(start_offset);
 3864            let end = buffer_snapshot.anchor_after(end_offset);
 3865            linked_edits
 3866                .entry(buffer.clone())
 3867                .or_default()
 3868                .push(start..end);
 3869        }
 3870        Some(linked_edits)
 3871    }
 3872
 3873    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3874        let text: Arc<str> = text.into();
 3875
 3876        if self.read_only(cx) {
 3877            return;
 3878        }
 3879
 3880        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3881
 3882        let selections = self.selections.all_adjusted(cx);
 3883        let mut bracket_inserted = false;
 3884        let mut edits = Vec::new();
 3885        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3886        let mut new_selections = Vec::with_capacity(selections.len());
 3887        let mut new_autoclose_regions = Vec::new();
 3888        let snapshot = self.buffer.read(cx).read(cx);
 3889        let mut clear_linked_edit_ranges = false;
 3890
 3891        for (selection, autoclose_region) in
 3892            self.selections_with_autoclose_regions(selections, &snapshot)
 3893        {
 3894            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3895                // Determine if the inserted text matches the opening or closing
 3896                // bracket of any of this language's bracket pairs.
 3897                let mut bracket_pair = None;
 3898                let mut is_bracket_pair_start = false;
 3899                let mut is_bracket_pair_end = false;
 3900                if !text.is_empty() {
 3901                    let mut bracket_pair_matching_end = None;
 3902                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3903                    //  and they are removing the character that triggered IME popup.
 3904                    for (pair, enabled) in scope.brackets() {
 3905                        if !pair.close && !pair.surround {
 3906                            continue;
 3907                        }
 3908
 3909                        if enabled && pair.start.ends_with(text.as_ref()) {
 3910                            let prefix_len = pair.start.len() - text.len();
 3911                            let preceding_text_matches_prefix = prefix_len == 0
 3912                                || (selection.start.column >= (prefix_len as u32)
 3913                                    && snapshot.contains_str_at(
 3914                                        Point::new(
 3915                                            selection.start.row,
 3916                                            selection.start.column - (prefix_len as u32),
 3917                                        ),
 3918                                        &pair.start[..prefix_len],
 3919                                    ));
 3920                            if preceding_text_matches_prefix {
 3921                                bracket_pair = Some(pair.clone());
 3922                                is_bracket_pair_start = true;
 3923                                break;
 3924                            }
 3925                        }
 3926                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3927                        {
 3928                            // take first bracket pair matching end, but don't break in case a later bracket
 3929                            // pair matches start
 3930                            bracket_pair_matching_end = Some(pair.clone());
 3931                        }
 3932                    }
 3933                    if let Some(end) = bracket_pair_matching_end
 3934                        && bracket_pair.is_none()
 3935                    {
 3936                        bracket_pair = Some(end);
 3937                        is_bracket_pair_end = true;
 3938                    }
 3939                }
 3940
 3941                if let Some(bracket_pair) = bracket_pair {
 3942                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3943                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3944                    let auto_surround =
 3945                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3946                    if selection.is_empty() {
 3947                        if is_bracket_pair_start {
 3948                            // If the inserted text is a suffix of an opening bracket and the
 3949                            // selection is preceded by the rest of the opening bracket, then
 3950                            // insert the closing bracket.
 3951                            let following_text_allows_autoclose = snapshot
 3952                                .chars_at(selection.start)
 3953                                .next()
 3954                                .map_or(true, |c| scope.should_autoclose_before(c));
 3955
 3956                            let preceding_text_allows_autoclose = selection.start.column == 0
 3957                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3958                                    true,
 3959                                    |c| {
 3960                                        bracket_pair.start != bracket_pair.end
 3961                                            || !snapshot
 3962                                                .char_classifier_at(selection.start)
 3963                                                .is_word(c)
 3964                                    },
 3965                                );
 3966
 3967                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3968                                && bracket_pair.start.len() == 1
 3969                            {
 3970                                let target = bracket_pair.start.chars().next().unwrap();
 3971                                let current_line_count = snapshot
 3972                                    .reversed_chars_at(selection.start)
 3973                                    .take_while(|&c| c != '\n')
 3974                                    .filter(|&c| c == target)
 3975                                    .count();
 3976                                current_line_count % 2 == 1
 3977                            } else {
 3978                                false
 3979                            };
 3980
 3981                            if autoclose
 3982                                && bracket_pair.close
 3983                                && following_text_allows_autoclose
 3984                                && preceding_text_allows_autoclose
 3985                                && !is_closing_quote
 3986                            {
 3987                                let anchor = snapshot.anchor_before(selection.end);
 3988                                new_selections.push((selection.map(|_| anchor), text.len()));
 3989                                new_autoclose_regions.push((
 3990                                    anchor,
 3991                                    text.len(),
 3992                                    selection.id,
 3993                                    bracket_pair.clone(),
 3994                                ));
 3995                                edits.push((
 3996                                    selection.range(),
 3997                                    format!("{}{}", text, bracket_pair.end).into(),
 3998                                ));
 3999                                bracket_inserted = true;
 4000                                continue;
 4001                            }
 4002                        }
 4003
 4004                        if let Some(region) = autoclose_region {
 4005                            // If the selection is followed by an auto-inserted closing bracket,
 4006                            // then don't insert that closing bracket again; just move the selection
 4007                            // past the closing bracket.
 4008                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4009                                && text.as_ref() == region.pair.end.as_str();
 4010                            if should_skip {
 4011                                let anchor = snapshot.anchor_after(selection.end);
 4012                                new_selections
 4013                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4014                                continue;
 4015                            }
 4016                        }
 4017
 4018                        let always_treat_brackets_as_autoclosed = snapshot
 4019                            .language_settings_at(selection.start, cx)
 4020                            .always_treat_brackets_as_autoclosed;
 4021                        if always_treat_brackets_as_autoclosed
 4022                            && is_bracket_pair_end
 4023                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4024                        {
 4025                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4026                            // and the inserted text is a closing bracket and the selection is followed
 4027                            // by the closing bracket then move the selection past the closing bracket.
 4028                            let anchor = snapshot.anchor_after(selection.end);
 4029                            new_selections.push((selection.map(|_| anchor), text.len()));
 4030                            continue;
 4031                        }
 4032                    }
 4033                    // If an opening bracket is 1 character long and is typed while
 4034                    // text is selected, then surround that text with the bracket pair.
 4035                    else if auto_surround
 4036                        && bracket_pair.surround
 4037                        && is_bracket_pair_start
 4038                        && bracket_pair.start.chars().count() == 1
 4039                    {
 4040                        edits.push((selection.start..selection.start, text.clone()));
 4041                        edits.push((
 4042                            selection.end..selection.end,
 4043                            bracket_pair.end.as_str().into(),
 4044                        ));
 4045                        bracket_inserted = true;
 4046                        new_selections.push((
 4047                            Selection {
 4048                                id: selection.id,
 4049                                start: snapshot.anchor_after(selection.start),
 4050                                end: snapshot.anchor_before(selection.end),
 4051                                reversed: selection.reversed,
 4052                                goal: selection.goal,
 4053                            },
 4054                            0,
 4055                        ));
 4056                        continue;
 4057                    }
 4058                }
 4059            }
 4060
 4061            if self.auto_replace_emoji_shortcode
 4062                && selection.is_empty()
 4063                && text.as_ref().ends_with(':')
 4064            {
 4065                if let Some(possible_emoji_short_code) =
 4066                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4067                {
 4068                    if !possible_emoji_short_code.is_empty() {
 4069                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4070                            let emoji_shortcode_start = Point::new(
 4071                                selection.start.row,
 4072                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4073                            );
 4074
 4075                            // Remove shortcode from buffer
 4076                            edits.push((
 4077                                emoji_shortcode_start..selection.start,
 4078                                "".to_string().into(),
 4079                            ));
 4080                            new_selections.push((
 4081                                Selection {
 4082                                    id: selection.id,
 4083                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4084                                    end: snapshot.anchor_before(selection.start),
 4085                                    reversed: selection.reversed,
 4086                                    goal: selection.goal,
 4087                                },
 4088                                0,
 4089                            ));
 4090
 4091                            // Insert emoji
 4092                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4093                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4094                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4095
 4096                            continue;
 4097                        }
 4098                    }
 4099                }
 4100            }
 4101
 4102            // If not handling any auto-close operation, then just replace the selected
 4103            // text with the given input and move the selection to the end of the
 4104            // newly inserted text.
 4105            let anchor = snapshot.anchor_after(selection.end);
 4106            if !self.linked_edit_ranges.is_empty() {
 4107                let start_anchor = snapshot.anchor_before(selection.start);
 4108
 4109                let is_word_char = text.chars().next().map_or(true, |char| {
 4110                    let classifier = snapshot
 4111                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4112                        .ignore_punctuation(true);
 4113                    classifier.is_word(char)
 4114                });
 4115
 4116                if is_word_char {
 4117                    if let Some(ranges) = self
 4118                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4119                    {
 4120                        for (buffer, edits) in ranges {
 4121                            linked_edits
 4122                                .entry(buffer.clone())
 4123                                .or_default()
 4124                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4125                        }
 4126                    }
 4127                } else {
 4128                    clear_linked_edit_ranges = true;
 4129                }
 4130            }
 4131
 4132            new_selections.push((selection.map(|_| anchor), 0));
 4133            edits.push((selection.start..selection.end, text.clone()));
 4134        }
 4135
 4136        drop(snapshot);
 4137
 4138        self.transact(window, cx, |this, window, cx| {
 4139            if clear_linked_edit_ranges {
 4140                this.linked_edit_ranges.clear();
 4141            }
 4142            let initial_buffer_versions =
 4143                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4144
 4145            this.buffer.update(cx, |buffer, cx| {
 4146                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4147            });
 4148            for (buffer, edits) in linked_edits {
 4149                buffer.update(cx, |buffer, cx| {
 4150                    let snapshot = buffer.snapshot();
 4151                    let edits = edits
 4152                        .into_iter()
 4153                        .map(|(range, text)| {
 4154                            use text::ToPoint as TP;
 4155                            let end_point = TP::to_point(&range.end, &snapshot);
 4156                            let start_point = TP::to_point(&range.start, &snapshot);
 4157                            (start_point..end_point, text)
 4158                        })
 4159                        .sorted_by_key(|(range, _)| range.start);
 4160                    buffer.edit(edits, None, cx);
 4161                })
 4162            }
 4163            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4164            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4165            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4166            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4167                .zip(new_selection_deltas)
 4168                .map(|(selection, delta)| Selection {
 4169                    id: selection.id,
 4170                    start: selection.start + delta,
 4171                    end: selection.end + delta,
 4172                    reversed: selection.reversed,
 4173                    goal: SelectionGoal::None,
 4174                })
 4175                .collect::<Vec<_>>();
 4176
 4177            let mut i = 0;
 4178            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4179                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4180                let start = map.buffer_snapshot.anchor_before(position);
 4181                let end = map.buffer_snapshot.anchor_after(position);
 4182                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4183                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4184                        Ordering::Less => i += 1,
 4185                        Ordering::Greater => break,
 4186                        Ordering::Equal => {
 4187                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4188                                Ordering::Less => i += 1,
 4189                                Ordering::Equal => break,
 4190                                Ordering::Greater => break,
 4191                            }
 4192                        }
 4193                    }
 4194                }
 4195                this.autoclose_regions.insert(
 4196                    i,
 4197                    AutocloseRegion {
 4198                        selection_id,
 4199                        range: start..end,
 4200                        pair,
 4201                    },
 4202                );
 4203            }
 4204
 4205            let had_active_inline_completion = this.has_active_inline_completion();
 4206            this.change_selections(
 4207                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4208                window,
 4209                cx,
 4210                |s| s.select(new_selections),
 4211            );
 4212
 4213            if !bracket_inserted {
 4214                if let Some(on_type_format_task) =
 4215                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4216                {
 4217                    on_type_format_task.detach_and_log_err(cx);
 4218                }
 4219            }
 4220
 4221            let editor_settings = EditorSettings::get_global(cx);
 4222            if bracket_inserted
 4223                && (editor_settings.auto_signature_help
 4224                    || editor_settings.show_signature_help_after_edits)
 4225            {
 4226                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4227            }
 4228
 4229            let trigger_in_words =
 4230                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4231            if this.hard_wrap.is_some() {
 4232                let latest: Range<Point> = this.selections.newest(cx).range();
 4233                if latest.is_empty()
 4234                    && this
 4235                        .buffer()
 4236                        .read(cx)
 4237                        .snapshot(cx)
 4238                        .line_len(MultiBufferRow(latest.start.row))
 4239                        == latest.start.column
 4240                {
 4241                    this.rewrap_impl(
 4242                        RewrapOptions {
 4243                            override_language_settings: true,
 4244                            preserve_existing_whitespace: true,
 4245                        },
 4246                        cx,
 4247                    )
 4248                }
 4249            }
 4250            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4251            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4252            this.refresh_inline_completion(true, false, window, cx);
 4253            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4254        });
 4255    }
 4256
 4257    fn find_possible_emoji_shortcode_at_position(
 4258        snapshot: &MultiBufferSnapshot,
 4259        position: Point,
 4260    ) -> Option<String> {
 4261        let mut chars = Vec::new();
 4262        let mut found_colon = false;
 4263        for char in snapshot.reversed_chars_at(position).take(100) {
 4264            // Found a possible emoji shortcode in the middle of the buffer
 4265            if found_colon {
 4266                if char.is_whitespace() {
 4267                    chars.reverse();
 4268                    return Some(chars.iter().collect());
 4269                }
 4270                // If the previous character is not a whitespace, we are in the middle of a word
 4271                // and we only want to complete the shortcode if the word is made up of other emojis
 4272                let mut containing_word = String::new();
 4273                for ch in snapshot
 4274                    .reversed_chars_at(position)
 4275                    .skip(chars.len() + 1)
 4276                    .take(100)
 4277                {
 4278                    if ch.is_whitespace() {
 4279                        break;
 4280                    }
 4281                    containing_word.push(ch);
 4282                }
 4283                let containing_word = containing_word.chars().rev().collect::<String>();
 4284                if util::word_consists_of_emojis(containing_word.as_str()) {
 4285                    chars.reverse();
 4286                    return Some(chars.iter().collect());
 4287                }
 4288            }
 4289
 4290            if char.is_whitespace() || !char.is_ascii() {
 4291                return None;
 4292            }
 4293            if char == ':' {
 4294                found_colon = true;
 4295            } else {
 4296                chars.push(char);
 4297            }
 4298        }
 4299        // Found a possible emoji shortcode at the beginning of the buffer
 4300        chars.reverse();
 4301        Some(chars.iter().collect())
 4302    }
 4303
 4304    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4306        self.transact(window, cx, |this, window, cx| {
 4307            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4308                let selections = this.selections.all::<usize>(cx);
 4309                let multi_buffer = this.buffer.read(cx);
 4310                let buffer = multi_buffer.snapshot(cx);
 4311                selections
 4312                    .iter()
 4313                    .map(|selection| {
 4314                        let start_point = selection.start.to_point(&buffer);
 4315                        let mut existing_indent =
 4316                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4317                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4318                        let start = selection.start;
 4319                        let end = selection.end;
 4320                        let selection_is_empty = start == end;
 4321                        let language_scope = buffer.language_scope_at(start);
 4322                        let (
 4323                            comment_delimiter,
 4324                            doc_delimiter,
 4325                            insert_extra_newline,
 4326                            indent_on_newline,
 4327                            indent_on_extra_newline,
 4328                        ) = if let Some(language) = &language_scope {
 4329                            let mut insert_extra_newline =
 4330                                insert_extra_newline_brackets(&buffer, start..end, language)
 4331                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4332
 4333                            // Comment extension on newline is allowed only for cursor selections
 4334                            let comment_delimiter = maybe!({
 4335                                if !selection_is_empty {
 4336                                    return None;
 4337                                }
 4338
 4339                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4340                                    return None;
 4341                                }
 4342
 4343                                let delimiters = language.line_comment_prefixes();
 4344                                let max_len_of_delimiter =
 4345                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4346                                let (snapshot, range) =
 4347                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4348
 4349                                let num_of_whitespaces = snapshot
 4350                                    .chars_for_range(range.clone())
 4351                                    .take_while(|c| c.is_whitespace())
 4352                                    .count();
 4353                                let comment_candidate = snapshot
 4354                                    .chars_for_range(range)
 4355                                    .skip(num_of_whitespaces)
 4356                                    .take(max_len_of_delimiter)
 4357                                    .collect::<String>();
 4358                                let (delimiter, trimmed_len) = delimiters
 4359                                    .iter()
 4360                                    .filter_map(|delimiter| {
 4361                                        let prefix = delimiter.trim_end();
 4362                                        if comment_candidate.starts_with(prefix) {
 4363                                            Some((delimiter, prefix.len()))
 4364                                        } else {
 4365                                            None
 4366                                        }
 4367                                    })
 4368                                    .max_by_key(|(_, len)| *len)?;
 4369
 4370                                let cursor_is_placed_after_comment_marker =
 4371                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4372                                if cursor_is_placed_after_comment_marker {
 4373                                    Some(delimiter.clone())
 4374                                } else {
 4375                                    None
 4376                                }
 4377                            });
 4378
 4379                            let mut indent_on_newline = IndentSize::spaces(0);
 4380                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4381
 4382                            let doc_delimiter = maybe!({
 4383                                if !selection_is_empty {
 4384                                    return None;
 4385                                }
 4386
 4387                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4388                                    return None;
 4389                                }
 4390
 4391                                let DocumentationConfig {
 4392                                    start: start_tag,
 4393                                    end: end_tag,
 4394                                    prefix: delimiter,
 4395                                    tab_size: len,
 4396                                } = language.documentation()?;
 4397
 4398                                let is_within_block_comment = buffer
 4399                                    .language_scope_at(start_point)
 4400                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4401                                if !is_within_block_comment {
 4402                                    return None;
 4403                                }
 4404
 4405                                let (snapshot, range) =
 4406                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4407
 4408                                let num_of_whitespaces = snapshot
 4409                                    .chars_for_range(range.clone())
 4410                                    .take_while(|c| c.is_whitespace())
 4411                                    .count();
 4412
 4413                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4414                                let column = start_point.column;
 4415                                let cursor_is_after_start_tag = {
 4416                                    let start_tag_len = start_tag.len();
 4417                                    let start_tag_line = snapshot
 4418                                        .chars_for_range(range.clone())
 4419                                        .skip(num_of_whitespaces)
 4420                                        .take(start_tag_len)
 4421                                        .collect::<String>();
 4422                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4423                                        num_of_whitespaces + start_tag_len <= column as usize
 4424                                    } else {
 4425                                        false
 4426                                    }
 4427                                };
 4428
 4429                                let cursor_is_after_delimiter = {
 4430                                    let delimiter_trim = delimiter.trim_end();
 4431                                    let delimiter_line = snapshot
 4432                                        .chars_for_range(range.clone())
 4433                                        .skip(num_of_whitespaces)
 4434                                        .take(delimiter_trim.len())
 4435                                        .collect::<String>();
 4436                                    if delimiter_line.starts_with(delimiter_trim) {
 4437                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4438                                    } else {
 4439                                        false
 4440                                    }
 4441                                };
 4442
 4443                                let cursor_is_before_end_tag_if_exists = {
 4444                                    let mut char_position = 0u32;
 4445                                    let mut end_tag_offset = None;
 4446
 4447                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4448                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4449                                            let chars_before_match =
 4450                                                chunk[..byte_pos].chars().count() as u32;
 4451                                            end_tag_offset =
 4452                                                Some(char_position + chars_before_match);
 4453                                            break 'outer;
 4454                                        }
 4455                                        char_position += chunk.chars().count() as u32;
 4456                                    }
 4457
 4458                                    if let Some(end_tag_offset) = end_tag_offset {
 4459                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4460                                        if cursor_is_after_start_tag {
 4461                                            if cursor_is_before_end_tag {
 4462                                                insert_extra_newline = true;
 4463                                            }
 4464                                            let cursor_is_at_start_of_end_tag =
 4465                                                column == end_tag_offset;
 4466                                            if cursor_is_at_start_of_end_tag {
 4467                                                indent_on_extra_newline.len = (*len).into();
 4468                                            }
 4469                                        }
 4470                                        cursor_is_before_end_tag
 4471                                    } else {
 4472                                        true
 4473                                    }
 4474                                };
 4475
 4476                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4477                                    && cursor_is_before_end_tag_if_exists
 4478                                {
 4479                                    if cursor_is_after_start_tag {
 4480                                        indent_on_newline.len = (*len).into();
 4481                                    }
 4482                                    Some(delimiter.clone())
 4483                                } else {
 4484                                    None
 4485                                }
 4486                            });
 4487
 4488                            (
 4489                                comment_delimiter,
 4490                                doc_delimiter,
 4491                                insert_extra_newline,
 4492                                indent_on_newline,
 4493                                indent_on_extra_newline,
 4494                            )
 4495                        } else {
 4496                            (
 4497                                None,
 4498                                None,
 4499                                false,
 4500                                IndentSize::default(),
 4501                                IndentSize::default(),
 4502                            )
 4503                        };
 4504
 4505                        let prevent_auto_indent = doc_delimiter.is_some();
 4506                        let delimiter = comment_delimiter.or(doc_delimiter);
 4507
 4508                        let capacity_for_delimiter =
 4509                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4510                        let mut new_text = String::with_capacity(
 4511                            1 + capacity_for_delimiter
 4512                                + existing_indent.len as usize
 4513                                + indent_on_newline.len as usize
 4514                                + indent_on_extra_newline.len as usize,
 4515                        );
 4516                        new_text.push('\n');
 4517                        new_text.extend(existing_indent.chars());
 4518                        new_text.extend(indent_on_newline.chars());
 4519
 4520                        if let Some(delimiter) = &delimiter {
 4521                            new_text.push_str(delimiter);
 4522                        }
 4523
 4524                        if insert_extra_newline {
 4525                            new_text.push('\n');
 4526                            new_text.extend(existing_indent.chars());
 4527                            new_text.extend(indent_on_extra_newline.chars());
 4528                        }
 4529
 4530                        let anchor = buffer.anchor_after(end);
 4531                        let new_selection = selection.map(|_| anchor);
 4532                        (
 4533                            ((start..end, new_text), prevent_auto_indent),
 4534                            (insert_extra_newline, new_selection),
 4535                        )
 4536                    })
 4537                    .unzip()
 4538            };
 4539
 4540            let mut auto_indent_edits = Vec::new();
 4541            let mut edits = Vec::new();
 4542            for (edit, prevent_auto_indent) in edits_with_flags {
 4543                if prevent_auto_indent {
 4544                    edits.push(edit);
 4545                } else {
 4546                    auto_indent_edits.push(edit);
 4547                }
 4548            }
 4549            if !edits.is_empty() {
 4550                this.edit(edits, cx);
 4551            }
 4552            if !auto_indent_edits.is_empty() {
 4553                this.edit_with_autoindent(auto_indent_edits, cx);
 4554            }
 4555
 4556            let buffer = this.buffer.read(cx).snapshot(cx);
 4557            let new_selections = selection_info
 4558                .into_iter()
 4559                .map(|(extra_newline_inserted, new_selection)| {
 4560                    let mut cursor = new_selection.end.to_point(&buffer);
 4561                    if extra_newline_inserted {
 4562                        cursor.row -= 1;
 4563                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4564                    }
 4565                    new_selection.map(|_| cursor)
 4566                })
 4567                .collect();
 4568
 4569            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4570            this.refresh_inline_completion(true, false, window, cx);
 4571        });
 4572    }
 4573
 4574    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4575        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4576
 4577        let buffer = self.buffer.read(cx);
 4578        let snapshot = buffer.snapshot(cx);
 4579
 4580        let mut edits = Vec::new();
 4581        let mut rows = Vec::new();
 4582
 4583        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4584            let cursor = selection.head();
 4585            let row = cursor.row;
 4586
 4587            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4588
 4589            let newline = "\n".to_string();
 4590            edits.push((start_of_line..start_of_line, newline));
 4591
 4592            rows.push(row + rows_inserted as u32);
 4593        }
 4594
 4595        self.transact(window, cx, |editor, window, cx| {
 4596            editor.edit(edits, cx);
 4597
 4598            editor.change_selections(Default::default(), window, cx, |s| {
 4599                let mut index = 0;
 4600                s.move_cursors_with(|map, _, _| {
 4601                    let row = rows[index];
 4602                    index += 1;
 4603
 4604                    let point = Point::new(row, 0);
 4605                    let boundary = map.next_line_boundary(point).1;
 4606                    let clipped = map.clip_point(boundary, Bias::Left);
 4607
 4608                    (clipped, SelectionGoal::None)
 4609                });
 4610            });
 4611
 4612            let mut indent_edits = Vec::new();
 4613            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4614            for row in rows {
 4615                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4616                for (row, indent) in indents {
 4617                    if indent.len == 0 {
 4618                        continue;
 4619                    }
 4620
 4621                    let text = match indent.kind {
 4622                        IndentKind::Space => " ".repeat(indent.len as usize),
 4623                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4624                    };
 4625                    let point = Point::new(row.0, 0);
 4626                    indent_edits.push((point..point, text));
 4627                }
 4628            }
 4629            editor.edit(indent_edits, cx);
 4630        });
 4631    }
 4632
 4633    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4634        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4635
 4636        let buffer = self.buffer.read(cx);
 4637        let snapshot = buffer.snapshot(cx);
 4638
 4639        let mut edits = Vec::new();
 4640        let mut rows = Vec::new();
 4641        let mut rows_inserted = 0;
 4642
 4643        for selection in self.selections.all_adjusted(cx) {
 4644            let cursor = selection.head();
 4645            let row = cursor.row;
 4646
 4647            let point = Point::new(row + 1, 0);
 4648            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4649
 4650            let newline = "\n".to_string();
 4651            edits.push((start_of_line..start_of_line, newline));
 4652
 4653            rows_inserted += 1;
 4654            rows.push(row + rows_inserted);
 4655        }
 4656
 4657        self.transact(window, cx, |editor, window, cx| {
 4658            editor.edit(edits, cx);
 4659
 4660            editor.change_selections(Default::default(), window, cx, |s| {
 4661                let mut index = 0;
 4662                s.move_cursors_with(|map, _, _| {
 4663                    let row = rows[index];
 4664                    index += 1;
 4665
 4666                    let point = Point::new(row, 0);
 4667                    let boundary = map.next_line_boundary(point).1;
 4668                    let clipped = map.clip_point(boundary, Bias::Left);
 4669
 4670                    (clipped, SelectionGoal::None)
 4671                });
 4672            });
 4673
 4674            let mut indent_edits = Vec::new();
 4675            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4676            for row in rows {
 4677                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4678                for (row, indent) in indents {
 4679                    if indent.len == 0 {
 4680                        continue;
 4681                    }
 4682
 4683                    let text = match indent.kind {
 4684                        IndentKind::Space => " ".repeat(indent.len as usize),
 4685                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4686                    };
 4687                    let point = Point::new(row.0, 0);
 4688                    indent_edits.push((point..point, text));
 4689                }
 4690            }
 4691            editor.edit(indent_edits, cx);
 4692        });
 4693    }
 4694
 4695    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4696        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4697            original_indent_columns: Vec::new(),
 4698        });
 4699        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4700    }
 4701
 4702    fn insert_with_autoindent_mode(
 4703        &mut self,
 4704        text: &str,
 4705        autoindent_mode: Option<AutoindentMode>,
 4706        window: &mut Window,
 4707        cx: &mut Context<Self>,
 4708    ) {
 4709        if self.read_only(cx) {
 4710            return;
 4711        }
 4712
 4713        let text: Arc<str> = text.into();
 4714        self.transact(window, cx, |this, window, cx| {
 4715            let old_selections = this.selections.all_adjusted(cx);
 4716            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4717                let anchors = {
 4718                    let snapshot = buffer.read(cx);
 4719                    old_selections
 4720                        .iter()
 4721                        .map(|s| {
 4722                            let anchor = snapshot.anchor_after(s.head());
 4723                            s.map(|_| anchor)
 4724                        })
 4725                        .collect::<Vec<_>>()
 4726                };
 4727                buffer.edit(
 4728                    old_selections
 4729                        .iter()
 4730                        .map(|s| (s.start..s.end, text.clone())),
 4731                    autoindent_mode,
 4732                    cx,
 4733                );
 4734                anchors
 4735            });
 4736
 4737            this.change_selections(Default::default(), window, cx, |s| {
 4738                s.select_anchors(selection_anchors);
 4739            });
 4740
 4741            cx.notify();
 4742        });
 4743    }
 4744
 4745    fn trigger_completion_on_input(
 4746        &mut self,
 4747        text: &str,
 4748        trigger_in_words: bool,
 4749        window: &mut Window,
 4750        cx: &mut Context<Self>,
 4751    ) {
 4752        let completions_source = self
 4753            .context_menu
 4754            .borrow()
 4755            .as_ref()
 4756            .and_then(|menu| match menu {
 4757                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4758                CodeContextMenu::CodeActions(_) => None,
 4759            });
 4760
 4761        match completions_source {
 4762            Some(CompletionsMenuSource::Words) => {
 4763                self.show_word_completions(&ShowWordCompletions, window, cx)
 4764            }
 4765            Some(CompletionsMenuSource::Normal)
 4766            | Some(CompletionsMenuSource::SnippetChoices)
 4767            | None
 4768                if self.is_completion_trigger(
 4769                    text,
 4770                    trigger_in_words,
 4771                    completions_source.is_some(),
 4772                    cx,
 4773                ) =>
 4774            {
 4775                self.show_completions(
 4776                    &ShowCompletions {
 4777                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4778                    },
 4779                    window,
 4780                    cx,
 4781                )
 4782            }
 4783            _ => {
 4784                self.hide_context_menu(window, cx);
 4785            }
 4786        }
 4787    }
 4788
 4789    fn is_completion_trigger(
 4790        &self,
 4791        text: &str,
 4792        trigger_in_words: bool,
 4793        menu_is_open: bool,
 4794        cx: &mut Context<Self>,
 4795    ) -> bool {
 4796        let position = self.selections.newest_anchor().head();
 4797        let multibuffer = self.buffer.read(cx);
 4798        let Some(buffer) = position
 4799            .buffer_id
 4800            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4801        else {
 4802            return false;
 4803        };
 4804
 4805        if let Some(completion_provider) = &self.completion_provider {
 4806            completion_provider.is_completion_trigger(
 4807                &buffer,
 4808                position.text_anchor,
 4809                text,
 4810                trigger_in_words,
 4811                menu_is_open,
 4812                cx,
 4813            )
 4814        } else {
 4815            false
 4816        }
 4817    }
 4818
 4819    /// If any empty selections is touching the start of its innermost containing autoclose
 4820    /// region, expand it to select the brackets.
 4821    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4822        let selections = self.selections.all::<usize>(cx);
 4823        let buffer = self.buffer.read(cx).read(cx);
 4824        let new_selections = self
 4825            .selections_with_autoclose_regions(selections, &buffer)
 4826            .map(|(mut selection, region)| {
 4827                if !selection.is_empty() {
 4828                    return selection;
 4829                }
 4830
 4831                if let Some(region) = region {
 4832                    let mut range = region.range.to_offset(&buffer);
 4833                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4834                        range.start -= region.pair.start.len();
 4835                        if buffer.contains_str_at(range.start, &region.pair.start)
 4836                            && buffer.contains_str_at(range.end, &region.pair.end)
 4837                        {
 4838                            range.end += region.pair.end.len();
 4839                            selection.start = range.start;
 4840                            selection.end = range.end;
 4841
 4842                            return selection;
 4843                        }
 4844                    }
 4845                }
 4846
 4847                let always_treat_brackets_as_autoclosed = buffer
 4848                    .language_settings_at(selection.start, cx)
 4849                    .always_treat_brackets_as_autoclosed;
 4850
 4851                if !always_treat_brackets_as_autoclosed {
 4852                    return selection;
 4853                }
 4854
 4855                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4856                    for (pair, enabled) in scope.brackets() {
 4857                        if !enabled || !pair.close {
 4858                            continue;
 4859                        }
 4860
 4861                        if buffer.contains_str_at(selection.start, &pair.end) {
 4862                            let pair_start_len = pair.start.len();
 4863                            if buffer.contains_str_at(
 4864                                selection.start.saturating_sub(pair_start_len),
 4865                                &pair.start,
 4866                            ) {
 4867                                selection.start -= pair_start_len;
 4868                                selection.end += pair.end.len();
 4869
 4870                                return selection;
 4871                            }
 4872                        }
 4873                    }
 4874                }
 4875
 4876                selection
 4877            })
 4878            .collect();
 4879
 4880        drop(buffer);
 4881        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4882            selections.select(new_selections)
 4883        });
 4884    }
 4885
 4886    /// Iterate the given selections, and for each one, find the smallest surrounding
 4887    /// autoclose region. This uses the ordering of the selections and the autoclose
 4888    /// regions to avoid repeated comparisons.
 4889    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4890        &'a self,
 4891        selections: impl IntoIterator<Item = Selection<D>>,
 4892        buffer: &'a MultiBufferSnapshot,
 4893    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4894        let mut i = 0;
 4895        let mut regions = self.autoclose_regions.as_slice();
 4896        selections.into_iter().map(move |selection| {
 4897            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4898
 4899            let mut enclosing = None;
 4900            while let Some(pair_state) = regions.get(i) {
 4901                if pair_state.range.end.to_offset(buffer) < range.start {
 4902                    regions = &regions[i + 1..];
 4903                    i = 0;
 4904                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4905                    break;
 4906                } else {
 4907                    if pair_state.selection_id == selection.id {
 4908                        enclosing = Some(pair_state);
 4909                    }
 4910                    i += 1;
 4911                }
 4912            }
 4913
 4914            (selection, enclosing)
 4915        })
 4916    }
 4917
 4918    /// Remove any autoclose regions that no longer contain their selection.
 4919    fn invalidate_autoclose_regions(
 4920        &mut self,
 4921        mut selections: &[Selection<Anchor>],
 4922        buffer: &MultiBufferSnapshot,
 4923    ) {
 4924        self.autoclose_regions.retain(|state| {
 4925            let mut i = 0;
 4926            while let Some(selection) = selections.get(i) {
 4927                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4928                    selections = &selections[1..];
 4929                    continue;
 4930                }
 4931                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4932                    break;
 4933                }
 4934                if selection.id == state.selection_id {
 4935                    return true;
 4936                } else {
 4937                    i += 1;
 4938                }
 4939            }
 4940            false
 4941        });
 4942    }
 4943
 4944    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4945        let offset = position.to_offset(buffer);
 4946        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4947        if offset > word_range.start && kind == Some(CharKind::Word) {
 4948            Some(
 4949                buffer
 4950                    .text_for_range(word_range.start..offset)
 4951                    .collect::<String>(),
 4952            )
 4953        } else {
 4954            None
 4955        }
 4956    }
 4957
 4958    pub fn toggle_inline_values(
 4959        &mut self,
 4960        _: &ToggleInlineValues,
 4961        _: &mut Window,
 4962        cx: &mut Context<Self>,
 4963    ) {
 4964        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4965
 4966        self.refresh_inline_values(cx);
 4967    }
 4968
 4969    pub fn toggle_inlay_hints(
 4970        &mut self,
 4971        _: &ToggleInlayHints,
 4972        _: &mut Window,
 4973        cx: &mut Context<Self>,
 4974    ) {
 4975        self.refresh_inlay_hints(
 4976            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4977            cx,
 4978        );
 4979    }
 4980
 4981    pub fn inlay_hints_enabled(&self) -> bool {
 4982        self.inlay_hint_cache.enabled
 4983    }
 4984
 4985    pub fn inline_values_enabled(&self) -> bool {
 4986        self.inline_value_cache.enabled
 4987    }
 4988
 4989    #[cfg(any(test, feature = "test-support"))]
 4990    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4991        self.display_map
 4992            .read(cx)
 4993            .current_inlays()
 4994            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4995            .cloned()
 4996            .collect()
 4997    }
 4998
 4999    #[cfg(any(test, feature = "test-support"))]
 5000    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5001        self.display_map
 5002            .read(cx)
 5003            .current_inlays()
 5004            .cloned()
 5005            .collect()
 5006    }
 5007
 5008    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5009        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5010            return;
 5011        }
 5012
 5013        let reason_description = reason.description();
 5014        let ignore_debounce = matches!(
 5015            reason,
 5016            InlayHintRefreshReason::SettingsChange(_)
 5017                | InlayHintRefreshReason::Toggle(_)
 5018                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5019                | InlayHintRefreshReason::ModifiersChanged(_)
 5020        );
 5021        let (invalidate_cache, required_languages) = match reason {
 5022            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5023                match self.inlay_hint_cache.modifiers_override(enabled) {
 5024                    Some(enabled) => {
 5025                        if enabled {
 5026                            (InvalidationStrategy::RefreshRequested, None)
 5027                        } else {
 5028                            self.splice_inlays(
 5029                                &self
 5030                                    .visible_inlay_hints(cx)
 5031                                    .iter()
 5032                                    .map(|inlay| inlay.id)
 5033                                    .collect::<Vec<InlayId>>(),
 5034                                Vec::new(),
 5035                                cx,
 5036                            );
 5037                            return;
 5038                        }
 5039                    }
 5040                    None => return,
 5041                }
 5042            }
 5043            InlayHintRefreshReason::Toggle(enabled) => {
 5044                if self.inlay_hint_cache.toggle(enabled) {
 5045                    if enabled {
 5046                        (InvalidationStrategy::RefreshRequested, None)
 5047                    } else {
 5048                        self.splice_inlays(
 5049                            &self
 5050                                .visible_inlay_hints(cx)
 5051                                .iter()
 5052                                .map(|inlay| inlay.id)
 5053                                .collect::<Vec<InlayId>>(),
 5054                            Vec::new(),
 5055                            cx,
 5056                        );
 5057                        return;
 5058                    }
 5059                } else {
 5060                    return;
 5061                }
 5062            }
 5063            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5064                match self.inlay_hint_cache.update_settings(
 5065                    &self.buffer,
 5066                    new_settings,
 5067                    self.visible_inlay_hints(cx),
 5068                    cx,
 5069                ) {
 5070                    ControlFlow::Break(Some(InlaySplice {
 5071                        to_remove,
 5072                        to_insert,
 5073                    })) => {
 5074                        self.splice_inlays(&to_remove, to_insert, cx);
 5075                        return;
 5076                    }
 5077                    ControlFlow::Break(None) => return,
 5078                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5079                }
 5080            }
 5081            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5082                if let Some(InlaySplice {
 5083                    to_remove,
 5084                    to_insert,
 5085                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5086                {
 5087                    self.splice_inlays(&to_remove, to_insert, cx);
 5088                }
 5089                self.display_map.update(cx, |display_map, _| {
 5090                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5091                });
 5092                return;
 5093            }
 5094            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5095            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5096                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5097            }
 5098            InlayHintRefreshReason::RefreshRequested => {
 5099                (InvalidationStrategy::RefreshRequested, None)
 5100            }
 5101        };
 5102
 5103        if let Some(InlaySplice {
 5104            to_remove,
 5105            to_insert,
 5106        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5107            reason_description,
 5108            self.visible_excerpts(required_languages.as_ref(), cx),
 5109            invalidate_cache,
 5110            ignore_debounce,
 5111            cx,
 5112        ) {
 5113            self.splice_inlays(&to_remove, to_insert, cx);
 5114        }
 5115    }
 5116
 5117    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5118        self.display_map
 5119            .read(cx)
 5120            .current_inlays()
 5121            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5122            .cloned()
 5123            .collect()
 5124    }
 5125
 5126    pub fn visible_excerpts(
 5127        &self,
 5128        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5129        cx: &mut Context<Editor>,
 5130    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5131        let Some(project) = self.project.as_ref() else {
 5132            return HashMap::default();
 5133        };
 5134        let project = project.read(cx);
 5135        let multi_buffer = self.buffer().read(cx);
 5136        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5137        let multi_buffer_visible_start = self
 5138            .scroll_manager
 5139            .anchor()
 5140            .anchor
 5141            .to_point(&multi_buffer_snapshot);
 5142        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5143            multi_buffer_visible_start
 5144                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5145            Bias::Left,
 5146        );
 5147        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5148        multi_buffer_snapshot
 5149            .range_to_buffer_ranges(multi_buffer_visible_range)
 5150            .into_iter()
 5151            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5152            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5153                let buffer_file = project::File::from_dyn(buffer.file())?;
 5154                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5155                let worktree_entry = buffer_worktree
 5156                    .read(cx)
 5157                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5158                if worktree_entry.is_ignored {
 5159                    return None;
 5160                }
 5161
 5162                let language = buffer.language()?;
 5163                if let Some(restrict_to_languages) = restrict_to_languages {
 5164                    if !restrict_to_languages.contains(language) {
 5165                        return None;
 5166                    }
 5167                }
 5168                Some((
 5169                    excerpt_id,
 5170                    (
 5171                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5172                        buffer.version().clone(),
 5173                        excerpt_visible_range,
 5174                    ),
 5175                ))
 5176            })
 5177            .collect()
 5178    }
 5179
 5180    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5181        TextLayoutDetails {
 5182            text_system: window.text_system().clone(),
 5183            editor_style: self.style.clone().unwrap(),
 5184            rem_size: window.rem_size(),
 5185            scroll_anchor: self.scroll_manager.anchor(),
 5186            visible_rows: self.visible_line_count(),
 5187            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5188        }
 5189    }
 5190
 5191    pub fn splice_inlays(
 5192        &self,
 5193        to_remove: &[InlayId],
 5194        to_insert: Vec<Inlay>,
 5195        cx: &mut Context<Self>,
 5196    ) {
 5197        self.display_map.update(cx, |display_map, cx| {
 5198            display_map.splice_inlays(to_remove, to_insert, cx)
 5199        });
 5200        cx.notify();
 5201    }
 5202
 5203    fn trigger_on_type_formatting(
 5204        &self,
 5205        input: String,
 5206        window: &mut Window,
 5207        cx: &mut Context<Self>,
 5208    ) -> Option<Task<Result<()>>> {
 5209        if input.len() != 1 {
 5210            return None;
 5211        }
 5212
 5213        let project = self.project.as_ref()?;
 5214        let position = self.selections.newest_anchor().head();
 5215        let (buffer, buffer_position) = self
 5216            .buffer
 5217            .read(cx)
 5218            .text_anchor_for_position(position, cx)?;
 5219
 5220        let settings = language_settings::language_settings(
 5221            buffer
 5222                .read(cx)
 5223                .language_at(buffer_position)
 5224                .map(|l| l.name()),
 5225            buffer.read(cx).file(),
 5226            cx,
 5227        );
 5228        if !settings.use_on_type_format {
 5229            return None;
 5230        }
 5231
 5232        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5233        // hence we do LSP request & edit on host side only — add formats to host's history.
 5234        let push_to_lsp_host_history = true;
 5235        // If this is not the host, append its history with new edits.
 5236        let push_to_client_history = project.read(cx).is_via_collab();
 5237
 5238        let on_type_formatting = project.update(cx, |project, cx| {
 5239            project.on_type_format(
 5240                buffer.clone(),
 5241                buffer_position,
 5242                input,
 5243                push_to_lsp_host_history,
 5244                cx,
 5245            )
 5246        });
 5247        Some(cx.spawn_in(window, async move |editor, cx| {
 5248            if let Some(transaction) = on_type_formatting.await? {
 5249                if push_to_client_history {
 5250                    buffer
 5251                        .update(cx, |buffer, _| {
 5252                            buffer.push_transaction(transaction, Instant::now());
 5253                            buffer.finalize_last_transaction();
 5254                        })
 5255                        .ok();
 5256                }
 5257                editor.update(cx, |editor, cx| {
 5258                    editor.refresh_document_highlights(cx);
 5259                })?;
 5260            }
 5261            Ok(())
 5262        }))
 5263    }
 5264
 5265    pub fn show_word_completions(
 5266        &mut self,
 5267        _: &ShowWordCompletions,
 5268        window: &mut Window,
 5269        cx: &mut Context<Self>,
 5270    ) {
 5271        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5272    }
 5273
 5274    pub fn show_completions(
 5275        &mut self,
 5276        options: &ShowCompletions,
 5277        window: &mut Window,
 5278        cx: &mut Context<Self>,
 5279    ) {
 5280        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5281    }
 5282
 5283    fn open_or_update_completions_menu(
 5284        &mut self,
 5285        requested_source: Option<CompletionsMenuSource>,
 5286        trigger: Option<&str>,
 5287        window: &mut Window,
 5288        cx: &mut Context<Self>,
 5289    ) {
 5290        if self.pending_rename.is_some() {
 5291            return;
 5292        }
 5293
 5294        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5295
 5296        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5297        // inserted and selected. To handle that case, the start of the selection is used so that
 5298        // the menu starts with all choices.
 5299        let position = self
 5300            .selections
 5301            .newest_anchor()
 5302            .start
 5303            .bias_right(&multibuffer_snapshot);
 5304        if position.diff_base_anchor.is_some() {
 5305            return;
 5306        }
 5307        let (buffer, buffer_position) =
 5308            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5309                output
 5310            } else {
 5311                return;
 5312            };
 5313        let buffer_snapshot = buffer.read(cx).snapshot();
 5314
 5315        let query: Option<Arc<String>> =
 5316            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5317
 5318        drop(multibuffer_snapshot);
 5319
 5320        let provider = match requested_source {
 5321            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5322            Some(CompletionsMenuSource::Words) => None,
 5323            Some(CompletionsMenuSource::SnippetChoices) => {
 5324                log::error!("bug: SnippetChoices requested_source is not handled");
 5325                None
 5326            }
 5327        };
 5328
 5329        let sort_completions = provider
 5330            .as_ref()
 5331            .map_or(false, |provider| provider.sort_completions());
 5332
 5333        let filter_completions = provider
 5334            .as_ref()
 5335            .map_or(true, |provider| provider.filter_completions());
 5336
 5337        let trigger_kind = match trigger {
 5338            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5339                CompletionTriggerKind::TRIGGER_CHARACTER
 5340            }
 5341            _ => CompletionTriggerKind::INVOKED,
 5342        };
 5343        let completion_context = CompletionContext {
 5344            trigger_character: trigger.and_then(|trigger| {
 5345                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5346                    Some(String::from(trigger))
 5347                } else {
 5348                    None
 5349                }
 5350            }),
 5351            trigger_kind,
 5352        };
 5353
 5354        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5355        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5356        // involve trigger chars, so this is skipped in that case.
 5357        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5358        {
 5359            let menu_is_open = matches!(
 5360                self.context_menu.borrow().as_ref(),
 5361                Some(CodeContextMenu::Completions(_))
 5362            );
 5363            if menu_is_open {
 5364                self.hide_context_menu(window, cx);
 5365            }
 5366        }
 5367
 5368        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5369            if filter_completions {
 5370                menu.filter(query.clone(), provider.clone(), window, cx);
 5371            }
 5372            // When `is_incomplete` is false, no need to re-query completions when the current query
 5373            // is a suffix of the initial query.
 5374            if !menu.is_incomplete {
 5375                // If the new query is a suffix of the old query (typing more characters) and
 5376                // the previous result was complete, the existing completions can be filtered.
 5377                //
 5378                // Note that this is always true for snippet completions.
 5379                let query_matches = match (&menu.initial_query, &query) {
 5380                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5381                    (None, _) => true,
 5382                    _ => false,
 5383                };
 5384                if query_matches {
 5385                    let position_matches = if menu.initial_position == position {
 5386                        true
 5387                    } else {
 5388                        let snapshot = self.buffer.read(cx).read(cx);
 5389                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5390                    };
 5391                    if position_matches {
 5392                        return;
 5393                    }
 5394                }
 5395            }
 5396        };
 5397
 5398        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5399            buffer_snapshot.surrounding_word(buffer_position)
 5400        {
 5401            let word_to_exclude = buffer_snapshot
 5402                .text_for_range(word_range.clone())
 5403                .collect::<String>();
 5404            (
 5405                buffer_snapshot.anchor_before(word_range.start)
 5406                    ..buffer_snapshot.anchor_after(buffer_position),
 5407                Some(word_to_exclude),
 5408            )
 5409        } else {
 5410            (buffer_position..buffer_position, None)
 5411        };
 5412
 5413        let language = buffer_snapshot
 5414            .language_at(buffer_position)
 5415            .map(|language| language.name());
 5416
 5417        let completion_settings =
 5418            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5419
 5420        let show_completion_documentation = buffer_snapshot
 5421            .settings_at(buffer_position, cx)
 5422            .show_completion_documentation;
 5423
 5424        // The document can be large, so stay in reasonable bounds when searching for words,
 5425        // otherwise completion pop-up might be slow to appear.
 5426        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5427        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5428        let min_word_search = buffer_snapshot.clip_point(
 5429            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5430            Bias::Left,
 5431        );
 5432        let max_word_search = buffer_snapshot.clip_point(
 5433            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5434            Bias::Right,
 5435        );
 5436        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5437            ..buffer_snapshot.point_to_offset(max_word_search);
 5438
 5439        let skip_digits = query
 5440            .as_ref()
 5441            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5442
 5443        let (mut words, provider_responses) = match &provider {
 5444            Some(provider) => {
 5445                let provider_responses = provider.completions(
 5446                    position.excerpt_id,
 5447                    &buffer,
 5448                    buffer_position,
 5449                    completion_context,
 5450                    window,
 5451                    cx,
 5452                );
 5453
 5454                let words = match completion_settings.words {
 5455                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5456                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5457                        .background_spawn(async move {
 5458                            buffer_snapshot.words_in_range(WordsQuery {
 5459                                fuzzy_contents: None,
 5460                                range: word_search_range,
 5461                                skip_digits,
 5462                            })
 5463                        }),
 5464                };
 5465
 5466                (words, provider_responses)
 5467            }
 5468            None => (
 5469                cx.background_spawn(async move {
 5470                    buffer_snapshot.words_in_range(WordsQuery {
 5471                        fuzzy_contents: None,
 5472                        range: word_search_range,
 5473                        skip_digits,
 5474                    })
 5475                }),
 5476                Task::ready(Ok(Vec::new())),
 5477            ),
 5478        };
 5479
 5480        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5481
 5482        let id = post_inc(&mut self.next_completion_id);
 5483        let task = cx.spawn_in(window, async move |editor, cx| {
 5484            let Ok(()) = editor.update(cx, |this, _| {
 5485                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5486            }) else {
 5487                return;
 5488            };
 5489
 5490            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5491            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5492            let mut completions = Vec::new();
 5493            let mut is_incomplete = false;
 5494            if let Some(provider_responses) = provider_responses.await.log_err() {
 5495                if !provider_responses.is_empty() {
 5496                    for response in provider_responses {
 5497                        completions.extend(response.completions);
 5498                        is_incomplete = is_incomplete || response.is_incomplete;
 5499                    }
 5500                    if completion_settings.words == WordsCompletionMode::Fallback {
 5501                        words = Task::ready(BTreeMap::default());
 5502                    }
 5503                }
 5504            }
 5505
 5506            let mut words = words.await;
 5507            if let Some(word_to_exclude) = &word_to_exclude {
 5508                words.remove(word_to_exclude);
 5509            }
 5510            for lsp_completion in &completions {
 5511                words.remove(&lsp_completion.new_text);
 5512            }
 5513            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5514                replace_range: word_replace_range.clone(),
 5515                new_text: word.clone(),
 5516                label: CodeLabel::plain(word, None),
 5517                icon_path: None,
 5518                documentation: None,
 5519                source: CompletionSource::BufferWord {
 5520                    word_range,
 5521                    resolved: false,
 5522                },
 5523                insert_text_mode: Some(InsertTextMode::AS_IS),
 5524                confirm: None,
 5525            }));
 5526
 5527            let menu = if completions.is_empty() {
 5528                None
 5529            } else {
 5530                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5531                    let languages = editor
 5532                        .workspace
 5533                        .as_ref()
 5534                        .and_then(|(workspace, _)| workspace.upgrade())
 5535                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5536                    let menu = CompletionsMenu::new(
 5537                        id,
 5538                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5539                        sort_completions,
 5540                        show_completion_documentation,
 5541                        position,
 5542                        query.clone(),
 5543                        is_incomplete,
 5544                        buffer.clone(),
 5545                        completions.into(),
 5546                        snippet_sort_order,
 5547                        languages,
 5548                        language,
 5549                        cx,
 5550                    );
 5551
 5552                    let query = if filter_completions { query } else { None };
 5553                    let matches_task = if let Some(query) = query {
 5554                        menu.do_async_filtering(query, cx)
 5555                    } else {
 5556                        Task::ready(menu.unfiltered_matches())
 5557                    };
 5558                    (menu, matches_task)
 5559                }) else {
 5560                    return;
 5561                };
 5562
 5563                let matches = matches_task.await;
 5564
 5565                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5566                    // Newer menu already set, so exit.
 5567                    match editor.context_menu.borrow().as_ref() {
 5568                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5569                            if prev_menu.id > id {
 5570                                return;
 5571                            }
 5572                        }
 5573                        _ => {}
 5574                    };
 5575
 5576                    // Only valid to take prev_menu because it the new menu is immediately set
 5577                    // below, or the menu is hidden.
 5578                    match editor.context_menu.borrow_mut().take() {
 5579                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5580                            let position_matches =
 5581                                if prev_menu.initial_position == menu.initial_position {
 5582                                    true
 5583                                } else {
 5584                                    let snapshot = editor.buffer.read(cx).read(cx);
 5585                                    prev_menu.initial_position.to_offset(&snapshot)
 5586                                        == menu.initial_position.to_offset(&snapshot)
 5587                                };
 5588                            if position_matches {
 5589                                // Preserve markdown cache before `set_filter_results` because it will
 5590                                // try to populate the documentation cache.
 5591                                menu.preserve_markdown_cache(prev_menu);
 5592                            }
 5593                        }
 5594                        _ => {}
 5595                    };
 5596
 5597                    menu.set_filter_results(matches, provider, window, cx);
 5598                }) else {
 5599                    return;
 5600                };
 5601
 5602                menu.visible().then_some(menu)
 5603            };
 5604
 5605            editor
 5606                .update_in(cx, |editor, window, cx| {
 5607                    if editor.focus_handle.is_focused(window) {
 5608                        if let Some(menu) = menu {
 5609                            *editor.context_menu.borrow_mut() =
 5610                                Some(CodeContextMenu::Completions(menu));
 5611
 5612                            crate::hover_popover::hide_hover(editor, cx);
 5613                            if editor.show_edit_predictions_in_menu() {
 5614                                editor.update_visible_inline_completion(window, cx);
 5615                            } else {
 5616                                editor.discard_inline_completion(false, cx);
 5617                            }
 5618
 5619                            cx.notify();
 5620                            return;
 5621                        }
 5622                    }
 5623
 5624                    if editor.completion_tasks.len() <= 1 {
 5625                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5626                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5627                        // If it was already hidden and we don't show inline completions in the menu, we should
 5628                        // also show the inline-completion when available.
 5629                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5630                            editor.update_visible_inline_completion(window, cx);
 5631                        }
 5632                    }
 5633                })
 5634                .ok();
 5635        });
 5636
 5637        self.completion_tasks.push((id, task));
 5638    }
 5639
 5640    #[cfg(feature = "test-support")]
 5641    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5642        let menu = self.context_menu.borrow();
 5643        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5644            let completions = menu.completions.borrow();
 5645            Some(completions.to_vec())
 5646        } else {
 5647            None
 5648        }
 5649    }
 5650
 5651    pub fn with_completions_menu_matching_id<R>(
 5652        &self,
 5653        id: CompletionId,
 5654        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5655    ) -> R {
 5656        let mut context_menu = self.context_menu.borrow_mut();
 5657        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5658            return f(None);
 5659        };
 5660        if completions_menu.id != id {
 5661            return f(None);
 5662        }
 5663        f(Some(completions_menu))
 5664    }
 5665
 5666    pub fn confirm_completion(
 5667        &mut self,
 5668        action: &ConfirmCompletion,
 5669        window: &mut Window,
 5670        cx: &mut Context<Self>,
 5671    ) -> Option<Task<Result<()>>> {
 5672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5673        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5674    }
 5675
 5676    pub fn confirm_completion_insert(
 5677        &mut self,
 5678        _: &ConfirmCompletionInsert,
 5679        window: &mut Window,
 5680        cx: &mut Context<Self>,
 5681    ) -> Option<Task<Result<()>>> {
 5682        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5683        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5684    }
 5685
 5686    pub fn confirm_completion_replace(
 5687        &mut self,
 5688        _: &ConfirmCompletionReplace,
 5689        window: &mut Window,
 5690        cx: &mut Context<Self>,
 5691    ) -> Option<Task<Result<()>>> {
 5692        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5693        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5694    }
 5695
 5696    pub fn compose_completion(
 5697        &mut self,
 5698        action: &ComposeCompletion,
 5699        window: &mut Window,
 5700        cx: &mut Context<Self>,
 5701    ) -> Option<Task<Result<()>>> {
 5702        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5703        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5704    }
 5705
 5706    fn do_completion(
 5707        &mut self,
 5708        item_ix: Option<usize>,
 5709        intent: CompletionIntent,
 5710        window: &mut Window,
 5711        cx: &mut Context<Editor>,
 5712    ) -> Option<Task<Result<()>>> {
 5713        use language::ToOffset as _;
 5714
 5715        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5716        else {
 5717            return None;
 5718        };
 5719
 5720        let candidate_id = {
 5721            let entries = completions_menu.entries.borrow();
 5722            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5723            if self.show_edit_predictions_in_menu() {
 5724                self.discard_inline_completion(true, cx);
 5725            }
 5726            mat.candidate_id
 5727        };
 5728
 5729        let completion = completions_menu
 5730            .completions
 5731            .borrow()
 5732            .get(candidate_id)?
 5733            .clone();
 5734        cx.stop_propagation();
 5735
 5736        let buffer_handle = completions_menu.buffer.clone();
 5737
 5738        let CompletionEdit {
 5739            new_text,
 5740            snippet,
 5741            replace_range,
 5742        } = process_completion_for_edit(
 5743            &completion,
 5744            intent,
 5745            &buffer_handle,
 5746            &completions_menu.initial_position.text_anchor,
 5747            cx,
 5748        );
 5749
 5750        let buffer = buffer_handle.read(cx);
 5751        let snapshot = self.buffer.read(cx).snapshot(cx);
 5752        let newest_anchor = self.selections.newest_anchor();
 5753        let replace_range_multibuffer = {
 5754            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5755            let multibuffer_anchor = snapshot
 5756                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5757                .unwrap()
 5758                ..snapshot
 5759                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5760                    .unwrap();
 5761            multibuffer_anchor.start.to_offset(&snapshot)
 5762                ..multibuffer_anchor.end.to_offset(&snapshot)
 5763        };
 5764        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5765            return None;
 5766        }
 5767
 5768        let old_text = buffer
 5769            .text_for_range(replace_range.clone())
 5770            .collect::<String>();
 5771        let lookbehind = newest_anchor
 5772            .start
 5773            .text_anchor
 5774            .to_offset(buffer)
 5775            .saturating_sub(replace_range.start);
 5776        let lookahead = replace_range
 5777            .end
 5778            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5779        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5780        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5781
 5782        let selections = self.selections.all::<usize>(cx);
 5783        let mut ranges = Vec::new();
 5784        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5785
 5786        for selection in &selections {
 5787            let range = if selection.id == newest_anchor.id {
 5788                replace_range_multibuffer.clone()
 5789            } else {
 5790                let mut range = selection.range();
 5791
 5792                // if prefix is present, don't duplicate it
 5793                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5794                    range.start = range.start.saturating_sub(lookbehind);
 5795
 5796                    // if suffix is also present, mimic the newest cursor and replace it
 5797                    if selection.id != newest_anchor.id
 5798                        && snapshot.contains_str_at(range.end, suffix)
 5799                    {
 5800                        range.end += lookahead;
 5801                    }
 5802                }
 5803                range
 5804            };
 5805
 5806            ranges.push(range.clone());
 5807
 5808            if !self.linked_edit_ranges.is_empty() {
 5809                let start_anchor = snapshot.anchor_before(range.start);
 5810                let end_anchor = snapshot.anchor_after(range.end);
 5811                if let Some(ranges) = self
 5812                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5813                {
 5814                    for (buffer, edits) in ranges {
 5815                        linked_edits
 5816                            .entry(buffer.clone())
 5817                            .or_default()
 5818                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5819                    }
 5820                }
 5821            }
 5822        }
 5823
 5824        let common_prefix_len = old_text
 5825            .chars()
 5826            .zip(new_text.chars())
 5827            .take_while(|(a, b)| a == b)
 5828            .map(|(a, _)| a.len_utf8())
 5829            .sum::<usize>();
 5830
 5831        cx.emit(EditorEvent::InputHandled {
 5832            utf16_range_to_replace: None,
 5833            text: new_text[common_prefix_len..].into(),
 5834        });
 5835
 5836        self.transact(window, cx, |this, window, cx| {
 5837            if let Some(mut snippet) = snippet {
 5838                snippet.text = new_text.to_string();
 5839                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5840            } else {
 5841                this.buffer.update(cx, |buffer, cx| {
 5842                    let auto_indent = match completion.insert_text_mode {
 5843                        Some(InsertTextMode::AS_IS) => None,
 5844                        _ => this.autoindent_mode.clone(),
 5845                    };
 5846                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5847                    buffer.edit(edits, auto_indent, cx);
 5848                });
 5849            }
 5850            for (buffer, edits) in linked_edits {
 5851                buffer.update(cx, |buffer, cx| {
 5852                    let snapshot = buffer.snapshot();
 5853                    let edits = edits
 5854                        .into_iter()
 5855                        .map(|(range, text)| {
 5856                            use text::ToPoint as TP;
 5857                            let end_point = TP::to_point(&range.end, &snapshot);
 5858                            let start_point = TP::to_point(&range.start, &snapshot);
 5859                            (start_point..end_point, text)
 5860                        })
 5861                        .sorted_by_key(|(range, _)| range.start);
 5862                    buffer.edit(edits, None, cx);
 5863                })
 5864            }
 5865
 5866            this.refresh_inline_completion(true, false, window, cx);
 5867        });
 5868
 5869        let show_new_completions_on_confirm = completion
 5870            .confirm
 5871            .as_ref()
 5872            .map_or(false, |confirm| confirm(intent, window, cx));
 5873        if show_new_completions_on_confirm {
 5874            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5875        }
 5876
 5877        let provider = self.completion_provider.as_ref()?;
 5878        drop(completion);
 5879        let apply_edits = provider.apply_additional_edits_for_completion(
 5880            buffer_handle,
 5881            completions_menu.completions.clone(),
 5882            candidate_id,
 5883            true,
 5884            cx,
 5885        );
 5886
 5887        let editor_settings = EditorSettings::get_global(cx);
 5888        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5889            // After the code completion is finished, users often want to know what signatures are needed.
 5890            // so we should automatically call signature_help
 5891            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5892        }
 5893
 5894        Some(cx.foreground_executor().spawn(async move {
 5895            apply_edits.await?;
 5896            Ok(())
 5897        }))
 5898    }
 5899
 5900    pub fn toggle_code_actions(
 5901        &mut self,
 5902        action: &ToggleCodeActions,
 5903        window: &mut Window,
 5904        cx: &mut Context<Self>,
 5905    ) {
 5906        let quick_launch = action.quick_launch;
 5907        let mut context_menu = self.context_menu.borrow_mut();
 5908        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5909            if code_actions.deployed_from == action.deployed_from {
 5910                // Toggle if we're selecting the same one
 5911                *context_menu = None;
 5912                cx.notify();
 5913                return;
 5914            } else {
 5915                // Otherwise, clear it and start a new one
 5916                *context_menu = None;
 5917                cx.notify();
 5918            }
 5919        }
 5920        drop(context_menu);
 5921        let snapshot = self.snapshot(window, cx);
 5922        let deployed_from = action.deployed_from.clone();
 5923        let action = action.clone();
 5924        self.completion_tasks.clear();
 5925        self.discard_inline_completion(false, cx);
 5926
 5927        let multibuffer_point = match &action.deployed_from {
 5928            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5929                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5930            }
 5931            _ => self.selections.newest::<Point>(cx).head(),
 5932        };
 5933        let Some((buffer, buffer_row)) = snapshot
 5934            .buffer_snapshot
 5935            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5936            .and_then(|(buffer_snapshot, range)| {
 5937                self.buffer()
 5938                    .read(cx)
 5939                    .buffer(buffer_snapshot.remote_id())
 5940                    .map(|buffer| (buffer, range.start.row))
 5941            })
 5942        else {
 5943            return;
 5944        };
 5945        let buffer_id = buffer.read(cx).remote_id();
 5946        let tasks = self
 5947            .tasks
 5948            .get(&(buffer_id, buffer_row))
 5949            .map(|t| Arc::new(t.to_owned()));
 5950
 5951        if !self.focus_handle.is_focused(window) {
 5952            return;
 5953        }
 5954        let project = self.project.clone();
 5955
 5956        let code_actions_task = match deployed_from {
 5957            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5958            _ => self.code_actions(buffer_row, window, cx),
 5959        };
 5960
 5961        let runnable_task = match deployed_from {
 5962            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5963            _ => {
 5964                let mut task_context_task = Task::ready(None);
 5965                if let Some(tasks) = &tasks {
 5966                    if let Some(project) = project {
 5967                        task_context_task =
 5968                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5969                    }
 5970                }
 5971
 5972                cx.spawn_in(window, {
 5973                    let buffer = buffer.clone();
 5974                    async move |editor, cx| {
 5975                        let task_context = task_context_task.await;
 5976
 5977                        let resolved_tasks =
 5978                            tasks
 5979                                .zip(task_context.clone())
 5980                                .map(|(tasks, task_context)| ResolvedTasks {
 5981                                    templates: tasks.resolve(&task_context).collect(),
 5982                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5983                                        multibuffer_point.row,
 5984                                        tasks.column,
 5985                                    )),
 5986                                });
 5987                        let debug_scenarios = editor
 5988                            .update(cx, |editor, cx| {
 5989                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5990                            })?
 5991                            .await;
 5992                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5993                    }
 5994                })
 5995            }
 5996        };
 5997
 5998        cx.spawn_in(window, async move |editor, cx| {
 5999            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6000            let code_actions = code_actions_task.await;
 6001            let spawn_straight_away = quick_launch
 6002                && resolved_tasks
 6003                    .as_ref()
 6004                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6005                && code_actions
 6006                    .as_ref()
 6007                    .map_or(true, |actions| actions.is_empty())
 6008                && debug_scenarios.is_empty();
 6009
 6010            editor.update_in(cx, |editor, window, cx| {
 6011                crate::hover_popover::hide_hover(editor, cx);
 6012                let actions = CodeActionContents::new(
 6013                    resolved_tasks,
 6014                    code_actions,
 6015                    debug_scenarios,
 6016                    task_context.unwrap_or_default(),
 6017                );
 6018
 6019                // Don't show the menu if there are no actions available
 6020                if actions.is_empty() {
 6021                    cx.notify();
 6022                    return Task::ready(Ok(()));
 6023                }
 6024
 6025                *editor.context_menu.borrow_mut() =
 6026                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6027                        buffer,
 6028                        actions,
 6029                        selected_item: Default::default(),
 6030                        scroll_handle: UniformListScrollHandle::default(),
 6031                        deployed_from,
 6032                    }));
 6033                cx.notify();
 6034                if spawn_straight_away {
 6035                    if let Some(task) = editor.confirm_code_action(
 6036                        &ConfirmCodeAction { item_ix: Some(0) },
 6037                        window,
 6038                        cx,
 6039                    ) {
 6040                        return task;
 6041                    }
 6042                }
 6043
 6044                Task::ready(Ok(()))
 6045            })
 6046        })
 6047        .detach_and_log_err(cx);
 6048    }
 6049
 6050    fn debug_scenarios(
 6051        &mut self,
 6052        resolved_tasks: &Option<ResolvedTasks>,
 6053        buffer: &Entity<Buffer>,
 6054        cx: &mut App,
 6055    ) -> Task<Vec<task::DebugScenario>> {
 6056        maybe!({
 6057            let project = self.project.as_ref()?;
 6058            let dap_store = project.read(cx).dap_store();
 6059            let mut scenarios = vec![];
 6060            let resolved_tasks = resolved_tasks.as_ref()?;
 6061            let buffer = buffer.read(cx);
 6062            let language = buffer.language()?;
 6063            let file = buffer.file();
 6064            let debug_adapter = language_settings(language.name().into(), file, cx)
 6065                .debuggers
 6066                .first()
 6067                .map(SharedString::from)
 6068                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6069
 6070            dap_store.update(cx, |dap_store, cx| {
 6071                for (_, task) in &resolved_tasks.templates {
 6072                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6073                        task.original_task().clone(),
 6074                        debug_adapter.clone().into(),
 6075                        task.display_label().to_owned().into(),
 6076                        cx,
 6077                    );
 6078                    scenarios.push(maybe_scenario);
 6079                }
 6080            });
 6081            Some(cx.background_spawn(async move {
 6082                let scenarios = futures::future::join_all(scenarios)
 6083                    .await
 6084                    .into_iter()
 6085                    .flatten()
 6086                    .collect::<Vec<_>>();
 6087                scenarios
 6088            }))
 6089        })
 6090        .unwrap_or_else(|| Task::ready(vec![]))
 6091    }
 6092
 6093    fn code_actions(
 6094        &mut self,
 6095        buffer_row: u32,
 6096        window: &mut Window,
 6097        cx: &mut Context<Self>,
 6098    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6099        let mut task = self.code_actions_task.take();
 6100        cx.spawn_in(window, async move |editor, cx| {
 6101            while let Some(prev_task) = task {
 6102                prev_task.await.log_err();
 6103                task = editor
 6104                    .update(cx, |this, _| this.code_actions_task.take())
 6105                    .ok()?;
 6106            }
 6107
 6108            editor
 6109                .update(cx, |editor, cx| {
 6110                    editor
 6111                        .available_code_actions
 6112                        .clone()
 6113                        .and_then(|(location, code_actions)| {
 6114                            let snapshot = location.buffer.read(cx).snapshot();
 6115                            let point_range = location.range.to_point(&snapshot);
 6116                            let point_range = point_range.start.row..=point_range.end.row;
 6117                            if point_range.contains(&buffer_row) {
 6118                                Some(code_actions)
 6119                            } else {
 6120                                None
 6121                            }
 6122                        })
 6123                })
 6124                .ok()
 6125                .flatten()
 6126        })
 6127    }
 6128
 6129    pub fn confirm_code_action(
 6130        &mut self,
 6131        action: &ConfirmCodeAction,
 6132        window: &mut Window,
 6133        cx: &mut Context<Self>,
 6134    ) -> Option<Task<Result<()>>> {
 6135        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6136
 6137        let actions_menu =
 6138            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6139                menu
 6140            } else {
 6141                return None;
 6142            };
 6143
 6144        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6145        let action = actions_menu.actions.get(action_ix)?;
 6146        let title = action.label();
 6147        let buffer = actions_menu.buffer;
 6148        let workspace = self.workspace()?;
 6149
 6150        match action {
 6151            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6152                workspace.update(cx, |workspace, cx| {
 6153                    workspace.schedule_resolved_task(
 6154                        task_source_kind,
 6155                        resolved_task,
 6156                        false,
 6157                        window,
 6158                        cx,
 6159                    );
 6160
 6161                    Some(Task::ready(Ok(())))
 6162                })
 6163            }
 6164            CodeActionsItem::CodeAction {
 6165                excerpt_id,
 6166                action,
 6167                provider,
 6168            } => {
 6169                let apply_code_action =
 6170                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6171                let workspace = workspace.downgrade();
 6172                Some(cx.spawn_in(window, async move |editor, cx| {
 6173                    let project_transaction = apply_code_action.await?;
 6174                    Self::open_project_transaction(
 6175                        &editor,
 6176                        workspace,
 6177                        project_transaction,
 6178                        title,
 6179                        cx,
 6180                    )
 6181                    .await
 6182                }))
 6183            }
 6184            CodeActionsItem::DebugScenario(scenario) => {
 6185                let context = actions_menu.actions.context.clone();
 6186
 6187                workspace.update(cx, |workspace, cx| {
 6188                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6189                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6190                });
 6191                Some(Task::ready(Ok(())))
 6192            }
 6193        }
 6194    }
 6195
 6196    pub async fn open_project_transaction(
 6197        this: &WeakEntity<Editor>,
 6198        workspace: WeakEntity<Workspace>,
 6199        transaction: ProjectTransaction,
 6200        title: String,
 6201        cx: &mut AsyncWindowContext,
 6202    ) -> Result<()> {
 6203        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6204        cx.update(|_, cx| {
 6205            entries.sort_unstable_by_key(|(buffer, _)| {
 6206                buffer.read(cx).file().map(|f| f.path().clone())
 6207            });
 6208        })?;
 6209
 6210        // If the project transaction's edits are all contained within this editor, then
 6211        // avoid opening a new editor to display them.
 6212
 6213        if let Some((buffer, transaction)) = entries.first() {
 6214            if entries.len() == 1 {
 6215                let excerpt = this.update(cx, |editor, cx| {
 6216                    editor
 6217                        .buffer()
 6218                        .read(cx)
 6219                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6220                })?;
 6221                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6222                    if excerpted_buffer == *buffer {
 6223                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6224                            let excerpt_range = excerpt_range.to_offset(buffer);
 6225                            buffer
 6226                                .edited_ranges_for_transaction::<usize>(transaction)
 6227                                .all(|range| {
 6228                                    excerpt_range.start <= range.start
 6229                                        && excerpt_range.end >= range.end
 6230                                })
 6231                        })?;
 6232
 6233                        if all_edits_within_excerpt {
 6234                            return Ok(());
 6235                        }
 6236                    }
 6237                }
 6238            }
 6239        } else {
 6240            return Ok(());
 6241        }
 6242
 6243        let mut ranges_to_highlight = Vec::new();
 6244        let excerpt_buffer = cx.new(|cx| {
 6245            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6246            for (buffer_handle, transaction) in &entries {
 6247                let edited_ranges = buffer_handle
 6248                    .read(cx)
 6249                    .edited_ranges_for_transaction::<Point>(transaction)
 6250                    .collect::<Vec<_>>();
 6251                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6252                    PathKey::for_buffer(buffer_handle, cx),
 6253                    buffer_handle.clone(),
 6254                    edited_ranges,
 6255                    DEFAULT_MULTIBUFFER_CONTEXT,
 6256                    cx,
 6257                );
 6258
 6259                ranges_to_highlight.extend(ranges);
 6260            }
 6261            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6262            multibuffer
 6263        })?;
 6264
 6265        workspace.update_in(cx, |workspace, window, cx| {
 6266            let project = workspace.project().clone();
 6267            let editor =
 6268                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6269            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6270            editor.update(cx, |editor, cx| {
 6271                editor.highlight_background::<Self>(
 6272                    &ranges_to_highlight,
 6273                    |theme| theme.colors().editor_highlighted_line_background,
 6274                    cx,
 6275                );
 6276            });
 6277        })?;
 6278
 6279        Ok(())
 6280    }
 6281
 6282    pub fn clear_code_action_providers(&mut self) {
 6283        self.code_action_providers.clear();
 6284        self.available_code_actions.take();
 6285    }
 6286
 6287    pub fn add_code_action_provider(
 6288        &mut self,
 6289        provider: Rc<dyn CodeActionProvider>,
 6290        window: &mut Window,
 6291        cx: &mut Context<Self>,
 6292    ) {
 6293        if self
 6294            .code_action_providers
 6295            .iter()
 6296            .any(|existing_provider| existing_provider.id() == provider.id())
 6297        {
 6298            return;
 6299        }
 6300
 6301        self.code_action_providers.push(provider);
 6302        self.refresh_code_actions(window, cx);
 6303    }
 6304
 6305    pub fn remove_code_action_provider(
 6306        &mut self,
 6307        id: Arc<str>,
 6308        window: &mut Window,
 6309        cx: &mut Context<Self>,
 6310    ) {
 6311        self.code_action_providers
 6312            .retain(|provider| provider.id() != id);
 6313        self.refresh_code_actions(window, cx);
 6314    }
 6315
 6316    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6317        !self.code_action_providers.is_empty()
 6318            && EditorSettings::get_global(cx).toolbar.code_actions
 6319    }
 6320
 6321    pub fn has_available_code_actions(&self) -> bool {
 6322        self.available_code_actions
 6323            .as_ref()
 6324            .is_some_and(|(_, actions)| !actions.is_empty())
 6325    }
 6326
 6327    fn render_inline_code_actions(
 6328        &self,
 6329        icon_size: ui::IconSize,
 6330        display_row: DisplayRow,
 6331        is_active: bool,
 6332        cx: &mut Context<Self>,
 6333    ) -> AnyElement {
 6334        let show_tooltip = !self.context_menu_visible();
 6335        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6336            .icon_size(icon_size)
 6337            .shape(ui::IconButtonShape::Square)
 6338            .style(ButtonStyle::Transparent)
 6339            .icon_color(ui::Color::Hidden)
 6340            .toggle_state(is_active)
 6341            .when(show_tooltip, |this| {
 6342                this.tooltip({
 6343                    let focus_handle = self.focus_handle.clone();
 6344                    move |window, cx| {
 6345                        Tooltip::for_action_in(
 6346                            "Toggle Code Actions",
 6347                            &ToggleCodeActions {
 6348                                deployed_from: None,
 6349                                quick_launch: false,
 6350                            },
 6351                            &focus_handle,
 6352                            window,
 6353                            cx,
 6354                        )
 6355                    }
 6356                })
 6357            })
 6358            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6359                window.focus(&editor.focus_handle(cx));
 6360                editor.toggle_code_actions(
 6361                    &crate::actions::ToggleCodeActions {
 6362                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6363                            display_row,
 6364                        )),
 6365                        quick_launch: false,
 6366                    },
 6367                    window,
 6368                    cx,
 6369                );
 6370            }))
 6371            .into_any_element()
 6372    }
 6373
 6374    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6375        &self.context_menu
 6376    }
 6377
 6378    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6379        let newest_selection = self.selections.newest_anchor().clone();
 6380        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6381        let buffer = self.buffer.read(cx);
 6382        if newest_selection.head().diff_base_anchor.is_some() {
 6383            return None;
 6384        }
 6385        let (start_buffer, start) =
 6386            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6387        let (end_buffer, end) =
 6388            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6389        if start_buffer != end_buffer {
 6390            return None;
 6391        }
 6392
 6393        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6394            cx.background_executor()
 6395                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6396                .await;
 6397
 6398            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6399                let providers = this.code_action_providers.clone();
 6400                let tasks = this
 6401                    .code_action_providers
 6402                    .iter()
 6403                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6404                    .collect::<Vec<_>>();
 6405                (providers, tasks)
 6406            })?;
 6407
 6408            let mut actions = Vec::new();
 6409            for (provider, provider_actions) in
 6410                providers.into_iter().zip(future::join_all(tasks).await)
 6411            {
 6412                if let Some(provider_actions) = provider_actions.log_err() {
 6413                    actions.extend(provider_actions.into_iter().map(|action| {
 6414                        AvailableCodeAction {
 6415                            excerpt_id: newest_selection.start.excerpt_id,
 6416                            action,
 6417                            provider: provider.clone(),
 6418                        }
 6419                    }));
 6420                }
 6421            }
 6422
 6423            this.update(cx, |this, cx| {
 6424                this.available_code_actions = if actions.is_empty() {
 6425                    None
 6426                } else {
 6427                    Some((
 6428                        Location {
 6429                            buffer: start_buffer,
 6430                            range: start..end,
 6431                        },
 6432                        actions.into(),
 6433                    ))
 6434                };
 6435                cx.notify();
 6436            })
 6437        }));
 6438        None
 6439    }
 6440
 6441    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6442        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6443            self.show_git_blame_inline = false;
 6444
 6445            self.show_git_blame_inline_delay_task =
 6446                Some(cx.spawn_in(window, async move |this, cx| {
 6447                    cx.background_executor().timer(delay).await;
 6448
 6449                    this.update(cx, |this, cx| {
 6450                        this.show_git_blame_inline = true;
 6451                        cx.notify();
 6452                    })
 6453                    .log_err();
 6454                }));
 6455        }
 6456    }
 6457
 6458    fn show_blame_popover(
 6459        &mut self,
 6460        blame_entry: &BlameEntry,
 6461        position: gpui::Point<Pixels>,
 6462        cx: &mut Context<Self>,
 6463    ) {
 6464        if let Some(state) = &mut self.inline_blame_popover {
 6465            state.hide_task.take();
 6466        } else {
 6467            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6468            let blame_entry = blame_entry.clone();
 6469            let show_task = cx.spawn(async move |editor, cx| {
 6470                cx.background_executor()
 6471                    .timer(std::time::Duration::from_millis(delay))
 6472                    .await;
 6473                editor
 6474                    .update(cx, |editor, cx| {
 6475                        editor.inline_blame_popover_show_task.take();
 6476                        let Some(blame) = editor.blame.as_ref() else {
 6477                            return;
 6478                        };
 6479                        let blame = blame.read(cx);
 6480                        let details = blame.details_for_entry(&blame_entry);
 6481                        let markdown = cx.new(|cx| {
 6482                            Markdown::new(
 6483                                details
 6484                                    .as_ref()
 6485                                    .map(|message| message.message.clone())
 6486                                    .unwrap_or_default(),
 6487                                None,
 6488                                None,
 6489                                cx,
 6490                            )
 6491                        });
 6492                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6493                            position,
 6494                            hide_task: None,
 6495                            popover_bounds: None,
 6496                            popover_state: InlineBlamePopoverState {
 6497                                scroll_handle: ScrollHandle::new(),
 6498                                commit_message: details,
 6499                                markdown,
 6500                            },
 6501                        });
 6502                        cx.notify();
 6503                    })
 6504                    .ok();
 6505            });
 6506            self.inline_blame_popover_show_task = Some(show_task);
 6507        }
 6508    }
 6509
 6510    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6511        self.inline_blame_popover_show_task.take();
 6512        if let Some(state) = &mut self.inline_blame_popover {
 6513            let hide_task = cx.spawn(async move |editor, cx| {
 6514                cx.background_executor()
 6515                    .timer(std::time::Duration::from_millis(100))
 6516                    .await;
 6517                editor
 6518                    .update(cx, |editor, cx| {
 6519                        editor.inline_blame_popover.take();
 6520                        cx.notify();
 6521                    })
 6522                    .ok();
 6523            });
 6524            state.hide_task = Some(hide_task);
 6525        }
 6526    }
 6527
 6528    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6529        if self.pending_rename.is_some() {
 6530            return None;
 6531        }
 6532
 6533        let provider = self.semantics_provider.clone()?;
 6534        let buffer = self.buffer.read(cx);
 6535        let newest_selection = self.selections.newest_anchor().clone();
 6536        let cursor_position = newest_selection.head();
 6537        let (cursor_buffer, cursor_buffer_position) =
 6538            buffer.text_anchor_for_position(cursor_position, cx)?;
 6539        let (tail_buffer, tail_buffer_position) =
 6540            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6541        if cursor_buffer != tail_buffer {
 6542            return None;
 6543        }
 6544
 6545        let snapshot = cursor_buffer.read(cx).snapshot();
 6546        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6547        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6548        if start_word_range != end_word_range {
 6549            self.document_highlights_task.take();
 6550            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6551            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6552            return None;
 6553        }
 6554
 6555        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6556        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6557            cx.background_executor()
 6558                .timer(Duration::from_millis(debounce))
 6559                .await;
 6560
 6561            let highlights = if let Some(highlights) = cx
 6562                .update(|cx| {
 6563                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6564                })
 6565                .ok()
 6566                .flatten()
 6567            {
 6568                highlights.await.log_err()
 6569            } else {
 6570                None
 6571            };
 6572
 6573            if let Some(highlights) = highlights {
 6574                this.update(cx, |this, cx| {
 6575                    if this.pending_rename.is_some() {
 6576                        return;
 6577                    }
 6578
 6579                    let buffer_id = cursor_position.buffer_id;
 6580                    let buffer = this.buffer.read(cx);
 6581                    if !buffer
 6582                        .text_anchor_for_position(cursor_position, cx)
 6583                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6584                    {
 6585                        return;
 6586                    }
 6587
 6588                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6589                    let mut write_ranges = Vec::new();
 6590                    let mut read_ranges = Vec::new();
 6591                    for highlight in highlights {
 6592                        for (excerpt_id, excerpt_range) in
 6593                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6594                        {
 6595                            let start = highlight
 6596                                .range
 6597                                .start
 6598                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6599                            let end = highlight
 6600                                .range
 6601                                .end
 6602                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6603                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6604                                continue;
 6605                            }
 6606
 6607                            let range = Anchor {
 6608                                buffer_id,
 6609                                excerpt_id,
 6610                                text_anchor: start,
 6611                                diff_base_anchor: None,
 6612                            }..Anchor {
 6613                                buffer_id,
 6614                                excerpt_id,
 6615                                text_anchor: end,
 6616                                diff_base_anchor: None,
 6617                            };
 6618                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6619                                write_ranges.push(range);
 6620                            } else {
 6621                                read_ranges.push(range);
 6622                            }
 6623                        }
 6624                    }
 6625
 6626                    this.highlight_background::<DocumentHighlightRead>(
 6627                        &read_ranges,
 6628                        |theme| theme.colors().editor_document_highlight_read_background,
 6629                        cx,
 6630                    );
 6631                    this.highlight_background::<DocumentHighlightWrite>(
 6632                        &write_ranges,
 6633                        |theme| theme.colors().editor_document_highlight_write_background,
 6634                        cx,
 6635                    );
 6636                    cx.notify();
 6637                })
 6638                .log_err();
 6639            }
 6640        }));
 6641        None
 6642    }
 6643
 6644    fn prepare_highlight_query_from_selection(
 6645        &mut self,
 6646        cx: &mut Context<Editor>,
 6647    ) -> Option<(String, Range<Anchor>)> {
 6648        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6649            return None;
 6650        }
 6651        if !EditorSettings::get_global(cx).selection_highlight {
 6652            return None;
 6653        }
 6654        if self.selections.count() != 1 || self.selections.line_mode {
 6655            return None;
 6656        }
 6657        let selection = self.selections.newest::<Point>(cx);
 6658        if selection.is_empty() || selection.start.row != selection.end.row {
 6659            return None;
 6660        }
 6661        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6662        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6663        let query = multi_buffer_snapshot
 6664            .text_for_range(selection_anchor_range.clone())
 6665            .collect::<String>();
 6666        if query.trim().is_empty() {
 6667            return None;
 6668        }
 6669        Some((query, selection_anchor_range))
 6670    }
 6671
 6672    fn update_selection_occurrence_highlights(
 6673        &mut self,
 6674        query_text: String,
 6675        query_range: Range<Anchor>,
 6676        multi_buffer_range_to_query: Range<Point>,
 6677        use_debounce: bool,
 6678        window: &mut Window,
 6679        cx: &mut Context<Editor>,
 6680    ) -> Task<()> {
 6681        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6682        cx.spawn_in(window, async move |editor, cx| {
 6683            if use_debounce {
 6684                cx.background_executor()
 6685                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6686                    .await;
 6687            }
 6688            let match_task = cx.background_spawn(async move {
 6689                let buffer_ranges = multi_buffer_snapshot
 6690                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6691                    .into_iter()
 6692                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6693                let mut match_ranges = Vec::new();
 6694                let Ok(regex) = project::search::SearchQuery::text(
 6695                    query_text.clone(),
 6696                    false,
 6697                    false,
 6698                    false,
 6699                    Default::default(),
 6700                    Default::default(),
 6701                    false,
 6702                    None,
 6703                ) else {
 6704                    return Vec::default();
 6705                };
 6706                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6707                    match_ranges.extend(
 6708                        regex
 6709                            .search(&buffer_snapshot, Some(search_range.clone()))
 6710                            .await
 6711                            .into_iter()
 6712                            .filter_map(|match_range| {
 6713                                let match_start = buffer_snapshot
 6714                                    .anchor_after(search_range.start + match_range.start);
 6715                                let match_end = buffer_snapshot
 6716                                    .anchor_before(search_range.start + match_range.end);
 6717                                let match_anchor_range = Anchor::range_in_buffer(
 6718                                    excerpt_id,
 6719                                    buffer_snapshot.remote_id(),
 6720                                    match_start..match_end,
 6721                                );
 6722                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6723                            }),
 6724                    );
 6725                }
 6726                match_ranges
 6727            });
 6728            let match_ranges = match_task.await;
 6729            editor
 6730                .update_in(cx, |editor, _, cx| {
 6731                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6732                    if !match_ranges.is_empty() {
 6733                        editor.highlight_background::<SelectedTextHighlight>(
 6734                            &match_ranges,
 6735                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6736                            cx,
 6737                        )
 6738                    }
 6739                })
 6740                .log_err();
 6741        })
 6742    }
 6743
 6744    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6745        struct NewlineFold;
 6746        let type_id = std::any::TypeId::of::<NewlineFold>();
 6747        if !self.mode.is_single_line() {
 6748            return;
 6749        }
 6750        let snapshot = self.snapshot(window, cx);
 6751        if snapshot.buffer_snapshot.max_point().row == 0 {
 6752            return;
 6753        }
 6754        let task = cx.background_spawn(async move {
 6755            let new_newlines = snapshot
 6756                .buffer_chars_at(0)
 6757                .filter_map(|(c, i)| {
 6758                    if c == '\n' {
 6759                        Some(
 6760                            snapshot.buffer_snapshot.anchor_after(i)
 6761                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6762                        )
 6763                    } else {
 6764                        None
 6765                    }
 6766                })
 6767                .collect::<Vec<_>>();
 6768            let existing_newlines = snapshot
 6769                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6770                .filter_map(|fold| {
 6771                    if fold.placeholder.type_tag == Some(type_id) {
 6772                        Some(fold.range.start..fold.range.end)
 6773                    } else {
 6774                        None
 6775                    }
 6776                })
 6777                .collect::<Vec<_>>();
 6778
 6779            (new_newlines, existing_newlines)
 6780        });
 6781        self.folding_newlines = cx.spawn(async move |this, cx| {
 6782            let (new_newlines, existing_newlines) = task.await;
 6783            if new_newlines == existing_newlines {
 6784                return;
 6785            }
 6786            let placeholder = FoldPlaceholder {
 6787                render: Arc::new(move |_, _, cx| {
 6788                    div()
 6789                        .bg(cx.theme().status().hint_background)
 6790                        .border_b_1()
 6791                        .size_full()
 6792                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6793                        .border_color(cx.theme().status().hint)
 6794                        .child("\\n")
 6795                        .into_any()
 6796                }),
 6797                constrain_width: false,
 6798                merge_adjacent: false,
 6799                type_tag: Some(type_id),
 6800            };
 6801            let creases = new_newlines
 6802                .into_iter()
 6803                .map(|range| Crease::simple(range, placeholder.clone()))
 6804                .collect();
 6805            this.update(cx, |this, cx| {
 6806                this.display_map.update(cx, |display_map, cx| {
 6807                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6808                    display_map.fold(creases, cx);
 6809                });
 6810            })
 6811            .ok();
 6812        });
 6813    }
 6814
 6815    fn refresh_selected_text_highlights(
 6816        &mut self,
 6817        on_buffer_edit: bool,
 6818        window: &mut Window,
 6819        cx: &mut Context<Editor>,
 6820    ) {
 6821        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6822        else {
 6823            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6824            self.quick_selection_highlight_task.take();
 6825            self.debounced_selection_highlight_task.take();
 6826            return;
 6827        };
 6828        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6829        if on_buffer_edit
 6830            || self
 6831                .quick_selection_highlight_task
 6832                .as_ref()
 6833                .map_or(true, |(prev_anchor_range, _)| {
 6834                    prev_anchor_range != &query_range
 6835                })
 6836        {
 6837            let multi_buffer_visible_start = self
 6838                .scroll_manager
 6839                .anchor()
 6840                .anchor
 6841                .to_point(&multi_buffer_snapshot);
 6842            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6843                multi_buffer_visible_start
 6844                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6845                Bias::Left,
 6846            );
 6847            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6848            self.quick_selection_highlight_task = Some((
 6849                query_range.clone(),
 6850                self.update_selection_occurrence_highlights(
 6851                    query_text.clone(),
 6852                    query_range.clone(),
 6853                    multi_buffer_visible_range,
 6854                    false,
 6855                    window,
 6856                    cx,
 6857                ),
 6858            ));
 6859        }
 6860        if on_buffer_edit
 6861            || self
 6862                .debounced_selection_highlight_task
 6863                .as_ref()
 6864                .map_or(true, |(prev_anchor_range, _)| {
 6865                    prev_anchor_range != &query_range
 6866                })
 6867        {
 6868            let multi_buffer_start = multi_buffer_snapshot
 6869                .anchor_before(0)
 6870                .to_point(&multi_buffer_snapshot);
 6871            let multi_buffer_end = multi_buffer_snapshot
 6872                .anchor_after(multi_buffer_snapshot.len())
 6873                .to_point(&multi_buffer_snapshot);
 6874            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6875            self.debounced_selection_highlight_task = Some((
 6876                query_range.clone(),
 6877                self.update_selection_occurrence_highlights(
 6878                    query_text,
 6879                    query_range,
 6880                    multi_buffer_full_range,
 6881                    true,
 6882                    window,
 6883                    cx,
 6884                ),
 6885            ));
 6886        }
 6887    }
 6888
 6889    pub fn refresh_inline_completion(
 6890        &mut self,
 6891        debounce: bool,
 6892        user_requested: bool,
 6893        window: &mut Window,
 6894        cx: &mut Context<Self>,
 6895    ) -> Option<()> {
 6896        let provider = self.edit_prediction_provider()?;
 6897        let cursor = self.selections.newest_anchor().head();
 6898        let (buffer, cursor_buffer_position) =
 6899            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6900
 6901        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6902            self.discard_inline_completion(false, cx);
 6903            return None;
 6904        }
 6905
 6906        if !user_requested
 6907            && (!self.should_show_edit_predictions()
 6908                || !self.is_focused(window)
 6909                || buffer.read(cx).is_empty())
 6910        {
 6911            self.discard_inline_completion(false, cx);
 6912            return None;
 6913        }
 6914
 6915        self.update_visible_inline_completion(window, cx);
 6916        provider.refresh(
 6917            self.project.clone(),
 6918            buffer,
 6919            cursor_buffer_position,
 6920            debounce,
 6921            cx,
 6922        );
 6923        Some(())
 6924    }
 6925
 6926    fn show_edit_predictions_in_menu(&self) -> bool {
 6927        match self.edit_prediction_settings {
 6928            EditPredictionSettings::Disabled => false,
 6929            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6930        }
 6931    }
 6932
 6933    pub fn edit_predictions_enabled(&self) -> bool {
 6934        match self.edit_prediction_settings {
 6935            EditPredictionSettings::Disabled => false,
 6936            EditPredictionSettings::Enabled { .. } => true,
 6937        }
 6938    }
 6939
 6940    fn edit_prediction_requires_modifier(&self) -> bool {
 6941        match self.edit_prediction_settings {
 6942            EditPredictionSettings::Disabled => false,
 6943            EditPredictionSettings::Enabled {
 6944                preview_requires_modifier,
 6945                ..
 6946            } => preview_requires_modifier,
 6947        }
 6948    }
 6949
 6950    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6951        if self.edit_prediction_provider.is_none() {
 6952            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6953        } else {
 6954            let selection = self.selections.newest_anchor();
 6955            let cursor = selection.head();
 6956
 6957            if let Some((buffer, cursor_buffer_position)) =
 6958                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6959            {
 6960                self.edit_prediction_settings =
 6961                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6962            }
 6963        }
 6964    }
 6965
 6966    fn edit_prediction_settings_at_position(
 6967        &self,
 6968        buffer: &Entity<Buffer>,
 6969        buffer_position: language::Anchor,
 6970        cx: &App,
 6971    ) -> EditPredictionSettings {
 6972        if !self.mode.is_full()
 6973            || !self.show_inline_completions_override.unwrap_or(true)
 6974            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6975        {
 6976            return EditPredictionSettings::Disabled;
 6977        }
 6978
 6979        let buffer = buffer.read(cx);
 6980
 6981        let file = buffer.file();
 6982
 6983        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6984            return EditPredictionSettings::Disabled;
 6985        };
 6986
 6987        let by_provider = matches!(
 6988            self.menu_inline_completions_policy,
 6989            MenuInlineCompletionsPolicy::ByProvider
 6990        );
 6991
 6992        let show_in_menu = by_provider
 6993            && self
 6994                .edit_prediction_provider
 6995                .as_ref()
 6996                .map_or(false, |provider| {
 6997                    provider.provider.show_completions_in_menu()
 6998                });
 6999
 7000        let preview_requires_modifier =
 7001            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7002
 7003        EditPredictionSettings::Enabled {
 7004            show_in_menu,
 7005            preview_requires_modifier,
 7006        }
 7007    }
 7008
 7009    fn should_show_edit_predictions(&self) -> bool {
 7010        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7011    }
 7012
 7013    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7014        matches!(
 7015            self.edit_prediction_preview,
 7016            EditPredictionPreview::Active { .. }
 7017        )
 7018    }
 7019
 7020    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7021        let cursor = self.selections.newest_anchor().head();
 7022        if let Some((buffer, cursor_position)) =
 7023            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7024        {
 7025            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7026        } else {
 7027            false
 7028        }
 7029    }
 7030
 7031    pub fn supports_minimap(&self, cx: &App) -> bool {
 7032        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7033    }
 7034
 7035    fn edit_predictions_enabled_in_buffer(
 7036        &self,
 7037        buffer: &Entity<Buffer>,
 7038        buffer_position: language::Anchor,
 7039        cx: &App,
 7040    ) -> bool {
 7041        maybe!({
 7042            if self.read_only(cx) {
 7043                return Some(false);
 7044            }
 7045            let provider = self.edit_prediction_provider()?;
 7046            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7047                return Some(false);
 7048            }
 7049            let buffer = buffer.read(cx);
 7050            let Some(file) = buffer.file() else {
 7051                return Some(true);
 7052            };
 7053            let settings = all_language_settings(Some(file), cx);
 7054            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7055        })
 7056        .unwrap_or(false)
 7057    }
 7058
 7059    fn cycle_inline_completion(
 7060        &mut self,
 7061        direction: Direction,
 7062        window: &mut Window,
 7063        cx: &mut Context<Self>,
 7064    ) -> Option<()> {
 7065        let provider = self.edit_prediction_provider()?;
 7066        let cursor = self.selections.newest_anchor().head();
 7067        let (buffer, cursor_buffer_position) =
 7068            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7069        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7070            return None;
 7071        }
 7072
 7073        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7074        self.update_visible_inline_completion(window, cx);
 7075
 7076        Some(())
 7077    }
 7078
 7079    pub fn show_inline_completion(
 7080        &mut self,
 7081        _: &ShowEditPrediction,
 7082        window: &mut Window,
 7083        cx: &mut Context<Self>,
 7084    ) {
 7085        if !self.has_active_inline_completion() {
 7086            self.refresh_inline_completion(false, true, window, cx);
 7087            return;
 7088        }
 7089
 7090        self.update_visible_inline_completion(window, cx);
 7091    }
 7092
 7093    pub fn display_cursor_names(
 7094        &mut self,
 7095        _: &DisplayCursorNames,
 7096        window: &mut Window,
 7097        cx: &mut Context<Self>,
 7098    ) {
 7099        self.show_cursor_names(window, cx);
 7100    }
 7101
 7102    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7103        self.show_cursor_names = true;
 7104        cx.notify();
 7105        cx.spawn_in(window, async move |this, cx| {
 7106            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7107            this.update(cx, |this, cx| {
 7108                this.show_cursor_names = false;
 7109                cx.notify()
 7110            })
 7111            .ok()
 7112        })
 7113        .detach();
 7114    }
 7115
 7116    pub fn next_edit_prediction(
 7117        &mut self,
 7118        _: &NextEditPrediction,
 7119        window: &mut Window,
 7120        cx: &mut Context<Self>,
 7121    ) {
 7122        if self.has_active_inline_completion() {
 7123            self.cycle_inline_completion(Direction::Next, window, cx);
 7124        } else {
 7125            let is_copilot_disabled = self
 7126                .refresh_inline_completion(false, true, window, cx)
 7127                .is_none();
 7128            if is_copilot_disabled {
 7129                cx.propagate();
 7130            }
 7131        }
 7132    }
 7133
 7134    pub fn previous_edit_prediction(
 7135        &mut self,
 7136        _: &PreviousEditPrediction,
 7137        window: &mut Window,
 7138        cx: &mut Context<Self>,
 7139    ) {
 7140        if self.has_active_inline_completion() {
 7141            self.cycle_inline_completion(Direction::Prev, window, cx);
 7142        } else {
 7143            let is_copilot_disabled = self
 7144                .refresh_inline_completion(false, true, window, cx)
 7145                .is_none();
 7146            if is_copilot_disabled {
 7147                cx.propagate();
 7148            }
 7149        }
 7150    }
 7151
 7152    pub fn accept_edit_prediction(
 7153        &mut self,
 7154        _: &AcceptEditPrediction,
 7155        window: &mut Window,
 7156        cx: &mut Context<Self>,
 7157    ) {
 7158        if self.show_edit_predictions_in_menu() {
 7159            self.hide_context_menu(window, cx);
 7160        }
 7161
 7162        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7163            return;
 7164        };
 7165
 7166        self.report_inline_completion_event(
 7167            active_inline_completion.completion_id.clone(),
 7168            true,
 7169            cx,
 7170        );
 7171
 7172        match &active_inline_completion.completion {
 7173            InlineCompletion::Move { target, .. } => {
 7174                let target = *target;
 7175
 7176                if let Some(position_map) = &self.last_position_map {
 7177                    if position_map
 7178                        .visible_row_range
 7179                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7180                        || !self.edit_prediction_requires_modifier()
 7181                    {
 7182                        self.unfold_ranges(&[target..target], true, false, cx);
 7183                        // Note that this is also done in vim's handler of the Tab action.
 7184                        self.change_selections(
 7185                            SelectionEffects::scroll(Autoscroll::newest()),
 7186                            window,
 7187                            cx,
 7188                            |selections| {
 7189                                selections.select_anchor_ranges([target..target]);
 7190                            },
 7191                        );
 7192                        self.clear_row_highlights::<EditPredictionPreview>();
 7193
 7194                        self.edit_prediction_preview
 7195                            .set_previous_scroll_position(None);
 7196                    } else {
 7197                        self.edit_prediction_preview
 7198                            .set_previous_scroll_position(Some(
 7199                                position_map.snapshot.scroll_anchor,
 7200                            ));
 7201
 7202                        self.highlight_rows::<EditPredictionPreview>(
 7203                            target..target,
 7204                            cx.theme().colors().editor_highlighted_line_background,
 7205                            RowHighlightOptions {
 7206                                autoscroll: true,
 7207                                ..Default::default()
 7208                            },
 7209                            cx,
 7210                        );
 7211                        self.request_autoscroll(Autoscroll::fit(), cx);
 7212                    }
 7213                }
 7214            }
 7215            InlineCompletion::Edit { edits, .. } => {
 7216                if let Some(provider) = self.edit_prediction_provider() {
 7217                    provider.accept(cx);
 7218                }
 7219
 7220                // Store the transaction ID and selections before applying the edit
 7221                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7222
 7223                let snapshot = self.buffer.read(cx).snapshot(cx);
 7224                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7225
 7226                self.buffer.update(cx, |buffer, cx| {
 7227                    buffer.edit(edits.iter().cloned(), None, cx)
 7228                });
 7229
 7230                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7231                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7232                });
 7233
 7234                let selections = self.selections.disjoint_anchors();
 7235                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7236                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7237                    if has_new_transaction {
 7238                        self.selection_history
 7239                            .insert_transaction(transaction_id_now, selections);
 7240                    }
 7241                }
 7242
 7243                self.update_visible_inline_completion(window, cx);
 7244                if self.active_inline_completion.is_none() {
 7245                    self.refresh_inline_completion(true, true, window, cx);
 7246                }
 7247
 7248                cx.notify();
 7249            }
 7250        }
 7251
 7252        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7253    }
 7254
 7255    pub fn accept_partial_inline_completion(
 7256        &mut self,
 7257        _: &AcceptPartialEditPrediction,
 7258        window: &mut Window,
 7259        cx: &mut Context<Self>,
 7260    ) {
 7261        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7262            return;
 7263        };
 7264        if self.selections.count() != 1 {
 7265            return;
 7266        }
 7267
 7268        self.report_inline_completion_event(
 7269            active_inline_completion.completion_id.clone(),
 7270            true,
 7271            cx,
 7272        );
 7273
 7274        match &active_inline_completion.completion {
 7275            InlineCompletion::Move { target, .. } => {
 7276                let target = *target;
 7277                self.change_selections(
 7278                    SelectionEffects::scroll(Autoscroll::newest()),
 7279                    window,
 7280                    cx,
 7281                    |selections| {
 7282                        selections.select_anchor_ranges([target..target]);
 7283                    },
 7284                );
 7285            }
 7286            InlineCompletion::Edit { edits, .. } => {
 7287                // Find an insertion that starts at the cursor position.
 7288                let snapshot = self.buffer.read(cx).snapshot(cx);
 7289                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7290                let insertion = edits.iter().find_map(|(range, text)| {
 7291                    let range = range.to_offset(&snapshot);
 7292                    if range.is_empty() && range.start == cursor_offset {
 7293                        Some(text)
 7294                    } else {
 7295                        None
 7296                    }
 7297                });
 7298
 7299                if let Some(text) = insertion {
 7300                    let mut partial_completion = text
 7301                        .chars()
 7302                        .by_ref()
 7303                        .take_while(|c| c.is_alphabetic())
 7304                        .collect::<String>();
 7305                    if partial_completion.is_empty() {
 7306                        partial_completion = text
 7307                            .chars()
 7308                            .by_ref()
 7309                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7310                            .collect::<String>();
 7311                    }
 7312
 7313                    cx.emit(EditorEvent::InputHandled {
 7314                        utf16_range_to_replace: None,
 7315                        text: partial_completion.clone().into(),
 7316                    });
 7317
 7318                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7319
 7320                    self.refresh_inline_completion(true, true, window, cx);
 7321                    cx.notify();
 7322                } else {
 7323                    self.accept_edit_prediction(&Default::default(), window, cx);
 7324                }
 7325            }
 7326        }
 7327    }
 7328
 7329    fn discard_inline_completion(
 7330        &mut self,
 7331        should_report_inline_completion_event: bool,
 7332        cx: &mut Context<Self>,
 7333    ) -> bool {
 7334        if should_report_inline_completion_event {
 7335            let completion_id = self
 7336                .active_inline_completion
 7337                .as_ref()
 7338                .and_then(|active_completion| active_completion.completion_id.clone());
 7339
 7340            self.report_inline_completion_event(completion_id, false, cx);
 7341        }
 7342
 7343        if let Some(provider) = self.edit_prediction_provider() {
 7344            provider.discard(cx);
 7345        }
 7346
 7347        self.take_active_inline_completion(cx)
 7348    }
 7349
 7350    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7351        let Some(provider) = self.edit_prediction_provider() else {
 7352            return;
 7353        };
 7354
 7355        let Some((_, buffer, _)) = self
 7356            .buffer
 7357            .read(cx)
 7358            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7359        else {
 7360            return;
 7361        };
 7362
 7363        let extension = buffer
 7364            .read(cx)
 7365            .file()
 7366            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7367
 7368        let event_type = match accepted {
 7369            true => "Edit Prediction Accepted",
 7370            false => "Edit Prediction Discarded",
 7371        };
 7372        telemetry::event!(
 7373            event_type,
 7374            provider = provider.name(),
 7375            prediction_id = id,
 7376            suggestion_accepted = accepted,
 7377            file_extension = extension,
 7378        );
 7379    }
 7380
 7381    pub fn has_active_inline_completion(&self) -> bool {
 7382        self.active_inline_completion.is_some()
 7383    }
 7384
 7385    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7386        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7387            return false;
 7388        };
 7389
 7390        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7391        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7392        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7393        true
 7394    }
 7395
 7396    /// Returns true when we're displaying the edit prediction popover below the cursor
 7397    /// like we are not previewing and the LSP autocomplete menu is visible
 7398    /// or we are in `when_holding_modifier` mode.
 7399    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7400        if self.edit_prediction_preview_is_active()
 7401            || !self.show_edit_predictions_in_menu()
 7402            || !self.edit_predictions_enabled()
 7403        {
 7404            return false;
 7405        }
 7406
 7407        if self.has_visible_completions_menu() {
 7408            return true;
 7409        }
 7410
 7411        has_completion && self.edit_prediction_requires_modifier()
 7412    }
 7413
 7414    fn handle_modifiers_changed(
 7415        &mut self,
 7416        modifiers: Modifiers,
 7417        position_map: &PositionMap,
 7418        window: &mut Window,
 7419        cx: &mut Context<Self>,
 7420    ) {
 7421        if self.show_edit_predictions_in_menu() {
 7422            self.update_edit_prediction_preview(&modifiers, window, cx);
 7423        }
 7424
 7425        self.update_selection_mode(&modifiers, position_map, window, cx);
 7426
 7427        let mouse_position = window.mouse_position();
 7428        if !position_map.text_hitbox.is_hovered(window) {
 7429            return;
 7430        }
 7431
 7432        self.update_hovered_link(
 7433            position_map.point_for_position(mouse_position),
 7434            &position_map.snapshot,
 7435            modifiers,
 7436            window,
 7437            cx,
 7438        )
 7439    }
 7440
 7441    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7442        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7443        if invert {
 7444            match multi_cursor_setting {
 7445                MultiCursorModifier::Alt => modifiers.alt,
 7446                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7447            }
 7448        } else {
 7449            match multi_cursor_setting {
 7450                MultiCursorModifier::Alt => modifiers.secondary(),
 7451                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7452            }
 7453        }
 7454    }
 7455
 7456    fn columnar_selection_mode(
 7457        modifiers: &Modifiers,
 7458        cx: &mut Context<Self>,
 7459    ) -> Option<ColumnarMode> {
 7460        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7461            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7462                Some(ColumnarMode::FromMouse)
 7463            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7464                Some(ColumnarMode::FromSelection)
 7465            } else {
 7466                None
 7467            }
 7468        } else {
 7469            None
 7470        }
 7471    }
 7472
 7473    fn update_selection_mode(
 7474        &mut self,
 7475        modifiers: &Modifiers,
 7476        position_map: &PositionMap,
 7477        window: &mut Window,
 7478        cx: &mut Context<Self>,
 7479    ) {
 7480        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7481            return;
 7482        };
 7483        if self.selections.pending.is_none() {
 7484            return;
 7485        }
 7486
 7487        let mouse_position = window.mouse_position();
 7488        let point_for_position = position_map.point_for_position(mouse_position);
 7489        let position = point_for_position.previous_valid;
 7490
 7491        self.select(
 7492            SelectPhase::BeginColumnar {
 7493                position,
 7494                reset: false,
 7495                mode,
 7496                goal_column: point_for_position.exact_unclipped.column(),
 7497            },
 7498            window,
 7499            cx,
 7500        );
 7501    }
 7502
 7503    fn update_edit_prediction_preview(
 7504        &mut self,
 7505        modifiers: &Modifiers,
 7506        window: &mut Window,
 7507        cx: &mut Context<Self>,
 7508    ) {
 7509        let mut modifiers_held = false;
 7510        if let Some(accept_keystroke) = self
 7511            .accept_edit_prediction_keybind(false, window, cx)
 7512            .keystroke()
 7513        {
 7514            modifiers_held = modifiers_held
 7515                || (&accept_keystroke.modifiers == modifiers
 7516                    && accept_keystroke.modifiers.modified());
 7517        };
 7518        if let Some(accept_partial_keystroke) = self
 7519            .accept_edit_prediction_keybind(true, window, cx)
 7520            .keystroke()
 7521        {
 7522            modifiers_held = modifiers_held
 7523                || (&accept_partial_keystroke.modifiers == modifiers
 7524                    && accept_partial_keystroke.modifiers.modified());
 7525        }
 7526
 7527        if modifiers_held {
 7528            if matches!(
 7529                self.edit_prediction_preview,
 7530                EditPredictionPreview::Inactive { .. }
 7531            ) {
 7532                self.edit_prediction_preview = EditPredictionPreview::Active {
 7533                    previous_scroll_position: None,
 7534                    since: Instant::now(),
 7535                };
 7536
 7537                self.update_visible_inline_completion(window, cx);
 7538                cx.notify();
 7539            }
 7540        } else if let EditPredictionPreview::Active {
 7541            previous_scroll_position,
 7542            since,
 7543        } = self.edit_prediction_preview
 7544        {
 7545            if let (Some(previous_scroll_position), Some(position_map)) =
 7546                (previous_scroll_position, self.last_position_map.as_ref())
 7547            {
 7548                self.set_scroll_position(
 7549                    previous_scroll_position
 7550                        .scroll_position(&position_map.snapshot.display_snapshot),
 7551                    window,
 7552                    cx,
 7553                );
 7554            }
 7555
 7556            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7557                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7558            };
 7559            self.clear_row_highlights::<EditPredictionPreview>();
 7560            self.update_visible_inline_completion(window, cx);
 7561            cx.notify();
 7562        }
 7563    }
 7564
 7565    fn update_visible_inline_completion(
 7566        &mut self,
 7567        _window: &mut Window,
 7568        cx: &mut Context<Self>,
 7569    ) -> Option<()> {
 7570        let selection = self.selections.newest_anchor();
 7571        let cursor = selection.head();
 7572        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7573        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7574        let excerpt_id = cursor.excerpt_id;
 7575
 7576        let show_in_menu = self.show_edit_predictions_in_menu();
 7577        let completions_menu_has_precedence = !show_in_menu
 7578            && (self.context_menu.borrow().is_some()
 7579                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7580
 7581        if completions_menu_has_precedence
 7582            || !offset_selection.is_empty()
 7583            || self
 7584                .active_inline_completion
 7585                .as_ref()
 7586                .map_or(false, |completion| {
 7587                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7588                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7589                    !invalidation_range.contains(&offset_selection.head())
 7590                })
 7591        {
 7592            self.discard_inline_completion(false, cx);
 7593            return None;
 7594        }
 7595
 7596        self.take_active_inline_completion(cx);
 7597        let Some(provider) = self.edit_prediction_provider() else {
 7598            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7599            return None;
 7600        };
 7601
 7602        let (buffer, cursor_buffer_position) =
 7603            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7604
 7605        self.edit_prediction_settings =
 7606            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7607
 7608        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7609
 7610        if self.edit_prediction_indent_conflict {
 7611            let cursor_point = cursor.to_point(&multibuffer);
 7612
 7613            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7614
 7615            if let Some((_, indent)) = indents.iter().next() {
 7616                if indent.len == cursor_point.column {
 7617                    self.edit_prediction_indent_conflict = false;
 7618                }
 7619            }
 7620        }
 7621
 7622        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7623        let edits = inline_completion
 7624            .edits
 7625            .into_iter()
 7626            .flat_map(|(range, new_text)| {
 7627                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7628                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7629                Some((start..end, new_text))
 7630            })
 7631            .collect::<Vec<_>>();
 7632        if edits.is_empty() {
 7633            return None;
 7634        }
 7635
 7636        let first_edit_start = edits.first().unwrap().0.start;
 7637        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7638        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7639
 7640        let last_edit_end = edits.last().unwrap().0.end;
 7641        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7642        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7643
 7644        let cursor_row = cursor.to_point(&multibuffer).row;
 7645
 7646        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7647
 7648        let mut inlay_ids = Vec::new();
 7649        let invalidation_row_range;
 7650        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7651            Some(cursor_row..edit_end_row)
 7652        } else if cursor_row > edit_end_row {
 7653            Some(edit_start_row..cursor_row)
 7654        } else {
 7655            None
 7656        };
 7657        let is_move =
 7658            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7659        let completion = if is_move {
 7660            invalidation_row_range =
 7661                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7662            let target = first_edit_start;
 7663            InlineCompletion::Move { target, snapshot }
 7664        } else {
 7665            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7666                && !self.inline_completions_hidden_for_vim_mode;
 7667
 7668            if show_completions_in_buffer {
 7669                if edits
 7670                    .iter()
 7671                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7672                {
 7673                    let mut inlays = Vec::new();
 7674                    for (range, new_text) in &edits {
 7675                        let inlay = Inlay::inline_completion(
 7676                            post_inc(&mut self.next_inlay_id),
 7677                            range.start,
 7678                            new_text.as_str(),
 7679                        );
 7680                        inlay_ids.push(inlay.id);
 7681                        inlays.push(inlay);
 7682                    }
 7683
 7684                    self.splice_inlays(&[], inlays, cx);
 7685                } else {
 7686                    let background_color = cx.theme().status().deleted_background;
 7687                    self.highlight_text::<InlineCompletionHighlight>(
 7688                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7689                        HighlightStyle {
 7690                            background_color: Some(background_color),
 7691                            ..Default::default()
 7692                        },
 7693                        cx,
 7694                    );
 7695                }
 7696            }
 7697
 7698            invalidation_row_range = edit_start_row..edit_end_row;
 7699
 7700            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7701                if provider.show_tab_accept_marker() {
 7702                    EditDisplayMode::TabAccept
 7703                } else {
 7704                    EditDisplayMode::Inline
 7705                }
 7706            } else {
 7707                EditDisplayMode::DiffPopover
 7708            };
 7709
 7710            InlineCompletion::Edit {
 7711                edits,
 7712                edit_preview: inline_completion.edit_preview,
 7713                display_mode,
 7714                snapshot,
 7715            }
 7716        };
 7717
 7718        let invalidation_range = multibuffer
 7719            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7720            ..multibuffer.anchor_after(Point::new(
 7721                invalidation_row_range.end,
 7722                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7723            ));
 7724
 7725        self.stale_inline_completion_in_menu = None;
 7726        self.active_inline_completion = Some(InlineCompletionState {
 7727            inlay_ids,
 7728            completion,
 7729            completion_id: inline_completion.id,
 7730            invalidation_range,
 7731        });
 7732
 7733        cx.notify();
 7734
 7735        Some(())
 7736    }
 7737
 7738    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7739        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7740    }
 7741
 7742    fn clear_tasks(&mut self) {
 7743        self.tasks.clear()
 7744    }
 7745
 7746    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7747        if self.tasks.insert(key, value).is_some() {
 7748            // This case should hopefully be rare, but just in case...
 7749            log::error!(
 7750                "multiple different run targets found on a single line, only the last target will be rendered"
 7751            )
 7752        }
 7753    }
 7754
 7755    /// Get all display points of breakpoints that will be rendered within editor
 7756    ///
 7757    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7758    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7759    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7760    fn active_breakpoints(
 7761        &self,
 7762        range: Range<DisplayRow>,
 7763        window: &mut Window,
 7764        cx: &mut Context<Self>,
 7765    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7766        let mut breakpoint_display_points = HashMap::default();
 7767
 7768        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7769            return breakpoint_display_points;
 7770        };
 7771
 7772        let snapshot = self.snapshot(window, cx);
 7773
 7774        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7775        let Some(project) = self.project.as_ref() else {
 7776            return breakpoint_display_points;
 7777        };
 7778
 7779        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7780            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7781
 7782        for (buffer_snapshot, range, excerpt_id) in
 7783            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7784        {
 7785            let Some(buffer) = project
 7786                .read(cx)
 7787                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7788            else {
 7789                continue;
 7790            };
 7791            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7792                &buffer,
 7793                Some(
 7794                    buffer_snapshot.anchor_before(range.start)
 7795                        ..buffer_snapshot.anchor_after(range.end),
 7796                ),
 7797                buffer_snapshot,
 7798                cx,
 7799            );
 7800            for (breakpoint, state) in breakpoints {
 7801                let multi_buffer_anchor =
 7802                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7803                let position = multi_buffer_anchor
 7804                    .to_point(&multi_buffer_snapshot)
 7805                    .to_display_point(&snapshot);
 7806
 7807                breakpoint_display_points.insert(
 7808                    position.row(),
 7809                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7810                );
 7811            }
 7812        }
 7813
 7814        breakpoint_display_points
 7815    }
 7816
 7817    fn breakpoint_context_menu(
 7818        &self,
 7819        anchor: Anchor,
 7820        window: &mut Window,
 7821        cx: &mut Context<Self>,
 7822    ) -> Entity<ui::ContextMenu> {
 7823        let weak_editor = cx.weak_entity();
 7824        let focus_handle = self.focus_handle(cx);
 7825
 7826        let row = self
 7827            .buffer
 7828            .read(cx)
 7829            .snapshot(cx)
 7830            .summary_for_anchor::<Point>(&anchor)
 7831            .row;
 7832
 7833        let breakpoint = self
 7834            .breakpoint_at_row(row, window, cx)
 7835            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7836
 7837        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7838            "Edit Log Breakpoint"
 7839        } else {
 7840            "Set Log Breakpoint"
 7841        };
 7842
 7843        let condition_breakpoint_msg = if breakpoint
 7844            .as_ref()
 7845            .is_some_and(|bp| bp.1.condition.is_some())
 7846        {
 7847            "Edit Condition Breakpoint"
 7848        } else {
 7849            "Set Condition Breakpoint"
 7850        };
 7851
 7852        let hit_condition_breakpoint_msg = if breakpoint
 7853            .as_ref()
 7854            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7855        {
 7856            "Edit Hit Condition Breakpoint"
 7857        } else {
 7858            "Set Hit Condition Breakpoint"
 7859        };
 7860
 7861        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7862            "Unset Breakpoint"
 7863        } else {
 7864            "Set Breakpoint"
 7865        };
 7866
 7867        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7868
 7869        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7870            BreakpointState::Enabled => Some("Disable"),
 7871            BreakpointState::Disabled => Some("Enable"),
 7872        });
 7873
 7874        let (anchor, breakpoint) =
 7875            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7876
 7877        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7878            menu.on_blur_subscription(Subscription::new(|| {}))
 7879                .context(focus_handle)
 7880                .when(run_to_cursor, |this| {
 7881                    let weak_editor = weak_editor.clone();
 7882                    this.entry("Run to cursor", None, move |window, cx| {
 7883                        weak_editor
 7884                            .update(cx, |editor, cx| {
 7885                                editor.change_selections(
 7886                                    SelectionEffects::no_scroll(),
 7887                                    window,
 7888                                    cx,
 7889                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7890                                );
 7891                            })
 7892                            .ok();
 7893
 7894                        window.dispatch_action(Box::new(RunToCursor), cx);
 7895                    })
 7896                    .separator()
 7897                })
 7898                .when_some(toggle_state_msg, |this, msg| {
 7899                    this.entry(msg, None, {
 7900                        let weak_editor = weak_editor.clone();
 7901                        let breakpoint = breakpoint.clone();
 7902                        move |_window, cx| {
 7903                            weak_editor
 7904                                .update(cx, |this, cx| {
 7905                                    this.edit_breakpoint_at_anchor(
 7906                                        anchor,
 7907                                        breakpoint.as_ref().clone(),
 7908                                        BreakpointEditAction::InvertState,
 7909                                        cx,
 7910                                    );
 7911                                })
 7912                                .log_err();
 7913                        }
 7914                    })
 7915                })
 7916                .entry(set_breakpoint_msg, None, {
 7917                    let weak_editor = weak_editor.clone();
 7918                    let breakpoint = breakpoint.clone();
 7919                    move |_window, cx| {
 7920                        weak_editor
 7921                            .update(cx, |this, cx| {
 7922                                this.edit_breakpoint_at_anchor(
 7923                                    anchor,
 7924                                    breakpoint.as_ref().clone(),
 7925                                    BreakpointEditAction::Toggle,
 7926                                    cx,
 7927                                );
 7928                            })
 7929                            .log_err();
 7930                    }
 7931                })
 7932                .entry(log_breakpoint_msg, None, {
 7933                    let breakpoint = breakpoint.clone();
 7934                    let weak_editor = weak_editor.clone();
 7935                    move |window, cx| {
 7936                        weak_editor
 7937                            .update(cx, |this, cx| {
 7938                                this.add_edit_breakpoint_block(
 7939                                    anchor,
 7940                                    breakpoint.as_ref(),
 7941                                    BreakpointPromptEditAction::Log,
 7942                                    window,
 7943                                    cx,
 7944                                );
 7945                            })
 7946                            .log_err();
 7947                    }
 7948                })
 7949                .entry(condition_breakpoint_msg, None, {
 7950                    let breakpoint = breakpoint.clone();
 7951                    let weak_editor = weak_editor.clone();
 7952                    move |window, cx| {
 7953                        weak_editor
 7954                            .update(cx, |this, cx| {
 7955                                this.add_edit_breakpoint_block(
 7956                                    anchor,
 7957                                    breakpoint.as_ref(),
 7958                                    BreakpointPromptEditAction::Condition,
 7959                                    window,
 7960                                    cx,
 7961                                );
 7962                            })
 7963                            .log_err();
 7964                    }
 7965                })
 7966                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7967                    weak_editor
 7968                        .update(cx, |this, cx| {
 7969                            this.add_edit_breakpoint_block(
 7970                                anchor,
 7971                                breakpoint.as_ref(),
 7972                                BreakpointPromptEditAction::HitCondition,
 7973                                window,
 7974                                cx,
 7975                            );
 7976                        })
 7977                        .log_err();
 7978                })
 7979        })
 7980    }
 7981
 7982    fn render_breakpoint(
 7983        &self,
 7984        position: Anchor,
 7985        row: DisplayRow,
 7986        breakpoint: &Breakpoint,
 7987        state: Option<BreakpointSessionState>,
 7988        cx: &mut Context<Self>,
 7989    ) -> IconButton {
 7990        let is_rejected = state.is_some_and(|s| !s.verified);
 7991        // Is it a breakpoint that shows up when hovering over gutter?
 7992        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7993            (false, false),
 7994            |PhantomBreakpointIndicator {
 7995                 is_active,
 7996                 display_row,
 7997                 collides_with_existing_breakpoint,
 7998             }| {
 7999                (
 8000                    is_active && display_row == row,
 8001                    collides_with_existing_breakpoint,
 8002                )
 8003            },
 8004        );
 8005
 8006        let (color, icon) = {
 8007            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8008                (false, false) => ui::IconName::DebugBreakpoint,
 8009                (true, false) => ui::IconName::DebugLogBreakpoint,
 8010                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8011                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8012            };
 8013
 8014            let color = if is_phantom {
 8015                Color::Hint
 8016            } else if is_rejected {
 8017                Color::Disabled
 8018            } else {
 8019                Color::Debugger
 8020            };
 8021
 8022            (color, icon)
 8023        };
 8024
 8025        let breakpoint = Arc::from(breakpoint.clone());
 8026
 8027        let alt_as_text = gpui::Keystroke {
 8028            modifiers: Modifiers::secondary_key(),
 8029            ..Default::default()
 8030        };
 8031        let primary_action_text = if breakpoint.is_disabled() {
 8032            "Enable breakpoint"
 8033        } else if is_phantom && !collides_with_existing {
 8034            "Set breakpoint"
 8035        } else {
 8036            "Unset breakpoint"
 8037        };
 8038        let focus_handle = self.focus_handle.clone();
 8039
 8040        let meta = if is_rejected {
 8041            SharedString::from("No executable code is associated with this line.")
 8042        } else if collides_with_existing && !breakpoint.is_disabled() {
 8043            SharedString::from(format!(
 8044                "{alt_as_text}-click to disable,\nright-click for more options."
 8045            ))
 8046        } else {
 8047            SharedString::from("Right-click for more options.")
 8048        };
 8049        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8050            .icon_size(IconSize::XSmall)
 8051            .size(ui::ButtonSize::None)
 8052            .when(is_rejected, |this| {
 8053                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8054            })
 8055            .icon_color(color)
 8056            .style(ButtonStyle::Transparent)
 8057            .on_click(cx.listener({
 8058                let breakpoint = breakpoint.clone();
 8059
 8060                move |editor, event: &ClickEvent, window, cx| {
 8061                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8062                        BreakpointEditAction::InvertState
 8063                    } else {
 8064                        BreakpointEditAction::Toggle
 8065                    };
 8066
 8067                    window.focus(&editor.focus_handle(cx));
 8068                    editor.edit_breakpoint_at_anchor(
 8069                        position,
 8070                        breakpoint.as_ref().clone(),
 8071                        edit_action,
 8072                        cx,
 8073                    );
 8074                }
 8075            }))
 8076            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8077                editor.set_breakpoint_context_menu(
 8078                    row,
 8079                    Some(position),
 8080                    event.down.position,
 8081                    window,
 8082                    cx,
 8083                );
 8084            }))
 8085            .tooltip(move |window, cx| {
 8086                Tooltip::with_meta_in(
 8087                    primary_action_text,
 8088                    Some(&ToggleBreakpoint),
 8089                    meta.clone(),
 8090                    &focus_handle,
 8091                    window,
 8092                    cx,
 8093                )
 8094            })
 8095    }
 8096
 8097    fn build_tasks_context(
 8098        project: &Entity<Project>,
 8099        buffer: &Entity<Buffer>,
 8100        buffer_row: u32,
 8101        tasks: &Arc<RunnableTasks>,
 8102        cx: &mut Context<Self>,
 8103    ) -> Task<Option<task::TaskContext>> {
 8104        let position = Point::new(buffer_row, tasks.column);
 8105        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8106        let location = Location {
 8107            buffer: buffer.clone(),
 8108            range: range_start..range_start,
 8109        };
 8110        // Fill in the environmental variables from the tree-sitter captures
 8111        let mut captured_task_variables = TaskVariables::default();
 8112        for (capture_name, value) in tasks.extra_variables.clone() {
 8113            captured_task_variables.insert(
 8114                task::VariableName::Custom(capture_name.into()),
 8115                value.clone(),
 8116            );
 8117        }
 8118        project.update(cx, |project, cx| {
 8119            project.task_store().update(cx, |task_store, cx| {
 8120                task_store.task_context_for_location(captured_task_variables, location, cx)
 8121            })
 8122        })
 8123    }
 8124
 8125    pub fn spawn_nearest_task(
 8126        &mut self,
 8127        action: &SpawnNearestTask,
 8128        window: &mut Window,
 8129        cx: &mut Context<Self>,
 8130    ) {
 8131        let Some((workspace, _)) = self.workspace.clone() else {
 8132            return;
 8133        };
 8134        let Some(project) = self.project.clone() else {
 8135            return;
 8136        };
 8137
 8138        // Try to find a closest, enclosing node using tree-sitter that has a
 8139        // task
 8140        let Some((buffer, buffer_row, tasks)) = self
 8141            .find_enclosing_node_task(cx)
 8142            // Or find the task that's closest in row-distance.
 8143            .or_else(|| self.find_closest_task(cx))
 8144        else {
 8145            return;
 8146        };
 8147
 8148        let reveal_strategy = action.reveal;
 8149        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8150        cx.spawn_in(window, async move |_, cx| {
 8151            let context = task_context.await?;
 8152            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8153
 8154            let resolved = &mut resolved_task.resolved;
 8155            resolved.reveal = reveal_strategy;
 8156
 8157            workspace
 8158                .update_in(cx, |workspace, window, cx| {
 8159                    workspace.schedule_resolved_task(
 8160                        task_source_kind,
 8161                        resolved_task,
 8162                        false,
 8163                        window,
 8164                        cx,
 8165                    );
 8166                })
 8167                .ok()
 8168        })
 8169        .detach();
 8170    }
 8171
 8172    fn find_closest_task(
 8173        &mut self,
 8174        cx: &mut Context<Self>,
 8175    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8176        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8177
 8178        let ((buffer_id, row), tasks) = self
 8179            .tasks
 8180            .iter()
 8181            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8182
 8183        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8184        let tasks = Arc::new(tasks.to_owned());
 8185        Some((buffer, *row, tasks))
 8186    }
 8187
 8188    fn find_enclosing_node_task(
 8189        &mut self,
 8190        cx: &mut Context<Self>,
 8191    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8192        let snapshot = self.buffer.read(cx).snapshot(cx);
 8193        let offset = self.selections.newest::<usize>(cx).head();
 8194        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8195        let buffer_id = excerpt.buffer().remote_id();
 8196
 8197        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8198        let mut cursor = layer.node().walk();
 8199
 8200        while cursor.goto_first_child_for_byte(offset).is_some() {
 8201            if cursor.node().end_byte() == offset {
 8202                cursor.goto_next_sibling();
 8203            }
 8204        }
 8205
 8206        // Ascend to the smallest ancestor that contains the range and has a task.
 8207        loop {
 8208            let node = cursor.node();
 8209            let node_range = node.byte_range();
 8210            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8211
 8212            // Check if this node contains our offset
 8213            if node_range.start <= offset && node_range.end >= offset {
 8214                // If it contains offset, check for task
 8215                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8216                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8217                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8218                }
 8219            }
 8220
 8221            if !cursor.goto_parent() {
 8222                break;
 8223            }
 8224        }
 8225        None
 8226    }
 8227
 8228    fn render_run_indicator(
 8229        &self,
 8230        _style: &EditorStyle,
 8231        is_active: bool,
 8232        row: DisplayRow,
 8233        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8234        cx: &mut Context<Self>,
 8235    ) -> IconButton {
 8236        let color = Color::Muted;
 8237        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8238
 8239        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8240            .shape(ui::IconButtonShape::Square)
 8241            .icon_size(IconSize::XSmall)
 8242            .icon_color(color)
 8243            .toggle_state(is_active)
 8244            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8245                let quick_launch = e.down.button == MouseButton::Left;
 8246                window.focus(&editor.focus_handle(cx));
 8247                editor.toggle_code_actions(
 8248                    &ToggleCodeActions {
 8249                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8250                        quick_launch,
 8251                    },
 8252                    window,
 8253                    cx,
 8254                );
 8255            }))
 8256            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8257                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8258            }))
 8259    }
 8260
 8261    pub fn context_menu_visible(&self) -> bool {
 8262        !self.edit_prediction_preview_is_active()
 8263            && self
 8264                .context_menu
 8265                .borrow()
 8266                .as_ref()
 8267                .map_or(false, |menu| menu.visible())
 8268    }
 8269
 8270    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8271        self.context_menu
 8272            .borrow()
 8273            .as_ref()
 8274            .map(|menu| menu.origin())
 8275    }
 8276
 8277    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8278        self.context_menu_options = Some(options);
 8279    }
 8280
 8281    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8282    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8283
 8284    fn render_edit_prediction_popover(
 8285        &mut self,
 8286        text_bounds: &Bounds<Pixels>,
 8287        content_origin: gpui::Point<Pixels>,
 8288        right_margin: Pixels,
 8289        editor_snapshot: &EditorSnapshot,
 8290        visible_row_range: Range<DisplayRow>,
 8291        scroll_top: f32,
 8292        scroll_bottom: f32,
 8293        line_layouts: &[LineWithInvisibles],
 8294        line_height: Pixels,
 8295        scroll_pixel_position: gpui::Point<Pixels>,
 8296        newest_selection_head: Option<DisplayPoint>,
 8297        editor_width: Pixels,
 8298        style: &EditorStyle,
 8299        window: &mut Window,
 8300        cx: &mut App,
 8301    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8302        if self.mode().is_minimap() {
 8303            return None;
 8304        }
 8305        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8306
 8307        if self.edit_prediction_visible_in_cursor_popover(true) {
 8308            return None;
 8309        }
 8310
 8311        match &active_inline_completion.completion {
 8312            InlineCompletion::Move { target, .. } => {
 8313                let target_display_point = target.to_display_point(editor_snapshot);
 8314
 8315                if self.edit_prediction_requires_modifier() {
 8316                    if !self.edit_prediction_preview_is_active() {
 8317                        return None;
 8318                    }
 8319
 8320                    self.render_edit_prediction_modifier_jump_popover(
 8321                        text_bounds,
 8322                        content_origin,
 8323                        visible_row_range,
 8324                        line_layouts,
 8325                        line_height,
 8326                        scroll_pixel_position,
 8327                        newest_selection_head,
 8328                        target_display_point,
 8329                        window,
 8330                        cx,
 8331                    )
 8332                } else {
 8333                    self.render_edit_prediction_eager_jump_popover(
 8334                        text_bounds,
 8335                        content_origin,
 8336                        editor_snapshot,
 8337                        visible_row_range,
 8338                        scroll_top,
 8339                        scroll_bottom,
 8340                        line_height,
 8341                        scroll_pixel_position,
 8342                        target_display_point,
 8343                        editor_width,
 8344                        window,
 8345                        cx,
 8346                    )
 8347                }
 8348            }
 8349            InlineCompletion::Edit {
 8350                display_mode: EditDisplayMode::Inline,
 8351                ..
 8352            } => None,
 8353            InlineCompletion::Edit {
 8354                display_mode: EditDisplayMode::TabAccept,
 8355                edits,
 8356                ..
 8357            } => {
 8358                let range = &edits.first()?.0;
 8359                let target_display_point = range.end.to_display_point(editor_snapshot);
 8360
 8361                self.render_edit_prediction_end_of_line_popover(
 8362                    "Accept",
 8363                    editor_snapshot,
 8364                    visible_row_range,
 8365                    target_display_point,
 8366                    line_height,
 8367                    scroll_pixel_position,
 8368                    content_origin,
 8369                    editor_width,
 8370                    window,
 8371                    cx,
 8372                )
 8373            }
 8374            InlineCompletion::Edit {
 8375                edits,
 8376                edit_preview,
 8377                display_mode: EditDisplayMode::DiffPopover,
 8378                snapshot,
 8379            } => self.render_edit_prediction_diff_popover(
 8380                text_bounds,
 8381                content_origin,
 8382                right_margin,
 8383                editor_snapshot,
 8384                visible_row_range,
 8385                line_layouts,
 8386                line_height,
 8387                scroll_pixel_position,
 8388                newest_selection_head,
 8389                editor_width,
 8390                style,
 8391                edits,
 8392                edit_preview,
 8393                snapshot,
 8394                window,
 8395                cx,
 8396            ),
 8397        }
 8398    }
 8399
 8400    fn render_edit_prediction_modifier_jump_popover(
 8401        &mut self,
 8402        text_bounds: &Bounds<Pixels>,
 8403        content_origin: gpui::Point<Pixels>,
 8404        visible_row_range: Range<DisplayRow>,
 8405        line_layouts: &[LineWithInvisibles],
 8406        line_height: Pixels,
 8407        scroll_pixel_position: gpui::Point<Pixels>,
 8408        newest_selection_head: Option<DisplayPoint>,
 8409        target_display_point: DisplayPoint,
 8410        window: &mut Window,
 8411        cx: &mut App,
 8412    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8413        let scrolled_content_origin =
 8414            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8415
 8416        const SCROLL_PADDING_Y: Pixels = px(12.);
 8417
 8418        if target_display_point.row() < visible_row_range.start {
 8419            return self.render_edit_prediction_scroll_popover(
 8420                |_| SCROLL_PADDING_Y,
 8421                IconName::ArrowUp,
 8422                visible_row_range,
 8423                line_layouts,
 8424                newest_selection_head,
 8425                scrolled_content_origin,
 8426                window,
 8427                cx,
 8428            );
 8429        } else if target_display_point.row() >= visible_row_range.end {
 8430            return self.render_edit_prediction_scroll_popover(
 8431                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8432                IconName::ArrowDown,
 8433                visible_row_range,
 8434                line_layouts,
 8435                newest_selection_head,
 8436                scrolled_content_origin,
 8437                window,
 8438                cx,
 8439            );
 8440        }
 8441
 8442        const POLE_WIDTH: Pixels = px(2.);
 8443
 8444        let line_layout =
 8445            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8446        let target_column = target_display_point.column() as usize;
 8447
 8448        let target_x = line_layout.x_for_index(target_column);
 8449        let target_y =
 8450            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8451
 8452        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8453
 8454        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8455        border_color.l += 0.001;
 8456
 8457        let mut element = v_flex()
 8458            .items_end()
 8459            .when(flag_on_right, |el| el.items_start())
 8460            .child(if flag_on_right {
 8461                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8462                    .rounded_bl(px(0.))
 8463                    .rounded_tl(px(0.))
 8464                    .border_l_2()
 8465                    .border_color(border_color)
 8466            } else {
 8467                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8468                    .rounded_br(px(0.))
 8469                    .rounded_tr(px(0.))
 8470                    .border_r_2()
 8471                    .border_color(border_color)
 8472            })
 8473            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8474            .into_any();
 8475
 8476        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8477
 8478        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8479            - point(
 8480                if flag_on_right {
 8481                    POLE_WIDTH
 8482                } else {
 8483                    size.width - POLE_WIDTH
 8484                },
 8485                size.height - line_height,
 8486            );
 8487
 8488        origin.x = origin.x.max(content_origin.x);
 8489
 8490        element.prepaint_at(origin, window, cx);
 8491
 8492        Some((element, origin))
 8493    }
 8494
 8495    fn render_edit_prediction_scroll_popover(
 8496        &mut self,
 8497        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8498        scroll_icon: IconName,
 8499        visible_row_range: Range<DisplayRow>,
 8500        line_layouts: &[LineWithInvisibles],
 8501        newest_selection_head: Option<DisplayPoint>,
 8502        scrolled_content_origin: gpui::Point<Pixels>,
 8503        window: &mut Window,
 8504        cx: &mut App,
 8505    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8506        let mut element = self
 8507            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8508            .into_any();
 8509
 8510        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8511
 8512        let cursor = newest_selection_head?;
 8513        let cursor_row_layout =
 8514            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8515        let cursor_column = cursor.column() as usize;
 8516
 8517        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8518
 8519        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8520
 8521        element.prepaint_at(origin, window, cx);
 8522        Some((element, origin))
 8523    }
 8524
 8525    fn render_edit_prediction_eager_jump_popover(
 8526        &mut self,
 8527        text_bounds: &Bounds<Pixels>,
 8528        content_origin: gpui::Point<Pixels>,
 8529        editor_snapshot: &EditorSnapshot,
 8530        visible_row_range: Range<DisplayRow>,
 8531        scroll_top: f32,
 8532        scroll_bottom: f32,
 8533        line_height: Pixels,
 8534        scroll_pixel_position: gpui::Point<Pixels>,
 8535        target_display_point: DisplayPoint,
 8536        editor_width: Pixels,
 8537        window: &mut Window,
 8538        cx: &mut App,
 8539    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8540        if target_display_point.row().as_f32() < scroll_top {
 8541            let mut element = self
 8542                .render_edit_prediction_line_popover(
 8543                    "Jump to Edit",
 8544                    Some(IconName::ArrowUp),
 8545                    window,
 8546                    cx,
 8547                )?
 8548                .into_any();
 8549
 8550            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8551            let offset = point(
 8552                (text_bounds.size.width - size.width) / 2.,
 8553                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8554            );
 8555
 8556            let origin = text_bounds.origin + offset;
 8557            element.prepaint_at(origin, window, cx);
 8558            Some((element, origin))
 8559        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8560            let mut element = self
 8561                .render_edit_prediction_line_popover(
 8562                    "Jump to Edit",
 8563                    Some(IconName::ArrowDown),
 8564                    window,
 8565                    cx,
 8566                )?
 8567                .into_any();
 8568
 8569            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8570            let offset = point(
 8571                (text_bounds.size.width - size.width) / 2.,
 8572                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8573            );
 8574
 8575            let origin = text_bounds.origin + offset;
 8576            element.prepaint_at(origin, window, cx);
 8577            Some((element, origin))
 8578        } else {
 8579            self.render_edit_prediction_end_of_line_popover(
 8580                "Jump to Edit",
 8581                editor_snapshot,
 8582                visible_row_range,
 8583                target_display_point,
 8584                line_height,
 8585                scroll_pixel_position,
 8586                content_origin,
 8587                editor_width,
 8588                window,
 8589                cx,
 8590            )
 8591        }
 8592    }
 8593
 8594    fn render_edit_prediction_end_of_line_popover(
 8595        self: &mut Editor,
 8596        label: &'static str,
 8597        editor_snapshot: &EditorSnapshot,
 8598        visible_row_range: Range<DisplayRow>,
 8599        target_display_point: DisplayPoint,
 8600        line_height: Pixels,
 8601        scroll_pixel_position: gpui::Point<Pixels>,
 8602        content_origin: gpui::Point<Pixels>,
 8603        editor_width: Pixels,
 8604        window: &mut Window,
 8605        cx: &mut App,
 8606    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8607        let target_line_end = DisplayPoint::new(
 8608            target_display_point.row(),
 8609            editor_snapshot.line_len(target_display_point.row()),
 8610        );
 8611
 8612        let mut element = self
 8613            .render_edit_prediction_line_popover(label, None, window, cx)?
 8614            .into_any();
 8615
 8616        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8617
 8618        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8619
 8620        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8621        let mut origin = start_point
 8622            + line_origin
 8623            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8624        origin.x = origin.x.max(content_origin.x);
 8625
 8626        let max_x = content_origin.x + editor_width - size.width;
 8627
 8628        if origin.x > max_x {
 8629            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8630
 8631            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8632                origin.y += offset;
 8633                IconName::ArrowUp
 8634            } else {
 8635                origin.y -= offset;
 8636                IconName::ArrowDown
 8637            };
 8638
 8639            element = self
 8640                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8641                .into_any();
 8642
 8643            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8644
 8645            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8646        }
 8647
 8648        element.prepaint_at(origin, window, cx);
 8649        Some((element, origin))
 8650    }
 8651
 8652    fn render_edit_prediction_diff_popover(
 8653        self: &Editor,
 8654        text_bounds: &Bounds<Pixels>,
 8655        content_origin: gpui::Point<Pixels>,
 8656        right_margin: Pixels,
 8657        editor_snapshot: &EditorSnapshot,
 8658        visible_row_range: Range<DisplayRow>,
 8659        line_layouts: &[LineWithInvisibles],
 8660        line_height: Pixels,
 8661        scroll_pixel_position: gpui::Point<Pixels>,
 8662        newest_selection_head: Option<DisplayPoint>,
 8663        editor_width: Pixels,
 8664        style: &EditorStyle,
 8665        edits: &Vec<(Range<Anchor>, String)>,
 8666        edit_preview: &Option<language::EditPreview>,
 8667        snapshot: &language::BufferSnapshot,
 8668        window: &mut Window,
 8669        cx: &mut App,
 8670    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8671        let edit_start = edits
 8672            .first()
 8673            .unwrap()
 8674            .0
 8675            .start
 8676            .to_display_point(editor_snapshot);
 8677        let edit_end = edits
 8678            .last()
 8679            .unwrap()
 8680            .0
 8681            .end
 8682            .to_display_point(editor_snapshot);
 8683
 8684        let is_visible = visible_row_range.contains(&edit_start.row())
 8685            || visible_row_range.contains(&edit_end.row());
 8686        if !is_visible {
 8687            return None;
 8688        }
 8689
 8690        let highlighted_edits =
 8691            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8692
 8693        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8694        let line_count = highlighted_edits.text.lines().count();
 8695
 8696        const BORDER_WIDTH: Pixels = px(1.);
 8697
 8698        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8699        let has_keybind = keybind.is_some();
 8700
 8701        let mut element = h_flex()
 8702            .items_start()
 8703            .child(
 8704                h_flex()
 8705                    .bg(cx.theme().colors().editor_background)
 8706                    .border(BORDER_WIDTH)
 8707                    .shadow_sm()
 8708                    .border_color(cx.theme().colors().border)
 8709                    .rounded_l_lg()
 8710                    .when(line_count > 1, |el| el.rounded_br_lg())
 8711                    .pr_1()
 8712                    .child(styled_text),
 8713            )
 8714            .child(
 8715                h_flex()
 8716                    .h(line_height + BORDER_WIDTH * 2.)
 8717                    .px_1p5()
 8718                    .gap_1()
 8719                    // Workaround: For some reason, there's a gap if we don't do this
 8720                    .ml(-BORDER_WIDTH)
 8721                    .shadow(vec![gpui::BoxShadow {
 8722                        color: gpui::black().opacity(0.05),
 8723                        offset: point(px(1.), px(1.)),
 8724                        blur_radius: px(2.),
 8725                        spread_radius: px(0.),
 8726                    }])
 8727                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8728                    .border(BORDER_WIDTH)
 8729                    .border_color(cx.theme().colors().border)
 8730                    .rounded_r_lg()
 8731                    .id("edit_prediction_diff_popover_keybind")
 8732                    .when(!has_keybind, |el| {
 8733                        let status_colors = cx.theme().status();
 8734
 8735                        el.bg(status_colors.error_background)
 8736                            .border_color(status_colors.error.opacity(0.6))
 8737                            .child(Icon::new(IconName::Info).color(Color::Error))
 8738                            .cursor_default()
 8739                            .hoverable_tooltip(move |_window, cx| {
 8740                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8741                            })
 8742                    })
 8743                    .children(keybind),
 8744            )
 8745            .into_any();
 8746
 8747        let longest_row =
 8748            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8749        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8750            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8751        } else {
 8752            layout_line(
 8753                longest_row,
 8754                editor_snapshot,
 8755                style,
 8756                editor_width,
 8757                |_| false,
 8758                window,
 8759                cx,
 8760            )
 8761            .width
 8762        };
 8763
 8764        let viewport_bounds =
 8765            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8766                right: -right_margin,
 8767                ..Default::default()
 8768            });
 8769
 8770        let x_after_longest =
 8771            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8772                - scroll_pixel_position.x;
 8773
 8774        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8775
 8776        // Fully visible if it can be displayed within the window (allow overlapping other
 8777        // panes). However, this is only allowed if the popover starts within text_bounds.
 8778        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8779            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8780
 8781        let mut origin = if can_position_to_the_right {
 8782            point(
 8783                x_after_longest,
 8784                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8785                    - scroll_pixel_position.y,
 8786            )
 8787        } else {
 8788            let cursor_row = newest_selection_head.map(|head| head.row());
 8789            let above_edit = edit_start
 8790                .row()
 8791                .0
 8792                .checked_sub(line_count as u32)
 8793                .map(DisplayRow);
 8794            let below_edit = Some(edit_end.row() + 1);
 8795            let above_cursor =
 8796                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8797            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8798
 8799            // Place the edit popover adjacent to the edit if there is a location
 8800            // available that is onscreen and does not obscure the cursor. Otherwise,
 8801            // place it adjacent to the cursor.
 8802            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8803                .into_iter()
 8804                .flatten()
 8805                .find(|&start_row| {
 8806                    let end_row = start_row + line_count as u32;
 8807                    visible_row_range.contains(&start_row)
 8808                        && visible_row_range.contains(&end_row)
 8809                        && cursor_row.map_or(true, |cursor_row| {
 8810                            !((start_row..end_row).contains(&cursor_row))
 8811                        })
 8812                })?;
 8813
 8814            content_origin
 8815                + point(
 8816                    -scroll_pixel_position.x,
 8817                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8818                )
 8819        };
 8820
 8821        origin.x -= BORDER_WIDTH;
 8822
 8823        window.defer_draw(element, origin, 1);
 8824
 8825        // Do not return an element, since it will already be drawn due to defer_draw.
 8826        None
 8827    }
 8828
 8829    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8830        px(30.)
 8831    }
 8832
 8833    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8834        if self.read_only(cx) {
 8835            cx.theme().players().read_only()
 8836        } else {
 8837            self.style.as_ref().unwrap().local_player
 8838        }
 8839    }
 8840
 8841    fn render_edit_prediction_accept_keybind(
 8842        &self,
 8843        window: &mut Window,
 8844        cx: &App,
 8845    ) -> Option<AnyElement> {
 8846        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8847        let accept_keystroke = accept_binding.keystroke()?;
 8848
 8849        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8850
 8851        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8852            Color::Accent
 8853        } else {
 8854            Color::Muted
 8855        };
 8856
 8857        h_flex()
 8858            .px_0p5()
 8859            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8860            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8861            .text_size(TextSize::XSmall.rems(cx))
 8862            .child(h_flex().children(ui::render_modifiers(
 8863                &accept_keystroke.modifiers,
 8864                PlatformStyle::platform(),
 8865                Some(modifiers_color),
 8866                Some(IconSize::XSmall.rems().into()),
 8867                true,
 8868            )))
 8869            .when(is_platform_style_mac, |parent| {
 8870                parent.child(accept_keystroke.key.clone())
 8871            })
 8872            .when(!is_platform_style_mac, |parent| {
 8873                parent.child(
 8874                    Key::new(
 8875                        util::capitalize(&accept_keystroke.key),
 8876                        Some(Color::Default),
 8877                    )
 8878                    .size(Some(IconSize::XSmall.rems().into())),
 8879                )
 8880            })
 8881            .into_any()
 8882            .into()
 8883    }
 8884
 8885    fn render_edit_prediction_line_popover(
 8886        &self,
 8887        label: impl Into<SharedString>,
 8888        icon: Option<IconName>,
 8889        window: &mut Window,
 8890        cx: &App,
 8891    ) -> Option<Stateful<Div>> {
 8892        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8893
 8894        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8895        let has_keybind = keybind.is_some();
 8896
 8897        let result = h_flex()
 8898            .id("ep-line-popover")
 8899            .py_0p5()
 8900            .pl_1()
 8901            .pr(padding_right)
 8902            .gap_1()
 8903            .rounded_md()
 8904            .border_1()
 8905            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8906            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8907            .shadow_sm()
 8908            .when(!has_keybind, |el| {
 8909                let status_colors = cx.theme().status();
 8910
 8911                el.bg(status_colors.error_background)
 8912                    .border_color(status_colors.error.opacity(0.6))
 8913                    .pl_2()
 8914                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8915                    .cursor_default()
 8916                    .hoverable_tooltip(move |_window, cx| {
 8917                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8918                    })
 8919            })
 8920            .children(keybind)
 8921            .child(
 8922                Label::new(label)
 8923                    .size(LabelSize::Small)
 8924                    .when(!has_keybind, |el| {
 8925                        el.color(cx.theme().status().error.into()).strikethrough()
 8926                    }),
 8927            )
 8928            .when(!has_keybind, |el| {
 8929                el.child(
 8930                    h_flex().ml_1().child(
 8931                        Icon::new(IconName::Info)
 8932                            .size(IconSize::Small)
 8933                            .color(cx.theme().status().error.into()),
 8934                    ),
 8935                )
 8936            })
 8937            .when_some(icon, |element, icon| {
 8938                element.child(
 8939                    div()
 8940                        .mt(px(1.5))
 8941                        .child(Icon::new(icon).size(IconSize::Small)),
 8942                )
 8943            });
 8944
 8945        Some(result)
 8946    }
 8947
 8948    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8949        let accent_color = cx.theme().colors().text_accent;
 8950        let editor_bg_color = cx.theme().colors().editor_background;
 8951        editor_bg_color.blend(accent_color.opacity(0.1))
 8952    }
 8953
 8954    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8955        let accent_color = cx.theme().colors().text_accent;
 8956        let editor_bg_color = cx.theme().colors().editor_background;
 8957        editor_bg_color.blend(accent_color.opacity(0.6))
 8958    }
 8959
 8960    fn render_edit_prediction_cursor_popover(
 8961        &self,
 8962        min_width: Pixels,
 8963        max_width: Pixels,
 8964        cursor_point: Point,
 8965        style: &EditorStyle,
 8966        accept_keystroke: Option<&gpui::Keystroke>,
 8967        _window: &Window,
 8968        cx: &mut Context<Editor>,
 8969    ) -> Option<AnyElement> {
 8970        let provider = self.edit_prediction_provider.as_ref()?;
 8971
 8972        if provider.provider.needs_terms_acceptance(cx) {
 8973            return Some(
 8974                h_flex()
 8975                    .min_w(min_width)
 8976                    .flex_1()
 8977                    .px_2()
 8978                    .py_1()
 8979                    .gap_3()
 8980                    .elevation_2(cx)
 8981                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8982                    .id("accept-terms")
 8983                    .cursor_pointer()
 8984                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8985                    .on_click(cx.listener(|this, _event, window, cx| {
 8986                        cx.stop_propagation();
 8987                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8988                        window.dispatch_action(
 8989                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8990                            cx,
 8991                        );
 8992                    }))
 8993                    .child(
 8994                        h_flex()
 8995                            .flex_1()
 8996                            .gap_2()
 8997                            .child(Icon::new(IconName::ZedPredict))
 8998                            .child(Label::new("Accept Terms of Service"))
 8999                            .child(div().w_full())
 9000                            .child(
 9001                                Icon::new(IconName::ArrowUpRight)
 9002                                    .color(Color::Muted)
 9003                                    .size(IconSize::Small),
 9004                            )
 9005                            .into_any_element(),
 9006                    )
 9007                    .into_any(),
 9008            );
 9009        }
 9010
 9011        let is_refreshing = provider.provider.is_refreshing(cx);
 9012
 9013        fn pending_completion_container() -> Div {
 9014            h_flex()
 9015                .h_full()
 9016                .flex_1()
 9017                .gap_2()
 9018                .child(Icon::new(IconName::ZedPredict))
 9019        }
 9020
 9021        let completion = match &self.active_inline_completion {
 9022            Some(prediction) => {
 9023                if !self.has_visible_completions_menu() {
 9024                    const RADIUS: Pixels = px(6.);
 9025                    const BORDER_WIDTH: Pixels = px(1.);
 9026
 9027                    return Some(
 9028                        h_flex()
 9029                            .elevation_2(cx)
 9030                            .border(BORDER_WIDTH)
 9031                            .border_color(cx.theme().colors().border)
 9032                            .when(accept_keystroke.is_none(), |el| {
 9033                                el.border_color(cx.theme().status().error)
 9034                            })
 9035                            .rounded(RADIUS)
 9036                            .rounded_tl(px(0.))
 9037                            .overflow_hidden()
 9038                            .child(div().px_1p5().child(match &prediction.completion {
 9039                                InlineCompletion::Move { target, snapshot } => {
 9040                                    use text::ToPoint as _;
 9041                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9042                                    {
 9043                                        Icon::new(IconName::ZedPredictDown)
 9044                                    } else {
 9045                                        Icon::new(IconName::ZedPredictUp)
 9046                                    }
 9047                                }
 9048                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9049                            }))
 9050                            .child(
 9051                                h_flex()
 9052                                    .gap_1()
 9053                                    .py_1()
 9054                                    .px_2()
 9055                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9056                                    .border_l_1()
 9057                                    .border_color(cx.theme().colors().border)
 9058                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9059                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9060                                        el.child(
 9061                                            Label::new("Hold")
 9062                                                .size(LabelSize::Small)
 9063                                                .when(accept_keystroke.is_none(), |el| {
 9064                                                    el.strikethrough()
 9065                                                })
 9066                                                .line_height_style(LineHeightStyle::UiLabel),
 9067                                        )
 9068                                    })
 9069                                    .id("edit_prediction_cursor_popover_keybind")
 9070                                    .when(accept_keystroke.is_none(), |el| {
 9071                                        let status_colors = cx.theme().status();
 9072
 9073                                        el.bg(status_colors.error_background)
 9074                                            .border_color(status_colors.error.opacity(0.6))
 9075                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9076                                            .cursor_default()
 9077                                            .hoverable_tooltip(move |_window, cx| {
 9078                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9079                                                    .into()
 9080                                            })
 9081                                    })
 9082                                    .when_some(
 9083                                        accept_keystroke.as_ref(),
 9084                                        |el, accept_keystroke| {
 9085                                            el.child(h_flex().children(ui::render_modifiers(
 9086                                                &accept_keystroke.modifiers,
 9087                                                PlatformStyle::platform(),
 9088                                                Some(Color::Default),
 9089                                                Some(IconSize::XSmall.rems().into()),
 9090                                                false,
 9091                                            )))
 9092                                        },
 9093                                    ),
 9094                            )
 9095                            .into_any(),
 9096                    );
 9097                }
 9098
 9099                self.render_edit_prediction_cursor_popover_preview(
 9100                    prediction,
 9101                    cursor_point,
 9102                    style,
 9103                    cx,
 9104                )?
 9105            }
 9106
 9107            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9108                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9109                    stale_completion,
 9110                    cursor_point,
 9111                    style,
 9112                    cx,
 9113                )?,
 9114
 9115                None => {
 9116                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9117                }
 9118            },
 9119
 9120            None => pending_completion_container().child(Label::new("No Prediction")),
 9121        };
 9122
 9123        let completion = if is_refreshing {
 9124            completion
 9125                .with_animation(
 9126                    "loading-completion",
 9127                    Animation::new(Duration::from_secs(2))
 9128                        .repeat()
 9129                        .with_easing(pulsating_between(0.4, 0.8)),
 9130                    |label, delta| label.opacity(delta),
 9131                )
 9132                .into_any_element()
 9133        } else {
 9134            completion.into_any_element()
 9135        };
 9136
 9137        let has_completion = self.active_inline_completion.is_some();
 9138
 9139        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9140        Some(
 9141            h_flex()
 9142                .min_w(min_width)
 9143                .max_w(max_width)
 9144                .flex_1()
 9145                .elevation_2(cx)
 9146                .border_color(cx.theme().colors().border)
 9147                .child(
 9148                    div()
 9149                        .flex_1()
 9150                        .py_1()
 9151                        .px_2()
 9152                        .overflow_hidden()
 9153                        .child(completion),
 9154                )
 9155                .when_some(accept_keystroke, |el, accept_keystroke| {
 9156                    if !accept_keystroke.modifiers.modified() {
 9157                        return el;
 9158                    }
 9159
 9160                    el.child(
 9161                        h_flex()
 9162                            .h_full()
 9163                            .border_l_1()
 9164                            .rounded_r_lg()
 9165                            .border_color(cx.theme().colors().border)
 9166                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9167                            .gap_1()
 9168                            .py_1()
 9169                            .px_2()
 9170                            .child(
 9171                                h_flex()
 9172                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9173                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9174                                    .child(h_flex().children(ui::render_modifiers(
 9175                                        &accept_keystroke.modifiers,
 9176                                        PlatformStyle::platform(),
 9177                                        Some(if !has_completion {
 9178                                            Color::Muted
 9179                                        } else {
 9180                                            Color::Default
 9181                                        }),
 9182                                        None,
 9183                                        false,
 9184                                    ))),
 9185                            )
 9186                            .child(Label::new("Preview").into_any_element())
 9187                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9188                    )
 9189                })
 9190                .into_any(),
 9191        )
 9192    }
 9193
 9194    fn render_edit_prediction_cursor_popover_preview(
 9195        &self,
 9196        completion: &InlineCompletionState,
 9197        cursor_point: Point,
 9198        style: &EditorStyle,
 9199        cx: &mut Context<Editor>,
 9200    ) -> Option<Div> {
 9201        use text::ToPoint as _;
 9202
 9203        fn render_relative_row_jump(
 9204            prefix: impl Into<String>,
 9205            current_row: u32,
 9206            target_row: u32,
 9207        ) -> Div {
 9208            let (row_diff, arrow) = if target_row < current_row {
 9209                (current_row - target_row, IconName::ArrowUp)
 9210            } else {
 9211                (target_row - current_row, IconName::ArrowDown)
 9212            };
 9213
 9214            h_flex()
 9215                .child(
 9216                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9217                        .color(Color::Muted)
 9218                        .size(LabelSize::Small),
 9219                )
 9220                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9221        }
 9222
 9223        match &completion.completion {
 9224            InlineCompletion::Move {
 9225                target, snapshot, ..
 9226            } => Some(
 9227                h_flex()
 9228                    .px_2()
 9229                    .gap_2()
 9230                    .flex_1()
 9231                    .child(
 9232                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9233                            Icon::new(IconName::ZedPredictDown)
 9234                        } else {
 9235                            Icon::new(IconName::ZedPredictUp)
 9236                        },
 9237                    )
 9238                    .child(Label::new("Jump to Edit")),
 9239            ),
 9240
 9241            InlineCompletion::Edit {
 9242                edits,
 9243                edit_preview,
 9244                snapshot,
 9245                display_mode: _,
 9246            } => {
 9247                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9248
 9249                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9250                    &snapshot,
 9251                    &edits,
 9252                    edit_preview.as_ref()?,
 9253                    true,
 9254                    cx,
 9255                )
 9256                .first_line_preview();
 9257
 9258                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9259                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9260
 9261                let preview = h_flex()
 9262                    .gap_1()
 9263                    .min_w_16()
 9264                    .child(styled_text)
 9265                    .when(has_more_lines, |parent| parent.child(""));
 9266
 9267                let left = if first_edit_row != cursor_point.row {
 9268                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9269                        .into_any_element()
 9270                } else {
 9271                    Icon::new(IconName::ZedPredict).into_any_element()
 9272                };
 9273
 9274                Some(
 9275                    h_flex()
 9276                        .h_full()
 9277                        .flex_1()
 9278                        .gap_2()
 9279                        .pr_1()
 9280                        .overflow_x_hidden()
 9281                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9282                        .child(left)
 9283                        .child(preview),
 9284                )
 9285            }
 9286        }
 9287    }
 9288
 9289    pub fn render_context_menu(
 9290        &self,
 9291        style: &EditorStyle,
 9292        max_height_in_lines: u32,
 9293        window: &mut Window,
 9294        cx: &mut Context<Editor>,
 9295    ) -> Option<AnyElement> {
 9296        let menu = self.context_menu.borrow();
 9297        let menu = menu.as_ref()?;
 9298        if !menu.visible() {
 9299            return None;
 9300        };
 9301        Some(menu.render(style, max_height_in_lines, window, cx))
 9302    }
 9303
 9304    fn render_context_menu_aside(
 9305        &mut self,
 9306        max_size: Size<Pixels>,
 9307        window: &mut Window,
 9308        cx: &mut Context<Editor>,
 9309    ) -> Option<AnyElement> {
 9310        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9311            if menu.visible() {
 9312                menu.render_aside(max_size, window, cx)
 9313            } else {
 9314                None
 9315            }
 9316        })
 9317    }
 9318
 9319    fn hide_context_menu(
 9320        &mut self,
 9321        window: &mut Window,
 9322        cx: &mut Context<Self>,
 9323    ) -> Option<CodeContextMenu> {
 9324        cx.notify();
 9325        self.completion_tasks.clear();
 9326        let context_menu = self.context_menu.borrow_mut().take();
 9327        self.stale_inline_completion_in_menu.take();
 9328        self.update_visible_inline_completion(window, cx);
 9329        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9330            if let Some(completion_provider) = &self.completion_provider {
 9331                completion_provider.selection_changed(None, window, cx);
 9332            }
 9333        }
 9334        context_menu
 9335    }
 9336
 9337    fn show_snippet_choices(
 9338        &mut self,
 9339        choices: &Vec<String>,
 9340        selection: Range<Anchor>,
 9341        cx: &mut Context<Self>,
 9342    ) {
 9343        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9344            (Some(a), Some(b)) if a == b => a,
 9345            _ => {
 9346                log::error!("expected anchor range to have matching buffer IDs");
 9347                return;
 9348            }
 9349        };
 9350        let multi_buffer = self.buffer().read(cx);
 9351        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9352            return;
 9353        };
 9354
 9355        let id = post_inc(&mut self.next_completion_id);
 9356        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9357        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9358            CompletionsMenu::new_snippet_choices(
 9359                id,
 9360                true,
 9361                choices,
 9362                selection,
 9363                buffer,
 9364                snippet_sort_order,
 9365            ),
 9366        ));
 9367    }
 9368
 9369    pub fn insert_snippet(
 9370        &mut self,
 9371        insertion_ranges: &[Range<usize>],
 9372        snippet: Snippet,
 9373        window: &mut Window,
 9374        cx: &mut Context<Self>,
 9375    ) -> Result<()> {
 9376        struct Tabstop<T> {
 9377            is_end_tabstop: bool,
 9378            ranges: Vec<Range<T>>,
 9379            choices: Option<Vec<String>>,
 9380        }
 9381
 9382        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9383            let snippet_text: Arc<str> = snippet.text.clone().into();
 9384            let edits = insertion_ranges
 9385                .iter()
 9386                .cloned()
 9387                .map(|range| (range, snippet_text.clone()));
 9388            let autoindent_mode = AutoindentMode::Block {
 9389                original_indent_columns: Vec::new(),
 9390            };
 9391            buffer.edit(edits, Some(autoindent_mode), cx);
 9392
 9393            let snapshot = &*buffer.read(cx);
 9394            let snippet = &snippet;
 9395            snippet
 9396                .tabstops
 9397                .iter()
 9398                .map(|tabstop| {
 9399                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9400                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9401                    });
 9402                    let mut tabstop_ranges = tabstop
 9403                        .ranges
 9404                        .iter()
 9405                        .flat_map(|tabstop_range| {
 9406                            let mut delta = 0_isize;
 9407                            insertion_ranges.iter().map(move |insertion_range| {
 9408                                let insertion_start = insertion_range.start as isize + delta;
 9409                                delta +=
 9410                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9411
 9412                                let start = ((insertion_start + tabstop_range.start) as usize)
 9413                                    .min(snapshot.len());
 9414                                let end = ((insertion_start + tabstop_range.end) as usize)
 9415                                    .min(snapshot.len());
 9416                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9417                            })
 9418                        })
 9419                        .collect::<Vec<_>>();
 9420                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9421
 9422                    Tabstop {
 9423                        is_end_tabstop,
 9424                        ranges: tabstop_ranges,
 9425                        choices: tabstop.choices.clone(),
 9426                    }
 9427                })
 9428                .collect::<Vec<_>>()
 9429        });
 9430        if let Some(tabstop) = tabstops.first() {
 9431            self.change_selections(Default::default(), window, cx, |s| {
 9432                // Reverse order so that the first range is the newest created selection.
 9433                // Completions will use it and autoscroll will prioritize it.
 9434                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9435            });
 9436
 9437            if let Some(choices) = &tabstop.choices {
 9438                if let Some(selection) = tabstop.ranges.first() {
 9439                    self.show_snippet_choices(choices, selection.clone(), cx)
 9440                }
 9441            }
 9442
 9443            // If we're already at the last tabstop and it's at the end of the snippet,
 9444            // we're done, we don't need to keep the state around.
 9445            if !tabstop.is_end_tabstop {
 9446                let choices = tabstops
 9447                    .iter()
 9448                    .map(|tabstop| tabstop.choices.clone())
 9449                    .collect();
 9450
 9451                let ranges = tabstops
 9452                    .into_iter()
 9453                    .map(|tabstop| tabstop.ranges)
 9454                    .collect::<Vec<_>>();
 9455
 9456                self.snippet_stack.push(SnippetState {
 9457                    active_index: 0,
 9458                    ranges,
 9459                    choices,
 9460                });
 9461            }
 9462
 9463            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9464            if self.autoclose_regions.is_empty() {
 9465                let snapshot = self.buffer.read(cx).snapshot(cx);
 9466                for selection in &mut self.selections.all::<Point>(cx) {
 9467                    let selection_head = selection.head();
 9468                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9469                        continue;
 9470                    };
 9471
 9472                    let mut bracket_pair = None;
 9473                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9474                    let prev_chars = snapshot
 9475                        .reversed_chars_at(selection_head)
 9476                        .collect::<String>();
 9477                    for (pair, enabled) in scope.brackets() {
 9478                        if enabled
 9479                            && pair.close
 9480                            && prev_chars.starts_with(pair.start.as_str())
 9481                            && next_chars.starts_with(pair.end.as_str())
 9482                        {
 9483                            bracket_pair = Some(pair.clone());
 9484                            break;
 9485                        }
 9486                    }
 9487                    if let Some(pair) = bracket_pair {
 9488                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9489                        let autoclose_enabled =
 9490                            self.use_autoclose && snapshot_settings.use_autoclose;
 9491                        if autoclose_enabled {
 9492                            let start = snapshot.anchor_after(selection_head);
 9493                            let end = snapshot.anchor_after(selection_head);
 9494                            self.autoclose_regions.push(AutocloseRegion {
 9495                                selection_id: selection.id,
 9496                                range: start..end,
 9497                                pair,
 9498                            });
 9499                        }
 9500                    }
 9501                }
 9502            }
 9503        }
 9504        Ok(())
 9505    }
 9506
 9507    pub fn move_to_next_snippet_tabstop(
 9508        &mut self,
 9509        window: &mut Window,
 9510        cx: &mut Context<Self>,
 9511    ) -> bool {
 9512        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9513    }
 9514
 9515    pub fn move_to_prev_snippet_tabstop(
 9516        &mut self,
 9517        window: &mut Window,
 9518        cx: &mut Context<Self>,
 9519    ) -> bool {
 9520        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9521    }
 9522
 9523    pub fn move_to_snippet_tabstop(
 9524        &mut self,
 9525        bias: Bias,
 9526        window: &mut Window,
 9527        cx: &mut Context<Self>,
 9528    ) -> bool {
 9529        if let Some(mut snippet) = self.snippet_stack.pop() {
 9530            match bias {
 9531                Bias::Left => {
 9532                    if snippet.active_index > 0 {
 9533                        snippet.active_index -= 1;
 9534                    } else {
 9535                        self.snippet_stack.push(snippet);
 9536                        return false;
 9537                    }
 9538                }
 9539                Bias::Right => {
 9540                    if snippet.active_index + 1 < snippet.ranges.len() {
 9541                        snippet.active_index += 1;
 9542                    } else {
 9543                        self.snippet_stack.push(snippet);
 9544                        return false;
 9545                    }
 9546                }
 9547            }
 9548            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9549                self.change_selections(Default::default(), window, cx, |s| {
 9550                    // Reverse order so that the first range is the newest created selection.
 9551                    // Completions will use it and autoscroll will prioritize it.
 9552                    s.select_ranges(current_ranges.iter().rev().cloned())
 9553                });
 9554
 9555                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9556                    if let Some(selection) = current_ranges.first() {
 9557                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9558                    }
 9559                }
 9560
 9561                // If snippet state is not at the last tabstop, push it back on the stack
 9562                if snippet.active_index + 1 < snippet.ranges.len() {
 9563                    self.snippet_stack.push(snippet);
 9564                }
 9565                return true;
 9566            }
 9567        }
 9568
 9569        false
 9570    }
 9571
 9572    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9573        self.transact(window, cx, |this, window, cx| {
 9574            this.select_all(&SelectAll, window, cx);
 9575            this.insert("", window, cx);
 9576        });
 9577    }
 9578
 9579    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9580        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9581        self.transact(window, cx, |this, window, cx| {
 9582            this.select_autoclose_pair(window, cx);
 9583            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9584            if !this.linked_edit_ranges.is_empty() {
 9585                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9586                let snapshot = this.buffer.read(cx).snapshot(cx);
 9587
 9588                for selection in selections.iter() {
 9589                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9590                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9591                    if selection_start.buffer_id != selection_end.buffer_id {
 9592                        continue;
 9593                    }
 9594                    if let Some(ranges) =
 9595                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9596                    {
 9597                        for (buffer, entries) in ranges {
 9598                            linked_ranges.entry(buffer).or_default().extend(entries);
 9599                        }
 9600                    }
 9601                }
 9602            }
 9603
 9604            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9605            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9606            for selection in &mut selections {
 9607                if selection.is_empty() {
 9608                    let old_head = selection.head();
 9609                    let mut new_head =
 9610                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9611                            .to_point(&display_map);
 9612                    if let Some((buffer, line_buffer_range)) = display_map
 9613                        .buffer_snapshot
 9614                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9615                    {
 9616                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9617                        let indent_len = match indent_size.kind {
 9618                            IndentKind::Space => {
 9619                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9620                            }
 9621                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9622                        };
 9623                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9624                            let indent_len = indent_len.get();
 9625                            new_head = cmp::min(
 9626                                new_head,
 9627                                MultiBufferPoint::new(
 9628                                    old_head.row,
 9629                                    ((old_head.column - 1) / indent_len) * indent_len,
 9630                                ),
 9631                            );
 9632                        }
 9633                    }
 9634
 9635                    selection.set_head(new_head, SelectionGoal::None);
 9636                }
 9637            }
 9638
 9639            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9640            this.insert("", window, cx);
 9641            let empty_str: Arc<str> = Arc::from("");
 9642            for (buffer, edits) in linked_ranges {
 9643                let snapshot = buffer.read(cx).snapshot();
 9644                use text::ToPoint as TP;
 9645
 9646                let edits = edits
 9647                    .into_iter()
 9648                    .map(|range| {
 9649                        let end_point = TP::to_point(&range.end, &snapshot);
 9650                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9651
 9652                        if end_point == start_point {
 9653                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9654                                .saturating_sub(1);
 9655                            start_point =
 9656                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9657                        };
 9658
 9659                        (start_point..end_point, empty_str.clone())
 9660                    })
 9661                    .sorted_by_key(|(range, _)| range.start)
 9662                    .collect::<Vec<_>>();
 9663                buffer.update(cx, |this, cx| {
 9664                    this.edit(edits, None, cx);
 9665                })
 9666            }
 9667            this.refresh_inline_completion(true, false, window, cx);
 9668            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9669        });
 9670    }
 9671
 9672    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9673        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9674        self.transact(window, cx, |this, window, cx| {
 9675            this.change_selections(Default::default(), window, cx, |s| {
 9676                s.move_with(|map, selection| {
 9677                    if selection.is_empty() {
 9678                        let cursor = movement::right(map, selection.head());
 9679                        selection.end = cursor;
 9680                        selection.reversed = true;
 9681                        selection.goal = SelectionGoal::None;
 9682                    }
 9683                })
 9684            });
 9685            this.insert("", window, cx);
 9686            this.refresh_inline_completion(true, false, window, cx);
 9687        });
 9688    }
 9689
 9690    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9691        if self.mode.is_single_line() {
 9692            cx.propagate();
 9693            return;
 9694        }
 9695
 9696        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9697        if self.move_to_prev_snippet_tabstop(window, cx) {
 9698            return;
 9699        }
 9700        self.outdent(&Outdent, window, cx);
 9701    }
 9702
 9703    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9704        if self.mode.is_single_line() {
 9705            cx.propagate();
 9706            return;
 9707        }
 9708
 9709        if self.move_to_next_snippet_tabstop(window, cx) {
 9710            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9711            return;
 9712        }
 9713        if self.read_only(cx) {
 9714            return;
 9715        }
 9716        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9717        let mut selections = self.selections.all_adjusted(cx);
 9718        let buffer = self.buffer.read(cx);
 9719        let snapshot = buffer.snapshot(cx);
 9720        let rows_iter = selections.iter().map(|s| s.head().row);
 9721        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9722
 9723        let has_some_cursor_in_whitespace = selections
 9724            .iter()
 9725            .filter(|selection| selection.is_empty())
 9726            .any(|selection| {
 9727                let cursor = selection.head();
 9728                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9729                cursor.column < current_indent.len
 9730            });
 9731
 9732        let mut edits = Vec::new();
 9733        let mut prev_edited_row = 0;
 9734        let mut row_delta = 0;
 9735        for selection in &mut selections {
 9736            if selection.start.row != prev_edited_row {
 9737                row_delta = 0;
 9738            }
 9739            prev_edited_row = selection.end.row;
 9740
 9741            // If the selection is non-empty, then increase the indentation of the selected lines.
 9742            if !selection.is_empty() {
 9743                row_delta =
 9744                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9745                continue;
 9746            }
 9747
 9748            let cursor = selection.head();
 9749            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9750            if let Some(suggested_indent) =
 9751                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9752            {
 9753                // Don't do anything if already at suggested indent
 9754                // and there is any other cursor which is not
 9755                if has_some_cursor_in_whitespace
 9756                    && cursor.column == current_indent.len
 9757                    && current_indent.len == suggested_indent.len
 9758                {
 9759                    continue;
 9760                }
 9761
 9762                // Adjust line and move cursor to suggested indent
 9763                // if cursor is not at suggested indent
 9764                if cursor.column < suggested_indent.len
 9765                    && cursor.column <= current_indent.len
 9766                    && current_indent.len <= suggested_indent.len
 9767                {
 9768                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9769                    selection.end = selection.start;
 9770                    if row_delta == 0 {
 9771                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9772                            cursor.row,
 9773                            current_indent,
 9774                            suggested_indent,
 9775                        ));
 9776                        row_delta = suggested_indent.len - current_indent.len;
 9777                    }
 9778                    continue;
 9779                }
 9780
 9781                // If current indent is more than suggested indent
 9782                // only move cursor to current indent and skip indent
 9783                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9784                    selection.start = Point::new(cursor.row, current_indent.len);
 9785                    selection.end = selection.start;
 9786                    continue;
 9787                }
 9788            }
 9789
 9790            // Otherwise, insert a hard or soft tab.
 9791            let settings = buffer.language_settings_at(cursor, cx);
 9792            let tab_size = if settings.hard_tabs {
 9793                IndentSize::tab()
 9794            } else {
 9795                let tab_size = settings.tab_size.get();
 9796                let indent_remainder = snapshot
 9797                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9798                    .flat_map(str::chars)
 9799                    .fold(row_delta % tab_size, |counter: u32, c| {
 9800                        if c == '\t' {
 9801                            0
 9802                        } else {
 9803                            (counter + 1) % tab_size
 9804                        }
 9805                    });
 9806
 9807                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9808                IndentSize::spaces(chars_to_next_tab_stop)
 9809            };
 9810            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9811            selection.end = selection.start;
 9812            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9813            row_delta += tab_size.len;
 9814        }
 9815
 9816        self.transact(window, cx, |this, window, cx| {
 9817            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9818            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9819            this.refresh_inline_completion(true, false, window, cx);
 9820        });
 9821    }
 9822
 9823    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9824        if self.read_only(cx) {
 9825            return;
 9826        }
 9827        if self.mode.is_single_line() {
 9828            cx.propagate();
 9829            return;
 9830        }
 9831
 9832        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9833        let mut selections = self.selections.all::<Point>(cx);
 9834        let mut prev_edited_row = 0;
 9835        let mut row_delta = 0;
 9836        let mut edits = Vec::new();
 9837        let buffer = self.buffer.read(cx);
 9838        let snapshot = buffer.snapshot(cx);
 9839        for selection in &mut selections {
 9840            if selection.start.row != prev_edited_row {
 9841                row_delta = 0;
 9842            }
 9843            prev_edited_row = selection.end.row;
 9844
 9845            row_delta =
 9846                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9847        }
 9848
 9849        self.transact(window, cx, |this, window, cx| {
 9850            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9851            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9852        });
 9853    }
 9854
 9855    fn indent_selection(
 9856        buffer: &MultiBuffer,
 9857        snapshot: &MultiBufferSnapshot,
 9858        selection: &mut Selection<Point>,
 9859        edits: &mut Vec<(Range<Point>, String)>,
 9860        delta_for_start_row: u32,
 9861        cx: &App,
 9862    ) -> u32 {
 9863        let settings = buffer.language_settings_at(selection.start, cx);
 9864        let tab_size = settings.tab_size.get();
 9865        let indent_kind = if settings.hard_tabs {
 9866            IndentKind::Tab
 9867        } else {
 9868            IndentKind::Space
 9869        };
 9870        let mut start_row = selection.start.row;
 9871        let mut end_row = selection.end.row + 1;
 9872
 9873        // If a selection ends at the beginning of a line, don't indent
 9874        // that last line.
 9875        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9876            end_row -= 1;
 9877        }
 9878
 9879        // Avoid re-indenting a row that has already been indented by a
 9880        // previous selection, but still update this selection's column
 9881        // to reflect that indentation.
 9882        if delta_for_start_row > 0 {
 9883            start_row += 1;
 9884            selection.start.column += delta_for_start_row;
 9885            if selection.end.row == selection.start.row {
 9886                selection.end.column += delta_for_start_row;
 9887            }
 9888        }
 9889
 9890        let mut delta_for_end_row = 0;
 9891        let has_multiple_rows = start_row + 1 != end_row;
 9892        for row in start_row..end_row {
 9893            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9894            let indent_delta = match (current_indent.kind, indent_kind) {
 9895                (IndentKind::Space, IndentKind::Space) => {
 9896                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9897                    IndentSize::spaces(columns_to_next_tab_stop)
 9898                }
 9899                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9900                (_, IndentKind::Tab) => IndentSize::tab(),
 9901            };
 9902
 9903            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9904                0
 9905            } else {
 9906                selection.start.column
 9907            };
 9908            let row_start = Point::new(row, start);
 9909            edits.push((
 9910                row_start..row_start,
 9911                indent_delta.chars().collect::<String>(),
 9912            ));
 9913
 9914            // Update this selection's endpoints to reflect the indentation.
 9915            if row == selection.start.row {
 9916                selection.start.column += indent_delta.len;
 9917            }
 9918            if row == selection.end.row {
 9919                selection.end.column += indent_delta.len;
 9920                delta_for_end_row = indent_delta.len;
 9921            }
 9922        }
 9923
 9924        if selection.start.row == selection.end.row {
 9925            delta_for_start_row + delta_for_end_row
 9926        } else {
 9927            delta_for_end_row
 9928        }
 9929    }
 9930
 9931    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9932        if self.read_only(cx) {
 9933            return;
 9934        }
 9935        if self.mode.is_single_line() {
 9936            cx.propagate();
 9937            return;
 9938        }
 9939
 9940        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9941        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9942        let selections = self.selections.all::<Point>(cx);
 9943        let mut deletion_ranges = Vec::new();
 9944        let mut last_outdent = None;
 9945        {
 9946            let buffer = self.buffer.read(cx);
 9947            let snapshot = buffer.snapshot(cx);
 9948            for selection in &selections {
 9949                let settings = buffer.language_settings_at(selection.start, cx);
 9950                let tab_size = settings.tab_size.get();
 9951                let mut rows = selection.spanned_rows(false, &display_map);
 9952
 9953                // Avoid re-outdenting a row that has already been outdented by a
 9954                // previous selection.
 9955                if let Some(last_row) = last_outdent {
 9956                    if last_row == rows.start {
 9957                        rows.start = rows.start.next_row();
 9958                    }
 9959                }
 9960                let has_multiple_rows = rows.len() > 1;
 9961                for row in rows.iter_rows() {
 9962                    let indent_size = snapshot.indent_size_for_line(row);
 9963                    if indent_size.len > 0 {
 9964                        let deletion_len = match indent_size.kind {
 9965                            IndentKind::Space => {
 9966                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9967                                if columns_to_prev_tab_stop == 0 {
 9968                                    tab_size
 9969                                } else {
 9970                                    columns_to_prev_tab_stop
 9971                                }
 9972                            }
 9973                            IndentKind::Tab => 1,
 9974                        };
 9975                        let start = if has_multiple_rows
 9976                            || deletion_len > selection.start.column
 9977                            || indent_size.len < selection.start.column
 9978                        {
 9979                            0
 9980                        } else {
 9981                            selection.start.column - deletion_len
 9982                        };
 9983                        deletion_ranges.push(
 9984                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9985                        );
 9986                        last_outdent = Some(row);
 9987                    }
 9988                }
 9989            }
 9990        }
 9991
 9992        self.transact(window, cx, |this, window, cx| {
 9993            this.buffer.update(cx, |buffer, cx| {
 9994                let empty_str: Arc<str> = Arc::default();
 9995                buffer.edit(
 9996                    deletion_ranges
 9997                        .into_iter()
 9998                        .map(|range| (range, empty_str.clone())),
 9999                    None,
10000                    cx,
10001                );
10002            });
10003            let selections = this.selections.all::<usize>(cx);
10004            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10005        });
10006    }
10007
10008    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10009        if self.read_only(cx) {
10010            return;
10011        }
10012        if self.mode.is_single_line() {
10013            cx.propagate();
10014            return;
10015        }
10016
10017        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10018        let selections = self
10019            .selections
10020            .all::<usize>(cx)
10021            .into_iter()
10022            .map(|s| s.range());
10023
10024        self.transact(window, cx, |this, window, cx| {
10025            this.buffer.update(cx, |buffer, cx| {
10026                buffer.autoindent_ranges(selections, cx);
10027            });
10028            let selections = this.selections.all::<usize>(cx);
10029            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10030        });
10031    }
10032
10033    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10034        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10035        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10036        let selections = self.selections.all::<Point>(cx);
10037
10038        let mut new_cursors = Vec::new();
10039        let mut edit_ranges = Vec::new();
10040        let mut selections = selections.iter().peekable();
10041        while let Some(selection) = selections.next() {
10042            let mut rows = selection.spanned_rows(false, &display_map);
10043            let goal_display_column = selection.head().to_display_point(&display_map).column();
10044
10045            // Accumulate contiguous regions of rows that we want to delete.
10046            while let Some(next_selection) = selections.peek() {
10047                let next_rows = next_selection.spanned_rows(false, &display_map);
10048                if next_rows.start <= rows.end {
10049                    rows.end = next_rows.end;
10050                    selections.next().unwrap();
10051                } else {
10052                    break;
10053                }
10054            }
10055
10056            let buffer = &display_map.buffer_snapshot;
10057            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10058            let edit_end;
10059            let cursor_buffer_row;
10060            if buffer.max_point().row >= rows.end.0 {
10061                // If there's a line after the range, delete the \n from the end of the row range
10062                // and position the cursor on the next line.
10063                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10064                cursor_buffer_row = rows.end;
10065            } else {
10066                // If there isn't a line after the range, delete the \n from the line before the
10067                // start of the row range and position the cursor there.
10068                edit_start = edit_start.saturating_sub(1);
10069                edit_end = buffer.len();
10070                cursor_buffer_row = rows.start.previous_row();
10071            }
10072
10073            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10074            *cursor.column_mut() =
10075                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10076
10077            new_cursors.push((
10078                selection.id,
10079                buffer.anchor_after(cursor.to_point(&display_map)),
10080            ));
10081            edit_ranges.push(edit_start..edit_end);
10082        }
10083
10084        self.transact(window, cx, |this, window, cx| {
10085            let buffer = this.buffer.update(cx, |buffer, cx| {
10086                let empty_str: Arc<str> = Arc::default();
10087                buffer.edit(
10088                    edit_ranges
10089                        .into_iter()
10090                        .map(|range| (range, empty_str.clone())),
10091                    None,
10092                    cx,
10093                );
10094                buffer.snapshot(cx)
10095            });
10096            let new_selections = new_cursors
10097                .into_iter()
10098                .map(|(id, cursor)| {
10099                    let cursor = cursor.to_point(&buffer);
10100                    Selection {
10101                        id,
10102                        start: cursor,
10103                        end: cursor,
10104                        reversed: false,
10105                        goal: SelectionGoal::None,
10106                    }
10107                })
10108                .collect();
10109
10110            this.change_selections(Default::default(), window, cx, |s| {
10111                s.select(new_selections);
10112            });
10113        });
10114    }
10115
10116    pub fn join_lines_impl(
10117        &mut self,
10118        insert_whitespace: bool,
10119        window: &mut Window,
10120        cx: &mut Context<Self>,
10121    ) {
10122        if self.read_only(cx) {
10123            return;
10124        }
10125        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10126        for selection in self.selections.all::<Point>(cx) {
10127            let start = MultiBufferRow(selection.start.row);
10128            // Treat single line selections as if they include the next line. Otherwise this action
10129            // would do nothing for single line selections individual cursors.
10130            let end = if selection.start.row == selection.end.row {
10131                MultiBufferRow(selection.start.row + 1)
10132            } else {
10133                MultiBufferRow(selection.end.row)
10134            };
10135
10136            if let Some(last_row_range) = row_ranges.last_mut() {
10137                if start <= last_row_range.end {
10138                    last_row_range.end = end;
10139                    continue;
10140                }
10141            }
10142            row_ranges.push(start..end);
10143        }
10144
10145        let snapshot = self.buffer.read(cx).snapshot(cx);
10146        let mut cursor_positions = Vec::new();
10147        for row_range in &row_ranges {
10148            let anchor = snapshot.anchor_before(Point::new(
10149                row_range.end.previous_row().0,
10150                snapshot.line_len(row_range.end.previous_row()),
10151            ));
10152            cursor_positions.push(anchor..anchor);
10153        }
10154
10155        self.transact(window, cx, |this, window, cx| {
10156            for row_range in row_ranges.into_iter().rev() {
10157                for row in row_range.iter_rows().rev() {
10158                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10159                    let next_line_row = row.next_row();
10160                    let indent = snapshot.indent_size_for_line(next_line_row);
10161                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10162
10163                    let replace =
10164                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10165                            " "
10166                        } else {
10167                            ""
10168                        };
10169
10170                    this.buffer.update(cx, |buffer, cx| {
10171                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10172                    });
10173                }
10174            }
10175
10176            this.change_selections(Default::default(), window, cx, |s| {
10177                s.select_anchor_ranges(cursor_positions)
10178            });
10179        });
10180    }
10181
10182    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10183        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10184        self.join_lines_impl(true, window, cx);
10185    }
10186
10187    pub fn sort_lines_case_sensitive(
10188        &mut self,
10189        _: &SortLinesCaseSensitive,
10190        window: &mut Window,
10191        cx: &mut Context<Self>,
10192    ) {
10193        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10194    }
10195
10196    pub fn sort_lines_case_insensitive(
10197        &mut self,
10198        _: &SortLinesCaseInsensitive,
10199        window: &mut Window,
10200        cx: &mut Context<Self>,
10201    ) {
10202        self.manipulate_immutable_lines(window, cx, |lines| {
10203            lines.sort_by_key(|line| line.to_lowercase())
10204        })
10205    }
10206
10207    pub fn unique_lines_case_insensitive(
10208        &mut self,
10209        _: &UniqueLinesCaseInsensitive,
10210        window: &mut Window,
10211        cx: &mut Context<Self>,
10212    ) {
10213        self.manipulate_immutable_lines(window, cx, |lines| {
10214            let mut seen = HashSet::default();
10215            lines.retain(|line| seen.insert(line.to_lowercase()));
10216        })
10217    }
10218
10219    pub fn unique_lines_case_sensitive(
10220        &mut self,
10221        _: &UniqueLinesCaseSensitive,
10222        window: &mut Window,
10223        cx: &mut Context<Self>,
10224    ) {
10225        self.manipulate_immutable_lines(window, cx, |lines| {
10226            let mut seen = HashSet::default();
10227            lines.retain(|line| seen.insert(*line));
10228        })
10229    }
10230
10231    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10232        let Some(project) = self.project.clone() else {
10233            return;
10234        };
10235        self.reload(project, window, cx)
10236            .detach_and_notify_err(window, cx);
10237    }
10238
10239    pub fn restore_file(
10240        &mut self,
10241        _: &::git::RestoreFile,
10242        window: &mut Window,
10243        cx: &mut Context<Self>,
10244    ) {
10245        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10246        let mut buffer_ids = HashSet::default();
10247        let snapshot = self.buffer().read(cx).snapshot(cx);
10248        for selection in self.selections.all::<usize>(cx) {
10249            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10250        }
10251
10252        let buffer = self.buffer().read(cx);
10253        let ranges = buffer_ids
10254            .into_iter()
10255            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10256            .collect::<Vec<_>>();
10257
10258        self.restore_hunks_in_ranges(ranges, window, cx);
10259    }
10260
10261    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10262        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10263        let selections = self
10264            .selections
10265            .all(cx)
10266            .into_iter()
10267            .map(|s| s.range())
10268            .collect();
10269        self.restore_hunks_in_ranges(selections, window, cx);
10270    }
10271
10272    pub fn restore_hunks_in_ranges(
10273        &mut self,
10274        ranges: Vec<Range<Point>>,
10275        window: &mut Window,
10276        cx: &mut Context<Editor>,
10277    ) {
10278        let mut revert_changes = HashMap::default();
10279        let chunk_by = self
10280            .snapshot(window, cx)
10281            .hunks_for_ranges(ranges)
10282            .into_iter()
10283            .chunk_by(|hunk| hunk.buffer_id);
10284        for (buffer_id, hunks) in &chunk_by {
10285            let hunks = hunks.collect::<Vec<_>>();
10286            for hunk in &hunks {
10287                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10288            }
10289            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10290        }
10291        drop(chunk_by);
10292        if !revert_changes.is_empty() {
10293            self.transact(window, cx, |editor, window, cx| {
10294                editor.restore(revert_changes, window, cx);
10295            });
10296        }
10297    }
10298
10299    pub fn open_active_item_in_terminal(
10300        &mut self,
10301        _: &OpenInTerminal,
10302        window: &mut Window,
10303        cx: &mut Context<Self>,
10304    ) {
10305        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10306            let project_path = buffer.read(cx).project_path(cx)?;
10307            let project = self.project.as_ref()?.read(cx);
10308            let entry = project.entry_for_path(&project_path, cx)?;
10309            let parent = match &entry.canonical_path {
10310                Some(canonical_path) => canonical_path.to_path_buf(),
10311                None => project.absolute_path(&project_path, cx)?,
10312            }
10313            .parent()?
10314            .to_path_buf();
10315            Some(parent)
10316        }) {
10317            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10318        }
10319    }
10320
10321    fn set_breakpoint_context_menu(
10322        &mut self,
10323        display_row: DisplayRow,
10324        position: Option<Anchor>,
10325        clicked_point: gpui::Point<Pixels>,
10326        window: &mut Window,
10327        cx: &mut Context<Self>,
10328    ) {
10329        let source = self
10330            .buffer
10331            .read(cx)
10332            .snapshot(cx)
10333            .anchor_before(Point::new(display_row.0, 0u32));
10334
10335        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10336
10337        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10338            self,
10339            source,
10340            clicked_point,
10341            context_menu,
10342            window,
10343            cx,
10344        );
10345    }
10346
10347    fn add_edit_breakpoint_block(
10348        &mut self,
10349        anchor: Anchor,
10350        breakpoint: &Breakpoint,
10351        edit_action: BreakpointPromptEditAction,
10352        window: &mut Window,
10353        cx: &mut Context<Self>,
10354    ) {
10355        let weak_editor = cx.weak_entity();
10356        let bp_prompt = cx.new(|cx| {
10357            BreakpointPromptEditor::new(
10358                weak_editor,
10359                anchor,
10360                breakpoint.clone(),
10361                edit_action,
10362                window,
10363                cx,
10364            )
10365        });
10366
10367        let height = bp_prompt.update(cx, |this, cx| {
10368            this.prompt
10369                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10370        });
10371        let cloned_prompt = bp_prompt.clone();
10372        let blocks = vec![BlockProperties {
10373            style: BlockStyle::Sticky,
10374            placement: BlockPlacement::Above(anchor),
10375            height: Some(height),
10376            render: Arc::new(move |cx| {
10377                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10378                cloned_prompt.clone().into_any_element()
10379            }),
10380            priority: 0,
10381            render_in_minimap: true,
10382        }];
10383
10384        let focus_handle = bp_prompt.focus_handle(cx);
10385        window.focus(&focus_handle);
10386
10387        let block_ids = self.insert_blocks(blocks, None, cx);
10388        bp_prompt.update(cx, |prompt, _| {
10389            prompt.add_block_ids(block_ids);
10390        });
10391    }
10392
10393    pub(crate) fn breakpoint_at_row(
10394        &self,
10395        row: u32,
10396        window: &mut Window,
10397        cx: &mut Context<Self>,
10398    ) -> Option<(Anchor, Breakpoint)> {
10399        let snapshot = self.snapshot(window, cx);
10400        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10401
10402        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10403    }
10404
10405    pub(crate) fn breakpoint_at_anchor(
10406        &self,
10407        breakpoint_position: Anchor,
10408        snapshot: &EditorSnapshot,
10409        cx: &mut Context<Self>,
10410    ) -> Option<(Anchor, Breakpoint)> {
10411        let project = self.project.clone()?;
10412
10413        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10414            snapshot
10415                .buffer_snapshot
10416                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10417        })?;
10418
10419        let enclosing_excerpt = breakpoint_position.excerpt_id;
10420        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10421        let buffer_snapshot = buffer.read(cx).snapshot();
10422
10423        let row = buffer_snapshot
10424            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10425            .row;
10426
10427        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10428        let anchor_end = snapshot
10429            .buffer_snapshot
10430            .anchor_after(Point::new(row, line_len));
10431
10432        let bp = self
10433            .breakpoint_store
10434            .as_ref()?
10435            .read_with(cx, |breakpoint_store, cx| {
10436                breakpoint_store
10437                    .breakpoints(
10438                        &buffer,
10439                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10440                        &buffer_snapshot,
10441                        cx,
10442                    )
10443                    .next()
10444                    .and_then(|(bp, _)| {
10445                        let breakpoint_row = buffer_snapshot
10446                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10447                            .row;
10448
10449                        if breakpoint_row == row {
10450                            snapshot
10451                                .buffer_snapshot
10452                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10453                                .map(|position| (position, bp.bp.clone()))
10454                        } else {
10455                            None
10456                        }
10457                    })
10458            });
10459        bp
10460    }
10461
10462    pub fn edit_log_breakpoint(
10463        &mut self,
10464        _: &EditLogBreakpoint,
10465        window: &mut Window,
10466        cx: &mut Context<Self>,
10467    ) {
10468        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10469            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10470                message: None,
10471                state: BreakpointState::Enabled,
10472                condition: None,
10473                hit_condition: None,
10474            });
10475
10476            self.add_edit_breakpoint_block(
10477                anchor,
10478                &breakpoint,
10479                BreakpointPromptEditAction::Log,
10480                window,
10481                cx,
10482            );
10483        }
10484    }
10485
10486    fn breakpoints_at_cursors(
10487        &self,
10488        window: &mut Window,
10489        cx: &mut Context<Self>,
10490    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10491        let snapshot = self.snapshot(window, cx);
10492        let cursors = self
10493            .selections
10494            .disjoint_anchors()
10495            .into_iter()
10496            .map(|selection| {
10497                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10498
10499                let breakpoint_position = self
10500                    .breakpoint_at_row(cursor_position.row, window, cx)
10501                    .map(|bp| bp.0)
10502                    .unwrap_or_else(|| {
10503                        snapshot
10504                            .display_snapshot
10505                            .buffer_snapshot
10506                            .anchor_after(Point::new(cursor_position.row, 0))
10507                    });
10508
10509                let breakpoint = self
10510                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10511                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10512
10513                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10514            })
10515            // 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.
10516            .collect::<HashMap<Anchor, _>>();
10517
10518        cursors.into_iter().collect()
10519    }
10520
10521    pub fn enable_breakpoint(
10522        &mut self,
10523        _: &crate::actions::EnableBreakpoint,
10524        window: &mut Window,
10525        cx: &mut Context<Self>,
10526    ) {
10527        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10528            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10529                continue;
10530            };
10531            self.edit_breakpoint_at_anchor(
10532                anchor,
10533                breakpoint,
10534                BreakpointEditAction::InvertState,
10535                cx,
10536            );
10537        }
10538    }
10539
10540    pub fn disable_breakpoint(
10541        &mut self,
10542        _: &crate::actions::DisableBreakpoint,
10543        window: &mut Window,
10544        cx: &mut Context<Self>,
10545    ) {
10546        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10547            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10548                continue;
10549            };
10550            self.edit_breakpoint_at_anchor(
10551                anchor,
10552                breakpoint,
10553                BreakpointEditAction::InvertState,
10554                cx,
10555            );
10556        }
10557    }
10558
10559    pub fn toggle_breakpoint(
10560        &mut self,
10561        _: &crate::actions::ToggleBreakpoint,
10562        window: &mut Window,
10563        cx: &mut Context<Self>,
10564    ) {
10565        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10566            if let Some(breakpoint) = breakpoint {
10567                self.edit_breakpoint_at_anchor(
10568                    anchor,
10569                    breakpoint,
10570                    BreakpointEditAction::Toggle,
10571                    cx,
10572                );
10573            } else {
10574                self.edit_breakpoint_at_anchor(
10575                    anchor,
10576                    Breakpoint::new_standard(),
10577                    BreakpointEditAction::Toggle,
10578                    cx,
10579                );
10580            }
10581        }
10582    }
10583
10584    pub fn edit_breakpoint_at_anchor(
10585        &mut self,
10586        breakpoint_position: Anchor,
10587        breakpoint: Breakpoint,
10588        edit_action: BreakpointEditAction,
10589        cx: &mut Context<Self>,
10590    ) {
10591        let Some(breakpoint_store) = &self.breakpoint_store else {
10592            return;
10593        };
10594
10595        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10596            if breakpoint_position == Anchor::min() {
10597                self.buffer()
10598                    .read(cx)
10599                    .excerpt_buffer_ids()
10600                    .into_iter()
10601                    .next()
10602            } else {
10603                None
10604            }
10605        }) else {
10606            return;
10607        };
10608
10609        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10610            return;
10611        };
10612
10613        breakpoint_store.update(cx, |breakpoint_store, cx| {
10614            breakpoint_store.toggle_breakpoint(
10615                buffer,
10616                BreakpointWithPosition {
10617                    position: breakpoint_position.text_anchor,
10618                    bp: breakpoint,
10619                },
10620                edit_action,
10621                cx,
10622            );
10623        });
10624
10625        cx.notify();
10626    }
10627
10628    #[cfg(any(test, feature = "test-support"))]
10629    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10630        self.breakpoint_store.clone()
10631    }
10632
10633    pub fn prepare_restore_change(
10634        &self,
10635        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10636        hunk: &MultiBufferDiffHunk,
10637        cx: &mut App,
10638    ) -> Option<()> {
10639        if hunk.is_created_file() {
10640            return None;
10641        }
10642        let buffer = self.buffer.read(cx);
10643        let diff = buffer.diff_for(hunk.buffer_id)?;
10644        let buffer = buffer.buffer(hunk.buffer_id)?;
10645        let buffer = buffer.read(cx);
10646        let original_text = diff
10647            .read(cx)
10648            .base_text()
10649            .as_rope()
10650            .slice(hunk.diff_base_byte_range.clone());
10651        let buffer_snapshot = buffer.snapshot();
10652        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10653        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10654            probe
10655                .0
10656                .start
10657                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10658                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10659        }) {
10660            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10661            Some(())
10662        } else {
10663            None
10664        }
10665    }
10666
10667    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10668        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10669    }
10670
10671    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10672        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10673    }
10674
10675    fn manipulate_lines<M>(
10676        &mut self,
10677        window: &mut Window,
10678        cx: &mut Context<Self>,
10679        mut manipulate: M,
10680    ) where
10681        M: FnMut(&str) -> LineManipulationResult,
10682    {
10683        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10684
10685        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10686        let buffer = self.buffer.read(cx).snapshot(cx);
10687
10688        let mut edits = Vec::new();
10689
10690        let selections = self.selections.all::<Point>(cx);
10691        let mut selections = selections.iter().peekable();
10692        let mut contiguous_row_selections = Vec::new();
10693        let mut new_selections = Vec::new();
10694        let mut added_lines = 0;
10695        let mut removed_lines = 0;
10696
10697        while let Some(selection) = selections.next() {
10698            let (start_row, end_row) = consume_contiguous_rows(
10699                &mut contiguous_row_selections,
10700                selection,
10701                &display_map,
10702                &mut selections,
10703            );
10704
10705            let start_point = Point::new(start_row.0, 0);
10706            let end_point = Point::new(
10707                end_row.previous_row().0,
10708                buffer.line_len(end_row.previous_row()),
10709            );
10710            let text = buffer
10711                .text_for_range(start_point..end_point)
10712                .collect::<String>();
10713
10714            let LineManipulationResult {
10715                new_text,
10716                line_count_before,
10717                line_count_after,
10718            } = manipulate(&text);
10719
10720            edits.push((start_point..end_point, new_text));
10721
10722            // Selections must change based on added and removed line count
10723            let start_row =
10724                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10725            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10726            new_selections.push(Selection {
10727                id: selection.id,
10728                start: start_row,
10729                end: end_row,
10730                goal: SelectionGoal::None,
10731                reversed: selection.reversed,
10732            });
10733
10734            if line_count_after > line_count_before {
10735                added_lines += line_count_after - line_count_before;
10736            } else if line_count_before > line_count_after {
10737                removed_lines += line_count_before - line_count_after;
10738            }
10739        }
10740
10741        self.transact(window, cx, |this, window, cx| {
10742            let buffer = this.buffer.update(cx, |buffer, cx| {
10743                buffer.edit(edits, None, cx);
10744                buffer.snapshot(cx)
10745            });
10746
10747            // Recalculate offsets on newly edited buffer
10748            let new_selections = new_selections
10749                .iter()
10750                .map(|s| {
10751                    let start_point = Point::new(s.start.0, 0);
10752                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10753                    Selection {
10754                        id: s.id,
10755                        start: buffer.point_to_offset(start_point),
10756                        end: buffer.point_to_offset(end_point),
10757                        goal: s.goal,
10758                        reversed: s.reversed,
10759                    }
10760                })
10761                .collect();
10762
10763            this.change_selections(Default::default(), window, cx, |s| {
10764                s.select(new_selections);
10765            });
10766
10767            this.request_autoscroll(Autoscroll::fit(), cx);
10768        });
10769    }
10770
10771    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10772        self.manipulate_text(window, cx, |text| {
10773            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10774            if has_upper_case_characters {
10775                text.to_lowercase()
10776            } else {
10777                text.to_uppercase()
10778            }
10779        })
10780    }
10781
10782    fn manipulate_immutable_lines<Fn>(
10783        &mut self,
10784        window: &mut Window,
10785        cx: &mut Context<Self>,
10786        mut callback: Fn,
10787    ) where
10788        Fn: FnMut(&mut Vec<&str>),
10789    {
10790        self.manipulate_lines(window, cx, |text| {
10791            let mut lines: Vec<&str> = text.split('\n').collect();
10792            let line_count_before = lines.len();
10793
10794            callback(&mut lines);
10795
10796            LineManipulationResult {
10797                new_text: lines.join("\n"),
10798                line_count_before,
10799                line_count_after: lines.len(),
10800            }
10801        });
10802    }
10803
10804    fn manipulate_mutable_lines<Fn>(
10805        &mut self,
10806        window: &mut Window,
10807        cx: &mut Context<Self>,
10808        mut callback: Fn,
10809    ) where
10810        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10811    {
10812        self.manipulate_lines(window, cx, |text| {
10813            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10814            let line_count_before = lines.len();
10815
10816            callback(&mut lines);
10817
10818            LineManipulationResult {
10819                new_text: lines.join("\n"),
10820                line_count_before,
10821                line_count_after: lines.len(),
10822            }
10823        });
10824    }
10825
10826    pub fn convert_indentation_to_spaces(
10827        &mut self,
10828        _: &ConvertIndentationToSpaces,
10829        window: &mut Window,
10830        cx: &mut Context<Self>,
10831    ) {
10832        let settings = self.buffer.read(cx).language_settings(cx);
10833        let tab_size = settings.tab_size.get() as usize;
10834
10835        self.manipulate_mutable_lines(window, cx, |lines| {
10836            // Allocates a reasonably sized scratch buffer once for the whole loop
10837            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10838            // Avoids recomputing spaces that could be inserted many times
10839            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10840                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10841                .collect();
10842
10843            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10844                let mut chars = line.as_ref().chars();
10845                let mut col = 0;
10846                let mut changed = false;
10847
10848                while let Some(ch) = chars.next() {
10849                    match ch {
10850                        ' ' => {
10851                            reindented_line.push(' ');
10852                            col += 1;
10853                        }
10854                        '\t' => {
10855                            // \t are converted to spaces depending on the current column
10856                            let spaces_len = tab_size - (col % tab_size);
10857                            reindented_line.extend(&space_cache[spaces_len - 1]);
10858                            col += spaces_len;
10859                            changed = true;
10860                        }
10861                        _ => {
10862                            // If we dont append before break, the character is consumed
10863                            reindented_line.push(ch);
10864                            break;
10865                        }
10866                    }
10867                }
10868
10869                if !changed {
10870                    reindented_line.clear();
10871                    continue;
10872                }
10873                // Append the rest of the line and replace old reference with new one
10874                reindented_line.extend(chars);
10875                *line = Cow::Owned(reindented_line.clone());
10876                reindented_line.clear();
10877            }
10878        });
10879    }
10880
10881    pub fn convert_indentation_to_tabs(
10882        &mut self,
10883        _: &ConvertIndentationToTabs,
10884        window: &mut Window,
10885        cx: &mut Context<Self>,
10886    ) {
10887        let settings = self.buffer.read(cx).language_settings(cx);
10888        let tab_size = settings.tab_size.get() as usize;
10889
10890        self.manipulate_mutable_lines(window, cx, |lines| {
10891            // Allocates a reasonably sized buffer once for the whole loop
10892            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10893            // Avoids recomputing spaces that could be inserted many times
10894            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10895                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10896                .collect();
10897
10898            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10899                let mut chars = line.chars();
10900                let mut spaces_count = 0;
10901                let mut first_non_indent_char = None;
10902                let mut changed = false;
10903
10904                while let Some(ch) = chars.next() {
10905                    match ch {
10906                        ' ' => {
10907                            // Keep track of spaces. Append \t when we reach tab_size
10908                            spaces_count += 1;
10909                            changed = true;
10910                            if spaces_count == tab_size {
10911                                reindented_line.push('\t');
10912                                spaces_count = 0;
10913                            }
10914                        }
10915                        '\t' => {
10916                            reindented_line.push('\t');
10917                            spaces_count = 0;
10918                        }
10919                        _ => {
10920                            // Dont append it yet, we might have remaining spaces
10921                            first_non_indent_char = Some(ch);
10922                            break;
10923                        }
10924                    }
10925                }
10926
10927                if !changed {
10928                    reindented_line.clear();
10929                    continue;
10930                }
10931                // Remaining spaces that didn't make a full tab stop
10932                if spaces_count > 0 {
10933                    reindented_line.extend(&space_cache[spaces_count - 1]);
10934                }
10935                // If we consume an extra character that was not indentation, add it back
10936                if let Some(extra_char) = first_non_indent_char {
10937                    reindented_line.push(extra_char);
10938                }
10939                // Append the rest of the line and replace old reference with new one
10940                reindented_line.extend(chars);
10941                *line = Cow::Owned(reindented_line.clone());
10942                reindented_line.clear();
10943            }
10944        });
10945    }
10946
10947    pub fn convert_to_upper_case(
10948        &mut self,
10949        _: &ConvertToUpperCase,
10950        window: &mut Window,
10951        cx: &mut Context<Self>,
10952    ) {
10953        self.manipulate_text(window, cx, |text| text.to_uppercase())
10954    }
10955
10956    pub fn convert_to_lower_case(
10957        &mut self,
10958        _: &ConvertToLowerCase,
10959        window: &mut Window,
10960        cx: &mut Context<Self>,
10961    ) {
10962        self.manipulate_text(window, cx, |text| text.to_lowercase())
10963    }
10964
10965    pub fn convert_to_title_case(
10966        &mut self,
10967        _: &ConvertToTitleCase,
10968        window: &mut Window,
10969        cx: &mut Context<Self>,
10970    ) {
10971        self.manipulate_text(window, cx, |text| {
10972            text.split('\n')
10973                .map(|line| line.to_case(Case::Title))
10974                .join("\n")
10975        })
10976    }
10977
10978    pub fn convert_to_snake_case(
10979        &mut self,
10980        _: &ConvertToSnakeCase,
10981        window: &mut Window,
10982        cx: &mut Context<Self>,
10983    ) {
10984        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10985    }
10986
10987    pub fn convert_to_kebab_case(
10988        &mut self,
10989        _: &ConvertToKebabCase,
10990        window: &mut Window,
10991        cx: &mut Context<Self>,
10992    ) {
10993        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10994    }
10995
10996    pub fn convert_to_upper_camel_case(
10997        &mut self,
10998        _: &ConvertToUpperCamelCase,
10999        window: &mut Window,
11000        cx: &mut Context<Self>,
11001    ) {
11002        self.manipulate_text(window, cx, |text| {
11003            text.split('\n')
11004                .map(|line| line.to_case(Case::UpperCamel))
11005                .join("\n")
11006        })
11007    }
11008
11009    pub fn convert_to_lower_camel_case(
11010        &mut self,
11011        _: &ConvertToLowerCamelCase,
11012        window: &mut Window,
11013        cx: &mut Context<Self>,
11014    ) {
11015        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11016    }
11017
11018    pub fn convert_to_opposite_case(
11019        &mut self,
11020        _: &ConvertToOppositeCase,
11021        window: &mut Window,
11022        cx: &mut Context<Self>,
11023    ) {
11024        self.manipulate_text(window, cx, |text| {
11025            text.chars()
11026                .fold(String::with_capacity(text.len()), |mut t, c| {
11027                    if c.is_uppercase() {
11028                        t.extend(c.to_lowercase());
11029                    } else {
11030                        t.extend(c.to_uppercase());
11031                    }
11032                    t
11033                })
11034        })
11035    }
11036
11037    pub fn convert_to_rot13(
11038        &mut self,
11039        _: &ConvertToRot13,
11040        window: &mut Window,
11041        cx: &mut Context<Self>,
11042    ) {
11043        self.manipulate_text(window, cx, |text| {
11044            text.chars()
11045                .map(|c| match c {
11046                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11047                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11048                    _ => c,
11049                })
11050                .collect()
11051        })
11052    }
11053
11054    pub fn convert_to_rot47(
11055        &mut self,
11056        _: &ConvertToRot47,
11057        window: &mut Window,
11058        cx: &mut Context<Self>,
11059    ) {
11060        self.manipulate_text(window, cx, |text| {
11061            text.chars()
11062                .map(|c| {
11063                    let code_point = c as u32;
11064                    if code_point >= 33 && code_point <= 126 {
11065                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11066                    }
11067                    c
11068                })
11069                .collect()
11070        })
11071    }
11072
11073    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11074    where
11075        Fn: FnMut(&str) -> String,
11076    {
11077        let buffer = self.buffer.read(cx).snapshot(cx);
11078
11079        let mut new_selections = Vec::new();
11080        let mut edits = Vec::new();
11081        let mut selection_adjustment = 0i32;
11082
11083        for selection in self.selections.all::<usize>(cx) {
11084            let selection_is_empty = selection.is_empty();
11085
11086            let (start, end) = if selection_is_empty {
11087                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11088                (word_range.start, word_range.end)
11089            } else {
11090                (selection.start, selection.end)
11091            };
11092
11093            let text = buffer.text_for_range(start..end).collect::<String>();
11094            let old_length = text.len() as i32;
11095            let text = callback(&text);
11096
11097            new_selections.push(Selection {
11098                start: (start as i32 - selection_adjustment) as usize,
11099                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11100                goal: SelectionGoal::None,
11101                ..selection
11102            });
11103
11104            selection_adjustment += old_length - text.len() as i32;
11105
11106            edits.push((start..end, text));
11107        }
11108
11109        self.transact(window, cx, |this, window, cx| {
11110            this.buffer.update(cx, |buffer, cx| {
11111                buffer.edit(edits, None, cx);
11112            });
11113
11114            this.change_selections(Default::default(), window, cx, |s| {
11115                s.select(new_selections);
11116            });
11117
11118            this.request_autoscroll(Autoscroll::fit(), cx);
11119        });
11120    }
11121
11122    pub fn move_selection_on_drop(
11123        &mut self,
11124        selection: &Selection<Anchor>,
11125        target: DisplayPoint,
11126        is_cut: bool,
11127        window: &mut Window,
11128        cx: &mut Context<Self>,
11129    ) {
11130        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11131        let buffer = &display_map.buffer_snapshot;
11132        let mut edits = Vec::new();
11133        let insert_point = display_map
11134            .clip_point(target, Bias::Left)
11135            .to_point(&display_map);
11136        let text = buffer
11137            .text_for_range(selection.start..selection.end)
11138            .collect::<String>();
11139        if is_cut {
11140            edits.push(((selection.start..selection.end), String::new()));
11141        }
11142        let insert_anchor = buffer.anchor_before(insert_point);
11143        edits.push(((insert_anchor..insert_anchor), text));
11144        let last_edit_start = insert_anchor.bias_left(buffer);
11145        let last_edit_end = insert_anchor.bias_right(buffer);
11146        self.transact(window, cx, |this, window, cx| {
11147            this.buffer.update(cx, |buffer, cx| {
11148                buffer.edit(edits, None, cx);
11149            });
11150            this.change_selections(Default::default(), window, cx, |s| {
11151                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11152            });
11153        });
11154    }
11155
11156    pub fn clear_selection_drag_state(&mut self) {
11157        self.selection_drag_state = SelectionDragState::None;
11158    }
11159
11160    pub fn duplicate(
11161        &mut self,
11162        upwards: bool,
11163        whole_lines: bool,
11164        window: &mut Window,
11165        cx: &mut Context<Self>,
11166    ) {
11167        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11168
11169        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11170        let buffer = &display_map.buffer_snapshot;
11171        let selections = self.selections.all::<Point>(cx);
11172
11173        let mut edits = Vec::new();
11174        let mut selections_iter = selections.iter().peekable();
11175        while let Some(selection) = selections_iter.next() {
11176            let mut rows = selection.spanned_rows(false, &display_map);
11177            // duplicate line-wise
11178            if whole_lines || selection.start == selection.end {
11179                // Avoid duplicating the same lines twice.
11180                while let Some(next_selection) = selections_iter.peek() {
11181                    let next_rows = next_selection.spanned_rows(false, &display_map);
11182                    if next_rows.start < rows.end {
11183                        rows.end = next_rows.end;
11184                        selections_iter.next().unwrap();
11185                    } else {
11186                        break;
11187                    }
11188                }
11189
11190                // Copy the text from the selected row region and splice it either at the start
11191                // or end of the region.
11192                let start = Point::new(rows.start.0, 0);
11193                let end = Point::new(
11194                    rows.end.previous_row().0,
11195                    buffer.line_len(rows.end.previous_row()),
11196                );
11197                let text = buffer
11198                    .text_for_range(start..end)
11199                    .chain(Some("\n"))
11200                    .collect::<String>();
11201                let insert_location = if upwards {
11202                    Point::new(rows.end.0, 0)
11203                } else {
11204                    start
11205                };
11206                edits.push((insert_location..insert_location, text));
11207            } else {
11208                // duplicate character-wise
11209                let start = selection.start;
11210                let end = selection.end;
11211                let text = buffer.text_for_range(start..end).collect::<String>();
11212                edits.push((selection.end..selection.end, text));
11213            }
11214        }
11215
11216        self.transact(window, cx, |this, _, cx| {
11217            this.buffer.update(cx, |buffer, cx| {
11218                buffer.edit(edits, None, cx);
11219            });
11220
11221            this.request_autoscroll(Autoscroll::fit(), cx);
11222        });
11223    }
11224
11225    pub fn duplicate_line_up(
11226        &mut self,
11227        _: &DuplicateLineUp,
11228        window: &mut Window,
11229        cx: &mut Context<Self>,
11230    ) {
11231        self.duplicate(true, true, window, cx);
11232    }
11233
11234    pub fn duplicate_line_down(
11235        &mut self,
11236        _: &DuplicateLineDown,
11237        window: &mut Window,
11238        cx: &mut Context<Self>,
11239    ) {
11240        self.duplicate(false, true, window, cx);
11241    }
11242
11243    pub fn duplicate_selection(
11244        &mut self,
11245        _: &DuplicateSelection,
11246        window: &mut Window,
11247        cx: &mut Context<Self>,
11248    ) {
11249        self.duplicate(false, false, window, cx);
11250    }
11251
11252    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11253        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11254        if self.mode.is_single_line() {
11255            cx.propagate();
11256            return;
11257        }
11258
11259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11260        let buffer = self.buffer.read(cx).snapshot(cx);
11261
11262        let mut edits = Vec::new();
11263        let mut unfold_ranges = Vec::new();
11264        let mut refold_creases = Vec::new();
11265
11266        let selections = self.selections.all::<Point>(cx);
11267        let mut selections = selections.iter().peekable();
11268        let mut contiguous_row_selections = Vec::new();
11269        let mut new_selections = Vec::new();
11270
11271        while let Some(selection) = selections.next() {
11272            // Find all the selections that span a contiguous row range
11273            let (start_row, end_row) = consume_contiguous_rows(
11274                &mut contiguous_row_selections,
11275                selection,
11276                &display_map,
11277                &mut selections,
11278            );
11279
11280            // Move the text spanned by the row range to be before the line preceding the row range
11281            if start_row.0 > 0 {
11282                let range_to_move = Point::new(
11283                    start_row.previous_row().0,
11284                    buffer.line_len(start_row.previous_row()),
11285                )
11286                    ..Point::new(
11287                        end_row.previous_row().0,
11288                        buffer.line_len(end_row.previous_row()),
11289                    );
11290                let insertion_point = display_map
11291                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11292                    .0;
11293
11294                // Don't move lines across excerpts
11295                if buffer
11296                    .excerpt_containing(insertion_point..range_to_move.end)
11297                    .is_some()
11298                {
11299                    let text = buffer
11300                        .text_for_range(range_to_move.clone())
11301                        .flat_map(|s| s.chars())
11302                        .skip(1)
11303                        .chain(['\n'])
11304                        .collect::<String>();
11305
11306                    edits.push((
11307                        buffer.anchor_after(range_to_move.start)
11308                            ..buffer.anchor_before(range_to_move.end),
11309                        String::new(),
11310                    ));
11311                    let insertion_anchor = buffer.anchor_after(insertion_point);
11312                    edits.push((insertion_anchor..insertion_anchor, text));
11313
11314                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11315
11316                    // Move selections up
11317                    new_selections.extend(contiguous_row_selections.drain(..).map(
11318                        |mut selection| {
11319                            selection.start.row -= row_delta;
11320                            selection.end.row -= row_delta;
11321                            selection
11322                        },
11323                    ));
11324
11325                    // Move folds up
11326                    unfold_ranges.push(range_to_move.clone());
11327                    for fold in display_map.folds_in_range(
11328                        buffer.anchor_before(range_to_move.start)
11329                            ..buffer.anchor_after(range_to_move.end),
11330                    ) {
11331                        let mut start = fold.range.start.to_point(&buffer);
11332                        let mut end = fold.range.end.to_point(&buffer);
11333                        start.row -= row_delta;
11334                        end.row -= row_delta;
11335                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11336                    }
11337                }
11338            }
11339
11340            // If we didn't move line(s), preserve the existing selections
11341            new_selections.append(&mut contiguous_row_selections);
11342        }
11343
11344        self.transact(window, cx, |this, window, cx| {
11345            this.unfold_ranges(&unfold_ranges, true, true, cx);
11346            this.buffer.update(cx, |buffer, cx| {
11347                for (range, text) in edits {
11348                    buffer.edit([(range, text)], None, cx);
11349                }
11350            });
11351            this.fold_creases(refold_creases, true, window, cx);
11352            this.change_selections(Default::default(), window, cx, |s| {
11353                s.select(new_selections);
11354            })
11355        });
11356    }
11357
11358    pub fn move_line_down(
11359        &mut self,
11360        _: &MoveLineDown,
11361        window: &mut Window,
11362        cx: &mut Context<Self>,
11363    ) {
11364        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11365        if self.mode.is_single_line() {
11366            cx.propagate();
11367            return;
11368        }
11369
11370        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11371        let buffer = self.buffer.read(cx).snapshot(cx);
11372
11373        let mut edits = Vec::new();
11374        let mut unfold_ranges = Vec::new();
11375        let mut refold_creases = Vec::new();
11376
11377        let selections = self.selections.all::<Point>(cx);
11378        let mut selections = selections.iter().peekable();
11379        let mut contiguous_row_selections = Vec::new();
11380        let mut new_selections = Vec::new();
11381
11382        while let Some(selection) = selections.next() {
11383            // Find all the selections that span a contiguous row range
11384            let (start_row, end_row) = consume_contiguous_rows(
11385                &mut contiguous_row_selections,
11386                selection,
11387                &display_map,
11388                &mut selections,
11389            );
11390
11391            // Move the text spanned by the row range to be after the last line of the row range
11392            if end_row.0 <= buffer.max_point().row {
11393                let range_to_move =
11394                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11395                let insertion_point = display_map
11396                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11397                    .0;
11398
11399                // Don't move lines across excerpt boundaries
11400                if buffer
11401                    .excerpt_containing(range_to_move.start..insertion_point)
11402                    .is_some()
11403                {
11404                    let mut text = String::from("\n");
11405                    text.extend(buffer.text_for_range(range_to_move.clone()));
11406                    text.pop(); // Drop trailing newline
11407                    edits.push((
11408                        buffer.anchor_after(range_to_move.start)
11409                            ..buffer.anchor_before(range_to_move.end),
11410                        String::new(),
11411                    ));
11412                    let insertion_anchor = buffer.anchor_after(insertion_point);
11413                    edits.push((insertion_anchor..insertion_anchor, text));
11414
11415                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11416
11417                    // Move selections down
11418                    new_selections.extend(contiguous_row_selections.drain(..).map(
11419                        |mut selection| {
11420                            selection.start.row += row_delta;
11421                            selection.end.row += row_delta;
11422                            selection
11423                        },
11424                    ));
11425
11426                    // Move folds down
11427                    unfold_ranges.push(range_to_move.clone());
11428                    for fold in display_map.folds_in_range(
11429                        buffer.anchor_before(range_to_move.start)
11430                            ..buffer.anchor_after(range_to_move.end),
11431                    ) {
11432                        let mut start = fold.range.start.to_point(&buffer);
11433                        let mut end = fold.range.end.to_point(&buffer);
11434                        start.row += row_delta;
11435                        end.row += row_delta;
11436                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11437                    }
11438                }
11439            }
11440
11441            // If we didn't move line(s), preserve the existing selections
11442            new_selections.append(&mut contiguous_row_selections);
11443        }
11444
11445        self.transact(window, cx, |this, window, cx| {
11446            this.unfold_ranges(&unfold_ranges, true, true, cx);
11447            this.buffer.update(cx, |buffer, cx| {
11448                for (range, text) in edits {
11449                    buffer.edit([(range, text)], None, cx);
11450                }
11451            });
11452            this.fold_creases(refold_creases, true, window, cx);
11453            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11454        });
11455    }
11456
11457    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11459        let text_layout_details = &self.text_layout_details(window);
11460        self.transact(window, cx, |this, window, cx| {
11461            let edits = this.change_selections(Default::default(), window, cx, |s| {
11462                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11463                s.move_with(|display_map, selection| {
11464                    if !selection.is_empty() {
11465                        return;
11466                    }
11467
11468                    let mut head = selection.head();
11469                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11470                    if head.column() == display_map.line_len(head.row()) {
11471                        transpose_offset = display_map
11472                            .buffer_snapshot
11473                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11474                    }
11475
11476                    if transpose_offset == 0 {
11477                        return;
11478                    }
11479
11480                    *head.column_mut() += 1;
11481                    head = display_map.clip_point(head, Bias::Right);
11482                    let goal = SelectionGoal::HorizontalPosition(
11483                        display_map
11484                            .x_for_display_point(head, text_layout_details)
11485                            .into(),
11486                    );
11487                    selection.collapse_to(head, goal);
11488
11489                    let transpose_start = display_map
11490                        .buffer_snapshot
11491                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11492                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11493                        let transpose_end = display_map
11494                            .buffer_snapshot
11495                            .clip_offset(transpose_offset + 1, Bias::Right);
11496                        if let Some(ch) =
11497                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11498                        {
11499                            edits.push((transpose_start..transpose_offset, String::new()));
11500                            edits.push((transpose_end..transpose_end, ch.to_string()));
11501                        }
11502                    }
11503                });
11504                edits
11505            });
11506            this.buffer
11507                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11508            let selections = this.selections.all::<usize>(cx);
11509            this.change_selections(Default::default(), window, cx, |s| {
11510                s.select(selections);
11511            });
11512        });
11513    }
11514
11515    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11516        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11517        if self.mode.is_single_line() {
11518            cx.propagate();
11519            return;
11520        }
11521
11522        self.rewrap_impl(RewrapOptions::default(), cx)
11523    }
11524
11525    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11526        let buffer = self.buffer.read(cx).snapshot(cx);
11527        let selections = self.selections.all::<Point>(cx);
11528
11529        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11530        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11531            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11532                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11533                .peekable();
11534
11535            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11536                row
11537            } else {
11538                return Vec::new();
11539            };
11540
11541            let language_settings = buffer.language_settings_at(selection.head(), cx);
11542            let language_scope = buffer.language_scope_at(selection.head());
11543
11544            let indent_and_prefix_for_row =
11545                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11546                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11547                    let (comment_prefix, rewrap_prefix) =
11548                        if let Some(language_scope) = &language_scope {
11549                            let indent_end = Point::new(row, indent.len);
11550                            let comment_prefix = language_scope
11551                                .line_comment_prefixes()
11552                                .iter()
11553                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11554                                .map(|prefix| prefix.to_string());
11555                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11556                            let line_text_after_indent = buffer
11557                                .text_for_range(indent_end..line_end)
11558                                .collect::<String>();
11559                            let rewrap_prefix = language_scope
11560                                .rewrap_prefixes()
11561                                .iter()
11562                                .find_map(|prefix_regex| {
11563                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11564                                        if mat.start() == 0 {
11565                                            Some(mat.as_str().to_string())
11566                                        } else {
11567                                            None
11568                                        }
11569                                    })
11570                                })
11571                                .flatten();
11572                            (comment_prefix, rewrap_prefix)
11573                        } else {
11574                            (None, None)
11575                        };
11576                    (indent, comment_prefix, rewrap_prefix)
11577                };
11578
11579            let mut ranges = Vec::new();
11580            let from_empty_selection = selection.is_empty();
11581
11582            let mut current_range_start = first_row;
11583            let mut prev_row = first_row;
11584            let (
11585                mut current_range_indent,
11586                mut current_range_comment_prefix,
11587                mut current_range_rewrap_prefix,
11588            ) = indent_and_prefix_for_row(first_row);
11589
11590            for row in non_blank_rows_iter.skip(1) {
11591                let has_paragraph_break = row > prev_row + 1;
11592
11593                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11594                    indent_and_prefix_for_row(row);
11595
11596                let has_indent_change = row_indent != current_range_indent;
11597                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11598
11599                let has_boundary_change = has_comment_change
11600                    || row_rewrap_prefix.is_some()
11601                    || (has_indent_change && current_range_comment_prefix.is_some());
11602
11603                if has_paragraph_break || has_boundary_change {
11604                    ranges.push((
11605                        language_settings.clone(),
11606                        Point::new(current_range_start, 0)
11607                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11608                        current_range_indent,
11609                        current_range_comment_prefix.clone(),
11610                        current_range_rewrap_prefix.clone(),
11611                        from_empty_selection,
11612                    ));
11613                    current_range_start = row;
11614                    current_range_indent = row_indent;
11615                    current_range_comment_prefix = row_comment_prefix;
11616                    current_range_rewrap_prefix = row_rewrap_prefix;
11617                }
11618                prev_row = row;
11619            }
11620
11621            ranges.push((
11622                language_settings.clone(),
11623                Point::new(current_range_start, 0)
11624                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11625                current_range_indent,
11626                current_range_comment_prefix,
11627                current_range_rewrap_prefix,
11628                from_empty_selection,
11629            ));
11630
11631            ranges
11632        });
11633
11634        let mut edits = Vec::new();
11635        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11636
11637        for (
11638            language_settings,
11639            wrap_range,
11640            indent_size,
11641            comment_prefix,
11642            rewrap_prefix,
11643            from_empty_selection,
11644        ) in wrap_ranges
11645        {
11646            let mut start_row = wrap_range.start.row;
11647            let mut end_row = wrap_range.end.row;
11648
11649            // Skip selections that overlap with a range that has already been rewrapped.
11650            let selection_range = start_row..end_row;
11651            if rewrapped_row_ranges
11652                .iter()
11653                .any(|range| range.overlaps(&selection_range))
11654            {
11655                continue;
11656            }
11657
11658            let tab_size = language_settings.tab_size;
11659
11660            let indent_prefix = indent_size.chars().collect::<String>();
11661            let mut line_prefix = indent_prefix.clone();
11662            let mut inside_comment = false;
11663            if let Some(prefix) = &comment_prefix {
11664                line_prefix.push_str(prefix);
11665                inside_comment = true;
11666            }
11667            if let Some(prefix) = &rewrap_prefix {
11668                line_prefix.push_str(prefix);
11669            }
11670
11671            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11672                RewrapBehavior::InComments => inside_comment,
11673                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11674                RewrapBehavior::Anywhere => true,
11675            };
11676
11677            let should_rewrap = options.override_language_settings
11678                || allow_rewrap_based_on_language
11679                || self.hard_wrap.is_some();
11680            if !should_rewrap {
11681                continue;
11682            }
11683
11684            if from_empty_selection {
11685                'expand_upwards: while start_row > 0 {
11686                    let prev_row = start_row - 1;
11687                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11688                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11689                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11690                    {
11691                        start_row = prev_row;
11692                    } else {
11693                        break 'expand_upwards;
11694                    }
11695                }
11696
11697                'expand_downwards: while end_row < buffer.max_point().row {
11698                    let next_row = end_row + 1;
11699                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11700                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11701                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11702                    {
11703                        end_row = next_row;
11704                    } else {
11705                        break 'expand_downwards;
11706                    }
11707                }
11708            }
11709
11710            let start = Point::new(start_row, 0);
11711            let start_offset = start.to_offset(&buffer);
11712            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11713            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11714            let Some(lines_without_prefixes) = selection_text
11715                .lines()
11716                .enumerate()
11717                .map(|(ix, line)| {
11718                    let line_trimmed = line.trim_start();
11719                    if rewrap_prefix.is_some() && ix > 0 {
11720                        Ok(line_trimmed)
11721                    } else {
11722                        line_trimmed
11723                            .strip_prefix(&line_prefix.trim_start())
11724                            .with_context(|| {
11725                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11726                            })
11727                    }
11728                })
11729                .collect::<Result<Vec<_>, _>>()
11730                .log_err()
11731            else {
11732                continue;
11733            };
11734
11735            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11736                buffer
11737                    .language_settings_at(Point::new(start_row, 0), cx)
11738                    .preferred_line_length as usize
11739            });
11740
11741            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11742                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11743            } else {
11744                line_prefix.clone()
11745            };
11746
11747            let wrapped_text = wrap_with_prefix(
11748                line_prefix,
11749                subsequent_lines_prefix,
11750                lines_without_prefixes.join("\n"),
11751                wrap_column,
11752                tab_size,
11753                options.preserve_existing_whitespace,
11754            );
11755
11756            // TODO: should always use char-based diff while still supporting cursor behavior that
11757            // matches vim.
11758            let mut diff_options = DiffOptions::default();
11759            if options.override_language_settings {
11760                diff_options.max_word_diff_len = 0;
11761                diff_options.max_word_diff_line_count = 0;
11762            } else {
11763                diff_options.max_word_diff_len = usize::MAX;
11764                diff_options.max_word_diff_line_count = usize::MAX;
11765            }
11766
11767            for (old_range, new_text) in
11768                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11769            {
11770                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11771                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11772                edits.push((edit_start..edit_end, new_text));
11773            }
11774
11775            rewrapped_row_ranges.push(start_row..=end_row);
11776        }
11777
11778        self.buffer
11779            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11780    }
11781
11782    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11783        let mut text = String::new();
11784        let buffer = self.buffer.read(cx).snapshot(cx);
11785        let mut selections = self.selections.all::<Point>(cx);
11786        let mut clipboard_selections = Vec::with_capacity(selections.len());
11787        {
11788            let max_point = buffer.max_point();
11789            let mut is_first = true;
11790            for selection in &mut selections {
11791                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11792                if is_entire_line {
11793                    selection.start = Point::new(selection.start.row, 0);
11794                    if !selection.is_empty() && selection.end.column == 0 {
11795                        selection.end = cmp::min(max_point, selection.end);
11796                    } else {
11797                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11798                    }
11799                    selection.goal = SelectionGoal::None;
11800                }
11801                if is_first {
11802                    is_first = false;
11803                } else {
11804                    text += "\n";
11805                }
11806                let mut len = 0;
11807                for chunk in buffer.text_for_range(selection.start..selection.end) {
11808                    text.push_str(chunk);
11809                    len += chunk.len();
11810                }
11811                clipboard_selections.push(ClipboardSelection {
11812                    len,
11813                    is_entire_line,
11814                    first_line_indent: buffer
11815                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11816                        .len,
11817                });
11818            }
11819        }
11820
11821        self.transact(window, cx, |this, window, cx| {
11822            this.change_selections(Default::default(), window, cx, |s| {
11823                s.select(selections);
11824            });
11825            this.insert("", window, cx);
11826        });
11827        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11828    }
11829
11830    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11831        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11832        let item = self.cut_common(window, cx);
11833        cx.write_to_clipboard(item);
11834    }
11835
11836    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11837        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11838        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11839            s.move_with(|snapshot, sel| {
11840                if sel.is_empty() {
11841                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11842                }
11843            });
11844        });
11845        let item = self.cut_common(window, cx);
11846        cx.set_global(KillRing(item))
11847    }
11848
11849    pub fn kill_ring_yank(
11850        &mut self,
11851        _: &KillRingYank,
11852        window: &mut Window,
11853        cx: &mut Context<Self>,
11854    ) {
11855        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11856        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11857            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11858                (kill_ring.text().to_string(), kill_ring.metadata_json())
11859            } else {
11860                return;
11861            }
11862        } else {
11863            return;
11864        };
11865        self.do_paste(&text, metadata, false, window, cx);
11866    }
11867
11868    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11869        self.do_copy(true, cx);
11870    }
11871
11872    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11873        self.do_copy(false, cx);
11874    }
11875
11876    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11877        let selections = self.selections.all::<Point>(cx);
11878        let buffer = self.buffer.read(cx).read(cx);
11879        let mut text = String::new();
11880
11881        let mut clipboard_selections = Vec::with_capacity(selections.len());
11882        {
11883            let max_point = buffer.max_point();
11884            let mut is_first = true;
11885            for selection in &selections {
11886                let mut start = selection.start;
11887                let mut end = selection.end;
11888                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11889                if is_entire_line {
11890                    start = Point::new(start.row, 0);
11891                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11892                }
11893
11894                let mut trimmed_selections = Vec::new();
11895                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11896                    let row = MultiBufferRow(start.row);
11897                    let first_indent = buffer.indent_size_for_line(row);
11898                    if first_indent.len == 0 || start.column > first_indent.len {
11899                        trimmed_selections.push(start..end);
11900                    } else {
11901                        trimmed_selections.push(
11902                            Point::new(row.0, first_indent.len)
11903                                ..Point::new(row.0, buffer.line_len(row)),
11904                        );
11905                        for row in start.row + 1..=end.row {
11906                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11907                            if row == end.row {
11908                                line_len = end.column;
11909                            }
11910                            if line_len == 0 {
11911                                trimmed_selections
11912                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11913                                continue;
11914                            }
11915                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11916                            if row_indent_size.len >= first_indent.len {
11917                                trimmed_selections.push(
11918                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11919                                );
11920                            } else {
11921                                trimmed_selections.clear();
11922                                trimmed_selections.push(start..end);
11923                                break;
11924                            }
11925                        }
11926                    }
11927                } else {
11928                    trimmed_selections.push(start..end);
11929                }
11930
11931                for trimmed_range in trimmed_selections {
11932                    if is_first {
11933                        is_first = false;
11934                    } else {
11935                        text += "\n";
11936                    }
11937                    let mut len = 0;
11938                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11939                        text.push_str(chunk);
11940                        len += chunk.len();
11941                    }
11942                    clipboard_selections.push(ClipboardSelection {
11943                        len,
11944                        is_entire_line,
11945                        first_line_indent: buffer
11946                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11947                            .len,
11948                    });
11949                }
11950            }
11951        }
11952
11953        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11954            text,
11955            clipboard_selections,
11956        ));
11957    }
11958
11959    pub fn do_paste(
11960        &mut self,
11961        text: &String,
11962        clipboard_selections: Option<Vec<ClipboardSelection>>,
11963        handle_entire_lines: bool,
11964        window: &mut Window,
11965        cx: &mut Context<Self>,
11966    ) {
11967        if self.read_only(cx) {
11968            return;
11969        }
11970
11971        let clipboard_text = Cow::Borrowed(text);
11972
11973        self.transact(window, cx, |this, window, cx| {
11974            if let Some(mut clipboard_selections) = clipboard_selections {
11975                let old_selections = this.selections.all::<usize>(cx);
11976                let all_selections_were_entire_line =
11977                    clipboard_selections.iter().all(|s| s.is_entire_line);
11978                let first_selection_indent_column =
11979                    clipboard_selections.first().map(|s| s.first_line_indent);
11980                if clipboard_selections.len() != old_selections.len() {
11981                    clipboard_selections.drain(..);
11982                }
11983                let cursor_offset = this.selections.last::<usize>(cx).head();
11984                let mut auto_indent_on_paste = true;
11985
11986                this.buffer.update(cx, |buffer, cx| {
11987                    let snapshot = buffer.read(cx);
11988                    auto_indent_on_paste = snapshot
11989                        .language_settings_at(cursor_offset, cx)
11990                        .auto_indent_on_paste;
11991
11992                    let mut start_offset = 0;
11993                    let mut edits = Vec::new();
11994                    let mut original_indent_columns = Vec::new();
11995                    for (ix, selection) in old_selections.iter().enumerate() {
11996                        let to_insert;
11997                        let entire_line;
11998                        let original_indent_column;
11999                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12000                            let end_offset = start_offset + clipboard_selection.len;
12001                            to_insert = &clipboard_text[start_offset..end_offset];
12002                            entire_line = clipboard_selection.is_entire_line;
12003                            start_offset = end_offset + 1;
12004                            original_indent_column = Some(clipboard_selection.first_line_indent);
12005                        } else {
12006                            to_insert = clipboard_text.as_str();
12007                            entire_line = all_selections_were_entire_line;
12008                            original_indent_column = first_selection_indent_column
12009                        }
12010
12011                        // If the corresponding selection was empty when this slice of the
12012                        // clipboard text was written, then the entire line containing the
12013                        // selection was copied. If this selection is also currently empty,
12014                        // then paste the line before the current line of the buffer.
12015                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12016                            let column = selection.start.to_point(&snapshot).column as usize;
12017                            let line_start = selection.start - column;
12018                            line_start..line_start
12019                        } else {
12020                            selection.range()
12021                        };
12022
12023                        edits.push((range, to_insert));
12024                        original_indent_columns.push(original_indent_column);
12025                    }
12026                    drop(snapshot);
12027
12028                    buffer.edit(
12029                        edits,
12030                        if auto_indent_on_paste {
12031                            Some(AutoindentMode::Block {
12032                                original_indent_columns,
12033                            })
12034                        } else {
12035                            None
12036                        },
12037                        cx,
12038                    );
12039                });
12040
12041                let selections = this.selections.all::<usize>(cx);
12042                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12043            } else {
12044                this.insert(&clipboard_text, window, cx);
12045            }
12046        });
12047    }
12048
12049    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12050        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12051        if let Some(item) = cx.read_from_clipboard() {
12052            let entries = item.entries();
12053
12054            match entries.first() {
12055                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12056                // of all the pasted entries.
12057                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12058                    .do_paste(
12059                        clipboard_string.text(),
12060                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12061                        true,
12062                        window,
12063                        cx,
12064                    ),
12065                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12066            }
12067        }
12068    }
12069
12070    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12071        if self.read_only(cx) {
12072            return;
12073        }
12074
12075        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12076
12077        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12078            if let Some((selections, _)) =
12079                self.selection_history.transaction(transaction_id).cloned()
12080            {
12081                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12082                    s.select_anchors(selections.to_vec());
12083                });
12084            } else {
12085                log::error!(
12086                    "No entry in selection_history found for undo. \
12087                     This may correspond to a bug where undo does not update the selection. \
12088                     If this is occurring, please add details to \
12089                     https://github.com/zed-industries/zed/issues/22692"
12090                );
12091            }
12092            self.request_autoscroll(Autoscroll::fit(), cx);
12093            self.unmark_text(window, cx);
12094            self.refresh_inline_completion(true, false, window, cx);
12095            cx.emit(EditorEvent::Edited { transaction_id });
12096            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12097        }
12098    }
12099
12100    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12101        if self.read_only(cx) {
12102            return;
12103        }
12104
12105        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12106
12107        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12108            if let Some((_, Some(selections))) =
12109                self.selection_history.transaction(transaction_id).cloned()
12110            {
12111                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12112                    s.select_anchors(selections.to_vec());
12113                });
12114            } else {
12115                log::error!(
12116                    "No entry in selection_history found for redo. \
12117                     This may correspond to a bug where undo does not update the selection. \
12118                     If this is occurring, please add details to \
12119                     https://github.com/zed-industries/zed/issues/22692"
12120                );
12121            }
12122            self.request_autoscroll(Autoscroll::fit(), cx);
12123            self.unmark_text(window, cx);
12124            self.refresh_inline_completion(true, false, window, cx);
12125            cx.emit(EditorEvent::Edited { transaction_id });
12126        }
12127    }
12128
12129    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12130        self.buffer
12131            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12132    }
12133
12134    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12135        self.buffer
12136            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12137    }
12138
12139    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12140        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12141        self.change_selections(Default::default(), window, cx, |s| {
12142            s.move_with(|map, selection| {
12143                let cursor = if selection.is_empty() {
12144                    movement::left(map, selection.start)
12145                } else {
12146                    selection.start
12147                };
12148                selection.collapse_to(cursor, SelectionGoal::None);
12149            });
12150        })
12151    }
12152
12153    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12154        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12155        self.change_selections(Default::default(), window, cx, |s| {
12156            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12157        })
12158    }
12159
12160    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12161        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12162        self.change_selections(Default::default(), window, cx, |s| {
12163            s.move_with(|map, selection| {
12164                let cursor = if selection.is_empty() {
12165                    movement::right(map, selection.end)
12166                } else {
12167                    selection.end
12168                };
12169                selection.collapse_to(cursor, SelectionGoal::None)
12170            });
12171        })
12172    }
12173
12174    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12175        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12176        self.change_selections(Default::default(), window, cx, |s| {
12177            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12178        })
12179    }
12180
12181    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12182        if self.take_rename(true, window, cx).is_some() {
12183            return;
12184        }
12185
12186        if self.mode.is_single_line() {
12187            cx.propagate();
12188            return;
12189        }
12190
12191        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12192
12193        let text_layout_details = &self.text_layout_details(window);
12194        let selection_count = self.selections.count();
12195        let first_selection = self.selections.first_anchor();
12196
12197        self.change_selections(Default::default(), window, cx, |s| {
12198            s.move_with(|map, selection| {
12199                if !selection.is_empty() {
12200                    selection.goal = SelectionGoal::None;
12201                }
12202                let (cursor, goal) = movement::up(
12203                    map,
12204                    selection.start,
12205                    selection.goal,
12206                    false,
12207                    text_layout_details,
12208                );
12209                selection.collapse_to(cursor, goal);
12210            });
12211        });
12212
12213        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12214        {
12215            cx.propagate();
12216        }
12217    }
12218
12219    pub fn move_up_by_lines(
12220        &mut self,
12221        action: &MoveUpByLines,
12222        window: &mut Window,
12223        cx: &mut Context<Self>,
12224    ) {
12225        if self.take_rename(true, window, cx).is_some() {
12226            return;
12227        }
12228
12229        if self.mode.is_single_line() {
12230            cx.propagate();
12231            return;
12232        }
12233
12234        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12235
12236        let text_layout_details = &self.text_layout_details(window);
12237
12238        self.change_selections(Default::default(), window, cx, |s| {
12239            s.move_with(|map, selection| {
12240                if !selection.is_empty() {
12241                    selection.goal = SelectionGoal::None;
12242                }
12243                let (cursor, goal) = movement::up_by_rows(
12244                    map,
12245                    selection.start,
12246                    action.lines,
12247                    selection.goal,
12248                    false,
12249                    text_layout_details,
12250                );
12251                selection.collapse_to(cursor, goal);
12252            });
12253        })
12254    }
12255
12256    pub fn move_down_by_lines(
12257        &mut self,
12258        action: &MoveDownByLines,
12259        window: &mut Window,
12260        cx: &mut Context<Self>,
12261    ) {
12262        if self.take_rename(true, window, cx).is_some() {
12263            return;
12264        }
12265
12266        if self.mode.is_single_line() {
12267            cx.propagate();
12268            return;
12269        }
12270
12271        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12272
12273        let text_layout_details = &self.text_layout_details(window);
12274
12275        self.change_selections(Default::default(), window, cx, |s| {
12276            s.move_with(|map, selection| {
12277                if !selection.is_empty() {
12278                    selection.goal = SelectionGoal::None;
12279                }
12280                let (cursor, goal) = movement::down_by_rows(
12281                    map,
12282                    selection.start,
12283                    action.lines,
12284                    selection.goal,
12285                    false,
12286                    text_layout_details,
12287                );
12288                selection.collapse_to(cursor, goal);
12289            });
12290        })
12291    }
12292
12293    pub fn select_down_by_lines(
12294        &mut self,
12295        action: &SelectDownByLines,
12296        window: &mut Window,
12297        cx: &mut Context<Self>,
12298    ) {
12299        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12300        let text_layout_details = &self.text_layout_details(window);
12301        self.change_selections(Default::default(), window, cx, |s| {
12302            s.move_heads_with(|map, head, goal| {
12303                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12304            })
12305        })
12306    }
12307
12308    pub fn select_up_by_lines(
12309        &mut self,
12310        action: &SelectUpByLines,
12311        window: &mut Window,
12312        cx: &mut Context<Self>,
12313    ) {
12314        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12315        let text_layout_details = &self.text_layout_details(window);
12316        self.change_selections(Default::default(), window, cx, |s| {
12317            s.move_heads_with(|map, head, goal| {
12318                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12319            })
12320        })
12321    }
12322
12323    pub fn select_page_up(
12324        &mut self,
12325        _: &SelectPageUp,
12326        window: &mut Window,
12327        cx: &mut Context<Self>,
12328    ) {
12329        let Some(row_count) = self.visible_row_count() else {
12330            return;
12331        };
12332
12333        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12334
12335        let text_layout_details = &self.text_layout_details(window);
12336
12337        self.change_selections(Default::default(), window, cx, |s| {
12338            s.move_heads_with(|map, head, goal| {
12339                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12340            })
12341        })
12342    }
12343
12344    pub fn move_page_up(
12345        &mut self,
12346        action: &MovePageUp,
12347        window: &mut Window,
12348        cx: &mut Context<Self>,
12349    ) {
12350        if self.take_rename(true, window, cx).is_some() {
12351            return;
12352        }
12353
12354        if self
12355            .context_menu
12356            .borrow_mut()
12357            .as_mut()
12358            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12359            .unwrap_or(false)
12360        {
12361            return;
12362        }
12363
12364        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12365            cx.propagate();
12366            return;
12367        }
12368
12369        let Some(row_count) = self.visible_row_count() else {
12370            return;
12371        };
12372
12373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12374
12375        let effects = if action.center_cursor {
12376            SelectionEffects::scroll(Autoscroll::center())
12377        } else {
12378            SelectionEffects::default()
12379        };
12380
12381        let text_layout_details = &self.text_layout_details(window);
12382
12383        self.change_selections(effects, window, cx, |s| {
12384            s.move_with(|map, selection| {
12385                if !selection.is_empty() {
12386                    selection.goal = SelectionGoal::None;
12387                }
12388                let (cursor, goal) = movement::up_by_rows(
12389                    map,
12390                    selection.end,
12391                    row_count,
12392                    selection.goal,
12393                    false,
12394                    text_layout_details,
12395                );
12396                selection.collapse_to(cursor, goal);
12397            });
12398        });
12399    }
12400
12401    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12402        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12403        let text_layout_details = &self.text_layout_details(window);
12404        self.change_selections(Default::default(), window, cx, |s| {
12405            s.move_heads_with(|map, head, goal| {
12406                movement::up(map, head, goal, false, text_layout_details)
12407            })
12408        })
12409    }
12410
12411    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12412        self.take_rename(true, window, cx);
12413
12414        if self.mode.is_single_line() {
12415            cx.propagate();
12416            return;
12417        }
12418
12419        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12420
12421        let text_layout_details = &self.text_layout_details(window);
12422        let selection_count = self.selections.count();
12423        let first_selection = self.selections.first_anchor();
12424
12425        self.change_selections(Default::default(), window, cx, |s| {
12426            s.move_with(|map, selection| {
12427                if !selection.is_empty() {
12428                    selection.goal = SelectionGoal::None;
12429                }
12430                let (cursor, goal) = movement::down(
12431                    map,
12432                    selection.end,
12433                    selection.goal,
12434                    false,
12435                    text_layout_details,
12436                );
12437                selection.collapse_to(cursor, goal);
12438            });
12439        });
12440
12441        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12442        {
12443            cx.propagate();
12444        }
12445    }
12446
12447    pub fn select_page_down(
12448        &mut self,
12449        _: &SelectPageDown,
12450        window: &mut Window,
12451        cx: &mut Context<Self>,
12452    ) {
12453        let Some(row_count) = self.visible_row_count() else {
12454            return;
12455        };
12456
12457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12458
12459        let text_layout_details = &self.text_layout_details(window);
12460
12461        self.change_selections(Default::default(), window, cx, |s| {
12462            s.move_heads_with(|map, head, goal| {
12463                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12464            })
12465        })
12466    }
12467
12468    pub fn move_page_down(
12469        &mut self,
12470        action: &MovePageDown,
12471        window: &mut Window,
12472        cx: &mut Context<Self>,
12473    ) {
12474        if self.take_rename(true, window, cx).is_some() {
12475            return;
12476        }
12477
12478        if self
12479            .context_menu
12480            .borrow_mut()
12481            .as_mut()
12482            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12483            .unwrap_or(false)
12484        {
12485            return;
12486        }
12487
12488        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12489            cx.propagate();
12490            return;
12491        }
12492
12493        let Some(row_count) = self.visible_row_count() else {
12494            return;
12495        };
12496
12497        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12498
12499        let effects = if action.center_cursor {
12500            SelectionEffects::scroll(Autoscroll::center())
12501        } else {
12502            SelectionEffects::default()
12503        };
12504
12505        let text_layout_details = &self.text_layout_details(window);
12506        self.change_selections(effects, window, cx, |s| {
12507            s.move_with(|map, selection| {
12508                if !selection.is_empty() {
12509                    selection.goal = SelectionGoal::None;
12510                }
12511                let (cursor, goal) = movement::down_by_rows(
12512                    map,
12513                    selection.end,
12514                    row_count,
12515                    selection.goal,
12516                    false,
12517                    text_layout_details,
12518                );
12519                selection.collapse_to(cursor, goal);
12520            });
12521        });
12522    }
12523
12524    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12526        let text_layout_details = &self.text_layout_details(window);
12527        self.change_selections(Default::default(), window, cx, |s| {
12528            s.move_heads_with(|map, head, goal| {
12529                movement::down(map, head, goal, false, text_layout_details)
12530            })
12531        });
12532    }
12533
12534    pub fn context_menu_first(
12535        &mut self,
12536        _: &ContextMenuFirst,
12537        window: &mut Window,
12538        cx: &mut Context<Self>,
12539    ) {
12540        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12541            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12542        }
12543    }
12544
12545    pub fn context_menu_prev(
12546        &mut self,
12547        _: &ContextMenuPrevious,
12548        window: &mut Window,
12549        cx: &mut Context<Self>,
12550    ) {
12551        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12552            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12553        }
12554    }
12555
12556    pub fn context_menu_next(
12557        &mut self,
12558        _: &ContextMenuNext,
12559        window: &mut Window,
12560        cx: &mut Context<Self>,
12561    ) {
12562        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12563            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12564        }
12565    }
12566
12567    pub fn context_menu_last(
12568        &mut self,
12569        _: &ContextMenuLast,
12570        window: &mut Window,
12571        cx: &mut Context<Self>,
12572    ) {
12573        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12574            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12575        }
12576    }
12577
12578    pub fn move_to_previous_word_start(
12579        &mut self,
12580        _: &MoveToPreviousWordStart,
12581        window: &mut Window,
12582        cx: &mut Context<Self>,
12583    ) {
12584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12585        self.change_selections(Default::default(), window, cx, |s| {
12586            s.move_cursors_with(|map, head, _| {
12587                (
12588                    movement::previous_word_start(map, head),
12589                    SelectionGoal::None,
12590                )
12591            });
12592        })
12593    }
12594
12595    pub fn move_to_previous_subword_start(
12596        &mut self,
12597        _: &MoveToPreviousSubwordStart,
12598        window: &mut Window,
12599        cx: &mut Context<Self>,
12600    ) {
12601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12602        self.change_selections(Default::default(), window, cx, |s| {
12603            s.move_cursors_with(|map, head, _| {
12604                (
12605                    movement::previous_subword_start(map, head),
12606                    SelectionGoal::None,
12607                )
12608            });
12609        })
12610    }
12611
12612    pub fn select_to_previous_word_start(
12613        &mut self,
12614        _: &SelectToPreviousWordStart,
12615        window: &mut Window,
12616        cx: &mut Context<Self>,
12617    ) {
12618        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12619        self.change_selections(Default::default(), window, cx, |s| {
12620            s.move_heads_with(|map, head, _| {
12621                (
12622                    movement::previous_word_start(map, head),
12623                    SelectionGoal::None,
12624                )
12625            });
12626        })
12627    }
12628
12629    pub fn select_to_previous_subword_start(
12630        &mut self,
12631        _: &SelectToPreviousSubwordStart,
12632        window: &mut Window,
12633        cx: &mut Context<Self>,
12634    ) {
12635        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12636        self.change_selections(Default::default(), window, cx, |s| {
12637            s.move_heads_with(|map, head, _| {
12638                (
12639                    movement::previous_subword_start(map, head),
12640                    SelectionGoal::None,
12641                )
12642            });
12643        })
12644    }
12645
12646    pub fn delete_to_previous_word_start(
12647        &mut self,
12648        action: &DeleteToPreviousWordStart,
12649        window: &mut Window,
12650        cx: &mut Context<Self>,
12651    ) {
12652        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12653        self.transact(window, cx, |this, window, cx| {
12654            this.select_autoclose_pair(window, cx);
12655            this.change_selections(Default::default(), window, cx, |s| {
12656                s.move_with(|map, selection| {
12657                    if selection.is_empty() {
12658                        let cursor = if action.ignore_newlines {
12659                            movement::previous_word_start(map, selection.head())
12660                        } else {
12661                            movement::previous_word_start_or_newline(map, selection.head())
12662                        };
12663                        selection.set_head(cursor, SelectionGoal::None);
12664                    }
12665                });
12666            });
12667            this.insert("", window, cx);
12668        });
12669    }
12670
12671    pub fn delete_to_previous_subword_start(
12672        &mut self,
12673        _: &DeleteToPreviousSubwordStart,
12674        window: &mut Window,
12675        cx: &mut Context<Self>,
12676    ) {
12677        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12678        self.transact(window, cx, |this, window, cx| {
12679            this.select_autoclose_pair(window, cx);
12680            this.change_selections(Default::default(), window, cx, |s| {
12681                s.move_with(|map, selection| {
12682                    if selection.is_empty() {
12683                        let cursor = movement::previous_subword_start(map, selection.head());
12684                        selection.set_head(cursor, SelectionGoal::None);
12685                    }
12686                });
12687            });
12688            this.insert("", window, cx);
12689        });
12690    }
12691
12692    pub fn move_to_next_word_end(
12693        &mut self,
12694        _: &MoveToNextWordEnd,
12695        window: &mut Window,
12696        cx: &mut Context<Self>,
12697    ) {
12698        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12699        self.change_selections(Default::default(), window, cx, |s| {
12700            s.move_cursors_with(|map, head, _| {
12701                (movement::next_word_end(map, head), SelectionGoal::None)
12702            });
12703        })
12704    }
12705
12706    pub fn move_to_next_subword_end(
12707        &mut self,
12708        _: &MoveToNextSubwordEnd,
12709        window: &mut Window,
12710        cx: &mut Context<Self>,
12711    ) {
12712        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12713        self.change_selections(Default::default(), window, cx, |s| {
12714            s.move_cursors_with(|map, head, _| {
12715                (movement::next_subword_end(map, head), SelectionGoal::None)
12716            });
12717        })
12718    }
12719
12720    pub fn select_to_next_word_end(
12721        &mut self,
12722        _: &SelectToNextWordEnd,
12723        window: &mut Window,
12724        cx: &mut Context<Self>,
12725    ) {
12726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12727        self.change_selections(Default::default(), window, cx, |s| {
12728            s.move_heads_with(|map, head, _| {
12729                (movement::next_word_end(map, head), SelectionGoal::None)
12730            });
12731        })
12732    }
12733
12734    pub fn select_to_next_subword_end(
12735        &mut self,
12736        _: &SelectToNextSubwordEnd,
12737        window: &mut Window,
12738        cx: &mut Context<Self>,
12739    ) {
12740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12741        self.change_selections(Default::default(), window, cx, |s| {
12742            s.move_heads_with(|map, head, _| {
12743                (movement::next_subword_end(map, head), SelectionGoal::None)
12744            });
12745        })
12746    }
12747
12748    pub fn delete_to_next_word_end(
12749        &mut self,
12750        action: &DeleteToNextWordEnd,
12751        window: &mut Window,
12752        cx: &mut Context<Self>,
12753    ) {
12754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12755        self.transact(window, cx, |this, window, cx| {
12756            this.change_selections(Default::default(), window, cx, |s| {
12757                s.move_with(|map, selection| {
12758                    if selection.is_empty() {
12759                        let cursor = if action.ignore_newlines {
12760                            movement::next_word_end(map, selection.head())
12761                        } else {
12762                            movement::next_word_end_or_newline(map, selection.head())
12763                        };
12764                        selection.set_head(cursor, SelectionGoal::None);
12765                    }
12766                });
12767            });
12768            this.insert("", window, cx);
12769        });
12770    }
12771
12772    pub fn delete_to_next_subword_end(
12773        &mut self,
12774        _: &DeleteToNextSubwordEnd,
12775        window: &mut Window,
12776        cx: &mut Context<Self>,
12777    ) {
12778        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12779        self.transact(window, cx, |this, window, cx| {
12780            this.change_selections(Default::default(), window, cx, |s| {
12781                s.move_with(|map, selection| {
12782                    if selection.is_empty() {
12783                        let cursor = movement::next_subword_end(map, selection.head());
12784                        selection.set_head(cursor, SelectionGoal::None);
12785                    }
12786                });
12787            });
12788            this.insert("", window, cx);
12789        });
12790    }
12791
12792    pub fn move_to_beginning_of_line(
12793        &mut self,
12794        action: &MoveToBeginningOfLine,
12795        window: &mut Window,
12796        cx: &mut Context<Self>,
12797    ) {
12798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12799        self.change_selections(Default::default(), window, cx, |s| {
12800            s.move_cursors_with(|map, head, _| {
12801                (
12802                    movement::indented_line_beginning(
12803                        map,
12804                        head,
12805                        action.stop_at_soft_wraps,
12806                        action.stop_at_indent,
12807                    ),
12808                    SelectionGoal::None,
12809                )
12810            });
12811        })
12812    }
12813
12814    pub fn select_to_beginning_of_line(
12815        &mut self,
12816        action: &SelectToBeginningOfLine,
12817        window: &mut Window,
12818        cx: &mut Context<Self>,
12819    ) {
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12821        self.change_selections(Default::default(), window, cx, |s| {
12822            s.move_heads_with(|map, head, _| {
12823                (
12824                    movement::indented_line_beginning(
12825                        map,
12826                        head,
12827                        action.stop_at_soft_wraps,
12828                        action.stop_at_indent,
12829                    ),
12830                    SelectionGoal::None,
12831                )
12832            });
12833        });
12834    }
12835
12836    pub fn delete_to_beginning_of_line(
12837        &mut self,
12838        action: &DeleteToBeginningOfLine,
12839        window: &mut Window,
12840        cx: &mut Context<Self>,
12841    ) {
12842        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12843        self.transact(window, cx, |this, window, cx| {
12844            this.change_selections(Default::default(), window, cx, |s| {
12845                s.move_with(|_, selection| {
12846                    selection.reversed = true;
12847                });
12848            });
12849
12850            this.select_to_beginning_of_line(
12851                &SelectToBeginningOfLine {
12852                    stop_at_soft_wraps: false,
12853                    stop_at_indent: action.stop_at_indent,
12854                },
12855                window,
12856                cx,
12857            );
12858            this.backspace(&Backspace, window, cx);
12859        });
12860    }
12861
12862    pub fn move_to_end_of_line(
12863        &mut self,
12864        action: &MoveToEndOfLine,
12865        window: &mut Window,
12866        cx: &mut Context<Self>,
12867    ) {
12868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12869        self.change_selections(Default::default(), window, cx, |s| {
12870            s.move_cursors_with(|map, head, _| {
12871                (
12872                    movement::line_end(map, head, action.stop_at_soft_wraps),
12873                    SelectionGoal::None,
12874                )
12875            });
12876        })
12877    }
12878
12879    pub fn select_to_end_of_line(
12880        &mut self,
12881        action: &SelectToEndOfLine,
12882        window: &mut Window,
12883        cx: &mut Context<Self>,
12884    ) {
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12886        self.change_selections(Default::default(), window, cx, |s| {
12887            s.move_heads_with(|map, head, _| {
12888                (
12889                    movement::line_end(map, head, action.stop_at_soft_wraps),
12890                    SelectionGoal::None,
12891                )
12892            });
12893        })
12894    }
12895
12896    pub fn delete_to_end_of_line(
12897        &mut self,
12898        _: &DeleteToEndOfLine,
12899        window: &mut Window,
12900        cx: &mut Context<Self>,
12901    ) {
12902        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12903        self.transact(window, cx, |this, window, cx| {
12904            this.select_to_end_of_line(
12905                &SelectToEndOfLine {
12906                    stop_at_soft_wraps: false,
12907                },
12908                window,
12909                cx,
12910            );
12911            this.delete(&Delete, window, cx);
12912        });
12913    }
12914
12915    pub fn cut_to_end_of_line(
12916        &mut self,
12917        _: &CutToEndOfLine,
12918        window: &mut Window,
12919        cx: &mut Context<Self>,
12920    ) {
12921        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12922        self.transact(window, cx, |this, window, cx| {
12923            this.select_to_end_of_line(
12924                &SelectToEndOfLine {
12925                    stop_at_soft_wraps: false,
12926                },
12927                window,
12928                cx,
12929            );
12930            this.cut(&Cut, window, cx);
12931        });
12932    }
12933
12934    pub fn move_to_start_of_paragraph(
12935        &mut self,
12936        _: &MoveToStartOfParagraph,
12937        window: &mut Window,
12938        cx: &mut Context<Self>,
12939    ) {
12940        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12941            cx.propagate();
12942            return;
12943        }
12944        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12945        self.change_selections(Default::default(), window, cx, |s| {
12946            s.move_with(|map, selection| {
12947                selection.collapse_to(
12948                    movement::start_of_paragraph(map, selection.head(), 1),
12949                    SelectionGoal::None,
12950                )
12951            });
12952        })
12953    }
12954
12955    pub fn move_to_end_of_paragraph(
12956        &mut self,
12957        _: &MoveToEndOfParagraph,
12958        window: &mut Window,
12959        cx: &mut Context<Self>,
12960    ) {
12961        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12962            cx.propagate();
12963            return;
12964        }
12965        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12966        self.change_selections(Default::default(), window, cx, |s| {
12967            s.move_with(|map, selection| {
12968                selection.collapse_to(
12969                    movement::end_of_paragraph(map, selection.head(), 1),
12970                    SelectionGoal::None,
12971                )
12972            });
12973        })
12974    }
12975
12976    pub fn select_to_start_of_paragraph(
12977        &mut self,
12978        _: &SelectToStartOfParagraph,
12979        window: &mut Window,
12980        cx: &mut Context<Self>,
12981    ) {
12982        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12983            cx.propagate();
12984            return;
12985        }
12986        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12987        self.change_selections(Default::default(), window, cx, |s| {
12988            s.move_heads_with(|map, head, _| {
12989                (
12990                    movement::start_of_paragraph(map, head, 1),
12991                    SelectionGoal::None,
12992                )
12993            });
12994        })
12995    }
12996
12997    pub fn select_to_end_of_paragraph(
12998        &mut self,
12999        _: &SelectToEndOfParagraph,
13000        window: &mut Window,
13001        cx: &mut Context<Self>,
13002    ) {
13003        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13004            cx.propagate();
13005            return;
13006        }
13007        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13008        self.change_selections(Default::default(), window, cx, |s| {
13009            s.move_heads_with(|map, head, _| {
13010                (
13011                    movement::end_of_paragraph(map, head, 1),
13012                    SelectionGoal::None,
13013                )
13014            });
13015        })
13016    }
13017
13018    pub fn move_to_start_of_excerpt(
13019        &mut self,
13020        _: &MoveToStartOfExcerpt,
13021        window: &mut Window,
13022        cx: &mut Context<Self>,
13023    ) {
13024        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13025            cx.propagate();
13026            return;
13027        }
13028        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13029        self.change_selections(Default::default(), window, cx, |s| {
13030            s.move_with(|map, selection| {
13031                selection.collapse_to(
13032                    movement::start_of_excerpt(
13033                        map,
13034                        selection.head(),
13035                        workspace::searchable::Direction::Prev,
13036                    ),
13037                    SelectionGoal::None,
13038                )
13039            });
13040        })
13041    }
13042
13043    pub fn move_to_start_of_next_excerpt(
13044        &mut self,
13045        _: &MoveToStartOfNextExcerpt,
13046        window: &mut Window,
13047        cx: &mut Context<Self>,
13048    ) {
13049        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13050            cx.propagate();
13051            return;
13052        }
13053
13054        self.change_selections(Default::default(), window, cx, |s| {
13055            s.move_with(|map, selection| {
13056                selection.collapse_to(
13057                    movement::start_of_excerpt(
13058                        map,
13059                        selection.head(),
13060                        workspace::searchable::Direction::Next,
13061                    ),
13062                    SelectionGoal::None,
13063                )
13064            });
13065        })
13066    }
13067
13068    pub fn move_to_end_of_excerpt(
13069        &mut self,
13070        _: &MoveToEndOfExcerpt,
13071        window: &mut Window,
13072        cx: &mut Context<Self>,
13073    ) {
13074        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13075            cx.propagate();
13076            return;
13077        }
13078        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13079        self.change_selections(Default::default(), window, cx, |s| {
13080            s.move_with(|map, selection| {
13081                selection.collapse_to(
13082                    movement::end_of_excerpt(
13083                        map,
13084                        selection.head(),
13085                        workspace::searchable::Direction::Next,
13086                    ),
13087                    SelectionGoal::None,
13088                )
13089            });
13090        })
13091    }
13092
13093    pub fn move_to_end_of_previous_excerpt(
13094        &mut self,
13095        _: &MoveToEndOfPreviousExcerpt,
13096        window: &mut Window,
13097        cx: &mut Context<Self>,
13098    ) {
13099        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13100            cx.propagate();
13101            return;
13102        }
13103        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13104        self.change_selections(Default::default(), window, cx, |s| {
13105            s.move_with(|map, selection| {
13106                selection.collapse_to(
13107                    movement::end_of_excerpt(
13108                        map,
13109                        selection.head(),
13110                        workspace::searchable::Direction::Prev,
13111                    ),
13112                    SelectionGoal::None,
13113                )
13114            });
13115        })
13116    }
13117
13118    pub fn select_to_start_of_excerpt(
13119        &mut self,
13120        _: &SelectToStartOfExcerpt,
13121        window: &mut Window,
13122        cx: &mut Context<Self>,
13123    ) {
13124        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13125            cx.propagate();
13126            return;
13127        }
13128        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13129        self.change_selections(Default::default(), window, cx, |s| {
13130            s.move_heads_with(|map, head, _| {
13131                (
13132                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13133                    SelectionGoal::None,
13134                )
13135            });
13136        })
13137    }
13138
13139    pub fn select_to_start_of_next_excerpt(
13140        &mut self,
13141        _: &SelectToStartOfNextExcerpt,
13142        window: &mut Window,
13143        cx: &mut Context<Self>,
13144    ) {
13145        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13146            cx.propagate();
13147            return;
13148        }
13149        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13150        self.change_selections(Default::default(), window, cx, |s| {
13151            s.move_heads_with(|map, head, _| {
13152                (
13153                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13154                    SelectionGoal::None,
13155                )
13156            });
13157        })
13158    }
13159
13160    pub fn select_to_end_of_excerpt(
13161        &mut self,
13162        _: &SelectToEndOfExcerpt,
13163        window: &mut Window,
13164        cx: &mut Context<Self>,
13165    ) {
13166        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13167            cx.propagate();
13168            return;
13169        }
13170        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13171        self.change_selections(Default::default(), window, cx, |s| {
13172            s.move_heads_with(|map, head, _| {
13173                (
13174                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13175                    SelectionGoal::None,
13176                )
13177            });
13178        })
13179    }
13180
13181    pub fn select_to_end_of_previous_excerpt(
13182        &mut self,
13183        _: &SelectToEndOfPreviousExcerpt,
13184        window: &mut Window,
13185        cx: &mut Context<Self>,
13186    ) {
13187        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13188            cx.propagate();
13189            return;
13190        }
13191        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13192        self.change_selections(Default::default(), window, cx, |s| {
13193            s.move_heads_with(|map, head, _| {
13194                (
13195                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13196                    SelectionGoal::None,
13197                )
13198            });
13199        })
13200    }
13201
13202    pub fn move_to_beginning(
13203        &mut self,
13204        _: &MoveToBeginning,
13205        window: &mut Window,
13206        cx: &mut Context<Self>,
13207    ) {
13208        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13209            cx.propagate();
13210            return;
13211        }
13212        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13213        self.change_selections(Default::default(), window, cx, |s| {
13214            s.select_ranges(vec![0..0]);
13215        });
13216    }
13217
13218    pub fn select_to_beginning(
13219        &mut self,
13220        _: &SelectToBeginning,
13221        window: &mut Window,
13222        cx: &mut Context<Self>,
13223    ) {
13224        let mut selection = self.selections.last::<Point>(cx);
13225        selection.set_head(Point::zero(), SelectionGoal::None);
13226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13227        self.change_selections(Default::default(), window, cx, |s| {
13228            s.select(vec![selection]);
13229        });
13230    }
13231
13232    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13233        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13234            cx.propagate();
13235            return;
13236        }
13237        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13238        let cursor = self.buffer.read(cx).read(cx).len();
13239        self.change_selections(Default::default(), window, cx, |s| {
13240            s.select_ranges(vec![cursor..cursor])
13241        });
13242    }
13243
13244    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13245        self.nav_history = nav_history;
13246    }
13247
13248    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13249        self.nav_history.as_ref()
13250    }
13251
13252    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13253        self.push_to_nav_history(
13254            self.selections.newest_anchor().head(),
13255            None,
13256            false,
13257            true,
13258            cx,
13259        );
13260    }
13261
13262    fn push_to_nav_history(
13263        &mut self,
13264        cursor_anchor: Anchor,
13265        new_position: Option<Point>,
13266        is_deactivate: bool,
13267        always: bool,
13268        cx: &mut Context<Self>,
13269    ) {
13270        if let Some(nav_history) = self.nav_history.as_mut() {
13271            let buffer = self.buffer.read(cx).read(cx);
13272            let cursor_position = cursor_anchor.to_point(&buffer);
13273            let scroll_state = self.scroll_manager.anchor();
13274            let scroll_top_row = scroll_state.top_row(&buffer);
13275            drop(buffer);
13276
13277            if let Some(new_position) = new_position {
13278                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13279                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13280                    return;
13281                }
13282            }
13283
13284            nav_history.push(
13285                Some(NavigationData {
13286                    cursor_anchor,
13287                    cursor_position,
13288                    scroll_anchor: scroll_state,
13289                    scroll_top_row,
13290                }),
13291                cx,
13292            );
13293            cx.emit(EditorEvent::PushedToNavHistory {
13294                anchor: cursor_anchor,
13295                is_deactivate,
13296            })
13297        }
13298    }
13299
13300    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13301        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13302        let buffer = self.buffer.read(cx).snapshot(cx);
13303        let mut selection = self.selections.first::<usize>(cx);
13304        selection.set_head(buffer.len(), SelectionGoal::None);
13305        self.change_selections(Default::default(), window, cx, |s| {
13306            s.select(vec![selection]);
13307        });
13308    }
13309
13310    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13311        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13312        let end = self.buffer.read(cx).read(cx).len();
13313        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13314            s.select_ranges(vec![0..end]);
13315        });
13316    }
13317
13318    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13319        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13320        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13321        let mut selections = self.selections.all::<Point>(cx);
13322        let max_point = display_map.buffer_snapshot.max_point();
13323        for selection in &mut selections {
13324            let rows = selection.spanned_rows(true, &display_map);
13325            selection.start = Point::new(rows.start.0, 0);
13326            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13327            selection.reversed = false;
13328        }
13329        self.change_selections(Default::default(), window, cx, |s| {
13330            s.select(selections);
13331        });
13332    }
13333
13334    pub fn split_selection_into_lines(
13335        &mut self,
13336        _: &SplitSelectionIntoLines,
13337        window: &mut Window,
13338        cx: &mut Context<Self>,
13339    ) {
13340        let selections = self
13341            .selections
13342            .all::<Point>(cx)
13343            .into_iter()
13344            .map(|selection| selection.start..selection.end)
13345            .collect::<Vec<_>>();
13346        self.unfold_ranges(&selections, true, true, cx);
13347
13348        let mut new_selection_ranges = Vec::new();
13349        {
13350            let buffer = self.buffer.read(cx).read(cx);
13351            for selection in selections {
13352                for row in selection.start.row..selection.end.row {
13353                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13354                    new_selection_ranges.push(cursor..cursor);
13355                }
13356
13357                let is_multiline_selection = selection.start.row != selection.end.row;
13358                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13359                // so this action feels more ergonomic when paired with other selection operations
13360                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13361                if !should_skip_last {
13362                    new_selection_ranges.push(selection.end..selection.end);
13363                }
13364            }
13365        }
13366        self.change_selections(Default::default(), window, cx, |s| {
13367            s.select_ranges(new_selection_ranges);
13368        });
13369    }
13370
13371    pub fn add_selection_above(
13372        &mut self,
13373        _: &AddSelectionAbove,
13374        window: &mut Window,
13375        cx: &mut Context<Self>,
13376    ) {
13377        self.add_selection(true, window, cx);
13378    }
13379
13380    pub fn add_selection_below(
13381        &mut self,
13382        _: &AddSelectionBelow,
13383        window: &mut Window,
13384        cx: &mut Context<Self>,
13385    ) {
13386        self.add_selection(false, window, cx);
13387    }
13388
13389    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13390        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13391
13392        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13393        let all_selections = self.selections.all::<Point>(cx);
13394        let text_layout_details = self.text_layout_details(window);
13395
13396        let (mut columnar_selections, new_selections_to_columnarize) = {
13397            if let Some(state) = self.add_selections_state.as_ref() {
13398                let columnar_selection_ids: HashSet<_> = state
13399                    .groups
13400                    .iter()
13401                    .flat_map(|group| group.stack.iter())
13402                    .copied()
13403                    .collect();
13404
13405                all_selections
13406                    .into_iter()
13407                    .partition(|s| columnar_selection_ids.contains(&s.id))
13408            } else {
13409                (Vec::new(), all_selections)
13410            }
13411        };
13412
13413        let mut state = self
13414            .add_selections_state
13415            .take()
13416            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13417
13418        for selection in new_selections_to_columnarize {
13419            let range = selection.display_range(&display_map).sorted();
13420            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13421            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13422            let positions = start_x.min(end_x)..start_x.max(end_x);
13423            let mut stack = Vec::new();
13424            for row in range.start.row().0..=range.end.row().0 {
13425                if let Some(selection) = self.selections.build_columnar_selection(
13426                    &display_map,
13427                    DisplayRow(row),
13428                    &positions,
13429                    selection.reversed,
13430                    &text_layout_details,
13431                ) {
13432                    stack.push(selection.id);
13433                    columnar_selections.push(selection);
13434                }
13435            }
13436            if !stack.is_empty() {
13437                if above {
13438                    stack.reverse();
13439                }
13440                state.groups.push(AddSelectionsGroup { above, stack });
13441            }
13442        }
13443
13444        let mut final_selections = Vec::new();
13445        let end_row = if above {
13446            DisplayRow(0)
13447        } else {
13448            display_map.max_point().row()
13449        };
13450
13451        let mut last_added_item_per_group = HashMap::default();
13452        for group in state.groups.iter_mut() {
13453            if let Some(last_id) = group.stack.last() {
13454                last_added_item_per_group.insert(*last_id, group);
13455            }
13456        }
13457
13458        for selection in columnar_selections {
13459            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13460                if above == group.above {
13461                    let range = selection.display_range(&display_map).sorted();
13462                    debug_assert_eq!(range.start.row(), range.end.row());
13463                    let mut row = range.start.row();
13464                    let positions =
13465                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13466                            px(start)..px(end)
13467                        } else {
13468                            let start_x =
13469                                display_map.x_for_display_point(range.start, &text_layout_details);
13470                            let end_x =
13471                                display_map.x_for_display_point(range.end, &text_layout_details);
13472                            start_x.min(end_x)..start_x.max(end_x)
13473                        };
13474
13475                    let mut maybe_new_selection = None;
13476                    while row != end_row {
13477                        if above {
13478                            row.0 -= 1;
13479                        } else {
13480                            row.0 += 1;
13481                        }
13482                        if let Some(new_selection) = self.selections.build_columnar_selection(
13483                            &display_map,
13484                            row,
13485                            &positions,
13486                            selection.reversed,
13487                            &text_layout_details,
13488                        ) {
13489                            maybe_new_selection = Some(new_selection);
13490                            break;
13491                        }
13492                    }
13493
13494                    if let Some(new_selection) = maybe_new_selection {
13495                        group.stack.push(new_selection.id);
13496                        if above {
13497                            final_selections.push(new_selection);
13498                            final_selections.push(selection);
13499                        } else {
13500                            final_selections.push(selection);
13501                            final_selections.push(new_selection);
13502                        }
13503                    } else {
13504                        final_selections.push(selection);
13505                    }
13506                } else {
13507                    group.stack.pop();
13508                }
13509            } else {
13510                final_selections.push(selection);
13511            }
13512        }
13513
13514        self.change_selections(Default::default(), window, cx, |s| {
13515            s.select(final_selections);
13516        });
13517
13518        let final_selection_ids: HashSet<_> = self
13519            .selections
13520            .all::<Point>(cx)
13521            .iter()
13522            .map(|s| s.id)
13523            .collect();
13524        state.groups.retain_mut(|group| {
13525            // selections might get merged above so we remove invalid items from stacks
13526            group.stack.retain(|id| final_selection_ids.contains(id));
13527
13528            // single selection in stack can be treated as initial state
13529            group.stack.len() > 1
13530        });
13531
13532        if !state.groups.is_empty() {
13533            self.add_selections_state = Some(state);
13534        }
13535    }
13536
13537    fn select_match_ranges(
13538        &mut self,
13539        range: Range<usize>,
13540        reversed: bool,
13541        replace_newest: bool,
13542        auto_scroll: Option<Autoscroll>,
13543        window: &mut Window,
13544        cx: &mut Context<Editor>,
13545    ) {
13546        self.unfold_ranges(
13547            std::slice::from_ref(&range),
13548            false,
13549            auto_scroll.is_some(),
13550            cx,
13551        );
13552        let effects = if let Some(scroll) = auto_scroll {
13553            SelectionEffects::scroll(scroll)
13554        } else {
13555            SelectionEffects::no_scroll()
13556        };
13557        self.change_selections(effects, window, cx, |s| {
13558            if replace_newest {
13559                s.delete(s.newest_anchor().id);
13560            }
13561            if reversed {
13562                s.insert_range(range.end..range.start);
13563            } else {
13564                s.insert_range(range);
13565            }
13566        });
13567    }
13568
13569    pub fn select_next_match_internal(
13570        &mut self,
13571        display_map: &DisplaySnapshot,
13572        replace_newest: bool,
13573        autoscroll: Option<Autoscroll>,
13574        window: &mut Window,
13575        cx: &mut Context<Self>,
13576    ) -> Result<()> {
13577        let buffer = &display_map.buffer_snapshot;
13578        let mut selections = self.selections.all::<usize>(cx);
13579        if let Some(mut select_next_state) = self.select_next_state.take() {
13580            let query = &select_next_state.query;
13581            if !select_next_state.done {
13582                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13583                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13584                let mut next_selected_range = None;
13585
13586                let bytes_after_last_selection =
13587                    buffer.bytes_in_range(last_selection.end..buffer.len());
13588                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13589                let query_matches = query
13590                    .stream_find_iter(bytes_after_last_selection)
13591                    .map(|result| (last_selection.end, result))
13592                    .chain(
13593                        query
13594                            .stream_find_iter(bytes_before_first_selection)
13595                            .map(|result| (0, result)),
13596                    );
13597
13598                for (start_offset, query_match) in query_matches {
13599                    let query_match = query_match.unwrap(); // can only fail due to I/O
13600                    let offset_range =
13601                        start_offset + query_match.start()..start_offset + query_match.end();
13602
13603                    if !select_next_state.wordwise
13604                        || (!buffer.is_inside_word(offset_range.start, false)
13605                            && !buffer.is_inside_word(offset_range.end, false))
13606                    {
13607                        // TODO: This is n^2, because we might check all the selections
13608                        if !selections
13609                            .iter()
13610                            .any(|selection| selection.range().overlaps(&offset_range))
13611                        {
13612                            next_selected_range = Some(offset_range);
13613                            break;
13614                        }
13615                    }
13616                }
13617
13618                if let Some(next_selected_range) = next_selected_range {
13619                    self.select_match_ranges(
13620                        next_selected_range,
13621                        last_selection.reversed,
13622                        replace_newest,
13623                        autoscroll,
13624                        window,
13625                        cx,
13626                    );
13627                } else {
13628                    select_next_state.done = true;
13629                }
13630            }
13631
13632            self.select_next_state = Some(select_next_state);
13633        } else {
13634            let mut only_carets = true;
13635            let mut same_text_selected = true;
13636            let mut selected_text = None;
13637
13638            let mut selections_iter = selections.iter().peekable();
13639            while let Some(selection) = selections_iter.next() {
13640                if selection.start != selection.end {
13641                    only_carets = false;
13642                }
13643
13644                if same_text_selected {
13645                    if selected_text.is_none() {
13646                        selected_text =
13647                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13648                    }
13649
13650                    if let Some(next_selection) = selections_iter.peek() {
13651                        if next_selection.range().len() == selection.range().len() {
13652                            let next_selected_text = buffer
13653                                .text_for_range(next_selection.range())
13654                                .collect::<String>();
13655                            if Some(next_selected_text) != selected_text {
13656                                same_text_selected = false;
13657                                selected_text = None;
13658                            }
13659                        } else {
13660                            same_text_selected = false;
13661                            selected_text = None;
13662                        }
13663                    }
13664                }
13665            }
13666
13667            if only_carets {
13668                for selection in &mut selections {
13669                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13670                    selection.start = word_range.start;
13671                    selection.end = word_range.end;
13672                    selection.goal = SelectionGoal::None;
13673                    selection.reversed = false;
13674                    self.select_match_ranges(
13675                        selection.start..selection.end,
13676                        selection.reversed,
13677                        replace_newest,
13678                        autoscroll,
13679                        window,
13680                        cx,
13681                    );
13682                }
13683
13684                if selections.len() == 1 {
13685                    let selection = selections
13686                        .last()
13687                        .expect("ensured that there's only one selection");
13688                    let query = buffer
13689                        .text_for_range(selection.start..selection.end)
13690                        .collect::<String>();
13691                    let is_empty = query.is_empty();
13692                    let select_state = SelectNextState {
13693                        query: AhoCorasick::new(&[query])?,
13694                        wordwise: true,
13695                        done: is_empty,
13696                    };
13697                    self.select_next_state = Some(select_state);
13698                } else {
13699                    self.select_next_state = None;
13700                }
13701            } else if let Some(selected_text) = selected_text {
13702                self.select_next_state = Some(SelectNextState {
13703                    query: AhoCorasick::new(&[selected_text])?,
13704                    wordwise: false,
13705                    done: false,
13706                });
13707                self.select_next_match_internal(
13708                    display_map,
13709                    replace_newest,
13710                    autoscroll,
13711                    window,
13712                    cx,
13713                )?;
13714            }
13715        }
13716        Ok(())
13717    }
13718
13719    pub fn select_all_matches(
13720        &mut self,
13721        _action: &SelectAllMatches,
13722        window: &mut Window,
13723        cx: &mut Context<Self>,
13724    ) -> Result<()> {
13725        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13726
13727        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13728
13729        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13730        let Some(select_next_state) = self.select_next_state.as_mut() else {
13731            return Ok(());
13732        };
13733        if select_next_state.done {
13734            return Ok(());
13735        }
13736
13737        let mut new_selections = Vec::new();
13738
13739        let reversed = self.selections.oldest::<usize>(cx).reversed;
13740        let buffer = &display_map.buffer_snapshot;
13741        let query_matches = select_next_state
13742            .query
13743            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13744
13745        for query_match in query_matches.into_iter() {
13746            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13747            let offset_range = if reversed {
13748                query_match.end()..query_match.start()
13749            } else {
13750                query_match.start()..query_match.end()
13751            };
13752
13753            if !select_next_state.wordwise
13754                || (!buffer.is_inside_word(offset_range.start, false)
13755                    && !buffer.is_inside_word(offset_range.end, false))
13756            {
13757                new_selections.push(offset_range.start..offset_range.end);
13758            }
13759        }
13760
13761        select_next_state.done = true;
13762
13763        if new_selections.is_empty() {
13764            log::error!("bug: new_selections is empty in select_all_matches");
13765            return Ok(());
13766        }
13767
13768        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13769        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13770            selections.select_ranges(new_selections)
13771        });
13772
13773        Ok(())
13774    }
13775
13776    pub fn select_next(
13777        &mut self,
13778        action: &SelectNext,
13779        window: &mut Window,
13780        cx: &mut Context<Self>,
13781    ) -> Result<()> {
13782        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13783        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13784        self.select_next_match_internal(
13785            &display_map,
13786            action.replace_newest,
13787            Some(Autoscroll::newest()),
13788            window,
13789            cx,
13790        )?;
13791        Ok(())
13792    }
13793
13794    pub fn select_previous(
13795        &mut self,
13796        action: &SelectPrevious,
13797        window: &mut Window,
13798        cx: &mut Context<Self>,
13799    ) -> Result<()> {
13800        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13801        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13802        let buffer = &display_map.buffer_snapshot;
13803        let mut selections = self.selections.all::<usize>(cx);
13804        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13805            let query = &select_prev_state.query;
13806            if !select_prev_state.done {
13807                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13808                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13809                let mut next_selected_range = None;
13810                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13811                let bytes_before_last_selection =
13812                    buffer.reversed_bytes_in_range(0..last_selection.start);
13813                let bytes_after_first_selection =
13814                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13815                let query_matches = query
13816                    .stream_find_iter(bytes_before_last_selection)
13817                    .map(|result| (last_selection.start, result))
13818                    .chain(
13819                        query
13820                            .stream_find_iter(bytes_after_first_selection)
13821                            .map(|result| (buffer.len(), result)),
13822                    );
13823                for (end_offset, query_match) in query_matches {
13824                    let query_match = query_match.unwrap(); // can only fail due to I/O
13825                    let offset_range =
13826                        end_offset - query_match.end()..end_offset - query_match.start();
13827
13828                    if !select_prev_state.wordwise
13829                        || (!buffer.is_inside_word(offset_range.start, false)
13830                            && !buffer.is_inside_word(offset_range.end, false))
13831                    {
13832                        next_selected_range = Some(offset_range);
13833                        break;
13834                    }
13835                }
13836
13837                if let Some(next_selected_range) = next_selected_range {
13838                    self.select_match_ranges(
13839                        next_selected_range,
13840                        last_selection.reversed,
13841                        action.replace_newest,
13842                        Some(Autoscroll::newest()),
13843                        window,
13844                        cx,
13845                    );
13846                } else {
13847                    select_prev_state.done = true;
13848                }
13849            }
13850
13851            self.select_prev_state = Some(select_prev_state);
13852        } else {
13853            let mut only_carets = true;
13854            let mut same_text_selected = true;
13855            let mut selected_text = None;
13856
13857            let mut selections_iter = selections.iter().peekable();
13858            while let Some(selection) = selections_iter.next() {
13859                if selection.start != selection.end {
13860                    only_carets = false;
13861                }
13862
13863                if same_text_selected {
13864                    if selected_text.is_none() {
13865                        selected_text =
13866                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13867                    }
13868
13869                    if let Some(next_selection) = selections_iter.peek() {
13870                        if next_selection.range().len() == selection.range().len() {
13871                            let next_selected_text = buffer
13872                                .text_for_range(next_selection.range())
13873                                .collect::<String>();
13874                            if Some(next_selected_text) != selected_text {
13875                                same_text_selected = false;
13876                                selected_text = None;
13877                            }
13878                        } else {
13879                            same_text_selected = false;
13880                            selected_text = None;
13881                        }
13882                    }
13883                }
13884            }
13885
13886            if only_carets {
13887                for selection in &mut selections {
13888                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13889                    selection.start = word_range.start;
13890                    selection.end = word_range.end;
13891                    selection.goal = SelectionGoal::None;
13892                    selection.reversed = false;
13893                    self.select_match_ranges(
13894                        selection.start..selection.end,
13895                        selection.reversed,
13896                        action.replace_newest,
13897                        Some(Autoscroll::newest()),
13898                        window,
13899                        cx,
13900                    );
13901                }
13902                if selections.len() == 1 {
13903                    let selection = selections
13904                        .last()
13905                        .expect("ensured that there's only one selection");
13906                    let query = buffer
13907                        .text_for_range(selection.start..selection.end)
13908                        .collect::<String>();
13909                    let is_empty = query.is_empty();
13910                    let select_state = SelectNextState {
13911                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13912                        wordwise: true,
13913                        done: is_empty,
13914                    };
13915                    self.select_prev_state = Some(select_state);
13916                } else {
13917                    self.select_prev_state = None;
13918                }
13919            } else if let Some(selected_text) = selected_text {
13920                self.select_prev_state = Some(SelectNextState {
13921                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13922                    wordwise: false,
13923                    done: false,
13924                });
13925                self.select_previous(action, window, cx)?;
13926            }
13927        }
13928        Ok(())
13929    }
13930
13931    pub fn find_next_match(
13932        &mut self,
13933        _: &FindNextMatch,
13934        window: &mut Window,
13935        cx: &mut Context<Self>,
13936    ) -> Result<()> {
13937        let selections = self.selections.disjoint_anchors();
13938        match selections.first() {
13939            Some(first) if selections.len() >= 2 => {
13940                self.change_selections(Default::default(), window, cx, |s| {
13941                    s.select_ranges([first.range()]);
13942                });
13943            }
13944            _ => self.select_next(
13945                &SelectNext {
13946                    replace_newest: true,
13947                },
13948                window,
13949                cx,
13950            )?,
13951        }
13952        Ok(())
13953    }
13954
13955    pub fn find_previous_match(
13956        &mut self,
13957        _: &FindPreviousMatch,
13958        window: &mut Window,
13959        cx: &mut Context<Self>,
13960    ) -> Result<()> {
13961        let selections = self.selections.disjoint_anchors();
13962        match selections.last() {
13963            Some(last) if selections.len() >= 2 => {
13964                self.change_selections(Default::default(), window, cx, |s| {
13965                    s.select_ranges([last.range()]);
13966                });
13967            }
13968            _ => self.select_previous(
13969                &SelectPrevious {
13970                    replace_newest: true,
13971                },
13972                window,
13973                cx,
13974            )?,
13975        }
13976        Ok(())
13977    }
13978
13979    pub fn toggle_comments(
13980        &mut self,
13981        action: &ToggleComments,
13982        window: &mut Window,
13983        cx: &mut Context<Self>,
13984    ) {
13985        if self.read_only(cx) {
13986            return;
13987        }
13988        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13989        let text_layout_details = &self.text_layout_details(window);
13990        self.transact(window, cx, |this, window, cx| {
13991            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13992            let mut edits = Vec::new();
13993            let mut selection_edit_ranges = Vec::new();
13994            let mut last_toggled_row = None;
13995            let snapshot = this.buffer.read(cx).read(cx);
13996            let empty_str: Arc<str> = Arc::default();
13997            let mut suffixes_inserted = Vec::new();
13998            let ignore_indent = action.ignore_indent;
13999
14000            fn comment_prefix_range(
14001                snapshot: &MultiBufferSnapshot,
14002                row: MultiBufferRow,
14003                comment_prefix: &str,
14004                comment_prefix_whitespace: &str,
14005                ignore_indent: bool,
14006            ) -> Range<Point> {
14007                let indent_size = if ignore_indent {
14008                    0
14009                } else {
14010                    snapshot.indent_size_for_line(row).len
14011                };
14012
14013                let start = Point::new(row.0, indent_size);
14014
14015                let mut line_bytes = snapshot
14016                    .bytes_in_range(start..snapshot.max_point())
14017                    .flatten()
14018                    .copied();
14019
14020                // If this line currently begins with the line comment prefix, then record
14021                // the range containing the prefix.
14022                if line_bytes
14023                    .by_ref()
14024                    .take(comment_prefix.len())
14025                    .eq(comment_prefix.bytes())
14026                {
14027                    // Include any whitespace that matches the comment prefix.
14028                    let matching_whitespace_len = line_bytes
14029                        .zip(comment_prefix_whitespace.bytes())
14030                        .take_while(|(a, b)| a == b)
14031                        .count() as u32;
14032                    let end = Point::new(
14033                        start.row,
14034                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14035                    );
14036                    start..end
14037                } else {
14038                    start..start
14039                }
14040            }
14041
14042            fn comment_suffix_range(
14043                snapshot: &MultiBufferSnapshot,
14044                row: MultiBufferRow,
14045                comment_suffix: &str,
14046                comment_suffix_has_leading_space: bool,
14047            ) -> Range<Point> {
14048                let end = Point::new(row.0, snapshot.line_len(row));
14049                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14050
14051                let mut line_end_bytes = snapshot
14052                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14053                    .flatten()
14054                    .copied();
14055
14056                let leading_space_len = if suffix_start_column > 0
14057                    && line_end_bytes.next() == Some(b' ')
14058                    && comment_suffix_has_leading_space
14059                {
14060                    1
14061                } else {
14062                    0
14063                };
14064
14065                // If this line currently begins with the line comment prefix, then record
14066                // the range containing the prefix.
14067                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14068                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14069                    start..end
14070                } else {
14071                    end..end
14072                }
14073            }
14074
14075            // TODO: Handle selections that cross excerpts
14076            for selection in &mut selections {
14077                let start_column = snapshot
14078                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14079                    .len;
14080                let language = if let Some(language) =
14081                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14082                {
14083                    language
14084                } else {
14085                    continue;
14086                };
14087
14088                selection_edit_ranges.clear();
14089
14090                // If multiple selections contain a given row, avoid processing that
14091                // row more than once.
14092                let mut start_row = MultiBufferRow(selection.start.row);
14093                if last_toggled_row == Some(start_row) {
14094                    start_row = start_row.next_row();
14095                }
14096                let end_row =
14097                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14098                        MultiBufferRow(selection.end.row - 1)
14099                    } else {
14100                        MultiBufferRow(selection.end.row)
14101                    };
14102                last_toggled_row = Some(end_row);
14103
14104                if start_row > end_row {
14105                    continue;
14106                }
14107
14108                // If the language has line comments, toggle those.
14109                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14110
14111                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14112                if ignore_indent {
14113                    full_comment_prefixes = full_comment_prefixes
14114                        .into_iter()
14115                        .map(|s| Arc::from(s.trim_end()))
14116                        .collect();
14117                }
14118
14119                if !full_comment_prefixes.is_empty() {
14120                    let first_prefix = full_comment_prefixes
14121                        .first()
14122                        .expect("prefixes is non-empty");
14123                    let prefix_trimmed_lengths = full_comment_prefixes
14124                        .iter()
14125                        .map(|p| p.trim_end_matches(' ').len())
14126                        .collect::<SmallVec<[usize; 4]>>();
14127
14128                    let mut all_selection_lines_are_comments = true;
14129
14130                    for row in start_row.0..=end_row.0 {
14131                        let row = MultiBufferRow(row);
14132                        if start_row < end_row && snapshot.is_line_blank(row) {
14133                            continue;
14134                        }
14135
14136                        let prefix_range = full_comment_prefixes
14137                            .iter()
14138                            .zip(prefix_trimmed_lengths.iter().copied())
14139                            .map(|(prefix, trimmed_prefix_len)| {
14140                                comment_prefix_range(
14141                                    snapshot.deref(),
14142                                    row,
14143                                    &prefix[..trimmed_prefix_len],
14144                                    &prefix[trimmed_prefix_len..],
14145                                    ignore_indent,
14146                                )
14147                            })
14148                            .max_by_key(|range| range.end.column - range.start.column)
14149                            .expect("prefixes is non-empty");
14150
14151                        if prefix_range.is_empty() {
14152                            all_selection_lines_are_comments = false;
14153                        }
14154
14155                        selection_edit_ranges.push(prefix_range);
14156                    }
14157
14158                    if all_selection_lines_are_comments {
14159                        edits.extend(
14160                            selection_edit_ranges
14161                                .iter()
14162                                .cloned()
14163                                .map(|range| (range, empty_str.clone())),
14164                        );
14165                    } else {
14166                        let min_column = selection_edit_ranges
14167                            .iter()
14168                            .map(|range| range.start.column)
14169                            .min()
14170                            .unwrap_or(0);
14171                        edits.extend(selection_edit_ranges.iter().map(|range| {
14172                            let position = Point::new(range.start.row, min_column);
14173                            (position..position, first_prefix.clone())
14174                        }));
14175                    }
14176                } else if let Some((full_comment_prefix, comment_suffix)) =
14177                    language.block_comment_delimiters()
14178                {
14179                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14180                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14181                    let prefix_range = comment_prefix_range(
14182                        snapshot.deref(),
14183                        start_row,
14184                        comment_prefix,
14185                        comment_prefix_whitespace,
14186                        ignore_indent,
14187                    );
14188                    let suffix_range = comment_suffix_range(
14189                        snapshot.deref(),
14190                        end_row,
14191                        comment_suffix.trim_start_matches(' '),
14192                        comment_suffix.starts_with(' '),
14193                    );
14194
14195                    if prefix_range.is_empty() || suffix_range.is_empty() {
14196                        edits.push((
14197                            prefix_range.start..prefix_range.start,
14198                            full_comment_prefix.clone(),
14199                        ));
14200                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14201                        suffixes_inserted.push((end_row, comment_suffix.len()));
14202                    } else {
14203                        edits.push((prefix_range, empty_str.clone()));
14204                        edits.push((suffix_range, empty_str.clone()));
14205                    }
14206                } else {
14207                    continue;
14208                }
14209            }
14210
14211            drop(snapshot);
14212            this.buffer.update(cx, |buffer, cx| {
14213                buffer.edit(edits, None, cx);
14214            });
14215
14216            // Adjust selections so that they end before any comment suffixes that
14217            // were inserted.
14218            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14219            let mut selections = this.selections.all::<Point>(cx);
14220            let snapshot = this.buffer.read(cx).read(cx);
14221            for selection in &mut selections {
14222                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14223                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14224                        Ordering::Less => {
14225                            suffixes_inserted.next();
14226                            continue;
14227                        }
14228                        Ordering::Greater => break,
14229                        Ordering::Equal => {
14230                            if selection.end.column == snapshot.line_len(row) {
14231                                if selection.is_empty() {
14232                                    selection.start.column -= suffix_len as u32;
14233                                }
14234                                selection.end.column -= suffix_len as u32;
14235                            }
14236                            break;
14237                        }
14238                    }
14239                }
14240            }
14241
14242            drop(snapshot);
14243            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14244
14245            let selections = this.selections.all::<Point>(cx);
14246            let selections_on_single_row = selections.windows(2).all(|selections| {
14247                selections[0].start.row == selections[1].start.row
14248                    && selections[0].end.row == selections[1].end.row
14249                    && selections[0].start.row == selections[0].end.row
14250            });
14251            let selections_selecting = selections
14252                .iter()
14253                .any(|selection| selection.start != selection.end);
14254            let advance_downwards = action.advance_downwards
14255                && selections_on_single_row
14256                && !selections_selecting
14257                && !matches!(this.mode, EditorMode::SingleLine { .. });
14258
14259            if advance_downwards {
14260                let snapshot = this.buffer.read(cx).snapshot(cx);
14261
14262                this.change_selections(Default::default(), window, cx, |s| {
14263                    s.move_cursors_with(|display_snapshot, display_point, _| {
14264                        let mut point = display_point.to_point(display_snapshot);
14265                        point.row += 1;
14266                        point = snapshot.clip_point(point, Bias::Left);
14267                        let display_point = point.to_display_point(display_snapshot);
14268                        let goal = SelectionGoal::HorizontalPosition(
14269                            display_snapshot
14270                                .x_for_display_point(display_point, text_layout_details)
14271                                .into(),
14272                        );
14273                        (display_point, goal)
14274                    })
14275                });
14276            }
14277        });
14278    }
14279
14280    pub fn select_enclosing_symbol(
14281        &mut self,
14282        _: &SelectEnclosingSymbol,
14283        window: &mut Window,
14284        cx: &mut Context<Self>,
14285    ) {
14286        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14287
14288        let buffer = self.buffer.read(cx).snapshot(cx);
14289        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14290
14291        fn update_selection(
14292            selection: &Selection<usize>,
14293            buffer_snap: &MultiBufferSnapshot,
14294        ) -> Option<Selection<usize>> {
14295            let cursor = selection.head();
14296            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14297            for symbol in symbols.iter().rev() {
14298                let start = symbol.range.start.to_offset(buffer_snap);
14299                let end = symbol.range.end.to_offset(buffer_snap);
14300                let new_range = start..end;
14301                if start < selection.start || end > selection.end {
14302                    return Some(Selection {
14303                        id: selection.id,
14304                        start: new_range.start,
14305                        end: new_range.end,
14306                        goal: SelectionGoal::None,
14307                        reversed: selection.reversed,
14308                    });
14309                }
14310            }
14311            None
14312        }
14313
14314        let mut selected_larger_symbol = false;
14315        let new_selections = old_selections
14316            .iter()
14317            .map(|selection| match update_selection(selection, &buffer) {
14318                Some(new_selection) => {
14319                    if new_selection.range() != selection.range() {
14320                        selected_larger_symbol = true;
14321                    }
14322                    new_selection
14323                }
14324                None => selection.clone(),
14325            })
14326            .collect::<Vec<_>>();
14327
14328        if selected_larger_symbol {
14329            self.change_selections(Default::default(), window, cx, |s| {
14330                s.select(new_selections);
14331            });
14332        }
14333    }
14334
14335    pub fn select_larger_syntax_node(
14336        &mut self,
14337        _: &SelectLargerSyntaxNode,
14338        window: &mut Window,
14339        cx: &mut Context<Self>,
14340    ) {
14341        let Some(visible_row_count) = self.visible_row_count() else {
14342            return;
14343        };
14344        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14345        if old_selections.is_empty() {
14346            return;
14347        }
14348
14349        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14350
14351        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14352        let buffer = self.buffer.read(cx).snapshot(cx);
14353
14354        let mut selected_larger_node = false;
14355        let mut new_selections = old_selections
14356            .iter()
14357            .map(|selection| {
14358                let old_range = selection.start..selection.end;
14359
14360                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14361                    // manually select word at selection
14362                    if ["string_content", "inline"].contains(&node.kind()) {
14363                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14364                        // ignore if word is already selected
14365                        if !word_range.is_empty() && old_range != word_range {
14366                            let (last_word_range, _) =
14367                                buffer.surrounding_word(old_range.end, false);
14368                            // only select word if start and end point belongs to same word
14369                            if word_range == last_word_range {
14370                                selected_larger_node = true;
14371                                return Selection {
14372                                    id: selection.id,
14373                                    start: word_range.start,
14374                                    end: word_range.end,
14375                                    goal: SelectionGoal::None,
14376                                    reversed: selection.reversed,
14377                                };
14378                            }
14379                        }
14380                    }
14381                }
14382
14383                let mut new_range = old_range.clone();
14384                while let Some((_node, containing_range)) =
14385                    buffer.syntax_ancestor(new_range.clone())
14386                {
14387                    new_range = match containing_range {
14388                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14389                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14390                    };
14391                    if !display_map.intersects_fold(new_range.start)
14392                        && !display_map.intersects_fold(new_range.end)
14393                    {
14394                        break;
14395                    }
14396                }
14397
14398                selected_larger_node |= new_range != old_range;
14399                Selection {
14400                    id: selection.id,
14401                    start: new_range.start,
14402                    end: new_range.end,
14403                    goal: SelectionGoal::None,
14404                    reversed: selection.reversed,
14405                }
14406            })
14407            .collect::<Vec<_>>();
14408
14409        if !selected_larger_node {
14410            return; // don't put this call in the history
14411        }
14412
14413        // scroll based on transformation done to the last selection created by the user
14414        let (last_old, last_new) = old_selections
14415            .last()
14416            .zip(new_selections.last().cloned())
14417            .expect("old_selections isn't empty");
14418
14419        // revert selection
14420        let is_selection_reversed = {
14421            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14422            new_selections.last_mut().expect("checked above").reversed =
14423                should_newest_selection_be_reversed;
14424            should_newest_selection_be_reversed
14425        };
14426
14427        if selected_larger_node {
14428            self.select_syntax_node_history.disable_clearing = true;
14429            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14430                s.select(new_selections.clone());
14431            });
14432            self.select_syntax_node_history.disable_clearing = false;
14433        }
14434
14435        let start_row = last_new.start.to_display_point(&display_map).row().0;
14436        let end_row = last_new.end.to_display_point(&display_map).row().0;
14437        let selection_height = end_row - start_row + 1;
14438        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14439
14440        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14441        let scroll_behavior = if fits_on_the_screen {
14442            self.request_autoscroll(Autoscroll::fit(), cx);
14443            SelectSyntaxNodeScrollBehavior::FitSelection
14444        } else if is_selection_reversed {
14445            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14446            SelectSyntaxNodeScrollBehavior::CursorTop
14447        } else {
14448            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14449            SelectSyntaxNodeScrollBehavior::CursorBottom
14450        };
14451
14452        self.select_syntax_node_history.push((
14453            old_selections,
14454            scroll_behavior,
14455            is_selection_reversed,
14456        ));
14457    }
14458
14459    pub fn select_smaller_syntax_node(
14460        &mut self,
14461        _: &SelectSmallerSyntaxNode,
14462        window: &mut Window,
14463        cx: &mut Context<Self>,
14464    ) {
14465        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14466
14467        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14468            self.select_syntax_node_history.pop()
14469        {
14470            if let Some(selection) = selections.last_mut() {
14471                selection.reversed = is_selection_reversed;
14472            }
14473
14474            self.select_syntax_node_history.disable_clearing = true;
14475            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14476                s.select(selections.to_vec());
14477            });
14478            self.select_syntax_node_history.disable_clearing = false;
14479
14480            match scroll_behavior {
14481                SelectSyntaxNodeScrollBehavior::CursorTop => {
14482                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14483                }
14484                SelectSyntaxNodeScrollBehavior::FitSelection => {
14485                    self.request_autoscroll(Autoscroll::fit(), cx);
14486                }
14487                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14488                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14489                }
14490            }
14491        }
14492    }
14493
14494    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14495        if !EditorSettings::get_global(cx).gutter.runnables {
14496            self.clear_tasks();
14497            return Task::ready(());
14498        }
14499        let project = self.project.as_ref().map(Entity::downgrade);
14500        let task_sources = self.lsp_task_sources(cx);
14501        let multi_buffer = self.buffer.downgrade();
14502        cx.spawn_in(window, async move |editor, cx| {
14503            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14504            let Some(project) = project.and_then(|p| p.upgrade()) else {
14505                return;
14506            };
14507            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14508                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14509            }) else {
14510                return;
14511            };
14512
14513            let hide_runnables = project
14514                .update(cx, |project, cx| {
14515                    // Do not display any test indicators in non-dev server remote projects.
14516                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14517                })
14518                .unwrap_or(true);
14519            if hide_runnables {
14520                return;
14521            }
14522            let new_rows =
14523                cx.background_spawn({
14524                    let snapshot = display_snapshot.clone();
14525                    async move {
14526                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14527                    }
14528                })
14529                    .await;
14530            let Ok(lsp_tasks) =
14531                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14532            else {
14533                return;
14534            };
14535            let lsp_tasks = lsp_tasks.await;
14536
14537            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14538                lsp_tasks
14539                    .into_iter()
14540                    .flat_map(|(kind, tasks)| {
14541                        tasks.into_iter().filter_map(move |(location, task)| {
14542                            Some((kind.clone(), location?, task))
14543                        })
14544                    })
14545                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14546                        let buffer = location.target.buffer;
14547                        let buffer_snapshot = buffer.read(cx).snapshot();
14548                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14549                            |(excerpt_id, snapshot, _)| {
14550                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14551                                    display_snapshot
14552                                        .buffer_snapshot
14553                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14554                                } else {
14555                                    None
14556                                }
14557                            },
14558                        );
14559                        if let Some(offset) = offset {
14560                            let task_buffer_range =
14561                                location.target.range.to_point(&buffer_snapshot);
14562                            let context_buffer_range =
14563                                task_buffer_range.to_offset(&buffer_snapshot);
14564                            let context_range = BufferOffset(context_buffer_range.start)
14565                                ..BufferOffset(context_buffer_range.end);
14566
14567                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14568                                .or_insert_with(|| RunnableTasks {
14569                                    templates: Vec::new(),
14570                                    offset,
14571                                    column: task_buffer_range.start.column,
14572                                    extra_variables: HashMap::default(),
14573                                    context_range,
14574                                })
14575                                .templates
14576                                .push((kind, task.original_task().clone()));
14577                        }
14578
14579                        acc
14580                    })
14581            }) else {
14582                return;
14583            };
14584
14585            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14586                buffer.language_settings(cx).tasks.prefer_lsp
14587            }) else {
14588                return;
14589            };
14590
14591            let rows = Self::runnable_rows(
14592                project,
14593                display_snapshot,
14594                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14595                new_rows,
14596                cx.clone(),
14597            )
14598            .await;
14599            editor
14600                .update(cx, |editor, _| {
14601                    editor.clear_tasks();
14602                    for (key, mut value) in rows {
14603                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14604                            value.templates.extend(lsp_tasks.templates);
14605                        }
14606
14607                        editor.insert_tasks(key, value);
14608                    }
14609                    for (key, value) in lsp_tasks_by_rows {
14610                        editor.insert_tasks(key, value);
14611                    }
14612                })
14613                .ok();
14614        })
14615    }
14616    fn fetch_runnable_ranges(
14617        snapshot: &DisplaySnapshot,
14618        range: Range<Anchor>,
14619    ) -> Vec<language::RunnableRange> {
14620        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14621    }
14622
14623    fn runnable_rows(
14624        project: Entity<Project>,
14625        snapshot: DisplaySnapshot,
14626        prefer_lsp: bool,
14627        runnable_ranges: Vec<RunnableRange>,
14628        cx: AsyncWindowContext,
14629    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14630        cx.spawn(async move |cx| {
14631            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14632            for mut runnable in runnable_ranges {
14633                let Some(tasks) = cx
14634                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14635                    .ok()
14636                else {
14637                    continue;
14638                };
14639                let mut tasks = tasks.await;
14640
14641                if prefer_lsp {
14642                    tasks.retain(|(task_kind, _)| {
14643                        !matches!(task_kind, TaskSourceKind::Language { .. })
14644                    });
14645                }
14646                if tasks.is_empty() {
14647                    continue;
14648                }
14649
14650                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14651                let Some(row) = snapshot
14652                    .buffer_snapshot
14653                    .buffer_line_for_row(MultiBufferRow(point.row))
14654                    .map(|(_, range)| range.start.row)
14655                else {
14656                    continue;
14657                };
14658
14659                let context_range =
14660                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14661                runnable_rows.push((
14662                    (runnable.buffer_id, row),
14663                    RunnableTasks {
14664                        templates: tasks,
14665                        offset: snapshot
14666                            .buffer_snapshot
14667                            .anchor_before(runnable.run_range.start),
14668                        context_range,
14669                        column: point.column,
14670                        extra_variables: runnable.extra_captures,
14671                    },
14672                ));
14673            }
14674            runnable_rows
14675        })
14676    }
14677
14678    fn templates_with_tags(
14679        project: &Entity<Project>,
14680        runnable: &mut Runnable,
14681        cx: &mut App,
14682    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14683        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14684            let (worktree_id, file) = project
14685                .buffer_for_id(runnable.buffer, cx)
14686                .and_then(|buffer| buffer.read(cx).file())
14687                .map(|file| (file.worktree_id(cx), file.clone()))
14688                .unzip();
14689
14690            (
14691                project.task_store().read(cx).task_inventory().cloned(),
14692                worktree_id,
14693                file,
14694            )
14695        });
14696
14697        let tags = mem::take(&mut runnable.tags);
14698        let language = runnable.language.clone();
14699        cx.spawn(async move |cx| {
14700            let mut templates_with_tags = Vec::new();
14701            if let Some(inventory) = inventory {
14702                for RunnableTag(tag) in tags {
14703                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14704                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14705                    }) else {
14706                        return templates_with_tags;
14707                    };
14708                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14709                        move |(_, template)| {
14710                            template.tags.iter().any(|source_tag| source_tag == &tag)
14711                        },
14712                    ));
14713                }
14714            }
14715            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14716
14717            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14718                // Strongest source wins; if we have worktree tag binding, prefer that to
14719                // global and language bindings;
14720                // if we have a global binding, prefer that to language binding.
14721                let first_mismatch = templates_with_tags
14722                    .iter()
14723                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14724                if let Some(index) = first_mismatch {
14725                    templates_with_tags.truncate(index);
14726                }
14727            }
14728
14729            templates_with_tags
14730        })
14731    }
14732
14733    pub fn move_to_enclosing_bracket(
14734        &mut self,
14735        _: &MoveToEnclosingBracket,
14736        window: &mut Window,
14737        cx: &mut Context<Self>,
14738    ) {
14739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14740        self.change_selections(Default::default(), window, cx, |s| {
14741            s.move_offsets_with(|snapshot, selection| {
14742                let Some(enclosing_bracket_ranges) =
14743                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14744                else {
14745                    return;
14746                };
14747
14748                let mut best_length = usize::MAX;
14749                let mut best_inside = false;
14750                let mut best_in_bracket_range = false;
14751                let mut best_destination = None;
14752                for (open, close) in enclosing_bracket_ranges {
14753                    let close = close.to_inclusive();
14754                    let length = close.end() - open.start;
14755                    let inside = selection.start >= open.end && selection.end <= *close.start();
14756                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14757                        || close.contains(&selection.head());
14758
14759                    // If best is next to a bracket and current isn't, skip
14760                    if !in_bracket_range && best_in_bracket_range {
14761                        continue;
14762                    }
14763
14764                    // Prefer smaller lengths unless best is inside and current isn't
14765                    if length > best_length && (best_inside || !inside) {
14766                        continue;
14767                    }
14768
14769                    best_length = length;
14770                    best_inside = inside;
14771                    best_in_bracket_range = in_bracket_range;
14772                    best_destination = Some(
14773                        if close.contains(&selection.start) && close.contains(&selection.end) {
14774                            if inside { open.end } else { open.start }
14775                        } else if inside {
14776                            *close.start()
14777                        } else {
14778                            *close.end()
14779                        },
14780                    );
14781                }
14782
14783                if let Some(destination) = best_destination {
14784                    selection.collapse_to(destination, SelectionGoal::None);
14785                }
14786            })
14787        });
14788    }
14789
14790    pub fn undo_selection(
14791        &mut self,
14792        _: &UndoSelection,
14793        window: &mut Window,
14794        cx: &mut Context<Self>,
14795    ) {
14796        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14797        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14798            self.selection_history.mode = SelectionHistoryMode::Undoing;
14799            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14800                this.end_selection(window, cx);
14801                this.change_selections(
14802                    SelectionEffects::scroll(Autoscroll::newest()),
14803                    window,
14804                    cx,
14805                    |s| s.select_anchors(entry.selections.to_vec()),
14806                );
14807            });
14808            self.selection_history.mode = SelectionHistoryMode::Normal;
14809
14810            self.select_next_state = entry.select_next_state;
14811            self.select_prev_state = entry.select_prev_state;
14812            self.add_selections_state = entry.add_selections_state;
14813        }
14814    }
14815
14816    pub fn redo_selection(
14817        &mut self,
14818        _: &RedoSelection,
14819        window: &mut Window,
14820        cx: &mut Context<Self>,
14821    ) {
14822        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14823        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14824            self.selection_history.mode = SelectionHistoryMode::Redoing;
14825            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14826                this.end_selection(window, cx);
14827                this.change_selections(
14828                    SelectionEffects::scroll(Autoscroll::newest()),
14829                    window,
14830                    cx,
14831                    |s| s.select_anchors(entry.selections.to_vec()),
14832                );
14833            });
14834            self.selection_history.mode = SelectionHistoryMode::Normal;
14835
14836            self.select_next_state = entry.select_next_state;
14837            self.select_prev_state = entry.select_prev_state;
14838            self.add_selections_state = entry.add_selections_state;
14839        }
14840    }
14841
14842    pub fn expand_excerpts(
14843        &mut self,
14844        action: &ExpandExcerpts,
14845        _: &mut Window,
14846        cx: &mut Context<Self>,
14847    ) {
14848        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14849    }
14850
14851    pub fn expand_excerpts_down(
14852        &mut self,
14853        action: &ExpandExcerptsDown,
14854        _: &mut Window,
14855        cx: &mut Context<Self>,
14856    ) {
14857        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14858    }
14859
14860    pub fn expand_excerpts_up(
14861        &mut self,
14862        action: &ExpandExcerptsUp,
14863        _: &mut Window,
14864        cx: &mut Context<Self>,
14865    ) {
14866        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14867    }
14868
14869    pub fn expand_excerpts_for_direction(
14870        &mut self,
14871        lines: u32,
14872        direction: ExpandExcerptDirection,
14873
14874        cx: &mut Context<Self>,
14875    ) {
14876        let selections = self.selections.disjoint_anchors();
14877
14878        let lines = if lines == 0 {
14879            EditorSettings::get_global(cx).expand_excerpt_lines
14880        } else {
14881            lines
14882        };
14883
14884        self.buffer.update(cx, |buffer, cx| {
14885            let snapshot = buffer.snapshot(cx);
14886            let mut excerpt_ids = selections
14887                .iter()
14888                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14889                .collect::<Vec<_>>();
14890            excerpt_ids.sort();
14891            excerpt_ids.dedup();
14892            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14893        })
14894    }
14895
14896    pub fn expand_excerpt(
14897        &mut self,
14898        excerpt: ExcerptId,
14899        direction: ExpandExcerptDirection,
14900        window: &mut Window,
14901        cx: &mut Context<Self>,
14902    ) {
14903        let current_scroll_position = self.scroll_position(cx);
14904        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14905        let mut should_scroll_up = false;
14906
14907        if direction == ExpandExcerptDirection::Down {
14908            let multi_buffer = self.buffer.read(cx);
14909            let snapshot = multi_buffer.snapshot(cx);
14910            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14911                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14912                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14913                        let buffer_snapshot = buffer.read(cx).snapshot();
14914                        let excerpt_end_row =
14915                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14916                        let last_row = buffer_snapshot.max_point().row;
14917                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14918                        should_scroll_up = lines_below >= lines_to_expand;
14919                    }
14920                }
14921            }
14922        }
14923
14924        self.buffer.update(cx, |buffer, cx| {
14925            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14926        });
14927
14928        if should_scroll_up {
14929            let new_scroll_position =
14930                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14931            self.set_scroll_position(new_scroll_position, window, cx);
14932        }
14933    }
14934
14935    pub fn go_to_singleton_buffer_point(
14936        &mut self,
14937        point: Point,
14938        window: &mut Window,
14939        cx: &mut Context<Self>,
14940    ) {
14941        self.go_to_singleton_buffer_range(point..point, window, cx);
14942    }
14943
14944    pub fn go_to_singleton_buffer_range(
14945        &mut self,
14946        range: Range<Point>,
14947        window: &mut Window,
14948        cx: &mut Context<Self>,
14949    ) {
14950        let multibuffer = self.buffer().read(cx);
14951        let Some(buffer) = multibuffer.as_singleton() else {
14952            return;
14953        };
14954        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14955            return;
14956        };
14957        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14958            return;
14959        };
14960        self.change_selections(
14961            SelectionEffects::default().nav_history(true),
14962            window,
14963            cx,
14964            |s| s.select_anchor_ranges([start..end]),
14965        );
14966    }
14967
14968    pub fn go_to_diagnostic(
14969        &mut self,
14970        _: &GoToDiagnostic,
14971        window: &mut Window,
14972        cx: &mut Context<Self>,
14973    ) {
14974        if !self.diagnostics_enabled() {
14975            return;
14976        }
14977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14978        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14979    }
14980
14981    pub fn go_to_prev_diagnostic(
14982        &mut self,
14983        _: &GoToPreviousDiagnostic,
14984        window: &mut Window,
14985        cx: &mut Context<Self>,
14986    ) {
14987        if !self.diagnostics_enabled() {
14988            return;
14989        }
14990        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14991        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14992    }
14993
14994    pub fn go_to_diagnostic_impl(
14995        &mut self,
14996        direction: Direction,
14997        window: &mut Window,
14998        cx: &mut Context<Self>,
14999    ) {
15000        let buffer = self.buffer.read(cx).snapshot(cx);
15001        let selection = self.selections.newest::<usize>(cx);
15002
15003        let mut active_group_id = None;
15004        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15005            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15006                active_group_id = Some(active_group.group_id);
15007            }
15008        }
15009
15010        fn filtered(
15011            snapshot: EditorSnapshot,
15012            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15013        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15014            diagnostics
15015                .filter(|entry| entry.range.start != entry.range.end)
15016                .filter(|entry| !entry.diagnostic.is_unnecessary)
15017                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15018        }
15019
15020        let snapshot = self.snapshot(window, cx);
15021        let before = filtered(
15022            snapshot.clone(),
15023            buffer
15024                .diagnostics_in_range(0..selection.start)
15025                .filter(|entry| entry.range.start <= selection.start),
15026        );
15027        let after = filtered(
15028            snapshot,
15029            buffer
15030                .diagnostics_in_range(selection.start..buffer.len())
15031                .filter(|entry| entry.range.start >= selection.start),
15032        );
15033
15034        let mut found: Option<DiagnosticEntry<usize>> = None;
15035        if direction == Direction::Prev {
15036            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15037            {
15038                for diagnostic in prev_diagnostics.into_iter().rev() {
15039                    if diagnostic.range.start != selection.start
15040                        || active_group_id
15041                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15042                    {
15043                        found = Some(diagnostic);
15044                        break 'outer;
15045                    }
15046                }
15047            }
15048        } else {
15049            for diagnostic in after.chain(before) {
15050                if diagnostic.range.start != selection.start
15051                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15052                {
15053                    found = Some(diagnostic);
15054                    break;
15055                }
15056            }
15057        }
15058        let Some(next_diagnostic) = found else {
15059            return;
15060        };
15061
15062        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15063            return;
15064        };
15065        self.change_selections(Default::default(), window, cx, |s| {
15066            s.select_ranges(vec![
15067                next_diagnostic.range.start..next_diagnostic.range.start,
15068            ])
15069        });
15070        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15071        self.refresh_inline_completion(false, true, window, cx);
15072    }
15073
15074    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15075        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15076        let snapshot = self.snapshot(window, cx);
15077        let selection = self.selections.newest::<Point>(cx);
15078        self.go_to_hunk_before_or_after_position(
15079            &snapshot,
15080            selection.head(),
15081            Direction::Next,
15082            window,
15083            cx,
15084        );
15085    }
15086
15087    pub fn go_to_hunk_before_or_after_position(
15088        &mut self,
15089        snapshot: &EditorSnapshot,
15090        position: Point,
15091        direction: Direction,
15092        window: &mut Window,
15093        cx: &mut Context<Editor>,
15094    ) {
15095        let row = if direction == Direction::Next {
15096            self.hunk_after_position(snapshot, position)
15097                .map(|hunk| hunk.row_range.start)
15098        } else {
15099            self.hunk_before_position(snapshot, position)
15100        };
15101
15102        if let Some(row) = row {
15103            let destination = Point::new(row.0, 0);
15104            let autoscroll = Autoscroll::center();
15105
15106            self.unfold_ranges(&[destination..destination], false, false, cx);
15107            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15108                s.select_ranges([destination..destination]);
15109            });
15110        }
15111    }
15112
15113    fn hunk_after_position(
15114        &mut self,
15115        snapshot: &EditorSnapshot,
15116        position: Point,
15117    ) -> Option<MultiBufferDiffHunk> {
15118        snapshot
15119            .buffer_snapshot
15120            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15121            .find(|hunk| hunk.row_range.start.0 > position.row)
15122            .or_else(|| {
15123                snapshot
15124                    .buffer_snapshot
15125                    .diff_hunks_in_range(Point::zero()..position)
15126                    .find(|hunk| hunk.row_range.end.0 < position.row)
15127            })
15128    }
15129
15130    fn go_to_prev_hunk(
15131        &mut self,
15132        _: &GoToPreviousHunk,
15133        window: &mut Window,
15134        cx: &mut Context<Self>,
15135    ) {
15136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15137        let snapshot = self.snapshot(window, cx);
15138        let selection = self.selections.newest::<Point>(cx);
15139        self.go_to_hunk_before_or_after_position(
15140            &snapshot,
15141            selection.head(),
15142            Direction::Prev,
15143            window,
15144            cx,
15145        );
15146    }
15147
15148    fn hunk_before_position(
15149        &mut self,
15150        snapshot: &EditorSnapshot,
15151        position: Point,
15152    ) -> Option<MultiBufferRow> {
15153        snapshot
15154            .buffer_snapshot
15155            .diff_hunk_before(position)
15156            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15157    }
15158
15159    fn go_to_next_change(
15160        &mut self,
15161        _: &GoToNextChange,
15162        window: &mut Window,
15163        cx: &mut Context<Self>,
15164    ) {
15165        if let Some(selections) = self
15166            .change_list
15167            .next_change(1, Direction::Next)
15168            .map(|s| s.to_vec())
15169        {
15170            self.change_selections(Default::default(), window, cx, |s| {
15171                let map = s.display_map();
15172                s.select_display_ranges(selections.iter().map(|a| {
15173                    let point = a.to_display_point(&map);
15174                    point..point
15175                }))
15176            })
15177        }
15178    }
15179
15180    fn go_to_previous_change(
15181        &mut self,
15182        _: &GoToPreviousChange,
15183        window: &mut Window,
15184        cx: &mut Context<Self>,
15185    ) {
15186        if let Some(selections) = self
15187            .change_list
15188            .next_change(1, Direction::Prev)
15189            .map(|s| s.to_vec())
15190        {
15191            self.change_selections(Default::default(), window, cx, |s| {
15192                let map = s.display_map();
15193                s.select_display_ranges(selections.iter().map(|a| {
15194                    let point = a.to_display_point(&map);
15195                    point..point
15196                }))
15197            })
15198        }
15199    }
15200
15201    fn go_to_line<T: 'static>(
15202        &mut self,
15203        position: Anchor,
15204        highlight_color: Option<Hsla>,
15205        window: &mut Window,
15206        cx: &mut Context<Self>,
15207    ) {
15208        let snapshot = self.snapshot(window, cx).display_snapshot;
15209        let position = position.to_point(&snapshot.buffer_snapshot);
15210        let start = snapshot
15211            .buffer_snapshot
15212            .clip_point(Point::new(position.row, 0), Bias::Left);
15213        let end = start + Point::new(1, 0);
15214        let start = snapshot.buffer_snapshot.anchor_before(start);
15215        let end = snapshot.buffer_snapshot.anchor_before(end);
15216
15217        self.highlight_rows::<T>(
15218            start..end,
15219            highlight_color
15220                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15221            Default::default(),
15222            cx,
15223        );
15224
15225        if self.buffer.read(cx).is_singleton() {
15226            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15227        }
15228    }
15229
15230    pub fn go_to_definition(
15231        &mut self,
15232        _: &GoToDefinition,
15233        window: &mut Window,
15234        cx: &mut Context<Self>,
15235    ) -> Task<Result<Navigated>> {
15236        let definition =
15237            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15238        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15239        cx.spawn_in(window, async move |editor, cx| {
15240            if definition.await? == Navigated::Yes {
15241                return Ok(Navigated::Yes);
15242            }
15243            match fallback_strategy {
15244                GoToDefinitionFallback::None => Ok(Navigated::No),
15245                GoToDefinitionFallback::FindAllReferences => {
15246                    match editor.update_in(cx, |editor, window, cx| {
15247                        editor.find_all_references(&FindAllReferences, window, cx)
15248                    })? {
15249                        Some(references) => references.await,
15250                        None => Ok(Navigated::No),
15251                    }
15252                }
15253            }
15254        })
15255    }
15256
15257    pub fn go_to_declaration(
15258        &mut self,
15259        _: &GoToDeclaration,
15260        window: &mut Window,
15261        cx: &mut Context<Self>,
15262    ) -> Task<Result<Navigated>> {
15263        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15264    }
15265
15266    pub fn go_to_declaration_split(
15267        &mut self,
15268        _: &GoToDeclaration,
15269        window: &mut Window,
15270        cx: &mut Context<Self>,
15271    ) -> Task<Result<Navigated>> {
15272        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15273    }
15274
15275    pub fn go_to_implementation(
15276        &mut self,
15277        _: &GoToImplementation,
15278        window: &mut Window,
15279        cx: &mut Context<Self>,
15280    ) -> Task<Result<Navigated>> {
15281        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15282    }
15283
15284    pub fn go_to_implementation_split(
15285        &mut self,
15286        _: &GoToImplementationSplit,
15287        window: &mut Window,
15288        cx: &mut Context<Self>,
15289    ) -> Task<Result<Navigated>> {
15290        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15291    }
15292
15293    pub fn go_to_type_definition(
15294        &mut self,
15295        _: &GoToTypeDefinition,
15296        window: &mut Window,
15297        cx: &mut Context<Self>,
15298    ) -> Task<Result<Navigated>> {
15299        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15300    }
15301
15302    pub fn go_to_definition_split(
15303        &mut self,
15304        _: &GoToDefinitionSplit,
15305        window: &mut Window,
15306        cx: &mut Context<Self>,
15307    ) -> Task<Result<Navigated>> {
15308        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15309    }
15310
15311    pub fn go_to_type_definition_split(
15312        &mut self,
15313        _: &GoToTypeDefinitionSplit,
15314        window: &mut Window,
15315        cx: &mut Context<Self>,
15316    ) -> Task<Result<Navigated>> {
15317        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15318    }
15319
15320    fn go_to_definition_of_kind(
15321        &mut self,
15322        kind: GotoDefinitionKind,
15323        split: bool,
15324        window: &mut Window,
15325        cx: &mut Context<Self>,
15326    ) -> Task<Result<Navigated>> {
15327        let Some(provider) = self.semantics_provider.clone() else {
15328            return Task::ready(Ok(Navigated::No));
15329        };
15330        let head = self.selections.newest::<usize>(cx).head();
15331        let buffer = self.buffer.read(cx);
15332        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15333            text_anchor
15334        } else {
15335            return Task::ready(Ok(Navigated::No));
15336        };
15337
15338        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15339            return Task::ready(Ok(Navigated::No));
15340        };
15341
15342        cx.spawn_in(window, async move |editor, cx| {
15343            let definitions = definitions.await?;
15344            let navigated = editor
15345                .update_in(cx, |editor, window, cx| {
15346                    editor.navigate_to_hover_links(
15347                        Some(kind),
15348                        definitions
15349                            .into_iter()
15350                            .filter(|location| {
15351                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15352                            })
15353                            .map(HoverLink::Text)
15354                            .collect::<Vec<_>>(),
15355                        split,
15356                        window,
15357                        cx,
15358                    )
15359                })?
15360                .await?;
15361            anyhow::Ok(navigated)
15362        })
15363    }
15364
15365    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15366        let selection = self.selections.newest_anchor();
15367        let head = selection.head();
15368        let tail = selection.tail();
15369
15370        let Some((buffer, start_position)) =
15371            self.buffer.read(cx).text_anchor_for_position(head, cx)
15372        else {
15373            return;
15374        };
15375
15376        let end_position = if head != tail {
15377            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15378                return;
15379            };
15380            Some(pos)
15381        } else {
15382            None
15383        };
15384
15385        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15386            let url = if let Some(end_pos) = end_position {
15387                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15388            } else {
15389                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15390            };
15391
15392            if let Some(url) = url {
15393                editor.update(cx, |_, cx| {
15394                    cx.open_url(&url);
15395                })
15396            } else {
15397                Ok(())
15398            }
15399        });
15400
15401        url_finder.detach();
15402    }
15403
15404    pub fn open_selected_filename(
15405        &mut self,
15406        _: &OpenSelectedFilename,
15407        window: &mut Window,
15408        cx: &mut Context<Self>,
15409    ) {
15410        let Some(workspace) = self.workspace() else {
15411            return;
15412        };
15413
15414        let position = self.selections.newest_anchor().head();
15415
15416        let Some((buffer, buffer_position)) =
15417            self.buffer.read(cx).text_anchor_for_position(position, cx)
15418        else {
15419            return;
15420        };
15421
15422        let project = self.project.clone();
15423
15424        cx.spawn_in(window, async move |_, cx| {
15425            let result = find_file(&buffer, project, buffer_position, cx).await;
15426
15427            if let Some((_, path)) = result {
15428                workspace
15429                    .update_in(cx, |workspace, window, cx| {
15430                        workspace.open_resolved_path(path, window, cx)
15431                    })?
15432                    .await?;
15433            }
15434            anyhow::Ok(())
15435        })
15436        .detach();
15437    }
15438
15439    pub(crate) fn navigate_to_hover_links(
15440        &mut self,
15441        kind: Option<GotoDefinitionKind>,
15442        mut definitions: Vec<HoverLink>,
15443        split: bool,
15444        window: &mut Window,
15445        cx: &mut Context<Editor>,
15446    ) -> Task<Result<Navigated>> {
15447        // If there is one definition, just open it directly
15448        if definitions.len() == 1 {
15449            let definition = definitions.pop().unwrap();
15450
15451            enum TargetTaskResult {
15452                Location(Option<Location>),
15453                AlreadyNavigated,
15454            }
15455
15456            let target_task = match definition {
15457                HoverLink::Text(link) => {
15458                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15459                }
15460                HoverLink::InlayHint(lsp_location, server_id) => {
15461                    let computation =
15462                        self.compute_target_location(lsp_location, server_id, window, cx);
15463                    cx.background_spawn(async move {
15464                        let location = computation.await?;
15465                        Ok(TargetTaskResult::Location(location))
15466                    })
15467                }
15468                HoverLink::Url(url) => {
15469                    cx.open_url(&url);
15470                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15471                }
15472                HoverLink::File(path) => {
15473                    if let Some(workspace) = self.workspace() {
15474                        cx.spawn_in(window, async move |_, cx| {
15475                            workspace
15476                                .update_in(cx, |workspace, window, cx| {
15477                                    workspace.open_resolved_path(path, window, cx)
15478                                })?
15479                                .await
15480                                .map(|_| TargetTaskResult::AlreadyNavigated)
15481                        })
15482                    } else {
15483                        Task::ready(Ok(TargetTaskResult::Location(None)))
15484                    }
15485                }
15486            };
15487            cx.spawn_in(window, async move |editor, cx| {
15488                let target = match target_task.await.context("target resolution task")? {
15489                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15490                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15491                    TargetTaskResult::Location(Some(target)) => target,
15492                };
15493
15494                editor.update_in(cx, |editor, window, cx| {
15495                    let Some(workspace) = editor.workspace() else {
15496                        return Navigated::No;
15497                    };
15498                    let pane = workspace.read(cx).active_pane().clone();
15499
15500                    let range = target.range.to_point(target.buffer.read(cx));
15501                    let range = editor.range_for_match(&range);
15502                    let range = collapse_multiline_range(range);
15503
15504                    if !split
15505                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15506                    {
15507                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15508                    } else {
15509                        window.defer(cx, move |window, cx| {
15510                            let target_editor: Entity<Self> =
15511                                workspace.update(cx, |workspace, cx| {
15512                                    let pane = if split {
15513                                        workspace.adjacent_pane(window, cx)
15514                                    } else {
15515                                        workspace.active_pane().clone()
15516                                    };
15517
15518                                    workspace.open_project_item(
15519                                        pane,
15520                                        target.buffer.clone(),
15521                                        true,
15522                                        true,
15523                                        window,
15524                                        cx,
15525                                    )
15526                                });
15527                            target_editor.update(cx, |target_editor, cx| {
15528                                // When selecting a definition in a different buffer, disable the nav history
15529                                // to avoid creating a history entry at the previous cursor location.
15530                                pane.update(cx, |pane, _| pane.disable_history());
15531                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15532                                pane.update(cx, |pane, _| pane.enable_history());
15533                            });
15534                        });
15535                    }
15536                    Navigated::Yes
15537                })
15538            })
15539        } else if !definitions.is_empty() {
15540            cx.spawn_in(window, async move |editor, cx| {
15541                let (title, location_tasks, workspace) = editor
15542                    .update_in(cx, |editor, window, cx| {
15543                        let tab_kind = match kind {
15544                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15545                            _ => "Definitions",
15546                        };
15547                        let title = definitions
15548                            .iter()
15549                            .find_map(|definition| match definition {
15550                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15551                                    let buffer = origin.buffer.read(cx);
15552                                    format!(
15553                                        "{} for {}",
15554                                        tab_kind,
15555                                        buffer
15556                                            .text_for_range(origin.range.clone())
15557                                            .collect::<String>()
15558                                    )
15559                                }),
15560                                HoverLink::InlayHint(_, _) => None,
15561                                HoverLink::Url(_) => None,
15562                                HoverLink::File(_) => None,
15563                            })
15564                            .unwrap_or(tab_kind.to_string());
15565                        let location_tasks = definitions
15566                            .into_iter()
15567                            .map(|definition| match definition {
15568                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15569                                HoverLink::InlayHint(lsp_location, server_id) => editor
15570                                    .compute_target_location(lsp_location, server_id, window, cx),
15571                                HoverLink::Url(_) => Task::ready(Ok(None)),
15572                                HoverLink::File(_) => Task::ready(Ok(None)),
15573                            })
15574                            .collect::<Vec<_>>();
15575                        (title, location_tasks, editor.workspace().clone())
15576                    })
15577                    .context("location tasks preparation")?;
15578
15579                let locations: Vec<Location> = future::join_all(location_tasks)
15580                    .await
15581                    .into_iter()
15582                    .filter_map(|location| location.transpose())
15583                    .collect::<Result<_>>()
15584                    .context("location tasks")?;
15585
15586                if locations.is_empty() {
15587                    return Ok(Navigated::No);
15588                }
15589
15590                let Some(workspace) = workspace else {
15591                    return Ok(Navigated::No);
15592                };
15593
15594                let opened = workspace
15595                    .update_in(cx, |workspace, window, cx| {
15596                        Self::open_locations_in_multibuffer(
15597                            workspace,
15598                            locations,
15599                            title,
15600                            split,
15601                            MultibufferSelectionMode::First,
15602                            window,
15603                            cx,
15604                        )
15605                    })
15606                    .ok();
15607
15608                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15609            })
15610        } else {
15611            Task::ready(Ok(Navigated::No))
15612        }
15613    }
15614
15615    fn compute_target_location(
15616        &self,
15617        lsp_location: lsp::Location,
15618        server_id: LanguageServerId,
15619        window: &mut Window,
15620        cx: &mut Context<Self>,
15621    ) -> Task<anyhow::Result<Option<Location>>> {
15622        let Some(project) = self.project.clone() else {
15623            return Task::ready(Ok(None));
15624        };
15625
15626        cx.spawn_in(window, async move |editor, cx| {
15627            let location_task = editor.update(cx, |_, cx| {
15628                project.update(cx, |project, cx| {
15629                    let language_server_name = project
15630                        .language_server_statuses(cx)
15631                        .find(|(id, _)| server_id == *id)
15632                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15633                    language_server_name.map(|language_server_name| {
15634                        project.open_local_buffer_via_lsp(
15635                            lsp_location.uri.clone(),
15636                            server_id,
15637                            language_server_name,
15638                            cx,
15639                        )
15640                    })
15641                })
15642            })?;
15643            let location = match location_task {
15644                Some(task) => Some({
15645                    let target_buffer_handle = task.await.context("open local buffer")?;
15646                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15647                        let target_start = target_buffer
15648                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15649                        let target_end = target_buffer
15650                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15651                        target_buffer.anchor_after(target_start)
15652                            ..target_buffer.anchor_before(target_end)
15653                    })?;
15654                    Location {
15655                        buffer: target_buffer_handle,
15656                        range,
15657                    }
15658                }),
15659                None => None,
15660            };
15661            Ok(location)
15662        })
15663    }
15664
15665    pub fn find_all_references(
15666        &mut self,
15667        _: &FindAllReferences,
15668        window: &mut Window,
15669        cx: &mut Context<Self>,
15670    ) -> Option<Task<Result<Navigated>>> {
15671        let selection = self.selections.newest::<usize>(cx);
15672        let multi_buffer = self.buffer.read(cx);
15673        let head = selection.head();
15674
15675        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15676        let head_anchor = multi_buffer_snapshot.anchor_at(
15677            head,
15678            if head < selection.tail() {
15679                Bias::Right
15680            } else {
15681                Bias::Left
15682            },
15683        );
15684
15685        match self
15686            .find_all_references_task_sources
15687            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15688        {
15689            Ok(_) => {
15690                log::info!(
15691                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15692                );
15693                return None;
15694            }
15695            Err(i) => {
15696                self.find_all_references_task_sources.insert(i, head_anchor);
15697            }
15698        }
15699
15700        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15701        let workspace = self.workspace()?;
15702        let project = workspace.read(cx).project().clone();
15703        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15704        Some(cx.spawn_in(window, async move |editor, cx| {
15705            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15706                if let Ok(i) = editor
15707                    .find_all_references_task_sources
15708                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15709                {
15710                    editor.find_all_references_task_sources.remove(i);
15711                }
15712            });
15713
15714            let locations = references.await?;
15715            if locations.is_empty() {
15716                return anyhow::Ok(Navigated::No);
15717            }
15718
15719            workspace.update_in(cx, |workspace, window, cx| {
15720                let title = locations
15721                    .first()
15722                    .as_ref()
15723                    .map(|location| {
15724                        let buffer = location.buffer.read(cx);
15725                        format!(
15726                            "References to `{}`",
15727                            buffer
15728                                .text_for_range(location.range.clone())
15729                                .collect::<String>()
15730                        )
15731                    })
15732                    .unwrap();
15733                Self::open_locations_in_multibuffer(
15734                    workspace,
15735                    locations,
15736                    title,
15737                    false,
15738                    MultibufferSelectionMode::First,
15739                    window,
15740                    cx,
15741                );
15742                Navigated::Yes
15743            })
15744        }))
15745    }
15746
15747    /// Opens a multibuffer with the given project locations in it
15748    pub fn open_locations_in_multibuffer(
15749        workspace: &mut Workspace,
15750        mut locations: Vec<Location>,
15751        title: String,
15752        split: bool,
15753        multibuffer_selection_mode: MultibufferSelectionMode,
15754        window: &mut Window,
15755        cx: &mut Context<Workspace>,
15756    ) {
15757        if locations.is_empty() {
15758            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15759            return;
15760        }
15761
15762        // If there are multiple definitions, open them in a multibuffer
15763        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15764        let mut locations = locations.into_iter().peekable();
15765        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15766        let capability = workspace.project().read(cx).capability();
15767
15768        let excerpt_buffer = cx.new(|cx| {
15769            let mut multibuffer = MultiBuffer::new(capability);
15770            while let Some(location) = locations.next() {
15771                let buffer = location.buffer.read(cx);
15772                let mut ranges_for_buffer = Vec::new();
15773                let range = location.range.to_point(buffer);
15774                ranges_for_buffer.push(range.clone());
15775
15776                while let Some(next_location) = locations.peek() {
15777                    if next_location.buffer == location.buffer {
15778                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15779                        locations.next();
15780                    } else {
15781                        break;
15782                    }
15783                }
15784
15785                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15786                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15787                    PathKey::for_buffer(&location.buffer, cx),
15788                    location.buffer.clone(),
15789                    ranges_for_buffer,
15790                    DEFAULT_MULTIBUFFER_CONTEXT,
15791                    cx,
15792                );
15793                ranges.extend(new_ranges)
15794            }
15795
15796            multibuffer.with_title(title)
15797        });
15798
15799        let editor = cx.new(|cx| {
15800            Editor::for_multibuffer(
15801                excerpt_buffer,
15802                Some(workspace.project().clone()),
15803                window,
15804                cx,
15805            )
15806        });
15807        editor.update(cx, |editor, cx| {
15808            match multibuffer_selection_mode {
15809                MultibufferSelectionMode::First => {
15810                    if let Some(first_range) = ranges.first() {
15811                        editor.change_selections(
15812                            SelectionEffects::no_scroll(),
15813                            window,
15814                            cx,
15815                            |selections| {
15816                                selections.clear_disjoint();
15817                                selections
15818                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
15819                            },
15820                        );
15821                    }
15822                    editor.highlight_background::<Self>(
15823                        &ranges,
15824                        |theme| theme.colors().editor_highlighted_line_background,
15825                        cx,
15826                    );
15827                }
15828                MultibufferSelectionMode::All => {
15829                    editor.change_selections(
15830                        SelectionEffects::no_scroll(),
15831                        window,
15832                        cx,
15833                        |selections| {
15834                            selections.clear_disjoint();
15835                            selections.select_anchor_ranges(ranges);
15836                        },
15837                    );
15838                }
15839            }
15840            editor.register_buffers_with_language_servers(cx);
15841        });
15842
15843        let item = Box::new(editor);
15844        let item_id = item.item_id();
15845
15846        if split {
15847            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15848        } else {
15849            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15850                let (preview_item_id, preview_item_idx) =
15851                    workspace.active_pane().read_with(cx, |pane, _| {
15852                        (pane.preview_item_id(), pane.preview_item_idx())
15853                    });
15854
15855                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15856
15857                if let Some(preview_item_id) = preview_item_id {
15858                    workspace.active_pane().update(cx, |pane, cx| {
15859                        pane.remove_item(preview_item_id, false, false, window, cx);
15860                    });
15861                }
15862            } else {
15863                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15864            }
15865        }
15866        workspace.active_pane().update(cx, |pane, cx| {
15867            pane.set_preview_item_id(Some(item_id), cx);
15868        });
15869    }
15870
15871    pub fn rename(
15872        &mut self,
15873        _: &Rename,
15874        window: &mut Window,
15875        cx: &mut Context<Self>,
15876    ) -> Option<Task<Result<()>>> {
15877        use language::ToOffset as _;
15878
15879        let provider = self.semantics_provider.clone()?;
15880        let selection = self.selections.newest_anchor().clone();
15881        let (cursor_buffer, cursor_buffer_position) = self
15882            .buffer
15883            .read(cx)
15884            .text_anchor_for_position(selection.head(), cx)?;
15885        let (tail_buffer, cursor_buffer_position_end) = self
15886            .buffer
15887            .read(cx)
15888            .text_anchor_for_position(selection.tail(), cx)?;
15889        if tail_buffer != cursor_buffer {
15890            return None;
15891        }
15892
15893        let snapshot = cursor_buffer.read(cx).snapshot();
15894        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15895        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15896        let prepare_rename = provider
15897            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15898            .unwrap_or_else(|| Task::ready(Ok(None)));
15899        drop(snapshot);
15900
15901        Some(cx.spawn_in(window, async move |this, cx| {
15902            let rename_range = if let Some(range) = prepare_rename.await? {
15903                Some(range)
15904            } else {
15905                this.update(cx, |this, cx| {
15906                    let buffer = this.buffer.read(cx).snapshot(cx);
15907                    let mut buffer_highlights = this
15908                        .document_highlights_for_position(selection.head(), &buffer)
15909                        .filter(|highlight| {
15910                            highlight.start.excerpt_id == selection.head().excerpt_id
15911                                && highlight.end.excerpt_id == selection.head().excerpt_id
15912                        });
15913                    buffer_highlights
15914                        .next()
15915                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15916                })?
15917            };
15918            if let Some(rename_range) = rename_range {
15919                this.update_in(cx, |this, window, cx| {
15920                    let snapshot = cursor_buffer.read(cx).snapshot();
15921                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15922                    let cursor_offset_in_rename_range =
15923                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15924                    let cursor_offset_in_rename_range_end =
15925                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15926
15927                    this.take_rename(false, window, cx);
15928                    let buffer = this.buffer.read(cx).read(cx);
15929                    let cursor_offset = selection.head().to_offset(&buffer);
15930                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15931                    let rename_end = rename_start + rename_buffer_range.len();
15932                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15933                    let mut old_highlight_id = None;
15934                    let old_name: Arc<str> = buffer
15935                        .chunks(rename_start..rename_end, true)
15936                        .map(|chunk| {
15937                            if old_highlight_id.is_none() {
15938                                old_highlight_id = chunk.syntax_highlight_id;
15939                            }
15940                            chunk.text
15941                        })
15942                        .collect::<String>()
15943                        .into();
15944
15945                    drop(buffer);
15946
15947                    // Position the selection in the rename editor so that it matches the current selection.
15948                    this.show_local_selections = false;
15949                    let rename_editor = cx.new(|cx| {
15950                        let mut editor = Editor::single_line(window, cx);
15951                        editor.buffer.update(cx, |buffer, cx| {
15952                            buffer.edit([(0..0, old_name.clone())], None, cx)
15953                        });
15954                        let rename_selection_range = match cursor_offset_in_rename_range
15955                            .cmp(&cursor_offset_in_rename_range_end)
15956                        {
15957                            Ordering::Equal => {
15958                                editor.select_all(&SelectAll, window, cx);
15959                                return editor;
15960                            }
15961                            Ordering::Less => {
15962                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15963                            }
15964                            Ordering::Greater => {
15965                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15966                            }
15967                        };
15968                        if rename_selection_range.end > old_name.len() {
15969                            editor.select_all(&SelectAll, window, cx);
15970                        } else {
15971                            editor.change_selections(Default::default(), window, cx, |s| {
15972                                s.select_ranges([rename_selection_range]);
15973                            });
15974                        }
15975                        editor
15976                    });
15977                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15978                        if e == &EditorEvent::Focused {
15979                            cx.emit(EditorEvent::FocusedIn)
15980                        }
15981                    })
15982                    .detach();
15983
15984                    let write_highlights =
15985                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15986                    let read_highlights =
15987                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15988                    let ranges = write_highlights
15989                        .iter()
15990                        .flat_map(|(_, ranges)| ranges.iter())
15991                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15992                        .cloned()
15993                        .collect();
15994
15995                    this.highlight_text::<Rename>(
15996                        ranges,
15997                        HighlightStyle {
15998                            fade_out: Some(0.6),
15999                            ..Default::default()
16000                        },
16001                        cx,
16002                    );
16003                    let rename_focus_handle = rename_editor.focus_handle(cx);
16004                    window.focus(&rename_focus_handle);
16005                    let block_id = this.insert_blocks(
16006                        [BlockProperties {
16007                            style: BlockStyle::Flex,
16008                            placement: BlockPlacement::Below(range.start),
16009                            height: Some(1),
16010                            render: Arc::new({
16011                                let rename_editor = rename_editor.clone();
16012                                move |cx: &mut BlockContext| {
16013                                    let mut text_style = cx.editor_style.text.clone();
16014                                    if let Some(highlight_style) = old_highlight_id
16015                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16016                                    {
16017                                        text_style = text_style.highlight(highlight_style);
16018                                    }
16019                                    div()
16020                                        .block_mouse_except_scroll()
16021                                        .pl(cx.anchor_x)
16022                                        .child(EditorElement::new(
16023                                            &rename_editor,
16024                                            EditorStyle {
16025                                                background: cx.theme().system().transparent,
16026                                                local_player: cx.editor_style.local_player,
16027                                                text: text_style,
16028                                                scrollbar_width: cx.editor_style.scrollbar_width,
16029                                                syntax: cx.editor_style.syntax.clone(),
16030                                                status: cx.editor_style.status.clone(),
16031                                                inlay_hints_style: HighlightStyle {
16032                                                    font_weight: Some(FontWeight::BOLD),
16033                                                    ..make_inlay_hints_style(cx.app)
16034                                                },
16035                                                inline_completion_styles: make_suggestion_styles(
16036                                                    cx.app,
16037                                                ),
16038                                                ..EditorStyle::default()
16039                                            },
16040                                        ))
16041                                        .into_any_element()
16042                                }
16043                            }),
16044                            priority: 0,
16045                            render_in_minimap: true,
16046                        }],
16047                        Some(Autoscroll::fit()),
16048                        cx,
16049                    )[0];
16050                    this.pending_rename = Some(RenameState {
16051                        range,
16052                        old_name,
16053                        editor: rename_editor,
16054                        block_id,
16055                    });
16056                })?;
16057            }
16058
16059            Ok(())
16060        }))
16061    }
16062
16063    pub fn confirm_rename(
16064        &mut self,
16065        _: &ConfirmRename,
16066        window: &mut Window,
16067        cx: &mut Context<Self>,
16068    ) -> Option<Task<Result<()>>> {
16069        let rename = self.take_rename(false, window, cx)?;
16070        let workspace = self.workspace()?.downgrade();
16071        let (buffer, start) = self
16072            .buffer
16073            .read(cx)
16074            .text_anchor_for_position(rename.range.start, cx)?;
16075        let (end_buffer, _) = self
16076            .buffer
16077            .read(cx)
16078            .text_anchor_for_position(rename.range.end, cx)?;
16079        if buffer != end_buffer {
16080            return None;
16081        }
16082
16083        let old_name = rename.old_name;
16084        let new_name = rename.editor.read(cx).text(cx);
16085
16086        let rename = self.semantics_provider.as_ref()?.perform_rename(
16087            &buffer,
16088            start,
16089            new_name.clone(),
16090            cx,
16091        )?;
16092
16093        Some(cx.spawn_in(window, async move |editor, cx| {
16094            let project_transaction = rename.await?;
16095            Self::open_project_transaction(
16096                &editor,
16097                workspace,
16098                project_transaction,
16099                format!("Rename: {}{}", old_name, new_name),
16100                cx,
16101            )
16102            .await?;
16103
16104            editor.update(cx, |editor, cx| {
16105                editor.refresh_document_highlights(cx);
16106            })?;
16107            Ok(())
16108        }))
16109    }
16110
16111    fn take_rename(
16112        &mut self,
16113        moving_cursor: bool,
16114        window: &mut Window,
16115        cx: &mut Context<Self>,
16116    ) -> Option<RenameState> {
16117        let rename = self.pending_rename.take()?;
16118        if rename.editor.focus_handle(cx).is_focused(window) {
16119            window.focus(&self.focus_handle);
16120        }
16121
16122        self.remove_blocks(
16123            [rename.block_id].into_iter().collect(),
16124            Some(Autoscroll::fit()),
16125            cx,
16126        );
16127        self.clear_highlights::<Rename>(cx);
16128        self.show_local_selections = true;
16129
16130        if moving_cursor {
16131            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16132                editor.selections.newest::<usize>(cx).head()
16133            });
16134
16135            // Update the selection to match the position of the selection inside
16136            // the rename editor.
16137            let snapshot = self.buffer.read(cx).read(cx);
16138            let rename_range = rename.range.to_offset(&snapshot);
16139            let cursor_in_editor = snapshot
16140                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16141                .min(rename_range.end);
16142            drop(snapshot);
16143
16144            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16145                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16146            });
16147        } else {
16148            self.refresh_document_highlights(cx);
16149        }
16150
16151        Some(rename)
16152    }
16153
16154    pub fn pending_rename(&self) -> Option<&RenameState> {
16155        self.pending_rename.as_ref()
16156    }
16157
16158    fn format(
16159        &mut self,
16160        _: &Format,
16161        window: &mut Window,
16162        cx: &mut Context<Self>,
16163    ) -> Option<Task<Result<()>>> {
16164        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16165
16166        let project = match &self.project {
16167            Some(project) => project.clone(),
16168            None => return None,
16169        };
16170
16171        Some(self.perform_format(
16172            project,
16173            FormatTrigger::Manual,
16174            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16175            window,
16176            cx,
16177        ))
16178    }
16179
16180    fn format_selections(
16181        &mut self,
16182        _: &FormatSelections,
16183        window: &mut Window,
16184        cx: &mut Context<Self>,
16185    ) -> Option<Task<Result<()>>> {
16186        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16187
16188        let project = match &self.project {
16189            Some(project) => project.clone(),
16190            None => return None,
16191        };
16192
16193        let ranges = self
16194            .selections
16195            .all_adjusted(cx)
16196            .into_iter()
16197            .map(|selection| selection.range())
16198            .collect_vec();
16199
16200        Some(self.perform_format(
16201            project,
16202            FormatTrigger::Manual,
16203            FormatTarget::Ranges(ranges),
16204            window,
16205            cx,
16206        ))
16207    }
16208
16209    fn perform_format(
16210        &mut self,
16211        project: Entity<Project>,
16212        trigger: FormatTrigger,
16213        target: FormatTarget,
16214        window: &mut Window,
16215        cx: &mut Context<Self>,
16216    ) -> Task<Result<()>> {
16217        let buffer = self.buffer.clone();
16218        let (buffers, target) = match target {
16219            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16220            FormatTarget::Ranges(selection_ranges) => {
16221                let multi_buffer = buffer.read(cx);
16222                let snapshot = multi_buffer.read(cx);
16223                let mut buffers = HashSet::default();
16224                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16225                    BTreeMap::new();
16226                for selection_range in selection_ranges {
16227                    for (buffer, buffer_range, _) in
16228                        snapshot.range_to_buffer_ranges(selection_range)
16229                    {
16230                        let buffer_id = buffer.remote_id();
16231                        let start = buffer.anchor_before(buffer_range.start);
16232                        let end = buffer.anchor_after(buffer_range.end);
16233                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16234                        buffer_id_to_ranges
16235                            .entry(buffer_id)
16236                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16237                            .or_insert_with(|| vec![start..end]);
16238                    }
16239                }
16240                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16241            }
16242        };
16243
16244        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16245        let selections_prev = transaction_id_prev
16246            .and_then(|transaction_id_prev| {
16247                // default to selections as they were after the last edit, if we have them,
16248                // instead of how they are now.
16249                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16250                // will take you back to where you made the last edit, instead of staying where you scrolled
16251                self.selection_history
16252                    .transaction(transaction_id_prev)
16253                    .map(|t| t.0.clone())
16254            })
16255            .unwrap_or_else(|| {
16256                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16257                self.selections.disjoint_anchors()
16258            });
16259
16260        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16261        let format = project.update(cx, |project, cx| {
16262            project.format(buffers, target, true, trigger, cx)
16263        });
16264
16265        cx.spawn_in(window, async move |editor, cx| {
16266            let transaction = futures::select_biased! {
16267                transaction = format.log_err().fuse() => transaction,
16268                () = timeout => {
16269                    log::warn!("timed out waiting for formatting");
16270                    None
16271                }
16272            };
16273
16274            buffer
16275                .update(cx, |buffer, cx| {
16276                    if let Some(transaction) = transaction {
16277                        if !buffer.is_singleton() {
16278                            buffer.push_transaction(&transaction.0, cx);
16279                        }
16280                    }
16281                    cx.notify();
16282                })
16283                .ok();
16284
16285            if let Some(transaction_id_now) =
16286                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16287            {
16288                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16289                if has_new_transaction {
16290                    _ = editor.update(cx, |editor, _| {
16291                        editor
16292                            .selection_history
16293                            .insert_transaction(transaction_id_now, selections_prev);
16294                    });
16295                }
16296            }
16297
16298            Ok(())
16299        })
16300    }
16301
16302    fn organize_imports(
16303        &mut self,
16304        _: &OrganizeImports,
16305        window: &mut Window,
16306        cx: &mut Context<Self>,
16307    ) -> Option<Task<Result<()>>> {
16308        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16309        let project = match &self.project {
16310            Some(project) => project.clone(),
16311            None => return None,
16312        };
16313        Some(self.perform_code_action_kind(
16314            project,
16315            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16316            window,
16317            cx,
16318        ))
16319    }
16320
16321    fn perform_code_action_kind(
16322        &mut self,
16323        project: Entity<Project>,
16324        kind: CodeActionKind,
16325        window: &mut Window,
16326        cx: &mut Context<Self>,
16327    ) -> Task<Result<()>> {
16328        let buffer = self.buffer.clone();
16329        let buffers = buffer.read(cx).all_buffers();
16330        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16331        let apply_action = project.update(cx, |project, cx| {
16332            project.apply_code_action_kind(buffers, kind, true, cx)
16333        });
16334        cx.spawn_in(window, async move |_, cx| {
16335            let transaction = futures::select_biased! {
16336                () = timeout => {
16337                    log::warn!("timed out waiting for executing code action");
16338                    None
16339                }
16340                transaction = apply_action.log_err().fuse() => transaction,
16341            };
16342            buffer
16343                .update(cx, |buffer, cx| {
16344                    // check if we need this
16345                    if let Some(transaction) = transaction {
16346                        if !buffer.is_singleton() {
16347                            buffer.push_transaction(&transaction.0, cx);
16348                        }
16349                    }
16350                    cx.notify();
16351                })
16352                .ok();
16353            Ok(())
16354        })
16355    }
16356
16357    pub fn restart_language_server(
16358        &mut self,
16359        _: &RestartLanguageServer,
16360        _: &mut Window,
16361        cx: &mut Context<Self>,
16362    ) {
16363        if let Some(project) = self.project.clone() {
16364            self.buffer.update(cx, |multi_buffer, cx| {
16365                project.update(cx, |project, cx| {
16366                    project.restart_language_servers_for_buffers(
16367                        multi_buffer.all_buffers().into_iter().collect(),
16368                        HashSet::default(),
16369                        cx,
16370                    );
16371                });
16372            })
16373        }
16374    }
16375
16376    pub fn stop_language_server(
16377        &mut self,
16378        _: &StopLanguageServer,
16379        _: &mut Window,
16380        cx: &mut Context<Self>,
16381    ) {
16382        if let Some(project) = self.project.clone() {
16383            self.buffer.update(cx, |multi_buffer, cx| {
16384                project.update(cx, |project, cx| {
16385                    project.stop_language_servers_for_buffers(
16386                        multi_buffer.all_buffers().into_iter().collect(),
16387                        HashSet::default(),
16388                        cx,
16389                    );
16390                    cx.emit(project::Event::RefreshInlayHints);
16391                });
16392            });
16393        }
16394    }
16395
16396    fn cancel_language_server_work(
16397        workspace: &mut Workspace,
16398        _: &actions::CancelLanguageServerWork,
16399        _: &mut Window,
16400        cx: &mut Context<Workspace>,
16401    ) {
16402        let project = workspace.project();
16403        let buffers = workspace
16404            .active_item(cx)
16405            .and_then(|item| item.act_as::<Editor>(cx))
16406            .map_or(HashSet::default(), |editor| {
16407                editor.read(cx).buffer.read(cx).all_buffers()
16408            });
16409        project.update(cx, |project, cx| {
16410            project.cancel_language_server_work_for_buffers(buffers, cx);
16411        });
16412    }
16413
16414    fn show_character_palette(
16415        &mut self,
16416        _: &ShowCharacterPalette,
16417        window: &mut Window,
16418        _: &mut Context<Self>,
16419    ) {
16420        window.show_character_palette();
16421    }
16422
16423    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16424        if !self.diagnostics_enabled() {
16425            return;
16426        }
16427
16428        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16429            let buffer = self.buffer.read(cx).snapshot(cx);
16430            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16431            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16432            let is_valid = buffer
16433                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16434                .any(|entry| {
16435                    entry.diagnostic.is_primary
16436                        && !entry.range.is_empty()
16437                        && entry.range.start == primary_range_start
16438                        && entry.diagnostic.message == active_diagnostics.active_message
16439                });
16440
16441            if !is_valid {
16442                self.dismiss_diagnostics(cx);
16443            }
16444        }
16445    }
16446
16447    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16448        match &self.active_diagnostics {
16449            ActiveDiagnostic::Group(group) => Some(group),
16450            _ => None,
16451        }
16452    }
16453
16454    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16455        if !self.diagnostics_enabled() {
16456            return;
16457        }
16458        self.dismiss_diagnostics(cx);
16459        self.active_diagnostics = ActiveDiagnostic::All;
16460    }
16461
16462    fn activate_diagnostics(
16463        &mut self,
16464        buffer_id: BufferId,
16465        diagnostic: DiagnosticEntry<usize>,
16466        window: &mut Window,
16467        cx: &mut Context<Self>,
16468    ) {
16469        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16470            return;
16471        }
16472        self.dismiss_diagnostics(cx);
16473        let snapshot = self.snapshot(window, cx);
16474        let buffer = self.buffer.read(cx).snapshot(cx);
16475        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16476            return;
16477        };
16478
16479        let diagnostic_group = buffer
16480            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16481            .collect::<Vec<_>>();
16482
16483        let blocks =
16484            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16485
16486        let blocks = self.display_map.update(cx, |display_map, cx| {
16487            display_map.insert_blocks(blocks, cx).into_iter().collect()
16488        });
16489        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16490            active_range: buffer.anchor_before(diagnostic.range.start)
16491                ..buffer.anchor_after(diagnostic.range.end),
16492            active_message: diagnostic.diagnostic.message.clone(),
16493            group_id: diagnostic.diagnostic.group_id,
16494            blocks,
16495        });
16496        cx.notify();
16497    }
16498
16499    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16500        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16501            return;
16502        };
16503
16504        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16505        if let ActiveDiagnostic::Group(group) = prev {
16506            self.display_map.update(cx, |display_map, cx| {
16507                display_map.remove_blocks(group.blocks, cx);
16508            });
16509            cx.notify();
16510        }
16511    }
16512
16513    /// Disable inline diagnostics rendering for this editor.
16514    pub fn disable_inline_diagnostics(&mut self) {
16515        self.inline_diagnostics_enabled = false;
16516        self.inline_diagnostics_update = Task::ready(());
16517        self.inline_diagnostics.clear();
16518    }
16519
16520    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16521        self.diagnostics_enabled = false;
16522        self.dismiss_diagnostics(cx);
16523        self.inline_diagnostics_update = Task::ready(());
16524        self.inline_diagnostics.clear();
16525    }
16526
16527    pub fn diagnostics_enabled(&self) -> bool {
16528        self.diagnostics_enabled && self.mode.is_full()
16529    }
16530
16531    pub fn inline_diagnostics_enabled(&self) -> bool {
16532        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16533    }
16534
16535    pub fn show_inline_diagnostics(&self) -> bool {
16536        self.show_inline_diagnostics
16537    }
16538
16539    pub fn toggle_inline_diagnostics(
16540        &mut self,
16541        _: &ToggleInlineDiagnostics,
16542        window: &mut Window,
16543        cx: &mut Context<Editor>,
16544    ) {
16545        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16546        self.refresh_inline_diagnostics(false, window, cx);
16547    }
16548
16549    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16550        self.diagnostics_max_severity = severity;
16551        self.display_map.update(cx, |display_map, _| {
16552            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16553        });
16554    }
16555
16556    pub fn toggle_diagnostics(
16557        &mut self,
16558        _: &ToggleDiagnostics,
16559        window: &mut Window,
16560        cx: &mut Context<Editor>,
16561    ) {
16562        if !self.diagnostics_enabled() {
16563            return;
16564        }
16565
16566        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16567            EditorSettings::get_global(cx)
16568                .diagnostics_max_severity
16569                .filter(|severity| severity != &DiagnosticSeverity::Off)
16570                .unwrap_or(DiagnosticSeverity::Hint)
16571        } else {
16572            DiagnosticSeverity::Off
16573        };
16574        self.set_max_diagnostics_severity(new_severity, cx);
16575        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16576            self.active_diagnostics = ActiveDiagnostic::None;
16577            self.inline_diagnostics_update = Task::ready(());
16578            self.inline_diagnostics.clear();
16579        } else {
16580            self.refresh_inline_diagnostics(false, window, cx);
16581        }
16582
16583        cx.notify();
16584    }
16585
16586    pub fn toggle_minimap(
16587        &mut self,
16588        _: &ToggleMinimap,
16589        window: &mut Window,
16590        cx: &mut Context<Editor>,
16591    ) {
16592        if self.supports_minimap(cx) {
16593            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16594        }
16595    }
16596
16597    fn refresh_inline_diagnostics(
16598        &mut self,
16599        debounce: bool,
16600        window: &mut Window,
16601        cx: &mut Context<Self>,
16602    ) {
16603        let max_severity = ProjectSettings::get_global(cx)
16604            .diagnostics
16605            .inline
16606            .max_severity
16607            .unwrap_or(self.diagnostics_max_severity);
16608
16609        if !self.inline_diagnostics_enabled()
16610            || !self.show_inline_diagnostics
16611            || max_severity == DiagnosticSeverity::Off
16612        {
16613            self.inline_diagnostics_update = Task::ready(());
16614            self.inline_diagnostics.clear();
16615            return;
16616        }
16617
16618        let debounce_ms = ProjectSettings::get_global(cx)
16619            .diagnostics
16620            .inline
16621            .update_debounce_ms;
16622        let debounce = if debounce && debounce_ms > 0 {
16623            Some(Duration::from_millis(debounce_ms))
16624        } else {
16625            None
16626        };
16627        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16628            if let Some(debounce) = debounce {
16629                cx.background_executor().timer(debounce).await;
16630            }
16631            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16632                editor
16633                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16634                    .ok()
16635            }) else {
16636                return;
16637            };
16638
16639            let new_inline_diagnostics = cx
16640                .background_spawn(async move {
16641                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16642                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16643                        let message = diagnostic_entry
16644                            .diagnostic
16645                            .message
16646                            .split_once('\n')
16647                            .map(|(line, _)| line)
16648                            .map(SharedString::new)
16649                            .unwrap_or_else(|| {
16650                                SharedString::from(diagnostic_entry.diagnostic.message)
16651                            });
16652                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16653                        let (Ok(i) | Err(i)) = inline_diagnostics
16654                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16655                        inline_diagnostics.insert(
16656                            i,
16657                            (
16658                                start_anchor,
16659                                InlineDiagnostic {
16660                                    message,
16661                                    group_id: diagnostic_entry.diagnostic.group_id,
16662                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16663                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16664                                    severity: diagnostic_entry.diagnostic.severity,
16665                                },
16666                            ),
16667                        );
16668                    }
16669                    inline_diagnostics
16670                })
16671                .await;
16672
16673            editor
16674                .update(cx, |editor, cx| {
16675                    editor.inline_diagnostics = new_inline_diagnostics;
16676                    cx.notify();
16677                })
16678                .ok();
16679        });
16680    }
16681
16682    fn pull_diagnostics(
16683        &mut self,
16684        buffer_id: Option<BufferId>,
16685        window: &Window,
16686        cx: &mut Context<Self>,
16687    ) -> Option<()> {
16688        if !self.mode().is_full() {
16689            return None;
16690        }
16691        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16692            .diagnostics
16693            .lsp_pull_diagnostics;
16694        if !pull_diagnostics_settings.enabled {
16695            return None;
16696        }
16697        let project = self.project.as_ref()?.downgrade();
16698        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16699        let mut buffers = self.buffer.read(cx).all_buffers();
16700        if let Some(buffer_id) = buffer_id {
16701            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16702        }
16703
16704        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16705            cx.background_executor().timer(debounce).await;
16706
16707            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16708                buffers
16709                    .into_iter()
16710                    .filter_map(|buffer| {
16711                        project
16712                            .update(cx, |project, cx| {
16713                                project.lsp_store().update(cx, |lsp_store, cx| {
16714                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16715                                })
16716                            })
16717                            .ok()
16718                    })
16719                    .collect::<FuturesUnordered<_>>()
16720            }) else {
16721                return;
16722            };
16723
16724            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16725                match pull_task {
16726                    Ok(()) => {
16727                        if editor
16728                            .update_in(cx, |editor, window, cx| {
16729                                editor.update_diagnostics_state(window, cx);
16730                            })
16731                            .is_err()
16732                        {
16733                            return;
16734                        }
16735                    }
16736                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16737                }
16738            }
16739        });
16740
16741        Some(())
16742    }
16743
16744    pub fn set_selections_from_remote(
16745        &mut self,
16746        selections: Vec<Selection<Anchor>>,
16747        pending_selection: Option<Selection<Anchor>>,
16748        window: &mut Window,
16749        cx: &mut Context<Self>,
16750    ) {
16751        let old_cursor_position = self.selections.newest_anchor().head();
16752        self.selections.change_with(cx, |s| {
16753            s.select_anchors(selections);
16754            if let Some(pending_selection) = pending_selection {
16755                s.set_pending(pending_selection, SelectMode::Character);
16756            } else {
16757                s.clear_pending();
16758            }
16759        });
16760        self.selections_did_change(
16761            false,
16762            &old_cursor_position,
16763            SelectionEffects::default(),
16764            window,
16765            cx,
16766        );
16767    }
16768
16769    pub fn transact(
16770        &mut self,
16771        window: &mut Window,
16772        cx: &mut Context<Self>,
16773        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16774    ) -> Option<TransactionId> {
16775        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16776            this.start_transaction_at(Instant::now(), window, cx);
16777            update(this, window, cx);
16778            this.end_transaction_at(Instant::now(), cx)
16779        })
16780    }
16781
16782    pub fn start_transaction_at(
16783        &mut self,
16784        now: Instant,
16785        window: &mut Window,
16786        cx: &mut Context<Self>,
16787    ) {
16788        self.end_selection(window, cx);
16789        if let Some(tx_id) = self
16790            .buffer
16791            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16792        {
16793            self.selection_history
16794                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16795            cx.emit(EditorEvent::TransactionBegun {
16796                transaction_id: tx_id,
16797            })
16798        }
16799    }
16800
16801    pub fn end_transaction_at(
16802        &mut self,
16803        now: Instant,
16804        cx: &mut Context<Self>,
16805    ) -> Option<TransactionId> {
16806        if let Some(transaction_id) = self
16807            .buffer
16808            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16809        {
16810            if let Some((_, end_selections)) =
16811                self.selection_history.transaction_mut(transaction_id)
16812            {
16813                *end_selections = Some(self.selections.disjoint_anchors());
16814            } else {
16815                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16816            }
16817
16818            cx.emit(EditorEvent::Edited { transaction_id });
16819            Some(transaction_id)
16820        } else {
16821            None
16822        }
16823    }
16824
16825    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16826        if self.selection_mark_mode {
16827            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16828                s.move_with(|_, sel| {
16829                    sel.collapse_to(sel.head(), SelectionGoal::None);
16830                });
16831            })
16832        }
16833        self.selection_mark_mode = true;
16834        cx.notify();
16835    }
16836
16837    pub fn swap_selection_ends(
16838        &mut self,
16839        _: &actions::SwapSelectionEnds,
16840        window: &mut Window,
16841        cx: &mut Context<Self>,
16842    ) {
16843        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16844            s.move_with(|_, sel| {
16845                if sel.start != sel.end {
16846                    sel.reversed = !sel.reversed
16847                }
16848            });
16849        });
16850        self.request_autoscroll(Autoscroll::newest(), cx);
16851        cx.notify();
16852    }
16853
16854    pub fn toggle_fold(
16855        &mut self,
16856        _: &actions::ToggleFold,
16857        window: &mut Window,
16858        cx: &mut Context<Self>,
16859    ) {
16860        if self.is_singleton(cx) {
16861            let selection = self.selections.newest::<Point>(cx);
16862
16863            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16864            let range = if selection.is_empty() {
16865                let point = selection.head().to_display_point(&display_map);
16866                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16867                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16868                    .to_point(&display_map);
16869                start..end
16870            } else {
16871                selection.range()
16872            };
16873            if display_map.folds_in_range(range).next().is_some() {
16874                self.unfold_lines(&Default::default(), window, cx)
16875            } else {
16876                self.fold(&Default::default(), window, cx)
16877            }
16878        } else {
16879            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16880            let buffer_ids: HashSet<_> = self
16881                .selections
16882                .disjoint_anchor_ranges()
16883                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16884                .collect();
16885
16886            let should_unfold = buffer_ids
16887                .iter()
16888                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16889
16890            for buffer_id in buffer_ids {
16891                if should_unfold {
16892                    self.unfold_buffer(buffer_id, cx);
16893                } else {
16894                    self.fold_buffer(buffer_id, cx);
16895                }
16896            }
16897        }
16898    }
16899
16900    pub fn toggle_fold_recursive(
16901        &mut self,
16902        _: &actions::ToggleFoldRecursive,
16903        window: &mut Window,
16904        cx: &mut Context<Self>,
16905    ) {
16906        let selection = self.selections.newest::<Point>(cx);
16907
16908        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16909        let range = if selection.is_empty() {
16910            let point = selection.head().to_display_point(&display_map);
16911            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16912            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16913                .to_point(&display_map);
16914            start..end
16915        } else {
16916            selection.range()
16917        };
16918        if display_map.folds_in_range(range).next().is_some() {
16919            self.unfold_recursive(&Default::default(), window, cx)
16920        } else {
16921            self.fold_recursive(&Default::default(), window, cx)
16922        }
16923    }
16924
16925    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16926        if self.is_singleton(cx) {
16927            let mut to_fold = Vec::new();
16928            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16929            let selections = self.selections.all_adjusted(cx);
16930
16931            for selection in selections {
16932                let range = selection.range().sorted();
16933                let buffer_start_row = range.start.row;
16934
16935                if range.start.row != range.end.row {
16936                    let mut found = false;
16937                    let mut row = range.start.row;
16938                    while row <= range.end.row {
16939                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16940                        {
16941                            found = true;
16942                            row = crease.range().end.row + 1;
16943                            to_fold.push(crease);
16944                        } else {
16945                            row += 1
16946                        }
16947                    }
16948                    if found {
16949                        continue;
16950                    }
16951                }
16952
16953                for row in (0..=range.start.row).rev() {
16954                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16955                        if crease.range().end.row >= buffer_start_row {
16956                            to_fold.push(crease);
16957                            if row <= range.start.row {
16958                                break;
16959                            }
16960                        }
16961                    }
16962                }
16963            }
16964
16965            self.fold_creases(to_fold, true, window, cx);
16966        } else {
16967            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16968            let buffer_ids = self
16969                .selections
16970                .disjoint_anchor_ranges()
16971                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16972                .collect::<HashSet<_>>();
16973            for buffer_id in buffer_ids {
16974                self.fold_buffer(buffer_id, cx);
16975            }
16976        }
16977    }
16978
16979    fn fold_at_level(
16980        &mut self,
16981        fold_at: &FoldAtLevel,
16982        window: &mut Window,
16983        cx: &mut Context<Self>,
16984    ) {
16985        if !self.buffer.read(cx).is_singleton() {
16986            return;
16987        }
16988
16989        let fold_at_level = fold_at.0;
16990        let snapshot = self.buffer.read(cx).snapshot(cx);
16991        let mut to_fold = Vec::new();
16992        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16993
16994        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16995            while start_row < end_row {
16996                match self
16997                    .snapshot(window, cx)
16998                    .crease_for_buffer_row(MultiBufferRow(start_row))
16999                {
17000                    Some(crease) => {
17001                        let nested_start_row = crease.range().start.row + 1;
17002                        let nested_end_row = crease.range().end.row;
17003
17004                        if current_level < fold_at_level {
17005                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17006                        } else if current_level == fold_at_level {
17007                            to_fold.push(crease);
17008                        }
17009
17010                        start_row = nested_end_row + 1;
17011                    }
17012                    None => start_row += 1,
17013                }
17014            }
17015        }
17016
17017        self.fold_creases(to_fold, true, window, cx);
17018    }
17019
17020    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17021        if self.buffer.read(cx).is_singleton() {
17022            let mut fold_ranges = Vec::new();
17023            let snapshot = self.buffer.read(cx).snapshot(cx);
17024
17025            for row in 0..snapshot.max_row().0 {
17026                if let Some(foldable_range) = self
17027                    .snapshot(window, cx)
17028                    .crease_for_buffer_row(MultiBufferRow(row))
17029                {
17030                    fold_ranges.push(foldable_range);
17031                }
17032            }
17033
17034            self.fold_creases(fold_ranges, true, window, cx);
17035        } else {
17036            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17037                editor
17038                    .update_in(cx, |editor, _, cx| {
17039                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17040                            editor.fold_buffer(buffer_id, cx);
17041                        }
17042                    })
17043                    .ok();
17044            });
17045        }
17046    }
17047
17048    pub fn fold_function_bodies(
17049        &mut self,
17050        _: &actions::FoldFunctionBodies,
17051        window: &mut Window,
17052        cx: &mut Context<Self>,
17053    ) {
17054        let snapshot = self.buffer.read(cx).snapshot(cx);
17055
17056        let ranges = snapshot
17057            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17058            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17059            .collect::<Vec<_>>();
17060
17061        let creases = ranges
17062            .into_iter()
17063            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17064            .collect();
17065
17066        self.fold_creases(creases, true, window, cx);
17067    }
17068
17069    pub fn fold_recursive(
17070        &mut self,
17071        _: &actions::FoldRecursive,
17072        window: &mut Window,
17073        cx: &mut Context<Self>,
17074    ) {
17075        let mut to_fold = Vec::new();
17076        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17077        let selections = self.selections.all_adjusted(cx);
17078
17079        for selection in selections {
17080            let range = selection.range().sorted();
17081            let buffer_start_row = range.start.row;
17082
17083            if range.start.row != range.end.row {
17084                let mut found = false;
17085                for row in range.start.row..=range.end.row {
17086                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17087                        found = true;
17088                        to_fold.push(crease);
17089                    }
17090                }
17091                if found {
17092                    continue;
17093                }
17094            }
17095
17096            for row in (0..=range.start.row).rev() {
17097                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17098                    if crease.range().end.row >= buffer_start_row {
17099                        to_fold.push(crease);
17100                    } else {
17101                        break;
17102                    }
17103                }
17104            }
17105        }
17106
17107        self.fold_creases(to_fold, true, window, cx);
17108    }
17109
17110    pub fn fold_at(
17111        &mut self,
17112        buffer_row: MultiBufferRow,
17113        window: &mut Window,
17114        cx: &mut Context<Self>,
17115    ) {
17116        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17117
17118        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17119            let autoscroll = self
17120                .selections
17121                .all::<Point>(cx)
17122                .iter()
17123                .any(|selection| crease.range().overlaps(&selection.range()));
17124
17125            self.fold_creases(vec![crease], autoscroll, window, cx);
17126        }
17127    }
17128
17129    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17130        if self.is_singleton(cx) {
17131            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17132            let buffer = &display_map.buffer_snapshot;
17133            let selections = self.selections.all::<Point>(cx);
17134            let ranges = selections
17135                .iter()
17136                .map(|s| {
17137                    let range = s.display_range(&display_map).sorted();
17138                    let mut start = range.start.to_point(&display_map);
17139                    let mut end = range.end.to_point(&display_map);
17140                    start.column = 0;
17141                    end.column = buffer.line_len(MultiBufferRow(end.row));
17142                    start..end
17143                })
17144                .collect::<Vec<_>>();
17145
17146            self.unfold_ranges(&ranges, true, true, cx);
17147        } else {
17148            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17149            let buffer_ids = self
17150                .selections
17151                .disjoint_anchor_ranges()
17152                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17153                .collect::<HashSet<_>>();
17154            for buffer_id in buffer_ids {
17155                self.unfold_buffer(buffer_id, cx);
17156            }
17157        }
17158    }
17159
17160    pub fn unfold_recursive(
17161        &mut self,
17162        _: &UnfoldRecursive,
17163        _window: &mut Window,
17164        cx: &mut Context<Self>,
17165    ) {
17166        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17167        let selections = self.selections.all::<Point>(cx);
17168        let ranges = selections
17169            .iter()
17170            .map(|s| {
17171                let mut range = s.display_range(&display_map).sorted();
17172                *range.start.column_mut() = 0;
17173                *range.end.column_mut() = display_map.line_len(range.end.row());
17174                let start = range.start.to_point(&display_map);
17175                let end = range.end.to_point(&display_map);
17176                start..end
17177            })
17178            .collect::<Vec<_>>();
17179
17180        self.unfold_ranges(&ranges, true, true, cx);
17181    }
17182
17183    pub fn unfold_at(
17184        &mut self,
17185        buffer_row: MultiBufferRow,
17186        _window: &mut Window,
17187        cx: &mut Context<Self>,
17188    ) {
17189        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17190
17191        let intersection_range = Point::new(buffer_row.0, 0)
17192            ..Point::new(
17193                buffer_row.0,
17194                display_map.buffer_snapshot.line_len(buffer_row),
17195            );
17196
17197        let autoscroll = self
17198            .selections
17199            .all::<Point>(cx)
17200            .iter()
17201            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17202
17203        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17204    }
17205
17206    pub fn unfold_all(
17207        &mut self,
17208        _: &actions::UnfoldAll,
17209        _window: &mut Window,
17210        cx: &mut Context<Self>,
17211    ) {
17212        if self.buffer.read(cx).is_singleton() {
17213            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17214            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17215        } else {
17216            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17217                editor
17218                    .update(cx, |editor, cx| {
17219                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17220                            editor.unfold_buffer(buffer_id, cx);
17221                        }
17222                    })
17223                    .ok();
17224            });
17225        }
17226    }
17227
17228    pub fn fold_selected_ranges(
17229        &mut self,
17230        _: &FoldSelectedRanges,
17231        window: &mut Window,
17232        cx: &mut Context<Self>,
17233    ) {
17234        let selections = self.selections.all_adjusted(cx);
17235        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17236        let ranges = selections
17237            .into_iter()
17238            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17239            .collect::<Vec<_>>();
17240        self.fold_creases(ranges, true, window, cx);
17241    }
17242
17243    pub fn fold_ranges<T: ToOffset + Clone>(
17244        &mut self,
17245        ranges: Vec<Range<T>>,
17246        auto_scroll: bool,
17247        window: &mut Window,
17248        cx: &mut Context<Self>,
17249    ) {
17250        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17251        let ranges = ranges
17252            .into_iter()
17253            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17254            .collect::<Vec<_>>();
17255        self.fold_creases(ranges, auto_scroll, window, cx);
17256    }
17257
17258    pub fn fold_creases<T: ToOffset + Clone>(
17259        &mut self,
17260        creases: Vec<Crease<T>>,
17261        auto_scroll: bool,
17262        _window: &mut Window,
17263        cx: &mut Context<Self>,
17264    ) {
17265        if creases.is_empty() {
17266            return;
17267        }
17268
17269        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17270
17271        if auto_scroll {
17272            self.request_autoscroll(Autoscroll::fit(), cx);
17273        }
17274
17275        cx.notify();
17276
17277        self.scrollbar_marker_state.dirty = true;
17278        self.folds_did_change(cx);
17279    }
17280
17281    /// Removes any folds whose ranges intersect any of the given ranges.
17282    pub fn unfold_ranges<T: ToOffset + Clone>(
17283        &mut self,
17284        ranges: &[Range<T>],
17285        inclusive: bool,
17286        auto_scroll: bool,
17287        cx: &mut Context<Self>,
17288    ) {
17289        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17290            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17291        });
17292        self.folds_did_change(cx);
17293    }
17294
17295    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17296        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17297            return;
17298        }
17299        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17300        self.display_map.update(cx, |display_map, cx| {
17301            display_map.fold_buffers([buffer_id], cx)
17302        });
17303        cx.emit(EditorEvent::BufferFoldToggled {
17304            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17305            folded: true,
17306        });
17307        cx.notify();
17308    }
17309
17310    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17311        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17312            return;
17313        }
17314        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17315        self.display_map.update(cx, |display_map, cx| {
17316            display_map.unfold_buffers([buffer_id], cx);
17317        });
17318        cx.emit(EditorEvent::BufferFoldToggled {
17319            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17320            folded: false,
17321        });
17322        cx.notify();
17323    }
17324
17325    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17326        self.display_map.read(cx).is_buffer_folded(buffer)
17327    }
17328
17329    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17330        self.display_map.read(cx).folded_buffers()
17331    }
17332
17333    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17334        self.display_map.update(cx, |display_map, cx| {
17335            display_map.disable_header_for_buffer(buffer_id, cx);
17336        });
17337        cx.notify();
17338    }
17339
17340    /// Removes any folds with the given ranges.
17341    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17342        &mut self,
17343        ranges: &[Range<T>],
17344        type_id: TypeId,
17345        auto_scroll: bool,
17346        cx: &mut Context<Self>,
17347    ) {
17348        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17349            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17350        });
17351        self.folds_did_change(cx);
17352    }
17353
17354    fn remove_folds_with<T: ToOffset + Clone>(
17355        &mut self,
17356        ranges: &[Range<T>],
17357        auto_scroll: bool,
17358        cx: &mut Context<Self>,
17359        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17360    ) {
17361        if ranges.is_empty() {
17362            return;
17363        }
17364
17365        let mut buffers_affected = HashSet::default();
17366        let multi_buffer = self.buffer().read(cx);
17367        for range in ranges {
17368            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17369                buffers_affected.insert(buffer.read(cx).remote_id());
17370            };
17371        }
17372
17373        self.display_map.update(cx, update);
17374
17375        if auto_scroll {
17376            self.request_autoscroll(Autoscroll::fit(), cx);
17377        }
17378
17379        cx.notify();
17380        self.scrollbar_marker_state.dirty = true;
17381        self.active_indent_guides_state.dirty = true;
17382    }
17383
17384    pub fn update_renderer_widths(
17385        &mut self,
17386        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17387        cx: &mut Context<Self>,
17388    ) -> bool {
17389        self.display_map
17390            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17391    }
17392
17393    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17394        self.display_map.read(cx).fold_placeholder.clone()
17395    }
17396
17397    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17398        self.buffer.update(cx, |buffer, cx| {
17399            buffer.set_all_diff_hunks_expanded(cx);
17400        });
17401    }
17402
17403    pub fn expand_all_diff_hunks(
17404        &mut self,
17405        _: &ExpandAllDiffHunks,
17406        _window: &mut Window,
17407        cx: &mut Context<Self>,
17408    ) {
17409        self.buffer.update(cx, |buffer, cx| {
17410            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17411        });
17412    }
17413
17414    pub fn toggle_selected_diff_hunks(
17415        &mut self,
17416        _: &ToggleSelectedDiffHunks,
17417        _window: &mut Window,
17418        cx: &mut Context<Self>,
17419    ) {
17420        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17421        self.toggle_diff_hunks_in_ranges(ranges, cx);
17422    }
17423
17424    pub fn diff_hunks_in_ranges<'a>(
17425        &'a self,
17426        ranges: &'a [Range<Anchor>],
17427        buffer: &'a MultiBufferSnapshot,
17428    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17429        ranges.iter().flat_map(move |range| {
17430            let end_excerpt_id = range.end.excerpt_id;
17431            let range = range.to_point(buffer);
17432            let mut peek_end = range.end;
17433            if range.end.row < buffer.max_row().0 {
17434                peek_end = Point::new(range.end.row + 1, 0);
17435            }
17436            buffer
17437                .diff_hunks_in_range(range.start..peek_end)
17438                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17439        })
17440    }
17441
17442    pub fn has_stageable_diff_hunks_in_ranges(
17443        &self,
17444        ranges: &[Range<Anchor>],
17445        snapshot: &MultiBufferSnapshot,
17446    ) -> bool {
17447        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17448        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17449    }
17450
17451    pub fn toggle_staged_selected_diff_hunks(
17452        &mut self,
17453        _: &::git::ToggleStaged,
17454        _: &mut Window,
17455        cx: &mut Context<Self>,
17456    ) {
17457        let snapshot = self.buffer.read(cx).snapshot(cx);
17458        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17459        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17460        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17461    }
17462
17463    pub fn set_render_diff_hunk_controls(
17464        &mut self,
17465        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17466        cx: &mut Context<Self>,
17467    ) {
17468        self.render_diff_hunk_controls = render_diff_hunk_controls;
17469        cx.notify();
17470    }
17471
17472    pub fn stage_and_next(
17473        &mut self,
17474        _: &::git::StageAndNext,
17475        window: &mut Window,
17476        cx: &mut Context<Self>,
17477    ) {
17478        self.do_stage_or_unstage_and_next(true, window, cx);
17479    }
17480
17481    pub fn unstage_and_next(
17482        &mut self,
17483        _: &::git::UnstageAndNext,
17484        window: &mut Window,
17485        cx: &mut Context<Self>,
17486    ) {
17487        self.do_stage_or_unstage_and_next(false, window, cx);
17488    }
17489
17490    pub fn stage_or_unstage_diff_hunks(
17491        &mut self,
17492        stage: bool,
17493        ranges: Vec<Range<Anchor>>,
17494        cx: &mut Context<Self>,
17495    ) {
17496        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17497        cx.spawn(async move |this, cx| {
17498            task.await?;
17499            this.update(cx, |this, cx| {
17500                let snapshot = this.buffer.read(cx).snapshot(cx);
17501                let chunk_by = this
17502                    .diff_hunks_in_ranges(&ranges, &snapshot)
17503                    .chunk_by(|hunk| hunk.buffer_id);
17504                for (buffer_id, hunks) in &chunk_by {
17505                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17506                }
17507            })
17508        })
17509        .detach_and_log_err(cx);
17510    }
17511
17512    fn save_buffers_for_ranges_if_needed(
17513        &mut self,
17514        ranges: &[Range<Anchor>],
17515        cx: &mut Context<Editor>,
17516    ) -> Task<Result<()>> {
17517        let multibuffer = self.buffer.read(cx);
17518        let snapshot = multibuffer.read(cx);
17519        let buffer_ids: HashSet<_> = ranges
17520            .iter()
17521            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17522            .collect();
17523        drop(snapshot);
17524
17525        let mut buffers = HashSet::default();
17526        for buffer_id in buffer_ids {
17527            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17528                let buffer = buffer_entity.read(cx);
17529                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17530                {
17531                    buffers.insert(buffer_entity);
17532                }
17533            }
17534        }
17535
17536        if let Some(project) = &self.project {
17537            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17538        } else {
17539            Task::ready(Ok(()))
17540        }
17541    }
17542
17543    fn do_stage_or_unstage_and_next(
17544        &mut self,
17545        stage: bool,
17546        window: &mut Window,
17547        cx: &mut Context<Self>,
17548    ) {
17549        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17550
17551        if ranges.iter().any(|range| range.start != range.end) {
17552            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17553            return;
17554        }
17555
17556        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17557        let snapshot = self.snapshot(window, cx);
17558        let position = self.selections.newest::<Point>(cx).head();
17559        let mut row = snapshot
17560            .buffer_snapshot
17561            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17562            .find(|hunk| hunk.row_range.start.0 > position.row)
17563            .map(|hunk| hunk.row_range.start);
17564
17565        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17566        // Outside of the project diff editor, wrap around to the beginning.
17567        if !all_diff_hunks_expanded {
17568            row = row.or_else(|| {
17569                snapshot
17570                    .buffer_snapshot
17571                    .diff_hunks_in_range(Point::zero()..position)
17572                    .find(|hunk| hunk.row_range.end.0 < position.row)
17573                    .map(|hunk| hunk.row_range.start)
17574            });
17575        }
17576
17577        if let Some(row) = row {
17578            let destination = Point::new(row.0, 0);
17579            let autoscroll = Autoscroll::center();
17580
17581            self.unfold_ranges(&[destination..destination], false, false, cx);
17582            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17583                s.select_ranges([destination..destination]);
17584            });
17585        }
17586    }
17587
17588    fn do_stage_or_unstage(
17589        &self,
17590        stage: bool,
17591        buffer_id: BufferId,
17592        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17593        cx: &mut App,
17594    ) -> Option<()> {
17595        let project = self.project.as_ref()?;
17596        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17597        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17598        let buffer_snapshot = buffer.read(cx).snapshot();
17599        let file_exists = buffer_snapshot
17600            .file()
17601            .is_some_and(|file| file.disk_state().exists());
17602        diff.update(cx, |diff, cx| {
17603            diff.stage_or_unstage_hunks(
17604                stage,
17605                &hunks
17606                    .map(|hunk| buffer_diff::DiffHunk {
17607                        buffer_range: hunk.buffer_range,
17608                        diff_base_byte_range: hunk.diff_base_byte_range,
17609                        secondary_status: hunk.secondary_status,
17610                        range: Point::zero()..Point::zero(), // unused
17611                    })
17612                    .collect::<Vec<_>>(),
17613                &buffer_snapshot,
17614                file_exists,
17615                cx,
17616            )
17617        });
17618        None
17619    }
17620
17621    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17622        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17623        self.buffer
17624            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17625    }
17626
17627    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17628        self.buffer.update(cx, |buffer, cx| {
17629            let ranges = vec![Anchor::min()..Anchor::max()];
17630            if !buffer.all_diff_hunks_expanded()
17631                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17632            {
17633                buffer.collapse_diff_hunks(ranges, cx);
17634                true
17635            } else {
17636                false
17637            }
17638        })
17639    }
17640
17641    fn toggle_diff_hunks_in_ranges(
17642        &mut self,
17643        ranges: Vec<Range<Anchor>>,
17644        cx: &mut Context<Editor>,
17645    ) {
17646        self.buffer.update(cx, |buffer, cx| {
17647            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17648            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17649        })
17650    }
17651
17652    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17653        self.buffer.update(cx, |buffer, cx| {
17654            let snapshot = buffer.snapshot(cx);
17655            let excerpt_id = range.end.excerpt_id;
17656            let point_range = range.to_point(&snapshot);
17657            let expand = !buffer.single_hunk_is_expanded(range, cx);
17658            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17659        })
17660    }
17661
17662    pub(crate) fn apply_all_diff_hunks(
17663        &mut self,
17664        _: &ApplyAllDiffHunks,
17665        window: &mut Window,
17666        cx: &mut Context<Self>,
17667    ) {
17668        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17669
17670        let buffers = self.buffer.read(cx).all_buffers();
17671        for branch_buffer in buffers {
17672            branch_buffer.update(cx, |branch_buffer, cx| {
17673                branch_buffer.merge_into_base(Vec::new(), cx);
17674            });
17675        }
17676
17677        if let Some(project) = self.project.clone() {
17678            self.save(
17679                SaveOptions {
17680                    format: true,
17681                    autosave: false,
17682                },
17683                project,
17684                window,
17685                cx,
17686            )
17687            .detach_and_log_err(cx);
17688        }
17689    }
17690
17691    pub(crate) fn apply_selected_diff_hunks(
17692        &mut self,
17693        _: &ApplyDiffHunk,
17694        window: &mut Window,
17695        cx: &mut Context<Self>,
17696    ) {
17697        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17698        let snapshot = self.snapshot(window, cx);
17699        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17700        let mut ranges_by_buffer = HashMap::default();
17701        self.transact(window, cx, |editor, _window, cx| {
17702            for hunk in hunks {
17703                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17704                    ranges_by_buffer
17705                        .entry(buffer.clone())
17706                        .or_insert_with(Vec::new)
17707                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17708                }
17709            }
17710
17711            for (buffer, ranges) in ranges_by_buffer {
17712                buffer.update(cx, |buffer, cx| {
17713                    buffer.merge_into_base(ranges, cx);
17714                });
17715            }
17716        });
17717
17718        if let Some(project) = self.project.clone() {
17719            self.save(
17720                SaveOptions {
17721                    format: true,
17722                    autosave: false,
17723                },
17724                project,
17725                window,
17726                cx,
17727            )
17728            .detach_and_log_err(cx);
17729        }
17730    }
17731
17732    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17733        if hovered != self.gutter_hovered {
17734            self.gutter_hovered = hovered;
17735            cx.notify();
17736        }
17737    }
17738
17739    pub fn insert_blocks(
17740        &mut self,
17741        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17742        autoscroll: Option<Autoscroll>,
17743        cx: &mut Context<Self>,
17744    ) -> Vec<CustomBlockId> {
17745        let blocks = self
17746            .display_map
17747            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17748        if let Some(autoscroll) = autoscroll {
17749            self.request_autoscroll(autoscroll, cx);
17750        }
17751        cx.notify();
17752        blocks
17753    }
17754
17755    pub fn resize_blocks(
17756        &mut self,
17757        heights: HashMap<CustomBlockId, u32>,
17758        autoscroll: Option<Autoscroll>,
17759        cx: &mut Context<Self>,
17760    ) {
17761        self.display_map
17762            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17763        if let Some(autoscroll) = autoscroll {
17764            self.request_autoscroll(autoscroll, cx);
17765        }
17766        cx.notify();
17767    }
17768
17769    pub fn replace_blocks(
17770        &mut self,
17771        renderers: HashMap<CustomBlockId, RenderBlock>,
17772        autoscroll: Option<Autoscroll>,
17773        cx: &mut Context<Self>,
17774    ) {
17775        self.display_map
17776            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17777        if let Some(autoscroll) = autoscroll {
17778            self.request_autoscroll(autoscroll, cx);
17779        }
17780        cx.notify();
17781    }
17782
17783    pub fn remove_blocks(
17784        &mut self,
17785        block_ids: HashSet<CustomBlockId>,
17786        autoscroll: Option<Autoscroll>,
17787        cx: &mut Context<Self>,
17788    ) {
17789        self.display_map.update(cx, |display_map, cx| {
17790            display_map.remove_blocks(block_ids, cx)
17791        });
17792        if let Some(autoscroll) = autoscroll {
17793            self.request_autoscroll(autoscroll, cx);
17794        }
17795        cx.notify();
17796    }
17797
17798    pub fn row_for_block(
17799        &self,
17800        block_id: CustomBlockId,
17801        cx: &mut Context<Self>,
17802    ) -> Option<DisplayRow> {
17803        self.display_map
17804            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17805    }
17806
17807    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17808        self.focused_block = Some(focused_block);
17809    }
17810
17811    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17812        self.focused_block.take()
17813    }
17814
17815    pub fn insert_creases(
17816        &mut self,
17817        creases: impl IntoIterator<Item = Crease<Anchor>>,
17818        cx: &mut Context<Self>,
17819    ) -> Vec<CreaseId> {
17820        self.display_map
17821            .update(cx, |map, cx| map.insert_creases(creases, cx))
17822    }
17823
17824    pub fn remove_creases(
17825        &mut self,
17826        ids: impl IntoIterator<Item = CreaseId>,
17827        cx: &mut Context<Self>,
17828    ) -> Vec<(CreaseId, Range<Anchor>)> {
17829        self.display_map
17830            .update(cx, |map, cx| map.remove_creases(ids, cx))
17831    }
17832
17833    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17834        self.display_map
17835            .update(cx, |map, cx| map.snapshot(cx))
17836            .longest_row()
17837    }
17838
17839    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17840        self.display_map
17841            .update(cx, |map, cx| map.snapshot(cx))
17842            .max_point()
17843    }
17844
17845    pub fn text(&self, cx: &App) -> String {
17846        self.buffer.read(cx).read(cx).text()
17847    }
17848
17849    pub fn is_empty(&self, cx: &App) -> bool {
17850        self.buffer.read(cx).read(cx).is_empty()
17851    }
17852
17853    pub fn text_option(&self, cx: &App) -> Option<String> {
17854        let text = self.text(cx);
17855        let text = text.trim();
17856
17857        if text.is_empty() {
17858            return None;
17859        }
17860
17861        Some(text.to_string())
17862    }
17863
17864    pub fn set_text(
17865        &mut self,
17866        text: impl Into<Arc<str>>,
17867        window: &mut Window,
17868        cx: &mut Context<Self>,
17869    ) {
17870        self.transact(window, cx, |this, _, cx| {
17871            this.buffer
17872                .read(cx)
17873                .as_singleton()
17874                .expect("you can only call set_text on editors for singleton buffers")
17875                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17876        });
17877    }
17878
17879    pub fn display_text(&self, cx: &mut App) -> String {
17880        self.display_map
17881            .update(cx, |map, cx| map.snapshot(cx))
17882            .text()
17883    }
17884
17885    fn create_minimap(
17886        &self,
17887        minimap_settings: MinimapSettings,
17888        window: &mut Window,
17889        cx: &mut Context<Self>,
17890    ) -> Option<Entity<Self>> {
17891        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17892            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17893    }
17894
17895    fn initialize_new_minimap(
17896        &self,
17897        minimap_settings: MinimapSettings,
17898        window: &mut Window,
17899        cx: &mut Context<Self>,
17900    ) -> Entity<Self> {
17901        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17902
17903        let mut minimap = Editor::new_internal(
17904            EditorMode::Minimap {
17905                parent: cx.weak_entity(),
17906            },
17907            self.buffer.clone(),
17908            self.project.clone(),
17909            Some(self.display_map.clone()),
17910            window,
17911            cx,
17912        );
17913        minimap.scroll_manager.clone_state(&self.scroll_manager);
17914        minimap.set_text_style_refinement(TextStyleRefinement {
17915            font_size: Some(MINIMAP_FONT_SIZE),
17916            font_weight: Some(MINIMAP_FONT_WEIGHT),
17917            ..Default::default()
17918        });
17919        minimap.update_minimap_configuration(minimap_settings, cx);
17920        cx.new(|_| minimap)
17921    }
17922
17923    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17924        let current_line_highlight = minimap_settings
17925            .current_line_highlight
17926            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17927        self.set_current_line_highlight(Some(current_line_highlight));
17928    }
17929
17930    pub fn minimap(&self) -> Option<&Entity<Self>> {
17931        self.minimap
17932            .as_ref()
17933            .filter(|_| self.minimap_visibility.visible())
17934    }
17935
17936    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17937        let mut wrap_guides = smallvec![];
17938
17939        if self.show_wrap_guides == Some(false) {
17940            return wrap_guides;
17941        }
17942
17943        let settings = self.buffer.read(cx).language_settings(cx);
17944        if settings.show_wrap_guides {
17945            match self.soft_wrap_mode(cx) {
17946                SoftWrap::Column(soft_wrap) => {
17947                    wrap_guides.push((soft_wrap as usize, true));
17948                }
17949                SoftWrap::Bounded(soft_wrap) => {
17950                    wrap_guides.push((soft_wrap as usize, true));
17951                }
17952                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17953            }
17954            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17955        }
17956
17957        wrap_guides
17958    }
17959
17960    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17961        let settings = self.buffer.read(cx).language_settings(cx);
17962        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17963        match mode {
17964            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17965                SoftWrap::None
17966            }
17967            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17968            language_settings::SoftWrap::PreferredLineLength => {
17969                SoftWrap::Column(settings.preferred_line_length)
17970            }
17971            language_settings::SoftWrap::Bounded => {
17972                SoftWrap::Bounded(settings.preferred_line_length)
17973            }
17974        }
17975    }
17976
17977    pub fn set_soft_wrap_mode(
17978        &mut self,
17979        mode: language_settings::SoftWrap,
17980
17981        cx: &mut Context<Self>,
17982    ) {
17983        self.soft_wrap_mode_override = Some(mode);
17984        cx.notify();
17985    }
17986
17987    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17988        self.hard_wrap = hard_wrap;
17989        cx.notify();
17990    }
17991
17992    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17993        self.text_style_refinement = Some(style);
17994    }
17995
17996    /// called by the Element so we know what style we were most recently rendered with.
17997    pub(crate) fn set_style(
17998        &mut self,
17999        style: EditorStyle,
18000        window: &mut Window,
18001        cx: &mut Context<Self>,
18002    ) {
18003        // We intentionally do not inform the display map about the minimap style
18004        // so that wrapping is not recalculated and stays consistent for the editor
18005        // and its linked minimap.
18006        if !self.mode.is_minimap() {
18007            let rem_size = window.rem_size();
18008            self.display_map.update(cx, |map, cx| {
18009                map.set_font(
18010                    style.text.font(),
18011                    style.text.font_size.to_pixels(rem_size),
18012                    cx,
18013                )
18014            });
18015        }
18016        self.style = Some(style);
18017    }
18018
18019    pub fn style(&self) -> Option<&EditorStyle> {
18020        self.style.as_ref()
18021    }
18022
18023    // Called by the element. This method is not designed to be called outside of the editor
18024    // element's layout code because it does not notify when rewrapping is computed synchronously.
18025    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18026        self.display_map
18027            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18028    }
18029
18030    pub fn set_soft_wrap(&mut self) {
18031        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18032    }
18033
18034    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18035        if self.soft_wrap_mode_override.is_some() {
18036            self.soft_wrap_mode_override.take();
18037        } else {
18038            let soft_wrap = match self.soft_wrap_mode(cx) {
18039                SoftWrap::GitDiff => return,
18040                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18041                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18042                    language_settings::SoftWrap::None
18043                }
18044            };
18045            self.soft_wrap_mode_override = Some(soft_wrap);
18046        }
18047        cx.notify();
18048    }
18049
18050    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18051        let Some(workspace) = self.workspace() else {
18052            return;
18053        };
18054        let fs = workspace.read(cx).app_state().fs.clone();
18055        let current_show = TabBarSettings::get_global(cx).show;
18056        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18057            setting.show = Some(!current_show);
18058        });
18059    }
18060
18061    pub fn toggle_indent_guides(
18062        &mut self,
18063        _: &ToggleIndentGuides,
18064        _: &mut Window,
18065        cx: &mut Context<Self>,
18066    ) {
18067        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18068            self.buffer
18069                .read(cx)
18070                .language_settings(cx)
18071                .indent_guides
18072                .enabled
18073        });
18074        self.show_indent_guides = Some(!currently_enabled);
18075        cx.notify();
18076    }
18077
18078    fn should_show_indent_guides(&self) -> Option<bool> {
18079        self.show_indent_guides
18080    }
18081
18082    pub fn toggle_line_numbers(
18083        &mut self,
18084        _: &ToggleLineNumbers,
18085        _: &mut Window,
18086        cx: &mut Context<Self>,
18087    ) {
18088        let mut editor_settings = EditorSettings::get_global(cx).clone();
18089        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18090        EditorSettings::override_global(editor_settings, cx);
18091    }
18092
18093    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18094        if let Some(show_line_numbers) = self.show_line_numbers {
18095            return show_line_numbers;
18096        }
18097        EditorSettings::get_global(cx).gutter.line_numbers
18098    }
18099
18100    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18101        self.use_relative_line_numbers
18102            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18103    }
18104
18105    pub fn toggle_relative_line_numbers(
18106        &mut self,
18107        _: &ToggleRelativeLineNumbers,
18108        _: &mut Window,
18109        cx: &mut Context<Self>,
18110    ) {
18111        let is_relative = self.should_use_relative_line_numbers(cx);
18112        self.set_relative_line_number(Some(!is_relative), cx)
18113    }
18114
18115    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18116        self.use_relative_line_numbers = is_relative;
18117        cx.notify();
18118    }
18119
18120    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18121        self.show_gutter = show_gutter;
18122        cx.notify();
18123    }
18124
18125    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18126        self.show_scrollbars = ScrollbarAxes {
18127            horizontal: show,
18128            vertical: show,
18129        };
18130        cx.notify();
18131    }
18132
18133    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18134        self.show_scrollbars.vertical = show;
18135        cx.notify();
18136    }
18137
18138    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18139        self.show_scrollbars.horizontal = show;
18140        cx.notify();
18141    }
18142
18143    pub fn set_minimap_visibility(
18144        &mut self,
18145        minimap_visibility: MinimapVisibility,
18146        window: &mut Window,
18147        cx: &mut Context<Self>,
18148    ) {
18149        if self.minimap_visibility != minimap_visibility {
18150            if minimap_visibility.visible() && self.minimap.is_none() {
18151                let minimap_settings = EditorSettings::get_global(cx).minimap;
18152                self.minimap =
18153                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18154            }
18155            self.minimap_visibility = minimap_visibility;
18156            cx.notify();
18157        }
18158    }
18159
18160    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18161        self.set_show_scrollbars(false, cx);
18162        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18163    }
18164
18165    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18166        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18167    }
18168
18169    /// Normally the text in full mode and auto height editors is padded on the
18170    /// left side by roughly half a character width for improved hit testing.
18171    ///
18172    /// Use this method to disable this for cases where this is not wanted (e.g.
18173    /// if you want to align the editor text with some other text above or below)
18174    /// or if you want to add this padding to single-line editors.
18175    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18176        self.offset_content = offset_content;
18177        cx.notify();
18178    }
18179
18180    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18181        self.show_line_numbers = Some(show_line_numbers);
18182        cx.notify();
18183    }
18184
18185    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18186        self.disable_expand_excerpt_buttons = true;
18187        cx.notify();
18188    }
18189
18190    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18191        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18192        cx.notify();
18193    }
18194
18195    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18196        self.show_code_actions = Some(show_code_actions);
18197        cx.notify();
18198    }
18199
18200    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18201        self.show_runnables = Some(show_runnables);
18202        cx.notify();
18203    }
18204
18205    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18206        self.show_breakpoints = Some(show_breakpoints);
18207        cx.notify();
18208    }
18209
18210    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18211        if self.display_map.read(cx).masked != masked {
18212            self.display_map.update(cx, |map, _| map.masked = masked);
18213        }
18214        cx.notify()
18215    }
18216
18217    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18218        self.show_wrap_guides = Some(show_wrap_guides);
18219        cx.notify();
18220    }
18221
18222    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18223        self.show_indent_guides = Some(show_indent_guides);
18224        cx.notify();
18225    }
18226
18227    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18228        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18229            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18230                if let Some(dir) = file.abs_path(cx).parent() {
18231                    return Some(dir.to_owned());
18232                }
18233            }
18234
18235            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18236                return Some(project_path.path.to_path_buf());
18237            }
18238        }
18239
18240        None
18241    }
18242
18243    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18244        self.active_excerpt(cx)?
18245            .1
18246            .read(cx)
18247            .file()
18248            .and_then(|f| f.as_local())
18249    }
18250
18251    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18252        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18253            let buffer = buffer.read(cx);
18254            if let Some(project_path) = buffer.project_path(cx) {
18255                let project = self.project.as_ref()?.read(cx);
18256                project.absolute_path(&project_path, cx)
18257            } else {
18258                buffer
18259                    .file()
18260                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18261            }
18262        })
18263    }
18264
18265    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18266        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18267            let project_path = buffer.read(cx).project_path(cx)?;
18268            let project = self.project.as_ref()?.read(cx);
18269            let entry = project.entry_for_path(&project_path, cx)?;
18270            let path = entry.path.to_path_buf();
18271            Some(path)
18272        })
18273    }
18274
18275    pub fn reveal_in_finder(
18276        &mut self,
18277        _: &RevealInFileManager,
18278        _window: &mut Window,
18279        cx: &mut Context<Self>,
18280    ) {
18281        if let Some(target) = self.target_file(cx) {
18282            cx.reveal_path(&target.abs_path(cx));
18283        }
18284    }
18285
18286    pub fn copy_path(
18287        &mut self,
18288        _: &zed_actions::workspace::CopyPath,
18289        _window: &mut Window,
18290        cx: &mut Context<Self>,
18291    ) {
18292        if let Some(path) = self.target_file_abs_path(cx) {
18293            if let Some(path) = path.to_str() {
18294                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18295            }
18296        }
18297    }
18298
18299    pub fn copy_relative_path(
18300        &mut self,
18301        _: &zed_actions::workspace::CopyRelativePath,
18302        _window: &mut Window,
18303        cx: &mut Context<Self>,
18304    ) {
18305        if let Some(path) = self.target_file_path(cx) {
18306            if let Some(path) = path.to_str() {
18307                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18308            }
18309        }
18310    }
18311
18312    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18313        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18314            buffer.read(cx).project_path(cx)
18315        } else {
18316            None
18317        }
18318    }
18319
18320    // Returns true if the editor handled a go-to-line request
18321    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18322        maybe!({
18323            let breakpoint_store = self.breakpoint_store.as_ref()?;
18324
18325            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18326            else {
18327                self.clear_row_highlights::<ActiveDebugLine>();
18328                return None;
18329            };
18330
18331            let position = active_stack_frame.position;
18332            let buffer_id = position.buffer_id?;
18333            let snapshot = self
18334                .project
18335                .as_ref()?
18336                .read(cx)
18337                .buffer_for_id(buffer_id, cx)?
18338                .read(cx)
18339                .snapshot();
18340
18341            let mut handled = false;
18342            for (id, ExcerptRange { context, .. }) in
18343                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18344            {
18345                if context.start.cmp(&position, &snapshot).is_ge()
18346                    || context.end.cmp(&position, &snapshot).is_lt()
18347                {
18348                    continue;
18349                }
18350                let snapshot = self.buffer.read(cx).snapshot(cx);
18351                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18352
18353                handled = true;
18354                self.clear_row_highlights::<ActiveDebugLine>();
18355
18356                self.go_to_line::<ActiveDebugLine>(
18357                    multibuffer_anchor,
18358                    Some(cx.theme().colors().editor_debugger_active_line_background),
18359                    window,
18360                    cx,
18361                );
18362
18363                cx.notify();
18364            }
18365
18366            handled.then_some(())
18367        })
18368        .is_some()
18369    }
18370
18371    pub fn copy_file_name_without_extension(
18372        &mut self,
18373        _: &CopyFileNameWithoutExtension,
18374        _: &mut Window,
18375        cx: &mut Context<Self>,
18376    ) {
18377        if let Some(file) = self.target_file(cx) {
18378            if let Some(file_stem) = file.path().file_stem() {
18379                if let Some(name) = file_stem.to_str() {
18380                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18381                }
18382            }
18383        }
18384    }
18385
18386    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18387        if let Some(file) = self.target_file(cx) {
18388            if let Some(file_name) = file.path().file_name() {
18389                if let Some(name) = file_name.to_str() {
18390                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18391                }
18392            }
18393        }
18394    }
18395
18396    pub fn toggle_git_blame(
18397        &mut self,
18398        _: &::git::Blame,
18399        window: &mut Window,
18400        cx: &mut Context<Self>,
18401    ) {
18402        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18403
18404        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18405            self.start_git_blame(true, window, cx);
18406        }
18407
18408        cx.notify();
18409    }
18410
18411    pub fn toggle_git_blame_inline(
18412        &mut self,
18413        _: &ToggleGitBlameInline,
18414        window: &mut Window,
18415        cx: &mut Context<Self>,
18416    ) {
18417        self.toggle_git_blame_inline_internal(true, window, cx);
18418        cx.notify();
18419    }
18420
18421    pub fn open_git_blame_commit(
18422        &mut self,
18423        _: &OpenGitBlameCommit,
18424        window: &mut Window,
18425        cx: &mut Context<Self>,
18426    ) {
18427        self.open_git_blame_commit_internal(window, cx);
18428    }
18429
18430    fn open_git_blame_commit_internal(
18431        &mut self,
18432        window: &mut Window,
18433        cx: &mut Context<Self>,
18434    ) -> Option<()> {
18435        let blame = self.blame.as_ref()?;
18436        let snapshot = self.snapshot(window, cx);
18437        let cursor = self.selections.newest::<Point>(cx).head();
18438        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18439        let blame_entry = blame
18440            .update(cx, |blame, cx| {
18441                blame
18442                    .blame_for_rows(
18443                        &[RowInfo {
18444                            buffer_id: Some(buffer.remote_id()),
18445                            buffer_row: Some(point.row),
18446                            ..Default::default()
18447                        }],
18448                        cx,
18449                    )
18450                    .next()
18451            })
18452            .flatten()?;
18453        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18454        let repo = blame.read(cx).repository(cx)?;
18455        let workspace = self.workspace()?.downgrade();
18456        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18457        None
18458    }
18459
18460    pub fn git_blame_inline_enabled(&self) -> bool {
18461        self.git_blame_inline_enabled
18462    }
18463
18464    pub fn toggle_selection_menu(
18465        &mut self,
18466        _: &ToggleSelectionMenu,
18467        _: &mut Window,
18468        cx: &mut Context<Self>,
18469    ) {
18470        self.show_selection_menu = self
18471            .show_selection_menu
18472            .map(|show_selections_menu| !show_selections_menu)
18473            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18474
18475        cx.notify();
18476    }
18477
18478    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18479        self.show_selection_menu
18480            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18481    }
18482
18483    fn start_git_blame(
18484        &mut self,
18485        user_triggered: bool,
18486        window: &mut Window,
18487        cx: &mut Context<Self>,
18488    ) {
18489        if let Some(project) = self.project.as_ref() {
18490            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18491                return;
18492            };
18493
18494            if buffer.read(cx).file().is_none() {
18495                return;
18496            }
18497
18498            let focused = self.focus_handle(cx).contains_focused(window, cx);
18499
18500            let project = project.clone();
18501            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18502            self.blame_subscription =
18503                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18504            self.blame = Some(blame);
18505        }
18506    }
18507
18508    fn toggle_git_blame_inline_internal(
18509        &mut self,
18510        user_triggered: bool,
18511        window: &mut Window,
18512        cx: &mut Context<Self>,
18513    ) {
18514        if self.git_blame_inline_enabled {
18515            self.git_blame_inline_enabled = false;
18516            self.show_git_blame_inline = false;
18517            self.show_git_blame_inline_delay_task.take();
18518        } else {
18519            self.git_blame_inline_enabled = true;
18520            self.start_git_blame_inline(user_triggered, window, cx);
18521        }
18522
18523        cx.notify();
18524    }
18525
18526    fn start_git_blame_inline(
18527        &mut self,
18528        user_triggered: bool,
18529        window: &mut Window,
18530        cx: &mut Context<Self>,
18531    ) {
18532        self.start_git_blame(user_triggered, window, cx);
18533
18534        if ProjectSettings::get_global(cx)
18535            .git
18536            .inline_blame_delay()
18537            .is_some()
18538        {
18539            self.start_inline_blame_timer(window, cx);
18540        } else {
18541            self.show_git_blame_inline = true
18542        }
18543    }
18544
18545    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18546        self.blame.as_ref()
18547    }
18548
18549    pub fn show_git_blame_gutter(&self) -> bool {
18550        self.show_git_blame_gutter
18551    }
18552
18553    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18554        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18555    }
18556
18557    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18558        self.show_git_blame_inline
18559            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18560            && !self.newest_selection_head_on_empty_line(cx)
18561            && self.has_blame_entries(cx)
18562    }
18563
18564    fn has_blame_entries(&self, cx: &App) -> bool {
18565        self.blame()
18566            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18567    }
18568
18569    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18570        let cursor_anchor = self.selections.newest_anchor().head();
18571
18572        let snapshot = self.buffer.read(cx).snapshot(cx);
18573        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18574
18575        snapshot.line_len(buffer_row) == 0
18576    }
18577
18578    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18579        let buffer_and_selection = maybe!({
18580            let selection = self.selections.newest::<Point>(cx);
18581            let selection_range = selection.range();
18582
18583            let multi_buffer = self.buffer().read(cx);
18584            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18585            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18586
18587            let (buffer, range, _) = if selection.reversed {
18588                buffer_ranges.first()
18589            } else {
18590                buffer_ranges.last()
18591            }?;
18592
18593            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18594                ..text::ToPoint::to_point(&range.end, &buffer).row;
18595            Some((
18596                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18597                selection,
18598            ))
18599        });
18600
18601        let Some((buffer, selection)) = buffer_and_selection else {
18602            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18603        };
18604
18605        let Some(project) = self.project.as_ref() else {
18606            return Task::ready(Err(anyhow!("editor does not have project")));
18607        };
18608
18609        project.update(cx, |project, cx| {
18610            project.get_permalink_to_line(&buffer, selection, cx)
18611        })
18612    }
18613
18614    pub fn copy_permalink_to_line(
18615        &mut self,
18616        _: &CopyPermalinkToLine,
18617        window: &mut Window,
18618        cx: &mut Context<Self>,
18619    ) {
18620        let permalink_task = self.get_permalink_to_line(cx);
18621        let workspace = self.workspace();
18622
18623        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18624            Ok(permalink) => {
18625                cx.update(|_, cx| {
18626                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18627                })
18628                .ok();
18629            }
18630            Err(err) => {
18631                let message = format!("Failed to copy permalink: {err}");
18632
18633                anyhow::Result::<()>::Err(err).log_err();
18634
18635                if let Some(workspace) = workspace {
18636                    workspace
18637                        .update_in(cx, |workspace, _, cx| {
18638                            struct CopyPermalinkToLine;
18639
18640                            workspace.show_toast(
18641                                Toast::new(
18642                                    NotificationId::unique::<CopyPermalinkToLine>(),
18643                                    message,
18644                                ),
18645                                cx,
18646                            )
18647                        })
18648                        .ok();
18649                }
18650            }
18651        })
18652        .detach();
18653    }
18654
18655    pub fn copy_file_location(
18656        &mut self,
18657        _: &CopyFileLocation,
18658        _: &mut Window,
18659        cx: &mut Context<Self>,
18660    ) {
18661        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18662        if let Some(file) = self.target_file(cx) {
18663            if let Some(path) = file.path().to_str() {
18664                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18665            }
18666        }
18667    }
18668
18669    pub fn open_permalink_to_line(
18670        &mut self,
18671        _: &OpenPermalinkToLine,
18672        window: &mut Window,
18673        cx: &mut Context<Self>,
18674    ) {
18675        let permalink_task = self.get_permalink_to_line(cx);
18676        let workspace = self.workspace();
18677
18678        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18679            Ok(permalink) => {
18680                cx.update(|_, cx| {
18681                    cx.open_url(permalink.as_ref());
18682                })
18683                .ok();
18684            }
18685            Err(err) => {
18686                let message = format!("Failed to open permalink: {err}");
18687
18688                anyhow::Result::<()>::Err(err).log_err();
18689
18690                if let Some(workspace) = workspace {
18691                    workspace
18692                        .update(cx, |workspace, cx| {
18693                            struct OpenPermalinkToLine;
18694
18695                            workspace.show_toast(
18696                                Toast::new(
18697                                    NotificationId::unique::<OpenPermalinkToLine>(),
18698                                    message,
18699                                ),
18700                                cx,
18701                            )
18702                        })
18703                        .ok();
18704                }
18705            }
18706        })
18707        .detach();
18708    }
18709
18710    pub fn insert_uuid_v4(
18711        &mut self,
18712        _: &InsertUuidV4,
18713        window: &mut Window,
18714        cx: &mut Context<Self>,
18715    ) {
18716        self.insert_uuid(UuidVersion::V4, window, cx);
18717    }
18718
18719    pub fn insert_uuid_v7(
18720        &mut self,
18721        _: &InsertUuidV7,
18722        window: &mut Window,
18723        cx: &mut Context<Self>,
18724    ) {
18725        self.insert_uuid(UuidVersion::V7, window, cx);
18726    }
18727
18728    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18729        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18730        self.transact(window, cx, |this, window, cx| {
18731            let edits = this
18732                .selections
18733                .all::<Point>(cx)
18734                .into_iter()
18735                .map(|selection| {
18736                    let uuid = match version {
18737                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18738                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18739                    };
18740
18741                    (selection.range(), uuid.to_string())
18742                });
18743            this.edit(edits, cx);
18744            this.refresh_inline_completion(true, false, window, cx);
18745        });
18746    }
18747
18748    pub fn open_selections_in_multibuffer(
18749        &mut self,
18750        _: &OpenSelectionsInMultibuffer,
18751        window: &mut Window,
18752        cx: &mut Context<Self>,
18753    ) {
18754        let multibuffer = self.buffer.read(cx);
18755
18756        let Some(buffer) = multibuffer.as_singleton() else {
18757            return;
18758        };
18759
18760        let Some(workspace) = self.workspace() else {
18761            return;
18762        };
18763
18764        let title = multibuffer.title(cx).to_string();
18765
18766        let locations = self
18767            .selections
18768            .all_anchors(cx)
18769            .into_iter()
18770            .map(|selection| Location {
18771                buffer: buffer.clone(),
18772                range: selection.start.text_anchor..selection.end.text_anchor,
18773            })
18774            .collect::<Vec<_>>();
18775
18776        cx.spawn_in(window, async move |_, cx| {
18777            workspace.update_in(cx, |workspace, window, cx| {
18778                Self::open_locations_in_multibuffer(
18779                    workspace,
18780                    locations,
18781                    format!("Selections for '{title}'"),
18782                    false,
18783                    MultibufferSelectionMode::All,
18784                    window,
18785                    cx,
18786                );
18787            })
18788        })
18789        .detach();
18790    }
18791
18792    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18793    /// last highlight added will be used.
18794    ///
18795    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18796    pub fn highlight_rows<T: 'static>(
18797        &mut self,
18798        range: Range<Anchor>,
18799        color: Hsla,
18800        options: RowHighlightOptions,
18801        cx: &mut Context<Self>,
18802    ) {
18803        let snapshot = self.buffer().read(cx).snapshot(cx);
18804        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18805        let ix = row_highlights.binary_search_by(|highlight| {
18806            Ordering::Equal
18807                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18808                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18809        });
18810
18811        if let Err(mut ix) = ix {
18812            let index = post_inc(&mut self.highlight_order);
18813
18814            // If this range intersects with the preceding highlight, then merge it with
18815            // the preceding highlight. Otherwise insert a new highlight.
18816            let mut merged = false;
18817            if ix > 0 {
18818                let prev_highlight = &mut row_highlights[ix - 1];
18819                if prev_highlight
18820                    .range
18821                    .end
18822                    .cmp(&range.start, &snapshot)
18823                    .is_ge()
18824                {
18825                    ix -= 1;
18826                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18827                        prev_highlight.range.end = range.end;
18828                    }
18829                    merged = true;
18830                    prev_highlight.index = index;
18831                    prev_highlight.color = color;
18832                    prev_highlight.options = options;
18833                }
18834            }
18835
18836            if !merged {
18837                row_highlights.insert(
18838                    ix,
18839                    RowHighlight {
18840                        range: range.clone(),
18841                        index,
18842                        color,
18843                        options,
18844                        type_id: TypeId::of::<T>(),
18845                    },
18846                );
18847            }
18848
18849            // If any of the following highlights intersect with this one, merge them.
18850            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18851                let highlight = &row_highlights[ix];
18852                if next_highlight
18853                    .range
18854                    .start
18855                    .cmp(&highlight.range.end, &snapshot)
18856                    .is_le()
18857                {
18858                    if next_highlight
18859                        .range
18860                        .end
18861                        .cmp(&highlight.range.end, &snapshot)
18862                        .is_gt()
18863                    {
18864                        row_highlights[ix].range.end = next_highlight.range.end;
18865                    }
18866                    row_highlights.remove(ix + 1);
18867                } else {
18868                    break;
18869                }
18870            }
18871        }
18872    }
18873
18874    /// Remove any highlighted row ranges of the given type that intersect the
18875    /// given ranges.
18876    pub fn remove_highlighted_rows<T: 'static>(
18877        &mut self,
18878        ranges_to_remove: Vec<Range<Anchor>>,
18879        cx: &mut Context<Self>,
18880    ) {
18881        let snapshot = self.buffer().read(cx).snapshot(cx);
18882        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18883        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18884        row_highlights.retain(|highlight| {
18885            while let Some(range_to_remove) = ranges_to_remove.peek() {
18886                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18887                    Ordering::Less | Ordering::Equal => {
18888                        ranges_to_remove.next();
18889                    }
18890                    Ordering::Greater => {
18891                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18892                            Ordering::Less | Ordering::Equal => {
18893                                return false;
18894                            }
18895                            Ordering::Greater => break,
18896                        }
18897                    }
18898                }
18899            }
18900
18901            true
18902        })
18903    }
18904
18905    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18906    pub fn clear_row_highlights<T: 'static>(&mut self) {
18907        self.highlighted_rows.remove(&TypeId::of::<T>());
18908    }
18909
18910    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18911    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18912        self.highlighted_rows
18913            .get(&TypeId::of::<T>())
18914            .map_or(&[] as &[_], |vec| vec.as_slice())
18915            .iter()
18916            .map(|highlight| (highlight.range.clone(), highlight.color))
18917    }
18918
18919    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18920    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18921    /// Allows to ignore certain kinds of highlights.
18922    pub fn highlighted_display_rows(
18923        &self,
18924        window: &mut Window,
18925        cx: &mut App,
18926    ) -> BTreeMap<DisplayRow, LineHighlight> {
18927        let snapshot = self.snapshot(window, cx);
18928        let mut used_highlight_orders = HashMap::default();
18929        self.highlighted_rows
18930            .iter()
18931            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18932            .fold(
18933                BTreeMap::<DisplayRow, LineHighlight>::new(),
18934                |mut unique_rows, highlight| {
18935                    let start = highlight.range.start.to_display_point(&snapshot);
18936                    let end = highlight.range.end.to_display_point(&snapshot);
18937                    let start_row = start.row().0;
18938                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18939                        && end.column() == 0
18940                    {
18941                        end.row().0.saturating_sub(1)
18942                    } else {
18943                        end.row().0
18944                    };
18945                    for row in start_row..=end_row {
18946                        let used_index =
18947                            used_highlight_orders.entry(row).or_insert(highlight.index);
18948                        if highlight.index >= *used_index {
18949                            *used_index = highlight.index;
18950                            unique_rows.insert(
18951                                DisplayRow(row),
18952                                LineHighlight {
18953                                    include_gutter: highlight.options.include_gutter,
18954                                    border: None,
18955                                    background: highlight.color.into(),
18956                                    type_id: Some(highlight.type_id),
18957                                },
18958                            );
18959                        }
18960                    }
18961                    unique_rows
18962                },
18963            )
18964    }
18965
18966    pub fn highlighted_display_row_for_autoscroll(
18967        &self,
18968        snapshot: &DisplaySnapshot,
18969    ) -> Option<DisplayRow> {
18970        self.highlighted_rows
18971            .values()
18972            .flat_map(|highlighted_rows| highlighted_rows.iter())
18973            .filter_map(|highlight| {
18974                if highlight.options.autoscroll {
18975                    Some(highlight.range.start.to_display_point(snapshot).row())
18976                } else {
18977                    None
18978                }
18979            })
18980            .min()
18981    }
18982
18983    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18984        self.highlight_background::<SearchWithinRange>(
18985            ranges,
18986            |colors| colors.colors().editor_document_highlight_read_background,
18987            cx,
18988        )
18989    }
18990
18991    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18992        self.breadcrumb_header = Some(new_header);
18993    }
18994
18995    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18996        self.clear_background_highlights::<SearchWithinRange>(cx);
18997    }
18998
18999    pub fn highlight_background<T: 'static>(
19000        &mut self,
19001        ranges: &[Range<Anchor>],
19002        color_fetcher: fn(&Theme) -> Hsla,
19003        cx: &mut Context<Self>,
19004    ) {
19005        self.background_highlights.insert(
19006            HighlightKey::Type(TypeId::of::<T>()),
19007            (color_fetcher, Arc::from(ranges)),
19008        );
19009        self.scrollbar_marker_state.dirty = true;
19010        cx.notify();
19011    }
19012
19013    pub fn highlight_background_key<T: 'static>(
19014        &mut self,
19015        key: usize,
19016        ranges: &[Range<Anchor>],
19017        color_fetcher: fn(&Theme) -> Hsla,
19018        cx: &mut Context<Self>,
19019    ) {
19020        self.background_highlights.insert(
19021            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19022            (color_fetcher, Arc::from(ranges)),
19023        );
19024        self.scrollbar_marker_state.dirty = true;
19025        cx.notify();
19026    }
19027
19028    pub fn clear_background_highlights<T: 'static>(
19029        &mut self,
19030        cx: &mut Context<Self>,
19031    ) -> Option<BackgroundHighlight> {
19032        let text_highlights = self
19033            .background_highlights
19034            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19035        if !text_highlights.1.is_empty() {
19036            self.scrollbar_marker_state.dirty = true;
19037            cx.notify();
19038        }
19039        Some(text_highlights)
19040    }
19041
19042    pub fn highlight_gutter<T: 'static>(
19043        &mut self,
19044        ranges: impl Into<Vec<Range<Anchor>>>,
19045        color_fetcher: fn(&App) -> Hsla,
19046        cx: &mut Context<Self>,
19047    ) {
19048        self.gutter_highlights
19049            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19050        cx.notify();
19051    }
19052
19053    pub fn clear_gutter_highlights<T: 'static>(
19054        &mut self,
19055        cx: &mut Context<Self>,
19056    ) -> Option<GutterHighlight> {
19057        cx.notify();
19058        self.gutter_highlights.remove(&TypeId::of::<T>())
19059    }
19060
19061    pub fn insert_gutter_highlight<T: 'static>(
19062        &mut self,
19063        range: Range<Anchor>,
19064        color_fetcher: fn(&App) -> Hsla,
19065        cx: &mut Context<Self>,
19066    ) {
19067        let snapshot = self.buffer().read(cx).snapshot(cx);
19068        let mut highlights = self
19069            .gutter_highlights
19070            .remove(&TypeId::of::<T>())
19071            .map(|(_, highlights)| highlights)
19072            .unwrap_or_default();
19073        let ix = highlights.binary_search_by(|highlight| {
19074            Ordering::Equal
19075                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19076                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19077        });
19078        if let Err(ix) = ix {
19079            highlights.insert(ix, range);
19080        }
19081        self.gutter_highlights
19082            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19083    }
19084
19085    pub fn remove_gutter_highlights<T: 'static>(
19086        &mut self,
19087        ranges_to_remove: Vec<Range<Anchor>>,
19088        cx: &mut Context<Self>,
19089    ) {
19090        let snapshot = self.buffer().read(cx).snapshot(cx);
19091        let Some((color_fetcher, mut gutter_highlights)) =
19092            self.gutter_highlights.remove(&TypeId::of::<T>())
19093        else {
19094            return;
19095        };
19096        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19097        gutter_highlights.retain(|highlight| {
19098            while let Some(range_to_remove) = ranges_to_remove.peek() {
19099                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19100                    Ordering::Less | Ordering::Equal => {
19101                        ranges_to_remove.next();
19102                    }
19103                    Ordering::Greater => {
19104                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19105                            Ordering::Less | Ordering::Equal => {
19106                                return false;
19107                            }
19108                            Ordering::Greater => break,
19109                        }
19110                    }
19111                }
19112            }
19113
19114            true
19115        });
19116        self.gutter_highlights
19117            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19118    }
19119
19120    #[cfg(feature = "test-support")]
19121    pub fn all_text_highlights(
19122        &self,
19123        window: &mut Window,
19124        cx: &mut Context<Self>,
19125    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19126        let snapshot = self.snapshot(window, cx);
19127        self.display_map.update(cx, |display_map, _| {
19128            display_map
19129                .all_text_highlights()
19130                .map(|highlight| {
19131                    let (style, ranges) = highlight.as_ref();
19132                    (
19133                        *style,
19134                        ranges
19135                            .iter()
19136                            .map(|range| range.clone().to_display_points(&snapshot))
19137                            .collect(),
19138                    )
19139                })
19140                .collect()
19141        })
19142    }
19143
19144    #[cfg(feature = "test-support")]
19145    pub fn all_text_background_highlights(
19146        &self,
19147        window: &mut Window,
19148        cx: &mut Context<Self>,
19149    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19150        let snapshot = self.snapshot(window, cx);
19151        let buffer = &snapshot.buffer_snapshot;
19152        let start = buffer.anchor_before(0);
19153        let end = buffer.anchor_after(buffer.len());
19154        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19155    }
19156
19157    #[cfg(feature = "test-support")]
19158    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19159        let snapshot = self.buffer().read(cx).snapshot(cx);
19160
19161        let highlights = self
19162            .background_highlights
19163            .get(&HighlightKey::Type(TypeId::of::<
19164                items::BufferSearchHighlights,
19165            >()));
19166
19167        if let Some((_color, ranges)) = highlights {
19168            ranges
19169                .iter()
19170                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19171                .collect_vec()
19172        } else {
19173            vec![]
19174        }
19175    }
19176
19177    fn document_highlights_for_position<'a>(
19178        &'a self,
19179        position: Anchor,
19180        buffer: &'a MultiBufferSnapshot,
19181    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19182        let read_highlights = self
19183            .background_highlights
19184            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19185            .map(|h| &h.1);
19186        let write_highlights = self
19187            .background_highlights
19188            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19189            .map(|h| &h.1);
19190        let left_position = position.bias_left(buffer);
19191        let right_position = position.bias_right(buffer);
19192        read_highlights
19193            .into_iter()
19194            .chain(write_highlights)
19195            .flat_map(move |ranges| {
19196                let start_ix = match ranges.binary_search_by(|probe| {
19197                    let cmp = probe.end.cmp(&left_position, buffer);
19198                    if cmp.is_ge() {
19199                        Ordering::Greater
19200                    } else {
19201                        Ordering::Less
19202                    }
19203                }) {
19204                    Ok(i) | Err(i) => i,
19205                };
19206
19207                ranges[start_ix..]
19208                    .iter()
19209                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19210            })
19211    }
19212
19213    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19214        self.background_highlights
19215            .get(&HighlightKey::Type(TypeId::of::<T>()))
19216            .map_or(false, |(_, highlights)| !highlights.is_empty())
19217    }
19218
19219    pub fn background_highlights_in_range(
19220        &self,
19221        search_range: Range<Anchor>,
19222        display_snapshot: &DisplaySnapshot,
19223        theme: &Theme,
19224    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19225        let mut results = Vec::new();
19226        for (color_fetcher, ranges) in self.background_highlights.values() {
19227            let color = color_fetcher(theme);
19228            let start_ix = match ranges.binary_search_by(|probe| {
19229                let cmp = probe
19230                    .end
19231                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19232                if cmp.is_gt() {
19233                    Ordering::Greater
19234                } else {
19235                    Ordering::Less
19236                }
19237            }) {
19238                Ok(i) | Err(i) => i,
19239            };
19240            for range in &ranges[start_ix..] {
19241                if range
19242                    .start
19243                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19244                    .is_ge()
19245                {
19246                    break;
19247                }
19248
19249                let start = range.start.to_display_point(display_snapshot);
19250                let end = range.end.to_display_point(display_snapshot);
19251                results.push((start..end, color))
19252            }
19253        }
19254        results
19255    }
19256
19257    pub fn background_highlight_row_ranges<T: 'static>(
19258        &self,
19259        search_range: Range<Anchor>,
19260        display_snapshot: &DisplaySnapshot,
19261        count: usize,
19262    ) -> Vec<RangeInclusive<DisplayPoint>> {
19263        let mut results = Vec::new();
19264        let Some((_, ranges)) = self
19265            .background_highlights
19266            .get(&HighlightKey::Type(TypeId::of::<T>()))
19267        else {
19268            return vec![];
19269        };
19270
19271        let start_ix = match ranges.binary_search_by(|probe| {
19272            let cmp = probe
19273                .end
19274                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19275            if cmp.is_gt() {
19276                Ordering::Greater
19277            } else {
19278                Ordering::Less
19279            }
19280        }) {
19281            Ok(i) | Err(i) => i,
19282        };
19283        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19284            if let (Some(start_display), Some(end_display)) = (start, end) {
19285                results.push(
19286                    start_display.to_display_point(display_snapshot)
19287                        ..=end_display.to_display_point(display_snapshot),
19288                );
19289            }
19290        };
19291        let mut start_row: Option<Point> = None;
19292        let mut end_row: Option<Point> = None;
19293        if ranges.len() > count {
19294            return Vec::new();
19295        }
19296        for range in &ranges[start_ix..] {
19297            if range
19298                .start
19299                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19300                .is_ge()
19301            {
19302                break;
19303            }
19304            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19305            if let Some(current_row) = &end_row {
19306                if end.row == current_row.row {
19307                    continue;
19308                }
19309            }
19310            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19311            if start_row.is_none() {
19312                assert_eq!(end_row, None);
19313                start_row = Some(start);
19314                end_row = Some(end);
19315                continue;
19316            }
19317            if let Some(current_end) = end_row.as_mut() {
19318                if start.row > current_end.row + 1 {
19319                    push_region(start_row, end_row);
19320                    start_row = Some(start);
19321                    end_row = Some(end);
19322                } else {
19323                    // Merge two hunks.
19324                    *current_end = end;
19325                }
19326            } else {
19327                unreachable!();
19328            }
19329        }
19330        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19331        push_region(start_row, end_row);
19332        results
19333    }
19334
19335    pub fn gutter_highlights_in_range(
19336        &self,
19337        search_range: Range<Anchor>,
19338        display_snapshot: &DisplaySnapshot,
19339        cx: &App,
19340    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19341        let mut results = Vec::new();
19342        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19343            let color = color_fetcher(cx);
19344            let start_ix = match ranges.binary_search_by(|probe| {
19345                let cmp = probe
19346                    .end
19347                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19348                if cmp.is_gt() {
19349                    Ordering::Greater
19350                } else {
19351                    Ordering::Less
19352                }
19353            }) {
19354                Ok(i) | Err(i) => i,
19355            };
19356            for range in &ranges[start_ix..] {
19357                if range
19358                    .start
19359                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19360                    .is_ge()
19361                {
19362                    break;
19363                }
19364
19365                let start = range.start.to_display_point(display_snapshot);
19366                let end = range.end.to_display_point(display_snapshot);
19367                results.push((start..end, color))
19368            }
19369        }
19370        results
19371    }
19372
19373    /// Get the text ranges corresponding to the redaction query
19374    pub fn redacted_ranges(
19375        &self,
19376        search_range: Range<Anchor>,
19377        display_snapshot: &DisplaySnapshot,
19378        cx: &App,
19379    ) -> Vec<Range<DisplayPoint>> {
19380        display_snapshot
19381            .buffer_snapshot
19382            .redacted_ranges(search_range, |file| {
19383                if let Some(file) = file {
19384                    file.is_private()
19385                        && EditorSettings::get(
19386                            Some(SettingsLocation {
19387                                worktree_id: file.worktree_id(cx),
19388                                path: file.path().as_ref(),
19389                            }),
19390                            cx,
19391                        )
19392                        .redact_private_values
19393                } else {
19394                    false
19395                }
19396            })
19397            .map(|range| {
19398                range.start.to_display_point(display_snapshot)
19399                    ..range.end.to_display_point(display_snapshot)
19400            })
19401            .collect()
19402    }
19403
19404    pub fn highlight_text_key<T: 'static>(
19405        &mut self,
19406        key: usize,
19407        ranges: Vec<Range<Anchor>>,
19408        style: HighlightStyle,
19409        cx: &mut Context<Self>,
19410    ) {
19411        self.display_map.update(cx, |map, _| {
19412            map.highlight_text(
19413                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19414                ranges,
19415                style,
19416            );
19417        });
19418        cx.notify();
19419    }
19420
19421    pub fn highlight_text<T: 'static>(
19422        &mut self,
19423        ranges: Vec<Range<Anchor>>,
19424        style: HighlightStyle,
19425        cx: &mut Context<Self>,
19426    ) {
19427        self.display_map.update(cx, |map, _| {
19428            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19429        });
19430        cx.notify();
19431    }
19432
19433    pub(crate) fn highlight_inlays<T: 'static>(
19434        &mut self,
19435        highlights: Vec<InlayHighlight>,
19436        style: HighlightStyle,
19437        cx: &mut Context<Self>,
19438    ) {
19439        self.display_map.update(cx, |map, _| {
19440            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19441        });
19442        cx.notify();
19443    }
19444
19445    pub fn text_highlights<'a, T: 'static>(
19446        &'a self,
19447        cx: &'a App,
19448    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19449        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19450    }
19451
19452    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19453        let cleared = self
19454            .display_map
19455            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19456        if cleared {
19457            cx.notify();
19458        }
19459    }
19460
19461    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19462        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19463            && self.focus_handle.is_focused(window)
19464    }
19465
19466    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19467        self.show_cursor_when_unfocused = is_enabled;
19468        cx.notify();
19469    }
19470
19471    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19472        cx.notify();
19473    }
19474
19475    fn on_debug_session_event(
19476        &mut self,
19477        _session: Entity<Session>,
19478        event: &SessionEvent,
19479        cx: &mut Context<Self>,
19480    ) {
19481        match event {
19482            SessionEvent::InvalidateInlineValue => {
19483                self.refresh_inline_values(cx);
19484            }
19485            _ => {}
19486        }
19487    }
19488
19489    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19490        let Some(project) = self.project.clone() else {
19491            return;
19492        };
19493
19494        if !self.inline_value_cache.enabled {
19495            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19496            self.splice_inlays(&inlays, Vec::new(), cx);
19497            return;
19498        }
19499
19500        let current_execution_position = self
19501            .highlighted_rows
19502            .get(&TypeId::of::<ActiveDebugLine>())
19503            .and_then(|lines| lines.last().map(|line| line.range.end));
19504
19505        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19506            let inline_values = editor
19507                .update(cx, |editor, cx| {
19508                    let Some(current_execution_position) = current_execution_position else {
19509                        return Some(Task::ready(Ok(Vec::new())));
19510                    };
19511
19512                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19513                        let snapshot = buffer.snapshot(cx);
19514
19515                        let excerpt = snapshot.excerpt_containing(
19516                            current_execution_position..current_execution_position,
19517                        )?;
19518
19519                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19520                    })?;
19521
19522                    let range =
19523                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19524
19525                    project.inline_values(buffer, range, cx)
19526                })
19527                .ok()
19528                .flatten()?
19529                .await
19530                .context("refreshing debugger inlays")
19531                .log_err()?;
19532
19533            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19534
19535            for (buffer_id, inline_value) in inline_values
19536                .into_iter()
19537                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19538            {
19539                buffer_inline_values
19540                    .entry(buffer_id)
19541                    .or_default()
19542                    .push(inline_value);
19543            }
19544
19545            editor
19546                .update(cx, |editor, cx| {
19547                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19548                    let mut new_inlays = Vec::default();
19549
19550                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19551                        let buffer_id = buffer_snapshot.remote_id();
19552                        buffer_inline_values
19553                            .get(&buffer_id)
19554                            .into_iter()
19555                            .flatten()
19556                            .for_each(|hint| {
19557                                let inlay = Inlay::debugger(
19558                                    post_inc(&mut editor.next_inlay_id),
19559                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19560                                    hint.text(),
19561                                );
19562
19563                                new_inlays.push(inlay);
19564                            });
19565                    }
19566
19567                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19568                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19569
19570                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19571                })
19572                .ok()?;
19573            Some(())
19574        });
19575    }
19576
19577    fn on_buffer_event(
19578        &mut self,
19579        multibuffer: &Entity<MultiBuffer>,
19580        event: &multi_buffer::Event,
19581        window: &mut Window,
19582        cx: &mut Context<Self>,
19583    ) {
19584        match event {
19585            multi_buffer::Event::Edited {
19586                singleton_buffer_edited,
19587                edited_buffer,
19588            } => {
19589                self.scrollbar_marker_state.dirty = true;
19590                self.active_indent_guides_state.dirty = true;
19591                self.refresh_active_diagnostics(cx);
19592                self.refresh_code_actions(window, cx);
19593                self.refresh_selected_text_highlights(true, window, cx);
19594                self.refresh_single_line_folds(window, cx);
19595                refresh_matching_bracket_highlights(self, window, cx);
19596                if self.has_active_inline_completion() {
19597                    self.update_visible_inline_completion(window, cx);
19598                }
19599                if let Some(project) = self.project.as_ref() {
19600                    if let Some(edited_buffer) = edited_buffer {
19601                        project.update(cx, |project, cx| {
19602                            self.registered_buffers
19603                                .entry(edited_buffer.read(cx).remote_id())
19604                                .or_insert_with(|| {
19605                                    project
19606                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19607                                });
19608                        });
19609                    }
19610                }
19611                cx.emit(EditorEvent::BufferEdited);
19612                cx.emit(SearchEvent::MatchesInvalidated);
19613
19614                if let Some(buffer) = edited_buffer {
19615                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19616                }
19617
19618                if *singleton_buffer_edited {
19619                    if let Some(buffer) = edited_buffer {
19620                        if buffer.read(cx).file().is_none() {
19621                            cx.emit(EditorEvent::TitleChanged);
19622                        }
19623                    }
19624                    if let Some(project) = &self.project {
19625                        #[allow(clippy::mutable_key_type)]
19626                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19627                            multibuffer
19628                                .all_buffers()
19629                                .into_iter()
19630                                .filter_map(|buffer| {
19631                                    buffer.update(cx, |buffer, cx| {
19632                                        let language = buffer.language()?;
19633                                        let should_discard = project.update(cx, |project, cx| {
19634                                            project.is_local()
19635                                                && !project.has_language_servers_for(buffer, cx)
19636                                        });
19637                                        should_discard.not().then_some(language.clone())
19638                                    })
19639                                })
19640                                .collect::<HashSet<_>>()
19641                        });
19642                        if !languages_affected.is_empty() {
19643                            self.refresh_inlay_hints(
19644                                InlayHintRefreshReason::BufferEdited(languages_affected),
19645                                cx,
19646                            );
19647                        }
19648                    }
19649                }
19650
19651                let Some(project) = &self.project else { return };
19652                let (telemetry, is_via_ssh) = {
19653                    let project = project.read(cx);
19654                    let telemetry = project.client().telemetry().clone();
19655                    let is_via_ssh = project.is_via_ssh();
19656                    (telemetry, is_via_ssh)
19657                };
19658                refresh_linked_ranges(self, window, cx);
19659                telemetry.log_edit_event("editor", is_via_ssh);
19660            }
19661            multi_buffer::Event::ExcerptsAdded {
19662                buffer,
19663                predecessor,
19664                excerpts,
19665            } => {
19666                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19667                let buffer_id = buffer.read(cx).remote_id();
19668                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19669                    if let Some(project) = &self.project {
19670                        update_uncommitted_diff_for_buffer(
19671                            cx.entity(),
19672                            project,
19673                            [buffer.clone()],
19674                            self.buffer.clone(),
19675                            cx,
19676                        )
19677                        .detach();
19678                    }
19679                }
19680                self.update_lsp_data(false, Some(buffer_id), window, cx);
19681                cx.emit(EditorEvent::ExcerptsAdded {
19682                    buffer: buffer.clone(),
19683                    predecessor: *predecessor,
19684                    excerpts: excerpts.clone(),
19685                });
19686                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19687            }
19688            multi_buffer::Event::ExcerptsRemoved {
19689                ids,
19690                removed_buffer_ids,
19691            } => {
19692                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19693                let buffer = self.buffer.read(cx);
19694                self.registered_buffers
19695                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19696                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19697                cx.emit(EditorEvent::ExcerptsRemoved {
19698                    ids: ids.clone(),
19699                    removed_buffer_ids: removed_buffer_ids.clone(),
19700                });
19701            }
19702            multi_buffer::Event::ExcerptsEdited {
19703                excerpt_ids,
19704                buffer_ids,
19705            } => {
19706                self.display_map.update(cx, |map, cx| {
19707                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19708                });
19709                cx.emit(EditorEvent::ExcerptsEdited {
19710                    ids: excerpt_ids.clone(),
19711                });
19712            }
19713            multi_buffer::Event::ExcerptsExpanded { ids } => {
19714                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19715                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19716            }
19717            multi_buffer::Event::Reparsed(buffer_id) => {
19718                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19719                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19720
19721                cx.emit(EditorEvent::Reparsed(*buffer_id));
19722            }
19723            multi_buffer::Event::DiffHunksToggled => {
19724                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19725            }
19726            multi_buffer::Event::LanguageChanged(buffer_id) => {
19727                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19728                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19729                cx.emit(EditorEvent::Reparsed(*buffer_id));
19730                cx.notify();
19731            }
19732            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19733            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19734            multi_buffer::Event::FileHandleChanged
19735            | multi_buffer::Event::Reloaded
19736            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19737            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19738            multi_buffer::Event::DiagnosticsUpdated => {
19739                self.update_diagnostics_state(window, cx);
19740            }
19741            _ => {}
19742        };
19743    }
19744
19745    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19746        if !self.diagnostics_enabled() {
19747            return;
19748        }
19749        self.refresh_active_diagnostics(cx);
19750        self.refresh_inline_diagnostics(true, window, cx);
19751        self.scrollbar_marker_state.dirty = true;
19752        cx.notify();
19753    }
19754
19755    pub fn start_temporary_diff_override(&mut self) {
19756        self.load_diff_task.take();
19757        self.temporary_diff_override = true;
19758    }
19759
19760    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19761        self.temporary_diff_override = false;
19762        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19763        self.buffer.update(cx, |buffer, cx| {
19764            buffer.set_all_diff_hunks_collapsed(cx);
19765        });
19766
19767        if let Some(project) = self.project.clone() {
19768            self.load_diff_task = Some(
19769                update_uncommitted_diff_for_buffer(
19770                    cx.entity(),
19771                    &project,
19772                    self.buffer.read(cx).all_buffers(),
19773                    self.buffer.clone(),
19774                    cx,
19775                )
19776                .shared(),
19777            );
19778        }
19779    }
19780
19781    fn on_display_map_changed(
19782        &mut self,
19783        _: Entity<DisplayMap>,
19784        _: &mut Window,
19785        cx: &mut Context<Self>,
19786    ) {
19787        cx.notify();
19788    }
19789
19790    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19791        let new_severity = if self.diagnostics_enabled() {
19792            EditorSettings::get_global(cx)
19793                .diagnostics_max_severity
19794                .unwrap_or(DiagnosticSeverity::Hint)
19795        } else {
19796            DiagnosticSeverity::Off
19797        };
19798        self.set_max_diagnostics_severity(new_severity, cx);
19799        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19800        self.update_edit_prediction_settings(cx);
19801        self.refresh_inline_completion(true, false, window, cx);
19802        self.refresh_inlay_hints(
19803            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19804                self.selections.newest_anchor().head(),
19805                &self.buffer.read(cx).snapshot(cx),
19806                cx,
19807            )),
19808            cx,
19809        );
19810
19811        let old_cursor_shape = self.cursor_shape;
19812
19813        {
19814            let editor_settings = EditorSettings::get_global(cx);
19815            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19816            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19817            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19818            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19819            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19820        }
19821
19822        if old_cursor_shape != self.cursor_shape {
19823            cx.emit(EditorEvent::CursorShapeChanged);
19824        }
19825
19826        let project_settings = ProjectSettings::get_global(cx);
19827        self.serialize_dirty_buffers =
19828            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19829
19830        if self.mode.is_full() {
19831            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19832            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19833            if self.show_inline_diagnostics != show_inline_diagnostics {
19834                self.show_inline_diagnostics = show_inline_diagnostics;
19835                self.refresh_inline_diagnostics(false, window, cx);
19836            }
19837
19838            if self.git_blame_inline_enabled != inline_blame_enabled {
19839                self.toggle_git_blame_inline_internal(false, window, cx);
19840            }
19841
19842            let minimap_settings = EditorSettings::get_global(cx).minimap;
19843            if self.minimap_visibility != MinimapVisibility::Disabled {
19844                if self.minimap_visibility.settings_visibility()
19845                    != minimap_settings.minimap_enabled()
19846                {
19847                    self.set_minimap_visibility(
19848                        MinimapVisibility::for_mode(self.mode(), cx),
19849                        window,
19850                        cx,
19851                    );
19852                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19853                    minimap_entity.update(cx, |minimap_editor, cx| {
19854                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19855                    })
19856                }
19857            }
19858        }
19859
19860        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19861            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19862        }) {
19863            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19864                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19865            }
19866            self.refresh_colors(false, None, window, cx);
19867        }
19868
19869        cx.notify();
19870    }
19871
19872    pub fn set_searchable(&mut self, searchable: bool) {
19873        self.searchable = searchable;
19874    }
19875
19876    pub fn searchable(&self) -> bool {
19877        self.searchable
19878    }
19879
19880    fn open_proposed_changes_editor(
19881        &mut self,
19882        _: &OpenProposedChangesEditor,
19883        window: &mut Window,
19884        cx: &mut Context<Self>,
19885    ) {
19886        let Some(workspace) = self.workspace() else {
19887            cx.propagate();
19888            return;
19889        };
19890
19891        let selections = self.selections.all::<usize>(cx);
19892        let multi_buffer = self.buffer.read(cx);
19893        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19894        let mut new_selections_by_buffer = HashMap::default();
19895        for selection in selections {
19896            for (buffer, range, _) in
19897                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19898            {
19899                let mut range = range.to_point(buffer);
19900                range.start.column = 0;
19901                range.end.column = buffer.line_len(range.end.row);
19902                new_selections_by_buffer
19903                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19904                    .or_insert(Vec::new())
19905                    .push(range)
19906            }
19907        }
19908
19909        let proposed_changes_buffers = new_selections_by_buffer
19910            .into_iter()
19911            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19912            .collect::<Vec<_>>();
19913        let proposed_changes_editor = cx.new(|cx| {
19914            ProposedChangesEditor::new(
19915                "Proposed changes",
19916                proposed_changes_buffers,
19917                self.project.clone(),
19918                window,
19919                cx,
19920            )
19921        });
19922
19923        window.defer(cx, move |window, cx| {
19924            workspace.update(cx, |workspace, cx| {
19925                workspace.active_pane().update(cx, |pane, cx| {
19926                    pane.add_item(
19927                        Box::new(proposed_changes_editor),
19928                        true,
19929                        true,
19930                        None,
19931                        window,
19932                        cx,
19933                    );
19934                });
19935            });
19936        });
19937    }
19938
19939    pub fn open_excerpts_in_split(
19940        &mut self,
19941        _: &OpenExcerptsSplit,
19942        window: &mut Window,
19943        cx: &mut Context<Self>,
19944    ) {
19945        self.open_excerpts_common(None, true, window, cx)
19946    }
19947
19948    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19949        self.open_excerpts_common(None, false, window, cx)
19950    }
19951
19952    fn open_excerpts_common(
19953        &mut self,
19954        jump_data: Option<JumpData>,
19955        split: bool,
19956        window: &mut Window,
19957        cx: &mut Context<Self>,
19958    ) {
19959        let Some(workspace) = self.workspace() else {
19960            cx.propagate();
19961            return;
19962        };
19963
19964        if self.buffer.read(cx).is_singleton() {
19965            cx.propagate();
19966            return;
19967        }
19968
19969        let mut new_selections_by_buffer = HashMap::default();
19970        match &jump_data {
19971            Some(JumpData::MultiBufferPoint {
19972                excerpt_id,
19973                position,
19974                anchor,
19975                line_offset_from_top,
19976            }) => {
19977                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19978                if let Some(buffer) = multi_buffer_snapshot
19979                    .buffer_id_for_excerpt(*excerpt_id)
19980                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19981                {
19982                    let buffer_snapshot = buffer.read(cx).snapshot();
19983                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19984                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19985                    } else {
19986                        buffer_snapshot.clip_point(*position, Bias::Left)
19987                    };
19988                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19989                    new_selections_by_buffer.insert(
19990                        buffer,
19991                        (
19992                            vec![jump_to_offset..jump_to_offset],
19993                            Some(*line_offset_from_top),
19994                        ),
19995                    );
19996                }
19997            }
19998            Some(JumpData::MultiBufferRow {
19999                row,
20000                line_offset_from_top,
20001            }) => {
20002                let point = MultiBufferPoint::new(row.0, 0);
20003                if let Some((buffer, buffer_point, _)) =
20004                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20005                {
20006                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20007                    new_selections_by_buffer
20008                        .entry(buffer)
20009                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20010                        .0
20011                        .push(buffer_offset..buffer_offset)
20012                }
20013            }
20014            None => {
20015                let selections = self.selections.all::<usize>(cx);
20016                let multi_buffer = self.buffer.read(cx);
20017                for selection in selections {
20018                    for (snapshot, range, _, anchor) in multi_buffer
20019                        .snapshot(cx)
20020                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20021                    {
20022                        if let Some(anchor) = anchor {
20023                            // selection is in a deleted hunk
20024                            let Some(buffer_id) = anchor.buffer_id else {
20025                                continue;
20026                            };
20027                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20028                                continue;
20029                            };
20030                            let offset = text::ToOffset::to_offset(
20031                                &anchor.text_anchor,
20032                                &buffer_handle.read(cx).snapshot(),
20033                            );
20034                            let range = offset..offset;
20035                            new_selections_by_buffer
20036                                .entry(buffer_handle)
20037                                .or_insert((Vec::new(), None))
20038                                .0
20039                                .push(range)
20040                        } else {
20041                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20042                            else {
20043                                continue;
20044                            };
20045                            new_selections_by_buffer
20046                                .entry(buffer_handle)
20047                                .or_insert((Vec::new(), None))
20048                                .0
20049                                .push(range)
20050                        }
20051                    }
20052                }
20053            }
20054        }
20055
20056        new_selections_by_buffer
20057            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20058
20059        if new_selections_by_buffer.is_empty() {
20060            return;
20061        }
20062
20063        // We defer the pane interaction because we ourselves are a workspace item
20064        // and activating a new item causes the pane to call a method on us reentrantly,
20065        // which panics if we're on the stack.
20066        window.defer(cx, move |window, cx| {
20067            workspace.update(cx, |workspace, cx| {
20068                let pane = if split {
20069                    workspace.adjacent_pane(window, cx)
20070                } else {
20071                    workspace.active_pane().clone()
20072                };
20073
20074                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20075                    let editor = buffer
20076                        .read(cx)
20077                        .file()
20078                        .is_none()
20079                        .then(|| {
20080                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20081                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20082                            // Instead, we try to activate the existing editor in the pane first.
20083                            let (editor, pane_item_index) =
20084                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20085                                    let editor = item.downcast::<Editor>()?;
20086                                    let singleton_buffer =
20087                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20088                                    if singleton_buffer == buffer {
20089                                        Some((editor, i))
20090                                    } else {
20091                                        None
20092                                    }
20093                                })?;
20094                            pane.update(cx, |pane, cx| {
20095                                pane.activate_item(pane_item_index, true, true, window, cx)
20096                            });
20097                            Some(editor)
20098                        })
20099                        .flatten()
20100                        .unwrap_or_else(|| {
20101                            workspace.open_project_item::<Self>(
20102                                pane.clone(),
20103                                buffer,
20104                                true,
20105                                true,
20106                                window,
20107                                cx,
20108                            )
20109                        });
20110
20111                    editor.update(cx, |editor, cx| {
20112                        let autoscroll = match scroll_offset {
20113                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20114                            None => Autoscroll::newest(),
20115                        };
20116                        let nav_history = editor.nav_history.take();
20117                        editor.change_selections(
20118                            SelectionEffects::scroll(autoscroll),
20119                            window,
20120                            cx,
20121                            |s| {
20122                                s.select_ranges(ranges);
20123                            },
20124                        );
20125                        editor.nav_history = nav_history;
20126                    });
20127                }
20128            })
20129        });
20130    }
20131
20132    // For now, don't allow opening excerpts in buffers that aren't backed by
20133    // regular project files.
20134    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20135        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20136    }
20137
20138    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20139        let snapshot = self.buffer.read(cx).read(cx);
20140        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20141        Some(
20142            ranges
20143                .iter()
20144                .map(move |range| {
20145                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20146                })
20147                .collect(),
20148        )
20149    }
20150
20151    fn selection_replacement_ranges(
20152        &self,
20153        range: Range<OffsetUtf16>,
20154        cx: &mut App,
20155    ) -> Vec<Range<OffsetUtf16>> {
20156        let selections = self.selections.all::<OffsetUtf16>(cx);
20157        let newest_selection = selections
20158            .iter()
20159            .max_by_key(|selection| selection.id)
20160            .unwrap();
20161        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20162        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20163        let snapshot = self.buffer.read(cx).read(cx);
20164        selections
20165            .into_iter()
20166            .map(|mut selection| {
20167                selection.start.0 =
20168                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20169                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20170                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20171                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20172            })
20173            .collect()
20174    }
20175
20176    fn report_editor_event(
20177        &self,
20178        event_type: &'static str,
20179        file_extension: Option<String>,
20180        cx: &App,
20181    ) {
20182        if cfg!(any(test, feature = "test-support")) {
20183            return;
20184        }
20185
20186        let Some(project) = &self.project else { return };
20187
20188        // If None, we are in a file without an extension
20189        let file = self
20190            .buffer
20191            .read(cx)
20192            .as_singleton()
20193            .and_then(|b| b.read(cx).file());
20194        let file_extension = file_extension.or(file
20195            .as_ref()
20196            .and_then(|file| Path::new(file.file_name(cx)).extension())
20197            .and_then(|e| e.to_str())
20198            .map(|a| a.to_string()));
20199
20200        let vim_mode = vim_enabled(cx);
20201
20202        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20203        let copilot_enabled = edit_predictions_provider
20204            == language::language_settings::EditPredictionProvider::Copilot;
20205        let copilot_enabled_for_language = self
20206            .buffer
20207            .read(cx)
20208            .language_settings(cx)
20209            .show_edit_predictions;
20210
20211        let project = project.read(cx);
20212        telemetry::event!(
20213            event_type,
20214            file_extension,
20215            vim_mode,
20216            copilot_enabled,
20217            copilot_enabled_for_language,
20218            edit_predictions_provider,
20219            is_via_ssh = project.is_via_ssh(),
20220        );
20221    }
20222
20223    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20224    /// with each line being an array of {text, highlight} objects.
20225    fn copy_highlight_json(
20226        &mut self,
20227        _: &CopyHighlightJson,
20228        window: &mut Window,
20229        cx: &mut Context<Self>,
20230    ) {
20231        #[derive(Serialize)]
20232        struct Chunk<'a> {
20233            text: String,
20234            highlight: Option<&'a str>,
20235        }
20236
20237        let snapshot = self.buffer.read(cx).snapshot(cx);
20238        let range = self
20239            .selected_text_range(false, window, cx)
20240            .and_then(|selection| {
20241                if selection.range.is_empty() {
20242                    None
20243                } else {
20244                    Some(selection.range)
20245                }
20246            })
20247            .unwrap_or_else(|| 0..snapshot.len());
20248
20249        let chunks = snapshot.chunks(range, true);
20250        let mut lines = Vec::new();
20251        let mut line: VecDeque<Chunk> = VecDeque::new();
20252
20253        let Some(style) = self.style.as_ref() else {
20254            return;
20255        };
20256
20257        for chunk in chunks {
20258            let highlight = chunk
20259                .syntax_highlight_id
20260                .and_then(|id| id.name(&style.syntax));
20261            let mut chunk_lines = chunk.text.split('\n').peekable();
20262            while let Some(text) = chunk_lines.next() {
20263                let mut merged_with_last_token = false;
20264                if let Some(last_token) = line.back_mut() {
20265                    if last_token.highlight == highlight {
20266                        last_token.text.push_str(text);
20267                        merged_with_last_token = true;
20268                    }
20269                }
20270
20271                if !merged_with_last_token {
20272                    line.push_back(Chunk {
20273                        text: text.into(),
20274                        highlight,
20275                    });
20276                }
20277
20278                if chunk_lines.peek().is_some() {
20279                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20280                        line.pop_front();
20281                    }
20282                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20283                        line.pop_back();
20284                    }
20285
20286                    lines.push(mem::take(&mut line));
20287                }
20288            }
20289        }
20290
20291        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20292            return;
20293        };
20294        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20295    }
20296
20297    pub fn open_context_menu(
20298        &mut self,
20299        _: &OpenContextMenu,
20300        window: &mut Window,
20301        cx: &mut Context<Self>,
20302    ) {
20303        self.request_autoscroll(Autoscroll::newest(), cx);
20304        let position = self.selections.newest_display(cx).start;
20305        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20306    }
20307
20308    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20309        &self.inlay_hint_cache
20310    }
20311
20312    pub fn replay_insert_event(
20313        &mut self,
20314        text: &str,
20315        relative_utf16_range: Option<Range<isize>>,
20316        window: &mut Window,
20317        cx: &mut Context<Self>,
20318    ) {
20319        if !self.input_enabled {
20320            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20321            return;
20322        }
20323        if let Some(relative_utf16_range) = relative_utf16_range {
20324            let selections = self.selections.all::<OffsetUtf16>(cx);
20325            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20326                let new_ranges = selections.into_iter().map(|range| {
20327                    let start = OffsetUtf16(
20328                        range
20329                            .head()
20330                            .0
20331                            .saturating_add_signed(relative_utf16_range.start),
20332                    );
20333                    let end = OffsetUtf16(
20334                        range
20335                            .head()
20336                            .0
20337                            .saturating_add_signed(relative_utf16_range.end),
20338                    );
20339                    start..end
20340                });
20341                s.select_ranges(new_ranges);
20342            });
20343        }
20344
20345        self.handle_input(text, window, cx);
20346    }
20347
20348    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20349        let Some(provider) = self.semantics_provider.as_ref() else {
20350            return false;
20351        };
20352
20353        let mut supports = false;
20354        self.buffer().update(cx, |this, cx| {
20355            this.for_each_buffer(|buffer| {
20356                supports |= provider.supports_inlay_hints(buffer, cx);
20357            });
20358        });
20359
20360        supports
20361    }
20362
20363    pub fn is_focused(&self, window: &Window) -> bool {
20364        self.focus_handle.is_focused(window)
20365    }
20366
20367    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20368        cx.emit(EditorEvent::Focused);
20369
20370        if let Some(descendant) = self
20371            .last_focused_descendant
20372            .take()
20373            .and_then(|descendant| descendant.upgrade())
20374        {
20375            window.focus(&descendant);
20376        } else {
20377            if let Some(blame) = self.blame.as_ref() {
20378                blame.update(cx, GitBlame::focus)
20379            }
20380
20381            self.blink_manager.update(cx, BlinkManager::enable);
20382            self.show_cursor_names(window, cx);
20383            self.buffer.update(cx, |buffer, cx| {
20384                buffer.finalize_last_transaction(cx);
20385                if self.leader_id.is_none() {
20386                    buffer.set_active_selections(
20387                        &self.selections.disjoint_anchors(),
20388                        self.selections.line_mode,
20389                        self.cursor_shape,
20390                        cx,
20391                    );
20392                }
20393            });
20394        }
20395    }
20396
20397    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20398        cx.emit(EditorEvent::FocusedIn)
20399    }
20400
20401    fn handle_focus_out(
20402        &mut self,
20403        event: FocusOutEvent,
20404        _window: &mut Window,
20405        cx: &mut Context<Self>,
20406    ) {
20407        if event.blurred != self.focus_handle {
20408            self.last_focused_descendant = Some(event.blurred);
20409        }
20410        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20411    }
20412
20413    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20414        self.blink_manager.update(cx, BlinkManager::disable);
20415        self.buffer
20416            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20417
20418        if let Some(blame) = self.blame.as_ref() {
20419            blame.update(cx, GitBlame::blur)
20420        }
20421        if !self.hover_state.focused(window, cx) {
20422            hide_hover(self, cx);
20423        }
20424        if !self
20425            .context_menu
20426            .borrow()
20427            .as_ref()
20428            .is_some_and(|context_menu| context_menu.focused(window, cx))
20429        {
20430            self.hide_context_menu(window, cx);
20431        }
20432        self.discard_inline_completion(false, cx);
20433        cx.emit(EditorEvent::Blurred);
20434        cx.notify();
20435    }
20436
20437    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20438        let mut pending: String = window
20439            .pending_input_keystrokes()
20440            .into_iter()
20441            .flatten()
20442            .filter_map(|keystroke| {
20443                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20444                    keystroke.key_char.clone()
20445                } else {
20446                    None
20447                }
20448            })
20449            .collect();
20450
20451        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20452            pending = "".to_string();
20453        }
20454
20455        let existing_pending = self
20456            .text_highlights::<PendingInput>(cx)
20457            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20458        if existing_pending.is_none() && pending.is_empty() {
20459            return;
20460        }
20461        let transaction =
20462            self.transact(window, cx, |this, window, cx| {
20463                let selections = this.selections.all::<usize>(cx);
20464                let edits = selections
20465                    .iter()
20466                    .map(|selection| (selection.end..selection.end, pending.clone()));
20467                this.edit(edits, cx);
20468                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20469                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20470                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20471                    }));
20472                });
20473                if let Some(existing_ranges) = existing_pending {
20474                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20475                    this.edit(edits, cx);
20476                }
20477            });
20478
20479        let snapshot = self.snapshot(window, cx);
20480        let ranges = self
20481            .selections
20482            .all::<usize>(cx)
20483            .into_iter()
20484            .map(|selection| {
20485                snapshot.buffer_snapshot.anchor_after(selection.end)
20486                    ..snapshot
20487                        .buffer_snapshot
20488                        .anchor_before(selection.end + pending.len())
20489            })
20490            .collect();
20491
20492        if pending.is_empty() {
20493            self.clear_highlights::<PendingInput>(cx);
20494        } else {
20495            self.highlight_text::<PendingInput>(
20496                ranges,
20497                HighlightStyle {
20498                    underline: Some(UnderlineStyle {
20499                        thickness: px(1.),
20500                        color: None,
20501                        wavy: false,
20502                    }),
20503                    ..Default::default()
20504                },
20505                cx,
20506            );
20507        }
20508
20509        self.ime_transaction = self.ime_transaction.or(transaction);
20510        if let Some(transaction) = self.ime_transaction {
20511            self.buffer.update(cx, |buffer, cx| {
20512                buffer.group_until_transaction(transaction, cx);
20513            });
20514        }
20515
20516        if self.text_highlights::<PendingInput>(cx).is_none() {
20517            self.ime_transaction.take();
20518        }
20519    }
20520
20521    pub fn register_action_renderer(
20522        &mut self,
20523        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20524    ) -> Subscription {
20525        let id = self.next_editor_action_id.post_inc();
20526        self.editor_actions
20527            .borrow_mut()
20528            .insert(id, Box::new(listener));
20529
20530        let editor_actions = self.editor_actions.clone();
20531        Subscription::new(move || {
20532            editor_actions.borrow_mut().remove(&id);
20533        })
20534    }
20535
20536    pub fn register_action<A: Action>(
20537        &mut self,
20538        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20539    ) -> Subscription {
20540        let id = self.next_editor_action_id.post_inc();
20541        let listener = Arc::new(listener);
20542        self.editor_actions.borrow_mut().insert(
20543            id,
20544            Box::new(move |_, window, _| {
20545                let listener = listener.clone();
20546                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20547                    let action = action.downcast_ref().unwrap();
20548                    if phase == DispatchPhase::Bubble {
20549                        listener(action, window, cx)
20550                    }
20551                })
20552            }),
20553        );
20554
20555        let editor_actions = self.editor_actions.clone();
20556        Subscription::new(move || {
20557            editor_actions.borrow_mut().remove(&id);
20558        })
20559    }
20560
20561    pub fn file_header_size(&self) -> u32 {
20562        FILE_HEADER_HEIGHT
20563    }
20564
20565    pub fn restore(
20566        &mut self,
20567        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20568        window: &mut Window,
20569        cx: &mut Context<Self>,
20570    ) {
20571        let workspace = self.workspace();
20572        let project = self.project.as_ref();
20573        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20574            let mut tasks = Vec::new();
20575            for (buffer_id, changes) in revert_changes {
20576                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20577                    buffer.update(cx, |buffer, cx| {
20578                        buffer.edit(
20579                            changes
20580                                .into_iter()
20581                                .map(|(range, text)| (range, text.to_string())),
20582                            None,
20583                            cx,
20584                        );
20585                    });
20586
20587                    if let Some(project) =
20588                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20589                    {
20590                        project.update(cx, |project, cx| {
20591                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20592                        })
20593                    }
20594                }
20595            }
20596            tasks
20597        });
20598        cx.spawn_in(window, async move |_, cx| {
20599            for (buffer, task) in save_tasks {
20600                let result = task.await;
20601                if result.is_err() {
20602                    let Some(path) = buffer
20603                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20604                        .ok()
20605                    else {
20606                        continue;
20607                    };
20608                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20609                        let Some(task) = cx
20610                            .update_window_entity(&workspace, |workspace, window, cx| {
20611                                workspace
20612                                    .open_path_preview(path, None, false, false, false, window, cx)
20613                            })
20614                            .ok()
20615                        else {
20616                            continue;
20617                        };
20618                        task.await.log_err();
20619                    }
20620                }
20621            }
20622        })
20623        .detach();
20624        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20625            selections.refresh()
20626        });
20627    }
20628
20629    pub fn to_pixel_point(
20630        &self,
20631        source: multi_buffer::Anchor,
20632        editor_snapshot: &EditorSnapshot,
20633        window: &mut Window,
20634    ) -> Option<gpui::Point<Pixels>> {
20635        let source_point = source.to_display_point(editor_snapshot);
20636        self.display_to_pixel_point(source_point, editor_snapshot, window)
20637    }
20638
20639    pub fn display_to_pixel_point(
20640        &self,
20641        source: DisplayPoint,
20642        editor_snapshot: &EditorSnapshot,
20643        window: &mut Window,
20644    ) -> Option<gpui::Point<Pixels>> {
20645        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20646        let text_layout_details = self.text_layout_details(window);
20647        let scroll_top = text_layout_details
20648            .scroll_anchor
20649            .scroll_position(editor_snapshot)
20650            .y;
20651
20652        if source.row().as_f32() < scroll_top.floor() {
20653            return None;
20654        }
20655        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20656        let source_y = line_height * (source.row().as_f32() - scroll_top);
20657        Some(gpui::Point::new(source_x, source_y))
20658    }
20659
20660    pub fn has_visible_completions_menu(&self) -> bool {
20661        !self.edit_prediction_preview_is_active()
20662            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20663                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20664            })
20665    }
20666
20667    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20668        if self.mode.is_minimap() {
20669            return;
20670        }
20671        self.addons
20672            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20673    }
20674
20675    pub fn unregister_addon<T: Addon>(&mut self) {
20676        self.addons.remove(&std::any::TypeId::of::<T>());
20677    }
20678
20679    pub fn addon<T: Addon>(&self) -> Option<&T> {
20680        let type_id = std::any::TypeId::of::<T>();
20681        self.addons
20682            .get(&type_id)
20683            .and_then(|item| item.to_any().downcast_ref::<T>())
20684    }
20685
20686    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20687        let type_id = std::any::TypeId::of::<T>();
20688        self.addons
20689            .get_mut(&type_id)
20690            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20691    }
20692
20693    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20694        let text_layout_details = self.text_layout_details(window);
20695        let style = &text_layout_details.editor_style;
20696        let font_id = window.text_system().resolve_font(&style.text.font());
20697        let font_size = style.text.font_size.to_pixels(window.rem_size());
20698        let line_height = style.text.line_height_in_pixels(window.rem_size());
20699        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20700        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20701
20702        CharacterDimensions {
20703            em_width,
20704            em_advance,
20705            line_height,
20706        }
20707    }
20708
20709    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20710        self.load_diff_task.clone()
20711    }
20712
20713    fn read_metadata_from_db(
20714        &mut self,
20715        item_id: u64,
20716        workspace_id: WorkspaceId,
20717        window: &mut Window,
20718        cx: &mut Context<Editor>,
20719    ) {
20720        if self.is_singleton(cx)
20721            && !self.mode.is_minimap()
20722            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20723        {
20724            let buffer_snapshot = OnceCell::new();
20725
20726            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20727                if !folds.is_empty() {
20728                    let snapshot =
20729                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20730                    self.fold_ranges(
20731                        folds
20732                            .into_iter()
20733                            .map(|(start, end)| {
20734                                snapshot.clip_offset(start, Bias::Left)
20735                                    ..snapshot.clip_offset(end, Bias::Right)
20736                            })
20737                            .collect(),
20738                        false,
20739                        window,
20740                        cx,
20741                    );
20742                }
20743            }
20744
20745            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20746                if !selections.is_empty() {
20747                    let snapshot =
20748                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20749                    // skip adding the initial selection to selection history
20750                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20751                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20752                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20753                            snapshot.clip_offset(start, Bias::Left)
20754                                ..snapshot.clip_offset(end, Bias::Right)
20755                        }));
20756                    });
20757                    self.selection_history.mode = SelectionHistoryMode::Normal;
20758                }
20759            };
20760        }
20761
20762        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20763    }
20764
20765    fn update_lsp_data(
20766        &mut self,
20767        ignore_cache: bool,
20768        for_buffer: Option<BufferId>,
20769        window: &mut Window,
20770        cx: &mut Context<'_, Self>,
20771    ) {
20772        self.pull_diagnostics(for_buffer, window, cx);
20773        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20774    }
20775}
20776
20777fn vim_enabled(cx: &App) -> bool {
20778    cx.global::<SettingsStore>()
20779        .raw_user_settings()
20780        .get("vim_mode")
20781        == Some(&serde_json::Value::Bool(true))
20782}
20783
20784fn process_completion_for_edit(
20785    completion: &Completion,
20786    intent: CompletionIntent,
20787    buffer: &Entity<Buffer>,
20788    cursor_position: &text::Anchor,
20789    cx: &mut Context<Editor>,
20790) -> CompletionEdit {
20791    let buffer = buffer.read(cx);
20792    let buffer_snapshot = buffer.snapshot();
20793    let (snippet, new_text) = if completion.is_snippet() {
20794        // Workaround for typescript language server issues so that methods don't expand within
20795        // strings and functions with type expressions. The previous point is used because the query
20796        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20797        let mut snippet_source = completion.new_text.clone();
20798        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20799        previous_point.column = previous_point.column.saturating_sub(1);
20800        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20801            if scope.prefers_label_for_snippet_in_completion() {
20802                if let Some(label) = completion.label() {
20803                    if matches!(
20804                        completion.kind(),
20805                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20806                    ) {
20807                        snippet_source = label;
20808                    }
20809                }
20810            }
20811        }
20812        match Snippet::parse(&snippet_source).log_err() {
20813            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20814            None => (None, completion.new_text.clone()),
20815        }
20816    } else {
20817        (None, completion.new_text.clone())
20818    };
20819
20820    let mut range_to_replace = {
20821        let replace_range = &completion.replace_range;
20822        if let CompletionSource::Lsp {
20823            insert_range: Some(insert_range),
20824            ..
20825        } = &completion.source
20826        {
20827            debug_assert_eq!(
20828                insert_range.start, replace_range.start,
20829                "insert_range and replace_range should start at the same position"
20830            );
20831            debug_assert!(
20832                insert_range
20833                    .start
20834                    .cmp(&cursor_position, &buffer_snapshot)
20835                    .is_le(),
20836                "insert_range should start before or at cursor position"
20837            );
20838            debug_assert!(
20839                replace_range
20840                    .start
20841                    .cmp(&cursor_position, &buffer_snapshot)
20842                    .is_le(),
20843                "replace_range should start before or at cursor position"
20844            );
20845            debug_assert!(
20846                insert_range
20847                    .end
20848                    .cmp(&cursor_position, &buffer_snapshot)
20849                    .is_le(),
20850                "insert_range should end before or at cursor position"
20851            );
20852
20853            let should_replace = match intent {
20854                CompletionIntent::CompleteWithInsert => false,
20855                CompletionIntent::CompleteWithReplace => true,
20856                CompletionIntent::Complete | CompletionIntent::Compose => {
20857                    let insert_mode =
20858                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20859                            .completions
20860                            .lsp_insert_mode;
20861                    match insert_mode {
20862                        LspInsertMode::Insert => false,
20863                        LspInsertMode::Replace => true,
20864                        LspInsertMode::ReplaceSubsequence => {
20865                            let mut text_to_replace = buffer.chars_for_range(
20866                                buffer.anchor_before(replace_range.start)
20867                                    ..buffer.anchor_after(replace_range.end),
20868                            );
20869                            let mut current_needle = text_to_replace.next();
20870                            for haystack_ch in completion.label.text.chars() {
20871                                if let Some(needle_ch) = current_needle {
20872                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20873                                        current_needle = text_to_replace.next();
20874                                    }
20875                                }
20876                            }
20877                            current_needle.is_none()
20878                        }
20879                        LspInsertMode::ReplaceSuffix => {
20880                            if replace_range
20881                                .end
20882                                .cmp(&cursor_position, &buffer_snapshot)
20883                                .is_gt()
20884                            {
20885                                let range_after_cursor = *cursor_position..replace_range.end;
20886                                let text_after_cursor = buffer
20887                                    .text_for_range(
20888                                        buffer.anchor_before(range_after_cursor.start)
20889                                            ..buffer.anchor_after(range_after_cursor.end),
20890                                    )
20891                                    .collect::<String>()
20892                                    .to_ascii_lowercase();
20893                                completion
20894                                    .label
20895                                    .text
20896                                    .to_ascii_lowercase()
20897                                    .ends_with(&text_after_cursor)
20898                            } else {
20899                                true
20900                            }
20901                        }
20902                    }
20903                }
20904            };
20905
20906            if should_replace {
20907                replace_range.clone()
20908            } else {
20909                insert_range.clone()
20910            }
20911        } else {
20912            replace_range.clone()
20913        }
20914    };
20915
20916    if range_to_replace
20917        .end
20918        .cmp(&cursor_position, &buffer_snapshot)
20919        .is_lt()
20920    {
20921        range_to_replace.end = *cursor_position;
20922    }
20923
20924    CompletionEdit {
20925        new_text,
20926        replace_range: range_to_replace.to_offset(&buffer),
20927        snippet,
20928    }
20929}
20930
20931struct CompletionEdit {
20932    new_text: String,
20933    replace_range: Range<usize>,
20934    snippet: Option<Snippet>,
20935}
20936
20937fn insert_extra_newline_brackets(
20938    buffer: &MultiBufferSnapshot,
20939    range: Range<usize>,
20940    language: &language::LanguageScope,
20941) -> bool {
20942    let leading_whitespace_len = buffer
20943        .reversed_chars_at(range.start)
20944        .take_while(|c| c.is_whitespace() && *c != '\n')
20945        .map(|c| c.len_utf8())
20946        .sum::<usize>();
20947    let trailing_whitespace_len = buffer
20948        .chars_at(range.end)
20949        .take_while(|c| c.is_whitespace() && *c != '\n')
20950        .map(|c| c.len_utf8())
20951        .sum::<usize>();
20952    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20953
20954    language.brackets().any(|(pair, enabled)| {
20955        let pair_start = pair.start.trim_end();
20956        let pair_end = pair.end.trim_start();
20957
20958        enabled
20959            && pair.newline
20960            && buffer.contains_str_at(range.end, pair_end)
20961            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20962    })
20963}
20964
20965fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20966    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20967        [(buffer, range, _)] => (*buffer, range.clone()),
20968        _ => return false,
20969    };
20970    let pair = {
20971        let mut result: Option<BracketMatch> = None;
20972
20973        for pair in buffer
20974            .all_bracket_ranges(range.clone())
20975            .filter(move |pair| {
20976                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20977            })
20978        {
20979            let len = pair.close_range.end - pair.open_range.start;
20980
20981            if let Some(existing) = &result {
20982                let existing_len = existing.close_range.end - existing.open_range.start;
20983                if len > existing_len {
20984                    continue;
20985                }
20986            }
20987
20988            result = Some(pair);
20989        }
20990
20991        result
20992    };
20993    let Some(pair) = pair else {
20994        return false;
20995    };
20996    pair.newline_only
20997        && buffer
20998            .chars_for_range(pair.open_range.end..range.start)
20999            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21000            .all(|c| c.is_whitespace() && c != '\n')
21001}
21002
21003fn update_uncommitted_diff_for_buffer(
21004    editor: Entity<Editor>,
21005    project: &Entity<Project>,
21006    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21007    buffer: Entity<MultiBuffer>,
21008    cx: &mut App,
21009) -> Task<()> {
21010    let mut tasks = Vec::new();
21011    project.update(cx, |project, cx| {
21012        for buffer in buffers {
21013            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21014                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21015            }
21016        }
21017    });
21018    cx.spawn(async move |cx| {
21019        let diffs = future::join_all(tasks).await;
21020        if editor
21021            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21022            .unwrap_or(false)
21023        {
21024            return;
21025        }
21026
21027        buffer
21028            .update(cx, |buffer, cx| {
21029                for diff in diffs.into_iter().flatten() {
21030                    buffer.add_diff(diff, cx);
21031                }
21032            })
21033            .ok();
21034    })
21035}
21036
21037fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21038    let tab_size = tab_size.get() as usize;
21039    let mut width = offset;
21040
21041    for ch in text.chars() {
21042        width += if ch == '\t' {
21043            tab_size - (width % tab_size)
21044        } else {
21045            1
21046        };
21047    }
21048
21049    width - offset
21050}
21051
21052#[cfg(test)]
21053mod tests {
21054    use super::*;
21055
21056    #[test]
21057    fn test_string_size_with_expanded_tabs() {
21058        let nz = |val| NonZeroU32::new(val).unwrap();
21059        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21060        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21061        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21062        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21063        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21064        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21065        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21066        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21067    }
21068}
21069
21070/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21071struct WordBreakingTokenizer<'a> {
21072    input: &'a str,
21073}
21074
21075impl<'a> WordBreakingTokenizer<'a> {
21076    fn new(input: &'a str) -> Self {
21077        Self { input }
21078    }
21079}
21080
21081fn is_char_ideographic(ch: char) -> bool {
21082    use unicode_script::Script::*;
21083    use unicode_script::UnicodeScript;
21084    matches!(ch.script(), Han | Tangut | Yi)
21085}
21086
21087fn is_grapheme_ideographic(text: &str) -> bool {
21088    text.chars().any(is_char_ideographic)
21089}
21090
21091fn is_grapheme_whitespace(text: &str) -> bool {
21092    text.chars().any(|x| x.is_whitespace())
21093}
21094
21095fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21096    text.chars().next().map_or(false, |ch| {
21097        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21098    })
21099}
21100
21101#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21102enum WordBreakToken<'a> {
21103    Word { token: &'a str, grapheme_len: usize },
21104    InlineWhitespace { token: &'a str, grapheme_len: usize },
21105    Newline,
21106}
21107
21108impl<'a> Iterator for WordBreakingTokenizer<'a> {
21109    /// Yields a span, the count of graphemes in the token, and whether it was
21110    /// whitespace. Note that it also breaks at word boundaries.
21111    type Item = WordBreakToken<'a>;
21112
21113    fn next(&mut self) -> Option<Self::Item> {
21114        use unicode_segmentation::UnicodeSegmentation;
21115        if self.input.is_empty() {
21116            return None;
21117        }
21118
21119        let mut iter = self.input.graphemes(true).peekable();
21120        let mut offset = 0;
21121        let mut grapheme_len = 0;
21122        if let Some(first_grapheme) = iter.next() {
21123            let is_newline = first_grapheme == "\n";
21124            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21125            offset += first_grapheme.len();
21126            grapheme_len += 1;
21127            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21128                if let Some(grapheme) = iter.peek().copied() {
21129                    if should_stay_with_preceding_ideograph(grapheme) {
21130                        offset += grapheme.len();
21131                        grapheme_len += 1;
21132                    }
21133                }
21134            } else {
21135                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21136                let mut next_word_bound = words.peek().copied();
21137                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21138                    next_word_bound = words.next();
21139                }
21140                while let Some(grapheme) = iter.peek().copied() {
21141                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21142                        break;
21143                    };
21144                    if is_grapheme_whitespace(grapheme) != is_whitespace
21145                        || (grapheme == "\n") != is_newline
21146                    {
21147                        break;
21148                    };
21149                    offset += grapheme.len();
21150                    grapheme_len += 1;
21151                    iter.next();
21152                }
21153            }
21154            let token = &self.input[..offset];
21155            self.input = &self.input[offset..];
21156            if token == "\n" {
21157                Some(WordBreakToken::Newline)
21158            } else if is_whitespace {
21159                Some(WordBreakToken::InlineWhitespace {
21160                    token,
21161                    grapheme_len,
21162                })
21163            } else {
21164                Some(WordBreakToken::Word {
21165                    token,
21166                    grapheme_len,
21167                })
21168            }
21169        } else {
21170            None
21171        }
21172    }
21173}
21174
21175#[test]
21176fn test_word_breaking_tokenizer() {
21177    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21178        ("", &[]),
21179        ("  ", &[whitespace("  ", 2)]),
21180        ("Ʒ", &[word("Ʒ", 1)]),
21181        ("Ǽ", &[word("Ǽ", 1)]),
21182        ("", &[word("", 1)]),
21183        ("⋑⋑", &[word("⋑⋑", 2)]),
21184        (
21185            "原理,进而",
21186            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21187        ),
21188        (
21189            "hello world",
21190            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21191        ),
21192        (
21193            "hello, world",
21194            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21195        ),
21196        (
21197            "  hello world",
21198            &[
21199                whitespace("  ", 2),
21200                word("hello", 5),
21201                whitespace(" ", 1),
21202                word("world", 5),
21203            ],
21204        ),
21205        (
21206            "这是什么 \n 钢笔",
21207            &[
21208                word("", 1),
21209                word("", 1),
21210                word("", 1),
21211                word("", 1),
21212                whitespace(" ", 1),
21213                newline(),
21214                whitespace(" ", 1),
21215                word("", 1),
21216                word("", 1),
21217            ],
21218        ),
21219        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21220    ];
21221
21222    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21223        WordBreakToken::Word {
21224            token,
21225            grapheme_len,
21226        }
21227    }
21228
21229    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21230        WordBreakToken::InlineWhitespace {
21231            token,
21232            grapheme_len,
21233        }
21234    }
21235
21236    fn newline() -> WordBreakToken<'static> {
21237        WordBreakToken::Newline
21238    }
21239
21240    for (input, result) in tests {
21241        assert_eq!(
21242            WordBreakingTokenizer::new(input)
21243                .collect::<Vec<_>>()
21244                .as_slice(),
21245            *result,
21246        );
21247    }
21248}
21249
21250fn wrap_with_prefix(
21251    first_line_prefix: String,
21252    subsequent_lines_prefix: String,
21253    unwrapped_text: String,
21254    wrap_column: usize,
21255    tab_size: NonZeroU32,
21256    preserve_existing_whitespace: bool,
21257) -> String {
21258    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21259    let subsequent_lines_prefix_len =
21260        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21261    let mut wrapped_text = String::new();
21262    let mut current_line = first_line_prefix.clone();
21263    let mut is_first_line = true;
21264
21265    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21266    let mut current_line_len = first_line_prefix_len;
21267    let mut in_whitespace = false;
21268    for token in tokenizer {
21269        let have_preceding_whitespace = in_whitespace;
21270        match token {
21271            WordBreakToken::Word {
21272                token,
21273                grapheme_len,
21274            } => {
21275                in_whitespace = false;
21276                let current_prefix_len = if is_first_line {
21277                    first_line_prefix_len
21278                } else {
21279                    subsequent_lines_prefix_len
21280                };
21281                if current_line_len + grapheme_len > wrap_column
21282                    && current_line_len != current_prefix_len
21283                {
21284                    wrapped_text.push_str(current_line.trim_end());
21285                    wrapped_text.push('\n');
21286                    is_first_line = false;
21287                    current_line = subsequent_lines_prefix.clone();
21288                    current_line_len = subsequent_lines_prefix_len;
21289                }
21290                current_line.push_str(token);
21291                current_line_len += grapheme_len;
21292            }
21293            WordBreakToken::InlineWhitespace {
21294                mut token,
21295                mut grapheme_len,
21296            } => {
21297                in_whitespace = true;
21298                if have_preceding_whitespace && !preserve_existing_whitespace {
21299                    continue;
21300                }
21301                if !preserve_existing_whitespace {
21302                    token = " ";
21303                    grapheme_len = 1;
21304                }
21305                let current_prefix_len = if is_first_line {
21306                    first_line_prefix_len
21307                } else {
21308                    subsequent_lines_prefix_len
21309                };
21310                if current_line_len + grapheme_len > wrap_column {
21311                    wrapped_text.push_str(current_line.trim_end());
21312                    wrapped_text.push('\n');
21313                    is_first_line = false;
21314                    current_line = subsequent_lines_prefix.clone();
21315                    current_line_len = subsequent_lines_prefix_len;
21316                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21317                    current_line.push_str(token);
21318                    current_line_len += grapheme_len;
21319                }
21320            }
21321            WordBreakToken::Newline => {
21322                in_whitespace = true;
21323                let current_prefix_len = if is_first_line {
21324                    first_line_prefix_len
21325                } else {
21326                    subsequent_lines_prefix_len
21327                };
21328                if preserve_existing_whitespace {
21329                    wrapped_text.push_str(current_line.trim_end());
21330                    wrapped_text.push('\n');
21331                    is_first_line = false;
21332                    current_line = subsequent_lines_prefix.clone();
21333                    current_line_len = subsequent_lines_prefix_len;
21334                } else if have_preceding_whitespace {
21335                    continue;
21336                } else if current_line_len + 1 > wrap_column
21337                    && current_line_len != current_prefix_len
21338                {
21339                    wrapped_text.push_str(current_line.trim_end());
21340                    wrapped_text.push('\n');
21341                    is_first_line = false;
21342                    current_line = subsequent_lines_prefix.clone();
21343                    current_line_len = subsequent_lines_prefix_len;
21344                } else if current_line_len != current_prefix_len {
21345                    current_line.push(' ');
21346                    current_line_len += 1;
21347                }
21348            }
21349        }
21350    }
21351
21352    if !current_line.is_empty() {
21353        wrapped_text.push_str(&current_line);
21354    }
21355    wrapped_text
21356}
21357
21358#[test]
21359fn test_wrap_with_prefix() {
21360    assert_eq!(
21361        wrap_with_prefix(
21362            "# ".to_string(),
21363            "# ".to_string(),
21364            "abcdefg".to_string(),
21365            4,
21366            NonZeroU32::new(4).unwrap(),
21367            false,
21368        ),
21369        "# abcdefg"
21370    );
21371    assert_eq!(
21372        wrap_with_prefix(
21373            "".to_string(),
21374            "".to_string(),
21375            "\thello world".to_string(),
21376            8,
21377            NonZeroU32::new(4).unwrap(),
21378            false,
21379        ),
21380        "hello\nworld"
21381    );
21382    assert_eq!(
21383        wrap_with_prefix(
21384            "// ".to_string(),
21385            "// ".to_string(),
21386            "xx \nyy zz aa bb cc".to_string(),
21387            12,
21388            NonZeroU32::new(4).unwrap(),
21389            false,
21390        ),
21391        "// xx yy zz\n// aa bb cc"
21392    );
21393    assert_eq!(
21394        wrap_with_prefix(
21395            String::new(),
21396            String::new(),
21397            "这是什么 \n 钢笔".to_string(),
21398            3,
21399            NonZeroU32::new(4).unwrap(),
21400            false,
21401        ),
21402        "这是什\n么 钢\n"
21403    );
21404}
21405
21406pub trait CollaborationHub {
21407    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21408    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21409    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21410}
21411
21412impl CollaborationHub for Entity<Project> {
21413    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21414        self.read(cx).collaborators()
21415    }
21416
21417    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21418        self.read(cx).user_store().read(cx).participant_indices()
21419    }
21420
21421    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21422        let this = self.read(cx);
21423        let user_ids = this.collaborators().values().map(|c| c.user_id);
21424        this.user_store().read(cx).participant_names(user_ids, cx)
21425    }
21426}
21427
21428pub trait SemanticsProvider {
21429    fn hover(
21430        &self,
21431        buffer: &Entity<Buffer>,
21432        position: text::Anchor,
21433        cx: &mut App,
21434    ) -> Option<Task<Vec<project::Hover>>>;
21435
21436    fn inline_values(
21437        &self,
21438        buffer_handle: Entity<Buffer>,
21439        range: Range<text::Anchor>,
21440        cx: &mut App,
21441    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21442
21443    fn inlay_hints(
21444        &self,
21445        buffer_handle: Entity<Buffer>,
21446        range: Range<text::Anchor>,
21447        cx: &mut App,
21448    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21449
21450    fn resolve_inlay_hint(
21451        &self,
21452        hint: InlayHint,
21453        buffer_handle: Entity<Buffer>,
21454        server_id: LanguageServerId,
21455        cx: &mut App,
21456    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21457
21458    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21459
21460    fn document_highlights(
21461        &self,
21462        buffer: &Entity<Buffer>,
21463        position: text::Anchor,
21464        cx: &mut App,
21465    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21466
21467    fn definitions(
21468        &self,
21469        buffer: &Entity<Buffer>,
21470        position: text::Anchor,
21471        kind: GotoDefinitionKind,
21472        cx: &mut App,
21473    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21474
21475    fn range_for_rename(
21476        &self,
21477        buffer: &Entity<Buffer>,
21478        position: text::Anchor,
21479        cx: &mut App,
21480    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21481
21482    fn perform_rename(
21483        &self,
21484        buffer: &Entity<Buffer>,
21485        position: text::Anchor,
21486        new_name: String,
21487        cx: &mut App,
21488    ) -> Option<Task<Result<ProjectTransaction>>>;
21489}
21490
21491pub trait CompletionProvider {
21492    fn completions(
21493        &self,
21494        excerpt_id: ExcerptId,
21495        buffer: &Entity<Buffer>,
21496        buffer_position: text::Anchor,
21497        trigger: CompletionContext,
21498        window: &mut Window,
21499        cx: &mut Context<Editor>,
21500    ) -> Task<Result<Vec<CompletionResponse>>>;
21501
21502    fn resolve_completions(
21503        &self,
21504        _buffer: Entity<Buffer>,
21505        _completion_indices: Vec<usize>,
21506        _completions: Rc<RefCell<Box<[Completion]>>>,
21507        _cx: &mut Context<Editor>,
21508    ) -> Task<Result<bool>> {
21509        Task::ready(Ok(false))
21510    }
21511
21512    fn apply_additional_edits_for_completion(
21513        &self,
21514        _buffer: Entity<Buffer>,
21515        _completions: Rc<RefCell<Box<[Completion]>>>,
21516        _completion_index: usize,
21517        _push_to_history: bool,
21518        _cx: &mut Context<Editor>,
21519    ) -> Task<Result<Option<language::Transaction>>> {
21520        Task::ready(Ok(None))
21521    }
21522
21523    fn is_completion_trigger(
21524        &self,
21525        buffer: &Entity<Buffer>,
21526        position: language::Anchor,
21527        text: &str,
21528        trigger_in_words: bool,
21529        menu_is_open: bool,
21530        cx: &mut Context<Editor>,
21531    ) -> bool;
21532
21533    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21534
21535    fn sort_completions(&self) -> bool {
21536        true
21537    }
21538
21539    fn filter_completions(&self) -> bool {
21540        true
21541    }
21542}
21543
21544pub trait CodeActionProvider {
21545    fn id(&self) -> Arc<str>;
21546
21547    fn code_actions(
21548        &self,
21549        buffer: &Entity<Buffer>,
21550        range: Range<text::Anchor>,
21551        window: &mut Window,
21552        cx: &mut App,
21553    ) -> Task<Result<Vec<CodeAction>>>;
21554
21555    fn apply_code_action(
21556        &self,
21557        buffer_handle: Entity<Buffer>,
21558        action: CodeAction,
21559        excerpt_id: ExcerptId,
21560        push_to_history: bool,
21561        window: &mut Window,
21562        cx: &mut App,
21563    ) -> Task<Result<ProjectTransaction>>;
21564}
21565
21566impl CodeActionProvider for Entity<Project> {
21567    fn id(&self) -> Arc<str> {
21568        "project".into()
21569    }
21570
21571    fn code_actions(
21572        &self,
21573        buffer: &Entity<Buffer>,
21574        range: Range<text::Anchor>,
21575        _window: &mut Window,
21576        cx: &mut App,
21577    ) -> Task<Result<Vec<CodeAction>>> {
21578        self.update(cx, |project, cx| {
21579            let code_lens = project.code_lens(buffer, range.clone(), cx);
21580            let code_actions = project.code_actions(buffer, range, None, cx);
21581            cx.background_spawn(async move {
21582                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21583                Ok(code_lens
21584                    .context("code lens fetch")?
21585                    .into_iter()
21586                    .chain(code_actions.context("code action fetch")?)
21587                    .collect())
21588            })
21589        })
21590    }
21591
21592    fn apply_code_action(
21593        &self,
21594        buffer_handle: Entity<Buffer>,
21595        action: CodeAction,
21596        _excerpt_id: ExcerptId,
21597        push_to_history: bool,
21598        _window: &mut Window,
21599        cx: &mut App,
21600    ) -> Task<Result<ProjectTransaction>> {
21601        self.update(cx, |project, cx| {
21602            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21603        })
21604    }
21605}
21606
21607fn snippet_completions(
21608    project: &Project,
21609    buffer: &Entity<Buffer>,
21610    buffer_position: text::Anchor,
21611    cx: &mut App,
21612) -> Task<Result<CompletionResponse>> {
21613    let languages = buffer.read(cx).languages_at(buffer_position);
21614    let snippet_store = project.snippets().read(cx);
21615
21616    let scopes: Vec<_> = languages
21617        .iter()
21618        .filter_map(|language| {
21619            let language_name = language.lsp_id();
21620            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21621
21622            if snippets.is_empty() {
21623                None
21624            } else {
21625                Some((language.default_scope(), snippets))
21626            }
21627        })
21628        .collect();
21629
21630    if scopes.is_empty() {
21631        return Task::ready(Ok(CompletionResponse {
21632            completions: vec![],
21633            is_incomplete: false,
21634        }));
21635    }
21636
21637    let snapshot = buffer.read(cx).text_snapshot();
21638    let chars: String = snapshot
21639        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21640        .collect();
21641    let executor = cx.background_executor().clone();
21642
21643    cx.background_spawn(async move {
21644        let mut is_incomplete = false;
21645        let mut completions: Vec<Completion> = Vec::new();
21646        for (scope, snippets) in scopes.into_iter() {
21647            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21648            let mut last_word = chars
21649                .chars()
21650                .take_while(|c| classifier.is_word(*c))
21651                .collect::<String>();
21652            last_word = last_word.chars().rev().collect();
21653
21654            if last_word.is_empty() {
21655                return Ok(CompletionResponse {
21656                    completions: vec![],
21657                    is_incomplete: true,
21658                });
21659            }
21660
21661            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21662            let to_lsp = |point: &text::Anchor| {
21663                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21664                point_to_lsp(end)
21665            };
21666            let lsp_end = to_lsp(&buffer_position);
21667
21668            let candidates = snippets
21669                .iter()
21670                .enumerate()
21671                .flat_map(|(ix, snippet)| {
21672                    snippet
21673                        .prefix
21674                        .iter()
21675                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21676                })
21677                .collect::<Vec<StringMatchCandidate>>();
21678
21679            const MAX_RESULTS: usize = 100;
21680            let mut matches = fuzzy::match_strings(
21681                &candidates,
21682                &last_word,
21683                last_word.chars().any(|c| c.is_uppercase()),
21684                true,
21685                MAX_RESULTS,
21686                &Default::default(),
21687                executor.clone(),
21688            )
21689            .await;
21690
21691            if matches.len() >= MAX_RESULTS {
21692                is_incomplete = true;
21693            }
21694
21695            // Remove all candidates where the query's start does not match the start of any word in the candidate
21696            if let Some(query_start) = last_word.chars().next() {
21697                matches.retain(|string_match| {
21698                    split_words(&string_match.string).any(|word| {
21699                        // Check that the first codepoint of the word as lowercase matches the first
21700                        // codepoint of the query as lowercase
21701                        word.chars()
21702                            .flat_map(|codepoint| codepoint.to_lowercase())
21703                            .zip(query_start.to_lowercase())
21704                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21705                    })
21706                });
21707            }
21708
21709            let matched_strings = matches
21710                .into_iter()
21711                .map(|m| m.string)
21712                .collect::<HashSet<_>>();
21713
21714            completions.extend(snippets.iter().filter_map(|snippet| {
21715                let matching_prefix = snippet
21716                    .prefix
21717                    .iter()
21718                    .find(|prefix| matched_strings.contains(*prefix))?;
21719                let start = as_offset - last_word.len();
21720                let start = snapshot.anchor_before(start);
21721                let range = start..buffer_position;
21722                let lsp_start = to_lsp(&start);
21723                let lsp_range = lsp::Range {
21724                    start: lsp_start,
21725                    end: lsp_end,
21726                };
21727                Some(Completion {
21728                    replace_range: range,
21729                    new_text: snippet.body.clone(),
21730                    source: CompletionSource::Lsp {
21731                        insert_range: None,
21732                        server_id: LanguageServerId(usize::MAX),
21733                        resolved: true,
21734                        lsp_completion: Box::new(lsp::CompletionItem {
21735                            label: snippet.prefix.first().unwrap().clone(),
21736                            kind: Some(CompletionItemKind::SNIPPET),
21737                            label_details: snippet.description.as_ref().map(|description| {
21738                                lsp::CompletionItemLabelDetails {
21739                                    detail: Some(description.clone()),
21740                                    description: None,
21741                                }
21742                            }),
21743                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21744                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21745                                lsp::InsertReplaceEdit {
21746                                    new_text: snippet.body.clone(),
21747                                    insert: lsp_range,
21748                                    replace: lsp_range,
21749                                },
21750                            )),
21751                            filter_text: Some(snippet.body.clone()),
21752                            sort_text: Some(char::MAX.to_string()),
21753                            ..lsp::CompletionItem::default()
21754                        }),
21755                        lsp_defaults: None,
21756                    },
21757                    label: CodeLabel {
21758                        text: matching_prefix.clone(),
21759                        runs: Vec::new(),
21760                        filter_range: 0..matching_prefix.len(),
21761                    },
21762                    icon_path: None,
21763                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21764                        single_line: snippet.name.clone().into(),
21765                        plain_text: snippet
21766                            .description
21767                            .clone()
21768                            .map(|description| description.into()),
21769                    }),
21770                    insert_text_mode: None,
21771                    confirm: None,
21772                })
21773            }))
21774        }
21775
21776        Ok(CompletionResponse {
21777            completions,
21778            is_incomplete,
21779        })
21780    })
21781}
21782
21783impl CompletionProvider for Entity<Project> {
21784    fn completions(
21785        &self,
21786        _excerpt_id: ExcerptId,
21787        buffer: &Entity<Buffer>,
21788        buffer_position: text::Anchor,
21789        options: CompletionContext,
21790        _window: &mut Window,
21791        cx: &mut Context<Editor>,
21792    ) -> Task<Result<Vec<CompletionResponse>>> {
21793        self.update(cx, |project, cx| {
21794            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21795            let project_completions = project.completions(buffer, buffer_position, options, cx);
21796            cx.background_spawn(async move {
21797                let mut responses = project_completions.await?;
21798                let snippets = snippets.await?;
21799                if !snippets.completions.is_empty() {
21800                    responses.push(snippets);
21801                }
21802                Ok(responses)
21803            })
21804        })
21805    }
21806
21807    fn resolve_completions(
21808        &self,
21809        buffer: Entity<Buffer>,
21810        completion_indices: Vec<usize>,
21811        completions: Rc<RefCell<Box<[Completion]>>>,
21812        cx: &mut Context<Editor>,
21813    ) -> Task<Result<bool>> {
21814        self.update(cx, |project, cx| {
21815            project.lsp_store().update(cx, |lsp_store, cx| {
21816                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21817            })
21818        })
21819    }
21820
21821    fn apply_additional_edits_for_completion(
21822        &self,
21823        buffer: Entity<Buffer>,
21824        completions: Rc<RefCell<Box<[Completion]>>>,
21825        completion_index: usize,
21826        push_to_history: bool,
21827        cx: &mut Context<Editor>,
21828    ) -> Task<Result<Option<language::Transaction>>> {
21829        self.update(cx, |project, cx| {
21830            project.lsp_store().update(cx, |lsp_store, cx| {
21831                lsp_store.apply_additional_edits_for_completion(
21832                    buffer,
21833                    completions,
21834                    completion_index,
21835                    push_to_history,
21836                    cx,
21837                )
21838            })
21839        })
21840    }
21841
21842    fn is_completion_trigger(
21843        &self,
21844        buffer: &Entity<Buffer>,
21845        position: language::Anchor,
21846        text: &str,
21847        trigger_in_words: bool,
21848        menu_is_open: bool,
21849        cx: &mut Context<Editor>,
21850    ) -> bool {
21851        let mut chars = text.chars();
21852        let char = if let Some(char) = chars.next() {
21853            char
21854        } else {
21855            return false;
21856        };
21857        if chars.next().is_some() {
21858            return false;
21859        }
21860
21861        let buffer = buffer.read(cx);
21862        let snapshot = buffer.snapshot();
21863        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21864            return false;
21865        }
21866        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21867        if trigger_in_words && classifier.is_word(char) {
21868            return true;
21869        }
21870
21871        buffer.completion_triggers().contains(text)
21872    }
21873}
21874
21875impl SemanticsProvider for Entity<Project> {
21876    fn hover(
21877        &self,
21878        buffer: &Entity<Buffer>,
21879        position: text::Anchor,
21880        cx: &mut App,
21881    ) -> Option<Task<Vec<project::Hover>>> {
21882        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21883    }
21884
21885    fn document_highlights(
21886        &self,
21887        buffer: &Entity<Buffer>,
21888        position: text::Anchor,
21889        cx: &mut App,
21890    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21891        Some(self.update(cx, |project, cx| {
21892            project.document_highlights(buffer, position, cx)
21893        }))
21894    }
21895
21896    fn definitions(
21897        &self,
21898        buffer: &Entity<Buffer>,
21899        position: text::Anchor,
21900        kind: GotoDefinitionKind,
21901        cx: &mut App,
21902    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21903        Some(self.update(cx, |project, cx| match kind {
21904            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21905            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21906            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21907            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21908        }))
21909    }
21910
21911    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21912        // TODO: make this work for remote projects
21913        self.update(cx, |project, cx| {
21914            if project
21915                .active_debug_session(cx)
21916                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21917            {
21918                return true;
21919            }
21920
21921            buffer.update(cx, |buffer, cx| {
21922                project.any_language_server_supports_inlay_hints(buffer, cx)
21923            })
21924        })
21925    }
21926
21927    fn inline_values(
21928        &self,
21929        buffer_handle: Entity<Buffer>,
21930        range: Range<text::Anchor>,
21931        cx: &mut App,
21932    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21933        self.update(cx, |project, cx| {
21934            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21935
21936            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21937        })
21938    }
21939
21940    fn inlay_hints(
21941        &self,
21942        buffer_handle: Entity<Buffer>,
21943        range: Range<text::Anchor>,
21944        cx: &mut App,
21945    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21946        Some(self.update(cx, |project, cx| {
21947            project.inlay_hints(buffer_handle, range, cx)
21948        }))
21949    }
21950
21951    fn resolve_inlay_hint(
21952        &self,
21953        hint: InlayHint,
21954        buffer_handle: Entity<Buffer>,
21955        server_id: LanguageServerId,
21956        cx: &mut App,
21957    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21958        Some(self.update(cx, |project, cx| {
21959            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21960        }))
21961    }
21962
21963    fn range_for_rename(
21964        &self,
21965        buffer: &Entity<Buffer>,
21966        position: text::Anchor,
21967        cx: &mut App,
21968    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21969        Some(self.update(cx, |project, cx| {
21970            let buffer = buffer.clone();
21971            let task = project.prepare_rename(buffer.clone(), position, cx);
21972            cx.spawn(async move |_, cx| {
21973                Ok(match task.await? {
21974                    PrepareRenameResponse::Success(range) => Some(range),
21975                    PrepareRenameResponse::InvalidPosition => None,
21976                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21977                        // Fallback on using TreeSitter info to determine identifier range
21978                        buffer.read_with(cx, |buffer, _| {
21979                            let snapshot = buffer.snapshot();
21980                            let (range, kind) = snapshot.surrounding_word(position);
21981                            if kind != Some(CharKind::Word) {
21982                                return None;
21983                            }
21984                            Some(
21985                                snapshot.anchor_before(range.start)
21986                                    ..snapshot.anchor_after(range.end),
21987                            )
21988                        })?
21989                    }
21990                })
21991            })
21992        }))
21993    }
21994
21995    fn perform_rename(
21996        &self,
21997        buffer: &Entity<Buffer>,
21998        position: text::Anchor,
21999        new_name: String,
22000        cx: &mut App,
22001    ) -> Option<Task<Result<ProjectTransaction>>> {
22002        Some(self.update(cx, |project, cx| {
22003            project.perform_rename(buffer.clone(), position, new_name, cx)
22004        }))
22005    }
22006}
22007
22008fn inlay_hint_settings(
22009    location: Anchor,
22010    snapshot: &MultiBufferSnapshot,
22011    cx: &mut Context<Editor>,
22012) -> InlayHintSettings {
22013    let file = snapshot.file_at(location);
22014    let language = snapshot.language_at(location).map(|l| l.name());
22015    language_settings(language, file, cx).inlay_hints
22016}
22017
22018fn consume_contiguous_rows(
22019    contiguous_row_selections: &mut Vec<Selection<Point>>,
22020    selection: &Selection<Point>,
22021    display_map: &DisplaySnapshot,
22022    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22023) -> (MultiBufferRow, MultiBufferRow) {
22024    contiguous_row_selections.push(selection.clone());
22025    let start_row = MultiBufferRow(selection.start.row);
22026    let mut end_row = ending_row(selection, display_map);
22027
22028    while let Some(next_selection) = selections.peek() {
22029        if next_selection.start.row <= end_row.0 {
22030            end_row = ending_row(next_selection, display_map);
22031            contiguous_row_selections.push(selections.next().unwrap().clone());
22032        } else {
22033            break;
22034        }
22035    }
22036    (start_row, end_row)
22037}
22038
22039fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22040    if next_selection.end.column > 0 || next_selection.is_empty() {
22041        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22042    } else {
22043        MultiBufferRow(next_selection.end.row)
22044    }
22045}
22046
22047impl EditorSnapshot {
22048    pub fn remote_selections_in_range<'a>(
22049        &'a self,
22050        range: &'a Range<Anchor>,
22051        collaboration_hub: &dyn CollaborationHub,
22052        cx: &'a App,
22053    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22054        let participant_names = collaboration_hub.user_names(cx);
22055        let participant_indices = collaboration_hub.user_participant_indices(cx);
22056        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22057        let collaborators_by_replica_id = collaborators_by_peer_id
22058            .values()
22059            .map(|collaborator| (collaborator.replica_id, collaborator))
22060            .collect::<HashMap<_, _>>();
22061        self.buffer_snapshot
22062            .selections_in_range(range, false)
22063            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22064                if replica_id == AGENT_REPLICA_ID {
22065                    Some(RemoteSelection {
22066                        replica_id,
22067                        selection,
22068                        cursor_shape,
22069                        line_mode,
22070                        collaborator_id: CollaboratorId::Agent,
22071                        user_name: Some("Agent".into()),
22072                        color: cx.theme().players().agent(),
22073                    })
22074                } else {
22075                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22076                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22077                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22078                    Some(RemoteSelection {
22079                        replica_id,
22080                        selection,
22081                        cursor_shape,
22082                        line_mode,
22083                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22084                        user_name,
22085                        color: if let Some(index) = participant_index {
22086                            cx.theme().players().color_for_participant(index.0)
22087                        } else {
22088                            cx.theme().players().absent()
22089                        },
22090                    })
22091                }
22092            })
22093    }
22094
22095    pub fn hunks_for_ranges(
22096        &self,
22097        ranges: impl IntoIterator<Item = Range<Point>>,
22098    ) -> Vec<MultiBufferDiffHunk> {
22099        let mut hunks = Vec::new();
22100        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22101            HashMap::default();
22102        for query_range in ranges {
22103            let query_rows =
22104                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22105            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22106                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22107            ) {
22108                // Include deleted hunks that are adjacent to the query range, because
22109                // otherwise they would be missed.
22110                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22111                if hunk.status().is_deleted() {
22112                    intersects_range |= hunk.row_range.start == query_rows.end;
22113                    intersects_range |= hunk.row_range.end == query_rows.start;
22114                }
22115                if intersects_range {
22116                    if !processed_buffer_rows
22117                        .entry(hunk.buffer_id)
22118                        .or_default()
22119                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22120                    {
22121                        continue;
22122                    }
22123                    hunks.push(hunk);
22124                }
22125            }
22126        }
22127
22128        hunks
22129    }
22130
22131    fn display_diff_hunks_for_rows<'a>(
22132        &'a self,
22133        display_rows: Range<DisplayRow>,
22134        folded_buffers: &'a HashSet<BufferId>,
22135    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22136        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22137        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22138
22139        self.buffer_snapshot
22140            .diff_hunks_in_range(buffer_start..buffer_end)
22141            .filter_map(|hunk| {
22142                if folded_buffers.contains(&hunk.buffer_id) {
22143                    return None;
22144                }
22145
22146                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22147                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22148
22149                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22150                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22151
22152                let display_hunk = if hunk_display_start.column() != 0 {
22153                    DisplayDiffHunk::Folded {
22154                        display_row: hunk_display_start.row(),
22155                    }
22156                } else {
22157                    let mut end_row = hunk_display_end.row();
22158                    if hunk_display_end.column() > 0 {
22159                        end_row.0 += 1;
22160                    }
22161                    let is_created_file = hunk.is_created_file();
22162                    DisplayDiffHunk::Unfolded {
22163                        status: hunk.status(),
22164                        diff_base_byte_range: hunk.diff_base_byte_range,
22165                        display_row_range: hunk_display_start.row()..end_row,
22166                        multi_buffer_range: Anchor::range_in_buffer(
22167                            hunk.excerpt_id,
22168                            hunk.buffer_id,
22169                            hunk.buffer_range,
22170                        ),
22171                        is_created_file,
22172                    }
22173                };
22174
22175                Some(display_hunk)
22176            })
22177    }
22178
22179    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22180        self.display_snapshot.buffer_snapshot.language_at(position)
22181    }
22182
22183    pub fn is_focused(&self) -> bool {
22184        self.is_focused
22185    }
22186
22187    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22188        self.placeholder_text.as_ref()
22189    }
22190
22191    pub fn scroll_position(&self) -> gpui::Point<f32> {
22192        self.scroll_anchor.scroll_position(&self.display_snapshot)
22193    }
22194
22195    fn gutter_dimensions(
22196        &self,
22197        font_id: FontId,
22198        font_size: Pixels,
22199        max_line_number_width: Pixels,
22200        cx: &App,
22201    ) -> Option<GutterDimensions> {
22202        if !self.show_gutter {
22203            return None;
22204        }
22205
22206        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22207        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22208
22209        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22210            matches!(
22211                ProjectSettings::get_global(cx).git.git_gutter,
22212                Some(GitGutterSetting::TrackedFiles)
22213            )
22214        });
22215        let gutter_settings = EditorSettings::get_global(cx).gutter;
22216        let show_line_numbers = self
22217            .show_line_numbers
22218            .unwrap_or(gutter_settings.line_numbers);
22219        let line_gutter_width = if show_line_numbers {
22220            // Avoid flicker-like gutter resizes when the line number gains another digit by
22221            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22222            let min_width_for_number_on_gutter =
22223                ch_advance * gutter_settings.min_line_number_digits as f32;
22224            max_line_number_width.max(min_width_for_number_on_gutter)
22225        } else {
22226            0.0.into()
22227        };
22228
22229        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22230        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22231
22232        let git_blame_entries_width =
22233            self.git_blame_gutter_max_author_length
22234                .map(|max_author_length| {
22235                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22236                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22237
22238                    /// The number of characters to dedicate to gaps and margins.
22239                    const SPACING_WIDTH: usize = 4;
22240
22241                    let max_char_count = max_author_length.min(renderer.max_author_length())
22242                        + ::git::SHORT_SHA_LENGTH
22243                        + MAX_RELATIVE_TIMESTAMP.len()
22244                        + SPACING_WIDTH;
22245
22246                    ch_advance * max_char_count
22247                });
22248
22249        let is_singleton = self.buffer_snapshot.is_singleton();
22250
22251        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22252        left_padding += if !is_singleton {
22253            ch_width * 4.0
22254        } else if show_runnables || show_breakpoints {
22255            ch_width * 3.0
22256        } else if show_git_gutter && show_line_numbers {
22257            ch_width * 2.0
22258        } else if show_git_gutter || show_line_numbers {
22259            ch_width
22260        } else {
22261            px(0.)
22262        };
22263
22264        let shows_folds = is_singleton && gutter_settings.folds;
22265
22266        let right_padding = if shows_folds && show_line_numbers {
22267            ch_width * 4.0
22268        } else if shows_folds || (!is_singleton && show_line_numbers) {
22269            ch_width * 3.0
22270        } else if show_line_numbers {
22271            ch_width
22272        } else {
22273            px(0.)
22274        };
22275
22276        Some(GutterDimensions {
22277            left_padding,
22278            right_padding,
22279            width: line_gutter_width + left_padding + right_padding,
22280            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22281            git_blame_entries_width,
22282        })
22283    }
22284
22285    pub fn render_crease_toggle(
22286        &self,
22287        buffer_row: MultiBufferRow,
22288        row_contains_cursor: bool,
22289        editor: Entity<Editor>,
22290        window: &mut Window,
22291        cx: &mut App,
22292    ) -> Option<AnyElement> {
22293        let folded = self.is_line_folded(buffer_row);
22294        let mut is_foldable = false;
22295
22296        if let Some(crease) = self
22297            .crease_snapshot
22298            .query_row(buffer_row, &self.buffer_snapshot)
22299        {
22300            is_foldable = true;
22301            match crease {
22302                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22303                    if let Some(render_toggle) = render_toggle {
22304                        let toggle_callback =
22305                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22306                                if folded {
22307                                    editor.update(cx, |editor, cx| {
22308                                        editor.fold_at(buffer_row, window, cx)
22309                                    });
22310                                } else {
22311                                    editor.update(cx, |editor, cx| {
22312                                        editor.unfold_at(buffer_row, window, cx)
22313                                    });
22314                                }
22315                            });
22316                        return Some((render_toggle)(
22317                            buffer_row,
22318                            folded,
22319                            toggle_callback,
22320                            window,
22321                            cx,
22322                        ));
22323                    }
22324                }
22325            }
22326        }
22327
22328        is_foldable |= self.starts_indent(buffer_row);
22329
22330        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22331            Some(
22332                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22333                    .toggle_state(folded)
22334                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22335                        if folded {
22336                            this.unfold_at(buffer_row, window, cx);
22337                        } else {
22338                            this.fold_at(buffer_row, window, cx);
22339                        }
22340                    }))
22341                    .into_any_element(),
22342            )
22343        } else {
22344            None
22345        }
22346    }
22347
22348    pub fn render_crease_trailer(
22349        &self,
22350        buffer_row: MultiBufferRow,
22351        window: &mut Window,
22352        cx: &mut App,
22353    ) -> Option<AnyElement> {
22354        let folded = self.is_line_folded(buffer_row);
22355        if let Crease::Inline { render_trailer, .. } = self
22356            .crease_snapshot
22357            .query_row(buffer_row, &self.buffer_snapshot)?
22358        {
22359            let render_trailer = render_trailer.as_ref()?;
22360            Some(render_trailer(buffer_row, folded, window, cx))
22361        } else {
22362            None
22363        }
22364    }
22365}
22366
22367impl Deref for EditorSnapshot {
22368    type Target = DisplaySnapshot;
22369
22370    fn deref(&self) -> &Self::Target {
22371        &self.display_snapshot
22372    }
22373}
22374
22375#[derive(Clone, Debug, PartialEq, Eq)]
22376pub enum EditorEvent {
22377    InputIgnored {
22378        text: Arc<str>,
22379    },
22380    InputHandled {
22381        utf16_range_to_replace: Option<Range<isize>>,
22382        text: Arc<str>,
22383    },
22384    ExcerptsAdded {
22385        buffer: Entity<Buffer>,
22386        predecessor: ExcerptId,
22387        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22388    },
22389    ExcerptsRemoved {
22390        ids: Vec<ExcerptId>,
22391        removed_buffer_ids: Vec<BufferId>,
22392    },
22393    BufferFoldToggled {
22394        ids: Vec<ExcerptId>,
22395        folded: bool,
22396    },
22397    ExcerptsEdited {
22398        ids: Vec<ExcerptId>,
22399    },
22400    ExcerptsExpanded {
22401        ids: Vec<ExcerptId>,
22402    },
22403    BufferEdited,
22404    Edited {
22405        transaction_id: clock::Lamport,
22406    },
22407    Reparsed(BufferId),
22408    Focused,
22409    FocusedIn,
22410    Blurred,
22411    DirtyChanged,
22412    Saved,
22413    TitleChanged,
22414    DiffBaseChanged,
22415    SelectionsChanged {
22416        local: bool,
22417    },
22418    ScrollPositionChanged {
22419        local: bool,
22420        autoscroll: bool,
22421    },
22422    Closed,
22423    TransactionUndone {
22424        transaction_id: clock::Lamport,
22425    },
22426    TransactionBegun {
22427        transaction_id: clock::Lamport,
22428    },
22429    Reloaded,
22430    CursorShapeChanged,
22431    PushedToNavHistory {
22432        anchor: Anchor,
22433        is_deactivate: bool,
22434    },
22435}
22436
22437impl EventEmitter<EditorEvent> for Editor {}
22438
22439impl Focusable for Editor {
22440    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22441        self.focus_handle.clone()
22442    }
22443}
22444
22445impl Render for Editor {
22446    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22447        let settings = ThemeSettings::get_global(cx);
22448
22449        let mut text_style = match self.mode {
22450            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22451                color: cx.theme().colors().editor_foreground,
22452                font_family: settings.ui_font.family.clone(),
22453                font_features: settings.ui_font.features.clone(),
22454                font_fallbacks: settings.ui_font.fallbacks.clone(),
22455                font_size: rems(0.875).into(),
22456                font_weight: settings.ui_font.weight,
22457                line_height: relative(settings.buffer_line_height.value()),
22458                ..Default::default()
22459            },
22460            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22461                color: cx.theme().colors().editor_foreground,
22462                font_family: settings.buffer_font.family.clone(),
22463                font_features: settings.buffer_font.features.clone(),
22464                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22465                font_size: settings.buffer_font_size(cx).into(),
22466                font_weight: settings.buffer_font.weight,
22467                line_height: relative(settings.buffer_line_height.value()),
22468                ..Default::default()
22469            },
22470        };
22471        if let Some(text_style_refinement) = &self.text_style_refinement {
22472            text_style.refine(text_style_refinement)
22473        }
22474
22475        let background = match self.mode {
22476            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22477            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22478            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22479            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22480        };
22481
22482        EditorElement::new(
22483            &cx.entity(),
22484            EditorStyle {
22485                background,
22486                border: cx.theme().colors().border,
22487                local_player: cx.theme().players().local(),
22488                text: text_style,
22489                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22490                syntax: cx.theme().syntax().clone(),
22491                status: cx.theme().status().clone(),
22492                inlay_hints_style: make_inlay_hints_style(cx),
22493                inline_completion_styles: make_suggestion_styles(cx),
22494                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22495                show_underlines: self.diagnostics_enabled(),
22496            },
22497        )
22498    }
22499}
22500
22501impl EntityInputHandler for Editor {
22502    fn text_for_range(
22503        &mut self,
22504        range_utf16: Range<usize>,
22505        adjusted_range: &mut Option<Range<usize>>,
22506        _: &mut Window,
22507        cx: &mut Context<Self>,
22508    ) -> Option<String> {
22509        let snapshot = self.buffer.read(cx).read(cx);
22510        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22511        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22512        if (start.0..end.0) != range_utf16 {
22513            adjusted_range.replace(start.0..end.0);
22514        }
22515        Some(snapshot.text_for_range(start..end).collect())
22516    }
22517
22518    fn selected_text_range(
22519        &mut self,
22520        ignore_disabled_input: bool,
22521        _: &mut Window,
22522        cx: &mut Context<Self>,
22523    ) -> Option<UTF16Selection> {
22524        // Prevent the IME menu from appearing when holding down an alphabetic key
22525        // while input is disabled.
22526        if !ignore_disabled_input && !self.input_enabled {
22527            return None;
22528        }
22529
22530        let selection = self.selections.newest::<OffsetUtf16>(cx);
22531        let range = selection.range();
22532
22533        Some(UTF16Selection {
22534            range: range.start.0..range.end.0,
22535            reversed: selection.reversed,
22536        })
22537    }
22538
22539    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22540        let snapshot = self.buffer.read(cx).read(cx);
22541        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22542        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22543    }
22544
22545    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22546        self.clear_highlights::<InputComposition>(cx);
22547        self.ime_transaction.take();
22548    }
22549
22550    fn replace_text_in_range(
22551        &mut self,
22552        range_utf16: Option<Range<usize>>,
22553        text: &str,
22554        window: &mut Window,
22555        cx: &mut Context<Self>,
22556    ) {
22557        if !self.input_enabled {
22558            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22559            return;
22560        }
22561
22562        self.transact(window, cx, |this, window, cx| {
22563            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22564                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22565                Some(this.selection_replacement_ranges(range_utf16, cx))
22566            } else {
22567                this.marked_text_ranges(cx)
22568            };
22569
22570            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22571                let newest_selection_id = this.selections.newest_anchor().id;
22572                this.selections
22573                    .all::<OffsetUtf16>(cx)
22574                    .iter()
22575                    .zip(ranges_to_replace.iter())
22576                    .find_map(|(selection, range)| {
22577                        if selection.id == newest_selection_id {
22578                            Some(
22579                                (range.start.0 as isize - selection.head().0 as isize)
22580                                    ..(range.end.0 as isize - selection.head().0 as isize),
22581                            )
22582                        } else {
22583                            None
22584                        }
22585                    })
22586            });
22587
22588            cx.emit(EditorEvent::InputHandled {
22589                utf16_range_to_replace: range_to_replace,
22590                text: text.into(),
22591            });
22592
22593            if let Some(new_selected_ranges) = new_selected_ranges {
22594                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22595                    selections.select_ranges(new_selected_ranges)
22596                });
22597                this.backspace(&Default::default(), window, cx);
22598            }
22599
22600            this.handle_input(text, window, cx);
22601        });
22602
22603        if let Some(transaction) = self.ime_transaction {
22604            self.buffer.update(cx, |buffer, cx| {
22605                buffer.group_until_transaction(transaction, cx);
22606            });
22607        }
22608
22609        self.unmark_text(window, cx);
22610    }
22611
22612    fn replace_and_mark_text_in_range(
22613        &mut self,
22614        range_utf16: Option<Range<usize>>,
22615        text: &str,
22616        new_selected_range_utf16: Option<Range<usize>>,
22617        window: &mut Window,
22618        cx: &mut Context<Self>,
22619    ) {
22620        if !self.input_enabled {
22621            return;
22622        }
22623
22624        let transaction = self.transact(window, cx, |this, window, cx| {
22625            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22626                let snapshot = this.buffer.read(cx).read(cx);
22627                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22628                    for marked_range in &mut marked_ranges {
22629                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22630                        marked_range.start.0 += relative_range_utf16.start;
22631                        marked_range.start =
22632                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22633                        marked_range.end =
22634                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22635                    }
22636                }
22637                Some(marked_ranges)
22638            } else if let Some(range_utf16) = range_utf16 {
22639                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22640                Some(this.selection_replacement_ranges(range_utf16, cx))
22641            } else {
22642                None
22643            };
22644
22645            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22646                let newest_selection_id = this.selections.newest_anchor().id;
22647                this.selections
22648                    .all::<OffsetUtf16>(cx)
22649                    .iter()
22650                    .zip(ranges_to_replace.iter())
22651                    .find_map(|(selection, range)| {
22652                        if selection.id == newest_selection_id {
22653                            Some(
22654                                (range.start.0 as isize - selection.head().0 as isize)
22655                                    ..(range.end.0 as isize - selection.head().0 as isize),
22656                            )
22657                        } else {
22658                            None
22659                        }
22660                    })
22661            });
22662
22663            cx.emit(EditorEvent::InputHandled {
22664                utf16_range_to_replace: range_to_replace,
22665                text: text.into(),
22666            });
22667
22668            if let Some(ranges) = ranges_to_replace {
22669                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22670                    s.select_ranges(ranges)
22671                });
22672            }
22673
22674            let marked_ranges = {
22675                let snapshot = this.buffer.read(cx).read(cx);
22676                this.selections
22677                    .disjoint_anchors()
22678                    .iter()
22679                    .map(|selection| {
22680                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22681                    })
22682                    .collect::<Vec<_>>()
22683            };
22684
22685            if text.is_empty() {
22686                this.unmark_text(window, cx);
22687            } else {
22688                this.highlight_text::<InputComposition>(
22689                    marked_ranges.clone(),
22690                    HighlightStyle {
22691                        underline: Some(UnderlineStyle {
22692                            thickness: px(1.),
22693                            color: None,
22694                            wavy: false,
22695                        }),
22696                        ..Default::default()
22697                    },
22698                    cx,
22699                );
22700            }
22701
22702            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22703            let use_autoclose = this.use_autoclose;
22704            let use_auto_surround = this.use_auto_surround;
22705            this.set_use_autoclose(false);
22706            this.set_use_auto_surround(false);
22707            this.handle_input(text, window, cx);
22708            this.set_use_autoclose(use_autoclose);
22709            this.set_use_auto_surround(use_auto_surround);
22710
22711            if let Some(new_selected_range) = new_selected_range_utf16 {
22712                let snapshot = this.buffer.read(cx).read(cx);
22713                let new_selected_ranges = marked_ranges
22714                    .into_iter()
22715                    .map(|marked_range| {
22716                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22717                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22718                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22719                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22720                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22721                    })
22722                    .collect::<Vec<_>>();
22723
22724                drop(snapshot);
22725                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22726                    selections.select_ranges(new_selected_ranges)
22727                });
22728            }
22729        });
22730
22731        self.ime_transaction = self.ime_transaction.or(transaction);
22732        if let Some(transaction) = self.ime_transaction {
22733            self.buffer.update(cx, |buffer, cx| {
22734                buffer.group_until_transaction(transaction, cx);
22735            });
22736        }
22737
22738        if self.text_highlights::<InputComposition>(cx).is_none() {
22739            self.ime_transaction.take();
22740        }
22741    }
22742
22743    fn bounds_for_range(
22744        &mut self,
22745        range_utf16: Range<usize>,
22746        element_bounds: gpui::Bounds<Pixels>,
22747        window: &mut Window,
22748        cx: &mut Context<Self>,
22749    ) -> Option<gpui::Bounds<Pixels>> {
22750        let text_layout_details = self.text_layout_details(window);
22751        let CharacterDimensions {
22752            em_width,
22753            em_advance,
22754            line_height,
22755        } = self.character_dimensions(window);
22756
22757        let snapshot = self.snapshot(window, cx);
22758        let scroll_position = snapshot.scroll_position();
22759        let scroll_left = scroll_position.x * em_advance;
22760
22761        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22762        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22763            + self.gutter_dimensions.full_width();
22764        let y = line_height * (start.row().as_f32() - scroll_position.y);
22765
22766        Some(Bounds {
22767            origin: element_bounds.origin + point(x, y),
22768            size: size(em_width, line_height),
22769        })
22770    }
22771
22772    fn character_index_for_point(
22773        &mut self,
22774        point: gpui::Point<Pixels>,
22775        _window: &mut Window,
22776        _cx: &mut Context<Self>,
22777    ) -> Option<usize> {
22778        let position_map = self.last_position_map.as_ref()?;
22779        if !position_map.text_hitbox.contains(&point) {
22780            return None;
22781        }
22782        let display_point = position_map.point_for_position(point).previous_valid;
22783        let anchor = position_map
22784            .snapshot
22785            .display_point_to_anchor(display_point, Bias::Left);
22786        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22787        Some(utf16_offset.0)
22788    }
22789}
22790
22791trait SelectionExt {
22792    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22793    fn spanned_rows(
22794        &self,
22795        include_end_if_at_line_start: bool,
22796        map: &DisplaySnapshot,
22797    ) -> Range<MultiBufferRow>;
22798}
22799
22800impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22801    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22802        let start = self
22803            .start
22804            .to_point(&map.buffer_snapshot)
22805            .to_display_point(map);
22806        let end = self
22807            .end
22808            .to_point(&map.buffer_snapshot)
22809            .to_display_point(map);
22810        if self.reversed {
22811            end..start
22812        } else {
22813            start..end
22814        }
22815    }
22816
22817    fn spanned_rows(
22818        &self,
22819        include_end_if_at_line_start: bool,
22820        map: &DisplaySnapshot,
22821    ) -> Range<MultiBufferRow> {
22822        let start = self.start.to_point(&map.buffer_snapshot);
22823        let mut end = self.end.to_point(&map.buffer_snapshot);
22824        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22825            end.row -= 1;
22826        }
22827
22828        let buffer_start = map.prev_line_boundary(start).0;
22829        let buffer_end = map.next_line_boundary(end).0;
22830        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22831    }
22832}
22833
22834impl<T: InvalidationRegion> InvalidationStack<T> {
22835    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22836    where
22837        S: Clone + ToOffset,
22838    {
22839        while let Some(region) = self.last() {
22840            let all_selections_inside_invalidation_ranges =
22841                if selections.len() == region.ranges().len() {
22842                    selections
22843                        .iter()
22844                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22845                        .all(|(selection, invalidation_range)| {
22846                            let head = selection.head().to_offset(buffer);
22847                            invalidation_range.start <= head && invalidation_range.end >= head
22848                        })
22849                } else {
22850                    false
22851                };
22852
22853            if all_selections_inside_invalidation_ranges {
22854                break;
22855            } else {
22856                self.pop();
22857            }
22858        }
22859    }
22860}
22861
22862impl<T> Default for InvalidationStack<T> {
22863    fn default() -> Self {
22864        Self(Default::default())
22865    }
22866}
22867
22868impl<T> Deref for InvalidationStack<T> {
22869    type Target = Vec<T>;
22870
22871    fn deref(&self) -> &Self::Target {
22872        &self.0
22873    }
22874}
22875
22876impl<T> DerefMut for InvalidationStack<T> {
22877    fn deref_mut(&mut self) -> &mut Self::Target {
22878        &mut self.0
22879    }
22880}
22881
22882impl InvalidationRegion for SnippetState {
22883    fn ranges(&self) -> &[Range<Anchor>] {
22884        &self.ranges[self.active_index]
22885    }
22886}
22887
22888fn inline_completion_edit_text(
22889    current_snapshot: &BufferSnapshot,
22890    edits: &[(Range<Anchor>, String)],
22891    edit_preview: &EditPreview,
22892    include_deletions: bool,
22893    cx: &App,
22894) -> HighlightedText {
22895    let edits = edits
22896        .iter()
22897        .map(|(anchor, text)| {
22898            (
22899                anchor.start.text_anchor..anchor.end.text_anchor,
22900                text.clone(),
22901            )
22902        })
22903        .collect::<Vec<_>>();
22904
22905    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22906}
22907
22908pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22909    match severity {
22910        lsp::DiagnosticSeverity::ERROR => colors.error,
22911        lsp::DiagnosticSeverity::WARNING => colors.warning,
22912        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22913        lsp::DiagnosticSeverity::HINT => colors.info,
22914        _ => colors.ignored,
22915    }
22916}
22917
22918pub fn styled_runs_for_code_label<'a>(
22919    label: &'a CodeLabel,
22920    syntax_theme: &'a theme::SyntaxTheme,
22921) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22922    let fade_out = HighlightStyle {
22923        fade_out: Some(0.35),
22924        ..Default::default()
22925    };
22926
22927    let mut prev_end = label.filter_range.end;
22928    label
22929        .runs
22930        .iter()
22931        .enumerate()
22932        .flat_map(move |(ix, (range, highlight_id))| {
22933            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22934                style
22935            } else {
22936                return Default::default();
22937            };
22938            let mut muted_style = style;
22939            muted_style.highlight(fade_out);
22940
22941            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22942            if range.start >= label.filter_range.end {
22943                if range.start > prev_end {
22944                    runs.push((prev_end..range.start, fade_out));
22945                }
22946                runs.push((range.clone(), muted_style));
22947            } else if range.end <= label.filter_range.end {
22948                runs.push((range.clone(), style));
22949            } else {
22950                runs.push((range.start..label.filter_range.end, style));
22951                runs.push((label.filter_range.end..range.end, muted_style));
22952            }
22953            prev_end = cmp::max(prev_end, range.end);
22954
22955            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22956                runs.push((prev_end..label.text.len(), fade_out));
22957            }
22958
22959            runs
22960        })
22961}
22962
22963pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22964    let mut prev_index = 0;
22965    let mut prev_codepoint: Option<char> = None;
22966    text.char_indices()
22967        .chain([(text.len(), '\0')])
22968        .filter_map(move |(index, codepoint)| {
22969            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22970            let is_boundary = index == text.len()
22971                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22972                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22973            if is_boundary {
22974                let chunk = &text[prev_index..index];
22975                prev_index = index;
22976                Some(chunk)
22977            } else {
22978                None
22979            }
22980        })
22981}
22982
22983pub trait RangeToAnchorExt: Sized {
22984    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22985
22986    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22987        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22988        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22989    }
22990}
22991
22992impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22993    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22994        let start_offset = self.start.to_offset(snapshot);
22995        let end_offset = self.end.to_offset(snapshot);
22996        if start_offset == end_offset {
22997            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22998        } else {
22999            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23000        }
23001    }
23002}
23003
23004pub trait RowExt {
23005    fn as_f32(&self) -> f32;
23006
23007    fn next_row(&self) -> Self;
23008
23009    fn previous_row(&self) -> Self;
23010
23011    fn minus(&self, other: Self) -> u32;
23012}
23013
23014impl RowExt for DisplayRow {
23015    fn as_f32(&self) -> f32 {
23016        self.0 as f32
23017    }
23018
23019    fn next_row(&self) -> Self {
23020        Self(self.0 + 1)
23021    }
23022
23023    fn previous_row(&self) -> Self {
23024        Self(self.0.saturating_sub(1))
23025    }
23026
23027    fn minus(&self, other: Self) -> u32 {
23028        self.0 - other.0
23029    }
23030}
23031
23032impl RowExt for MultiBufferRow {
23033    fn as_f32(&self) -> f32 {
23034        self.0 as f32
23035    }
23036
23037    fn next_row(&self) -> Self {
23038        Self(self.0 + 1)
23039    }
23040
23041    fn previous_row(&self) -> Self {
23042        Self(self.0.saturating_sub(1))
23043    }
23044
23045    fn minus(&self, other: Self) -> u32 {
23046        self.0 - other.0
23047    }
23048}
23049
23050trait RowRangeExt {
23051    type Row;
23052
23053    fn len(&self) -> usize;
23054
23055    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23056}
23057
23058impl RowRangeExt for Range<MultiBufferRow> {
23059    type Row = MultiBufferRow;
23060
23061    fn len(&self) -> usize {
23062        (self.end.0 - self.start.0) as usize
23063    }
23064
23065    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23066        (self.start.0..self.end.0).map(MultiBufferRow)
23067    }
23068}
23069
23070impl RowRangeExt for Range<DisplayRow> {
23071    type Row = DisplayRow;
23072
23073    fn len(&self) -> usize {
23074        (self.end.0 - self.start.0) as usize
23075    }
23076
23077    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23078        (self.start.0..self.end.0).map(DisplayRow)
23079    }
23080}
23081
23082/// If select range has more than one line, we
23083/// just point the cursor to range.start.
23084fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23085    if range.start.row == range.end.row {
23086        range
23087    } else {
23088        range.start..range.start
23089    }
23090}
23091pub struct KillRing(ClipboardItem);
23092impl Global for KillRing {}
23093
23094const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23095
23096enum BreakpointPromptEditAction {
23097    Log,
23098    Condition,
23099    HitCondition,
23100}
23101
23102struct BreakpointPromptEditor {
23103    pub(crate) prompt: Entity<Editor>,
23104    editor: WeakEntity<Editor>,
23105    breakpoint_anchor: Anchor,
23106    breakpoint: Breakpoint,
23107    edit_action: BreakpointPromptEditAction,
23108    block_ids: HashSet<CustomBlockId>,
23109    editor_margins: Arc<Mutex<EditorMargins>>,
23110    _subscriptions: Vec<Subscription>,
23111}
23112
23113impl BreakpointPromptEditor {
23114    const MAX_LINES: u8 = 4;
23115
23116    fn new(
23117        editor: WeakEntity<Editor>,
23118        breakpoint_anchor: Anchor,
23119        breakpoint: Breakpoint,
23120        edit_action: BreakpointPromptEditAction,
23121        window: &mut Window,
23122        cx: &mut Context<Self>,
23123    ) -> Self {
23124        let base_text = match edit_action {
23125            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23126            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23127            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23128        }
23129        .map(|msg| msg.to_string())
23130        .unwrap_or_default();
23131
23132        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23133        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23134
23135        let prompt = cx.new(|cx| {
23136            let mut prompt = Editor::new(
23137                EditorMode::AutoHeight {
23138                    min_lines: 1,
23139                    max_lines: Some(Self::MAX_LINES as usize),
23140                },
23141                buffer,
23142                None,
23143                window,
23144                cx,
23145            );
23146            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23147            prompt.set_show_cursor_when_unfocused(false, cx);
23148            prompt.set_placeholder_text(
23149                match edit_action {
23150                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23151                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23152                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23153                },
23154                cx,
23155            );
23156
23157            prompt
23158        });
23159
23160        Self {
23161            prompt,
23162            editor,
23163            breakpoint_anchor,
23164            breakpoint,
23165            edit_action,
23166            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23167            block_ids: Default::default(),
23168            _subscriptions: vec![],
23169        }
23170    }
23171
23172    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23173        self.block_ids.extend(block_ids)
23174    }
23175
23176    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23177        if let Some(editor) = self.editor.upgrade() {
23178            let message = self
23179                .prompt
23180                .read(cx)
23181                .buffer
23182                .read(cx)
23183                .as_singleton()
23184                .expect("A multi buffer in breakpoint prompt isn't possible")
23185                .read(cx)
23186                .as_rope()
23187                .to_string();
23188
23189            editor.update(cx, |editor, cx| {
23190                editor.edit_breakpoint_at_anchor(
23191                    self.breakpoint_anchor,
23192                    self.breakpoint.clone(),
23193                    match self.edit_action {
23194                        BreakpointPromptEditAction::Log => {
23195                            BreakpointEditAction::EditLogMessage(message.into())
23196                        }
23197                        BreakpointPromptEditAction::Condition => {
23198                            BreakpointEditAction::EditCondition(message.into())
23199                        }
23200                        BreakpointPromptEditAction::HitCondition => {
23201                            BreakpointEditAction::EditHitCondition(message.into())
23202                        }
23203                    },
23204                    cx,
23205                );
23206
23207                editor.remove_blocks(self.block_ids.clone(), None, cx);
23208                cx.focus_self(window);
23209            });
23210        }
23211    }
23212
23213    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23214        self.editor
23215            .update(cx, |editor, cx| {
23216                editor.remove_blocks(self.block_ids.clone(), None, cx);
23217                window.focus(&editor.focus_handle);
23218            })
23219            .log_err();
23220    }
23221
23222    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23223        let settings = ThemeSettings::get_global(cx);
23224        let text_style = TextStyle {
23225            color: if self.prompt.read(cx).read_only(cx) {
23226                cx.theme().colors().text_disabled
23227            } else {
23228                cx.theme().colors().text
23229            },
23230            font_family: settings.buffer_font.family.clone(),
23231            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23232            font_size: settings.buffer_font_size(cx).into(),
23233            font_weight: settings.buffer_font.weight,
23234            line_height: relative(settings.buffer_line_height.value()),
23235            ..Default::default()
23236        };
23237        EditorElement::new(
23238            &self.prompt,
23239            EditorStyle {
23240                background: cx.theme().colors().editor_background,
23241                local_player: cx.theme().players().local(),
23242                text: text_style,
23243                ..Default::default()
23244            },
23245        )
23246    }
23247}
23248
23249impl Render for BreakpointPromptEditor {
23250    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23251        let editor_margins = *self.editor_margins.lock();
23252        let gutter_dimensions = editor_margins.gutter;
23253        h_flex()
23254            .key_context("Editor")
23255            .bg(cx.theme().colors().editor_background)
23256            .border_y_1()
23257            .border_color(cx.theme().status().info_border)
23258            .size_full()
23259            .py(window.line_height() / 2.5)
23260            .on_action(cx.listener(Self::confirm))
23261            .on_action(cx.listener(Self::cancel))
23262            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23263            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23264    }
23265}
23266
23267impl Focusable for BreakpointPromptEditor {
23268    fn focus_handle(&self, cx: &App) -> FocusHandle {
23269        self.prompt.focus_handle(cx)
23270    }
23271}
23272
23273fn all_edits_insertions_or_deletions(
23274    edits: &Vec<(Range<Anchor>, String)>,
23275    snapshot: &MultiBufferSnapshot,
23276) -> bool {
23277    let mut all_insertions = true;
23278    let mut all_deletions = true;
23279
23280    for (range, new_text) in edits.iter() {
23281        let range_is_empty = range.to_offset(&snapshot).is_empty();
23282        let text_is_empty = new_text.is_empty();
23283
23284        if range_is_empty != text_is_empty {
23285            if range_is_empty {
23286                all_deletions = false;
23287            } else {
23288                all_insertions = false;
23289            }
23290        } else {
23291            return false;
23292        }
23293
23294        if !all_insertions && !all_deletions {
23295            return false;
23296        }
23297    }
23298    all_insertions || all_deletions
23299}
23300
23301struct MissingEditPredictionKeybindingTooltip;
23302
23303impl Render for MissingEditPredictionKeybindingTooltip {
23304    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23305        ui::tooltip_container(window, cx, |container, _, cx| {
23306            container
23307                .flex_shrink_0()
23308                .max_w_80()
23309                .min_h(rems_from_px(124.))
23310                .justify_between()
23311                .child(
23312                    v_flex()
23313                        .flex_1()
23314                        .text_ui_sm(cx)
23315                        .child(Label::new("Conflict with Accept Keybinding"))
23316                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23317                )
23318                .child(
23319                    h_flex()
23320                        .pb_1()
23321                        .gap_1()
23322                        .items_end()
23323                        .w_full()
23324                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23325                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23326                        }))
23327                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23328                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23329                        })),
23330                )
23331        })
23332    }
23333}
23334
23335#[derive(Debug, Clone, Copy, PartialEq)]
23336pub struct LineHighlight {
23337    pub background: Background,
23338    pub border: Option<gpui::Hsla>,
23339    pub include_gutter: bool,
23340    pub type_id: Option<TypeId>,
23341}
23342
23343struct LineManipulationResult {
23344    pub new_text: String,
23345    pub line_count_before: usize,
23346    pub line_count_after: usize,
23347}
23348
23349fn render_diff_hunk_controls(
23350    row: u32,
23351    status: &DiffHunkStatus,
23352    hunk_range: Range<Anchor>,
23353    is_created_file: bool,
23354    line_height: Pixels,
23355    editor: &Entity<Editor>,
23356    _window: &mut Window,
23357    cx: &mut App,
23358) -> AnyElement {
23359    h_flex()
23360        .h(line_height)
23361        .mr_1()
23362        .gap_1()
23363        .px_0p5()
23364        .pb_1()
23365        .border_x_1()
23366        .border_b_1()
23367        .border_color(cx.theme().colors().border_variant)
23368        .rounded_b_lg()
23369        .bg(cx.theme().colors().editor_background)
23370        .gap_1()
23371        .block_mouse_except_scroll()
23372        .shadow_md()
23373        .child(if status.has_secondary_hunk() {
23374            Button::new(("stage", row as u64), "Stage")
23375                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23376                .tooltip({
23377                    let focus_handle = editor.focus_handle(cx);
23378                    move |window, cx| {
23379                        Tooltip::for_action_in(
23380                            "Stage Hunk",
23381                            &::git::ToggleStaged,
23382                            &focus_handle,
23383                            window,
23384                            cx,
23385                        )
23386                    }
23387                })
23388                .on_click({
23389                    let editor = editor.clone();
23390                    move |_event, _window, cx| {
23391                        editor.update(cx, |editor, cx| {
23392                            editor.stage_or_unstage_diff_hunks(
23393                                true,
23394                                vec![hunk_range.start..hunk_range.start],
23395                                cx,
23396                            );
23397                        });
23398                    }
23399                })
23400        } else {
23401            Button::new(("unstage", row as u64), "Unstage")
23402                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23403                .tooltip({
23404                    let focus_handle = editor.focus_handle(cx);
23405                    move |window, cx| {
23406                        Tooltip::for_action_in(
23407                            "Unstage Hunk",
23408                            &::git::ToggleStaged,
23409                            &focus_handle,
23410                            window,
23411                            cx,
23412                        )
23413                    }
23414                })
23415                .on_click({
23416                    let editor = editor.clone();
23417                    move |_event, _window, cx| {
23418                        editor.update(cx, |editor, cx| {
23419                            editor.stage_or_unstage_diff_hunks(
23420                                false,
23421                                vec![hunk_range.start..hunk_range.start],
23422                                cx,
23423                            );
23424                        });
23425                    }
23426                })
23427        })
23428        .child(
23429            Button::new(("restore", row as u64), "Restore")
23430                .tooltip({
23431                    let focus_handle = editor.focus_handle(cx);
23432                    move |window, cx| {
23433                        Tooltip::for_action_in(
23434                            "Restore Hunk",
23435                            &::git::Restore,
23436                            &focus_handle,
23437                            window,
23438                            cx,
23439                        )
23440                    }
23441                })
23442                .on_click({
23443                    let editor = editor.clone();
23444                    move |_event, window, cx| {
23445                        editor.update(cx, |editor, cx| {
23446                            let snapshot = editor.snapshot(window, cx);
23447                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23448                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23449                        });
23450                    }
23451                })
23452                .disabled(is_created_file),
23453        )
23454        .when(
23455            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23456            |el| {
23457                el.child(
23458                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23459                        .shape(IconButtonShape::Square)
23460                        .icon_size(IconSize::Small)
23461                        // .disabled(!has_multiple_hunks)
23462                        .tooltip({
23463                            let focus_handle = editor.focus_handle(cx);
23464                            move |window, cx| {
23465                                Tooltip::for_action_in(
23466                                    "Next Hunk",
23467                                    &GoToHunk,
23468                                    &focus_handle,
23469                                    window,
23470                                    cx,
23471                                )
23472                            }
23473                        })
23474                        .on_click({
23475                            let editor = editor.clone();
23476                            move |_event, window, cx| {
23477                                editor.update(cx, |editor, cx| {
23478                                    let snapshot = editor.snapshot(window, cx);
23479                                    let position =
23480                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23481                                    editor.go_to_hunk_before_or_after_position(
23482                                        &snapshot,
23483                                        position,
23484                                        Direction::Next,
23485                                        window,
23486                                        cx,
23487                                    );
23488                                    editor.expand_selected_diff_hunks(cx);
23489                                });
23490                            }
23491                        }),
23492                )
23493                .child(
23494                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23495                        .shape(IconButtonShape::Square)
23496                        .icon_size(IconSize::Small)
23497                        // .disabled(!has_multiple_hunks)
23498                        .tooltip({
23499                            let focus_handle = editor.focus_handle(cx);
23500                            move |window, cx| {
23501                                Tooltip::for_action_in(
23502                                    "Previous Hunk",
23503                                    &GoToPreviousHunk,
23504                                    &focus_handle,
23505                                    window,
23506                                    cx,
23507                                )
23508                            }
23509                        })
23510                        .on_click({
23511                            let editor = editor.clone();
23512                            move |_event, window, cx| {
23513                                editor.update(cx, |editor, cx| {
23514                                    let snapshot = editor.snapshot(window, cx);
23515                                    let point =
23516                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23517                                    editor.go_to_hunk_before_or_after_position(
23518                                        &snapshot,
23519                                        point,
23520                                        Direction::Prev,
23521                                        window,
23522                                        cx,
23523                                    );
23524                                    editor.expand_selected_diff_hunks(cx);
23525                                });
23526                            }
23527                        }),
23528                )
23529            },
23530        )
23531        .into_any_element()
23532}