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        if self.signature_help_state.has_multiple_signatures() {
 2366            key_context.add("showing_signature_help");
 2367        }
 2368
 2369        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2370        if !self.focus_handle(cx).contains_focused(window, cx)
 2371            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2372        {
 2373            for addon in self.addons.values() {
 2374                addon.extend_key_context(&mut key_context, cx)
 2375            }
 2376        }
 2377
 2378        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2379            if let Some(extension) = singleton_buffer
 2380                .read(cx)
 2381                .file()
 2382                .and_then(|file| file.path().extension()?.to_str())
 2383            {
 2384                key_context.set("extension", extension.to_string());
 2385            }
 2386        } else {
 2387            key_context.add("multibuffer");
 2388        }
 2389
 2390        if has_active_edit_prediction {
 2391            if self.edit_prediction_in_conflict() {
 2392                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2393            } else {
 2394                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2395                key_context.add("copilot_suggestion");
 2396            }
 2397        }
 2398
 2399        if self.selection_mark_mode {
 2400            key_context.add("selection_mode");
 2401        }
 2402
 2403        key_context
 2404    }
 2405
 2406    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2407        if self.mouse_cursor_hidden {
 2408            self.mouse_cursor_hidden = false;
 2409            cx.notify();
 2410        }
 2411    }
 2412
 2413    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2414        let hide_mouse_cursor = match origin {
 2415            HideMouseCursorOrigin::TypingAction => {
 2416                matches!(
 2417                    self.hide_mouse_mode,
 2418                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2419                )
 2420            }
 2421            HideMouseCursorOrigin::MovementAction => {
 2422                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2423            }
 2424        };
 2425        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2426            self.mouse_cursor_hidden = hide_mouse_cursor;
 2427            cx.notify();
 2428        }
 2429    }
 2430
 2431    pub fn edit_prediction_in_conflict(&self) -> bool {
 2432        if !self.show_edit_predictions_in_menu() {
 2433            return false;
 2434        }
 2435
 2436        let showing_completions = self
 2437            .context_menu
 2438            .borrow()
 2439            .as_ref()
 2440            .map_or(false, |context| {
 2441                matches!(context, CodeContextMenu::Completions(_))
 2442            });
 2443
 2444        showing_completions
 2445            || self.edit_prediction_requires_modifier()
 2446            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2447            // bindings to insert tab characters.
 2448            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2449    }
 2450
 2451    pub fn accept_edit_prediction_keybind(
 2452        &self,
 2453        accept_partial: bool,
 2454        window: &Window,
 2455        cx: &App,
 2456    ) -> AcceptEditPredictionBinding {
 2457        let key_context = self.key_context_internal(true, window, cx);
 2458        let in_conflict = self.edit_prediction_in_conflict();
 2459
 2460        let bindings = if accept_partial {
 2461            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2462        } else {
 2463            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2464        };
 2465
 2466        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2467        // just the first one.
 2468        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2469            !in_conflict
 2470                || binding
 2471                    .keystrokes()
 2472                    .first()
 2473                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2474        }))
 2475    }
 2476
 2477    pub fn new_file(
 2478        workspace: &mut Workspace,
 2479        _: &workspace::NewFile,
 2480        window: &mut Window,
 2481        cx: &mut Context<Workspace>,
 2482    ) {
 2483        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2484            "Failed to create buffer",
 2485            window,
 2486            cx,
 2487            |e, _, _| match e.error_code() {
 2488                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2489                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2490                e.error_tag("required").unwrap_or("the latest version")
 2491            )),
 2492                _ => None,
 2493            },
 2494        );
 2495    }
 2496
 2497    pub fn new_in_workspace(
 2498        workspace: &mut Workspace,
 2499        window: &mut Window,
 2500        cx: &mut Context<Workspace>,
 2501    ) -> Task<Result<Entity<Editor>>> {
 2502        let project = workspace.project().clone();
 2503        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2504
 2505        cx.spawn_in(window, async move |workspace, cx| {
 2506            let buffer = create.await?;
 2507            workspace.update_in(cx, |workspace, window, cx| {
 2508                let editor =
 2509                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2510                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2511                editor
 2512            })
 2513        })
 2514    }
 2515
 2516    fn new_file_vertical(
 2517        workspace: &mut Workspace,
 2518        _: &workspace::NewFileSplitVertical,
 2519        window: &mut Window,
 2520        cx: &mut Context<Workspace>,
 2521    ) {
 2522        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2523    }
 2524
 2525    fn new_file_horizontal(
 2526        workspace: &mut Workspace,
 2527        _: &workspace::NewFileSplitHorizontal,
 2528        window: &mut Window,
 2529        cx: &mut Context<Workspace>,
 2530    ) {
 2531        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2532    }
 2533
 2534    fn new_file_in_direction(
 2535        workspace: &mut Workspace,
 2536        direction: SplitDirection,
 2537        window: &mut Window,
 2538        cx: &mut Context<Workspace>,
 2539    ) {
 2540        let project = workspace.project().clone();
 2541        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2542
 2543        cx.spawn_in(window, async move |workspace, cx| {
 2544            let buffer = create.await?;
 2545            workspace.update_in(cx, move |workspace, window, cx| {
 2546                workspace.split_item(
 2547                    direction,
 2548                    Box::new(
 2549                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2550                    ),
 2551                    window,
 2552                    cx,
 2553                )
 2554            })?;
 2555            anyhow::Ok(())
 2556        })
 2557        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2558            match e.error_code() {
 2559                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2560                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2561                e.error_tag("required").unwrap_or("the latest version")
 2562            )),
 2563                _ => None,
 2564            }
 2565        });
 2566    }
 2567
 2568    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2569        self.leader_id
 2570    }
 2571
 2572    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2573        &self.buffer
 2574    }
 2575
 2576    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2577        self.workspace.as_ref()?.0.upgrade()
 2578    }
 2579
 2580    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2581        self.buffer().read(cx).title(cx)
 2582    }
 2583
 2584    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2585        let git_blame_gutter_max_author_length = self
 2586            .render_git_blame_gutter(cx)
 2587            .then(|| {
 2588                if let Some(blame) = self.blame.as_ref() {
 2589                    let max_author_length =
 2590                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2591                    Some(max_author_length)
 2592                } else {
 2593                    None
 2594                }
 2595            })
 2596            .flatten();
 2597
 2598        EditorSnapshot {
 2599            mode: self.mode.clone(),
 2600            show_gutter: self.show_gutter,
 2601            show_line_numbers: self.show_line_numbers,
 2602            show_git_diff_gutter: self.show_git_diff_gutter,
 2603            show_code_actions: self.show_code_actions,
 2604            show_runnables: self.show_runnables,
 2605            show_breakpoints: self.show_breakpoints,
 2606            git_blame_gutter_max_author_length,
 2607            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2608            scroll_anchor: self.scroll_manager.anchor(),
 2609            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2610            placeholder_text: self.placeholder_text.clone(),
 2611            is_focused: self.focus_handle.is_focused(window),
 2612            current_line_highlight: self
 2613                .current_line_highlight
 2614                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2615            gutter_hovered: self.gutter_hovered,
 2616        }
 2617    }
 2618
 2619    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2620        self.buffer.read(cx).language_at(point, cx)
 2621    }
 2622
 2623    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2624        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2625    }
 2626
 2627    pub fn active_excerpt(
 2628        &self,
 2629        cx: &App,
 2630    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2631        self.buffer
 2632            .read(cx)
 2633            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2634    }
 2635
 2636    pub fn mode(&self) -> &EditorMode {
 2637        &self.mode
 2638    }
 2639
 2640    pub fn set_mode(&mut self, mode: EditorMode) {
 2641        self.mode = mode;
 2642    }
 2643
 2644    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2645        self.collaboration_hub.as_deref()
 2646    }
 2647
 2648    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2649        self.collaboration_hub = Some(hub);
 2650    }
 2651
 2652    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2653        self.in_project_search = in_project_search;
 2654    }
 2655
 2656    pub fn set_custom_context_menu(
 2657        &mut self,
 2658        f: impl 'static
 2659        + Fn(
 2660            &mut Self,
 2661            DisplayPoint,
 2662            &mut Window,
 2663            &mut Context<Self>,
 2664        ) -> Option<Entity<ui::ContextMenu>>,
 2665    ) {
 2666        self.custom_context_menu = Some(Box::new(f))
 2667    }
 2668
 2669    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2670        self.completion_provider = provider;
 2671    }
 2672
 2673    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2674        self.semantics_provider.clone()
 2675    }
 2676
 2677    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2678        self.semantics_provider = provider;
 2679    }
 2680
 2681    pub fn set_edit_prediction_provider<T>(
 2682        &mut self,
 2683        provider: Option<Entity<T>>,
 2684        window: &mut Window,
 2685        cx: &mut Context<Self>,
 2686    ) where
 2687        T: EditPredictionProvider,
 2688    {
 2689        self.edit_prediction_provider =
 2690            provider.map(|provider| RegisteredInlineCompletionProvider {
 2691                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2692                    if this.focus_handle.is_focused(window) {
 2693                        this.update_visible_inline_completion(window, cx);
 2694                    }
 2695                }),
 2696                provider: Arc::new(provider),
 2697            });
 2698        self.update_edit_prediction_settings(cx);
 2699        self.refresh_inline_completion(false, false, window, cx);
 2700    }
 2701
 2702    pub fn placeholder_text(&self) -> Option<&str> {
 2703        self.placeholder_text.as_deref()
 2704    }
 2705
 2706    pub fn set_placeholder_text(
 2707        &mut self,
 2708        placeholder_text: impl Into<Arc<str>>,
 2709        cx: &mut Context<Self>,
 2710    ) {
 2711        let placeholder_text = Some(placeholder_text.into());
 2712        if self.placeholder_text != placeholder_text {
 2713            self.placeholder_text = placeholder_text;
 2714            cx.notify();
 2715        }
 2716    }
 2717
 2718    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2719        self.cursor_shape = cursor_shape;
 2720
 2721        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2722        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2723
 2724        cx.notify();
 2725    }
 2726
 2727    pub fn set_current_line_highlight(
 2728        &mut self,
 2729        current_line_highlight: Option<CurrentLineHighlight>,
 2730    ) {
 2731        self.current_line_highlight = current_line_highlight;
 2732    }
 2733
 2734    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2735        self.collapse_matches = collapse_matches;
 2736    }
 2737
 2738    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2739        let buffers = self.buffer.read(cx).all_buffers();
 2740        let Some(project) = self.project.as_ref() else {
 2741            return;
 2742        };
 2743        project.update(cx, |project, cx| {
 2744            for buffer in buffers {
 2745                self.registered_buffers
 2746                    .entry(buffer.read(cx).remote_id())
 2747                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2748            }
 2749        })
 2750    }
 2751
 2752    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2753        if self.collapse_matches {
 2754            return range.start..range.start;
 2755        }
 2756        range.clone()
 2757    }
 2758
 2759    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2760        if self.display_map.read(cx).clip_at_line_ends != clip {
 2761            self.display_map
 2762                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2763        }
 2764    }
 2765
 2766    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2767        self.input_enabled = input_enabled;
 2768    }
 2769
 2770    pub fn set_inline_completions_hidden_for_vim_mode(
 2771        &mut self,
 2772        hidden: bool,
 2773        window: &mut Window,
 2774        cx: &mut Context<Self>,
 2775    ) {
 2776        if hidden != self.inline_completions_hidden_for_vim_mode {
 2777            self.inline_completions_hidden_for_vim_mode = hidden;
 2778            if hidden {
 2779                self.update_visible_inline_completion(window, cx);
 2780            } else {
 2781                self.refresh_inline_completion(true, false, window, cx);
 2782            }
 2783        }
 2784    }
 2785
 2786    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2787        self.menu_inline_completions_policy = value;
 2788    }
 2789
 2790    pub fn set_autoindent(&mut self, autoindent: bool) {
 2791        if autoindent {
 2792            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2793        } else {
 2794            self.autoindent_mode = None;
 2795        }
 2796    }
 2797
 2798    pub fn read_only(&self, cx: &App) -> bool {
 2799        self.read_only || self.buffer.read(cx).read_only()
 2800    }
 2801
 2802    pub fn set_read_only(&mut self, read_only: bool) {
 2803        self.read_only = read_only;
 2804    }
 2805
 2806    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2807        self.use_autoclose = autoclose;
 2808    }
 2809
 2810    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2811        self.use_auto_surround = auto_surround;
 2812    }
 2813
 2814    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2815        self.auto_replace_emoji_shortcode = auto_replace;
 2816    }
 2817
 2818    pub fn toggle_edit_predictions(
 2819        &mut self,
 2820        _: &ToggleEditPrediction,
 2821        window: &mut Window,
 2822        cx: &mut Context<Self>,
 2823    ) {
 2824        if self.show_inline_completions_override.is_some() {
 2825            self.set_show_edit_predictions(None, window, cx);
 2826        } else {
 2827            let show_edit_predictions = !self.edit_predictions_enabled();
 2828            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2829        }
 2830    }
 2831
 2832    pub fn set_show_edit_predictions(
 2833        &mut self,
 2834        show_edit_predictions: Option<bool>,
 2835        window: &mut Window,
 2836        cx: &mut Context<Self>,
 2837    ) {
 2838        self.show_inline_completions_override = show_edit_predictions;
 2839        self.update_edit_prediction_settings(cx);
 2840
 2841        if let Some(false) = show_edit_predictions {
 2842            self.discard_inline_completion(false, cx);
 2843        } else {
 2844            self.refresh_inline_completion(false, true, window, cx);
 2845        }
 2846    }
 2847
 2848    fn inline_completions_disabled_in_scope(
 2849        &self,
 2850        buffer: &Entity<Buffer>,
 2851        buffer_position: language::Anchor,
 2852        cx: &App,
 2853    ) -> bool {
 2854        let snapshot = buffer.read(cx).snapshot();
 2855        let settings = snapshot.settings_at(buffer_position, cx);
 2856
 2857        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2858            return false;
 2859        };
 2860
 2861        scope.override_name().map_or(false, |scope_name| {
 2862            settings
 2863                .edit_predictions_disabled_in
 2864                .iter()
 2865                .any(|s| s == scope_name)
 2866        })
 2867    }
 2868
 2869    pub fn set_use_modal_editing(&mut self, to: bool) {
 2870        self.use_modal_editing = to;
 2871    }
 2872
 2873    pub fn use_modal_editing(&self) -> bool {
 2874        self.use_modal_editing
 2875    }
 2876
 2877    fn selections_did_change(
 2878        &mut self,
 2879        local: bool,
 2880        old_cursor_position: &Anchor,
 2881        effects: SelectionEffects,
 2882        window: &mut Window,
 2883        cx: &mut Context<Self>,
 2884    ) {
 2885        window.invalidate_character_coordinates();
 2886
 2887        // Copy selections to primary selection buffer
 2888        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2889        if local {
 2890            let selections = self.selections.all::<usize>(cx);
 2891            let buffer_handle = self.buffer.read(cx).read(cx);
 2892
 2893            let mut text = String::new();
 2894            for (index, selection) in selections.iter().enumerate() {
 2895                let text_for_selection = buffer_handle
 2896                    .text_for_range(selection.start..selection.end)
 2897                    .collect::<String>();
 2898
 2899                text.push_str(&text_for_selection);
 2900                if index != selections.len() - 1 {
 2901                    text.push('\n');
 2902                }
 2903            }
 2904
 2905            if !text.is_empty() {
 2906                cx.write_to_primary(ClipboardItem::new_string(text));
 2907            }
 2908        }
 2909
 2910        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2911            self.buffer.update(cx, |buffer, cx| {
 2912                buffer.set_active_selections(
 2913                    &self.selections.disjoint_anchors(),
 2914                    self.selections.line_mode,
 2915                    self.cursor_shape,
 2916                    cx,
 2917                )
 2918            });
 2919        }
 2920        let display_map = self
 2921            .display_map
 2922            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2923        let buffer = &display_map.buffer_snapshot;
 2924        if self.selections.count() == 1 {
 2925            self.add_selections_state = None;
 2926        }
 2927        self.select_next_state = None;
 2928        self.select_prev_state = None;
 2929        self.select_syntax_node_history.try_clear();
 2930        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2931        self.snippet_stack
 2932            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2933        self.take_rename(false, window, cx);
 2934
 2935        let newest_selection = self.selections.newest_anchor();
 2936        let new_cursor_position = newest_selection.head();
 2937        let selection_start = newest_selection.start;
 2938
 2939        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2940            self.push_to_nav_history(
 2941                *old_cursor_position,
 2942                Some(new_cursor_position.to_point(buffer)),
 2943                false,
 2944                effects.nav_history == Some(true),
 2945                cx,
 2946            );
 2947        }
 2948
 2949        if local {
 2950            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2951                if !self.registered_buffers.contains_key(&buffer_id) {
 2952                    if let Some(project) = self.project.as_ref() {
 2953                        project.update(cx, |project, cx| {
 2954                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2955                                return;
 2956                            };
 2957                            self.registered_buffers.insert(
 2958                                buffer_id,
 2959                                project.register_buffer_with_language_servers(&buffer, cx),
 2960                            );
 2961                        })
 2962                    }
 2963                }
 2964            }
 2965
 2966            let mut context_menu = self.context_menu.borrow_mut();
 2967            let completion_menu = match context_menu.as_ref() {
 2968                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2969                Some(CodeContextMenu::CodeActions(_)) => {
 2970                    *context_menu = None;
 2971                    None
 2972                }
 2973                None => None,
 2974            };
 2975            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2976            drop(context_menu);
 2977
 2978            if effects.completions {
 2979                if let Some(completion_position) = completion_position {
 2980                    let start_offset = selection_start.to_offset(buffer);
 2981                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2982                    let continue_showing = if position_matches {
 2983                        if self.snippet_stack.is_empty() {
 2984                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2985                        } else {
 2986                            // Snippet choices can be shown even when the cursor is in whitespace.
 2987                            // Dismissing the menu with actions like backspace is handled by
 2988                            // invalidation regions.
 2989                            true
 2990                        }
 2991                    } else {
 2992                        false
 2993                    };
 2994
 2995                    if continue_showing {
 2996                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2997                    } else {
 2998                        self.hide_context_menu(window, cx);
 2999                    }
 3000                }
 3001            }
 3002
 3003            hide_hover(self, cx);
 3004
 3005            if old_cursor_position.to_display_point(&display_map).row()
 3006                != new_cursor_position.to_display_point(&display_map).row()
 3007            {
 3008                self.available_code_actions.take();
 3009            }
 3010            self.refresh_code_actions(window, cx);
 3011            self.refresh_document_highlights(cx);
 3012            self.refresh_selected_text_highlights(false, window, cx);
 3013            refresh_matching_bracket_highlights(self, window, cx);
 3014            self.update_visible_inline_completion(window, cx);
 3015            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3016            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3017            self.inline_blame_popover.take();
 3018            if self.git_blame_inline_enabled {
 3019                self.start_inline_blame_timer(window, cx);
 3020            }
 3021        }
 3022
 3023        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3024        cx.emit(EditorEvent::SelectionsChanged { local });
 3025
 3026        let selections = &self.selections.disjoint;
 3027        if selections.len() == 1 {
 3028            cx.emit(SearchEvent::ActiveMatchChanged)
 3029        }
 3030        if local {
 3031            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3032                let inmemory_selections = selections
 3033                    .iter()
 3034                    .map(|s| {
 3035                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3036                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3037                    })
 3038                    .collect();
 3039                self.update_restoration_data(cx, |data| {
 3040                    data.selections = inmemory_selections;
 3041                });
 3042
 3043                if WorkspaceSettings::get(None, cx).restore_on_startup
 3044                    != RestoreOnStartupBehavior::None
 3045                {
 3046                    if let Some(workspace_id) =
 3047                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3048                    {
 3049                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3050                        let selections = selections.clone();
 3051                        let background_executor = cx.background_executor().clone();
 3052                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3053                        self.serialize_selections = cx.background_spawn(async move {
 3054                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3055                            let db_selections = selections
 3056                                .iter()
 3057                                .map(|selection| {
 3058                                    (
 3059                                        selection.start.to_offset(&snapshot),
 3060                                        selection.end.to_offset(&snapshot),
 3061                                    )
 3062                                })
 3063                                .collect();
 3064
 3065                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3066                                .await
 3067                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3068                                .log_err();
 3069                        });
 3070                    }
 3071                }
 3072            }
 3073        }
 3074
 3075        cx.notify();
 3076    }
 3077
 3078    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3079        use text::ToOffset as _;
 3080        use text::ToPoint as _;
 3081
 3082        if self.mode.is_minimap()
 3083            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3084        {
 3085            return;
 3086        }
 3087
 3088        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3089            return;
 3090        };
 3091
 3092        let snapshot = singleton.read(cx).snapshot();
 3093        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3094            let display_snapshot = display_map.snapshot(cx);
 3095
 3096            display_snapshot
 3097                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3098                .map(|fold| {
 3099                    fold.range.start.text_anchor.to_point(&snapshot)
 3100                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3101                })
 3102                .collect()
 3103        });
 3104        self.update_restoration_data(cx, |data| {
 3105            data.folds = inmemory_folds;
 3106        });
 3107
 3108        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3109            return;
 3110        };
 3111        let background_executor = cx.background_executor().clone();
 3112        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3113        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3114            display_map
 3115                .snapshot(cx)
 3116                .folds_in_range(0..snapshot.len())
 3117                .map(|fold| {
 3118                    (
 3119                        fold.range.start.text_anchor.to_offset(&snapshot),
 3120                        fold.range.end.text_anchor.to_offset(&snapshot),
 3121                    )
 3122                })
 3123                .collect()
 3124        });
 3125        self.serialize_folds = cx.background_spawn(async move {
 3126            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3127            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3128                .await
 3129                .with_context(|| {
 3130                    format!(
 3131                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3132                    )
 3133                })
 3134                .log_err();
 3135        });
 3136    }
 3137
 3138    pub fn sync_selections(
 3139        &mut self,
 3140        other: Entity<Editor>,
 3141        cx: &mut Context<Self>,
 3142    ) -> gpui::Subscription {
 3143        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3144        self.selections.change_with(cx, |selections| {
 3145            selections.select_anchors(other_selections);
 3146        });
 3147
 3148        let other_subscription =
 3149            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3150                EditorEvent::SelectionsChanged { local: true } => {
 3151                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3152                    if other_selections.is_empty() {
 3153                        return;
 3154                    }
 3155                    this.selections.change_with(cx, |selections| {
 3156                        selections.select_anchors(other_selections);
 3157                    });
 3158                }
 3159                _ => {}
 3160            });
 3161
 3162        let this_subscription =
 3163            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3164                EditorEvent::SelectionsChanged { local: true } => {
 3165                    let these_selections = this.selections.disjoint.to_vec();
 3166                    if these_selections.is_empty() {
 3167                        return;
 3168                    }
 3169                    other.update(cx, |other_editor, cx| {
 3170                        other_editor.selections.change_with(cx, |selections| {
 3171                            selections.select_anchors(these_selections);
 3172                        })
 3173                    });
 3174                }
 3175                _ => {}
 3176            });
 3177
 3178        Subscription::join(other_subscription, this_subscription)
 3179    }
 3180
 3181    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3182    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3183    /// effects of selection change occur at the end of the transaction.
 3184    pub fn change_selections<R>(
 3185        &mut self,
 3186        effects: SelectionEffects,
 3187        window: &mut Window,
 3188        cx: &mut Context<Self>,
 3189        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3190    ) -> R {
 3191        if let Some(state) = &mut self.deferred_selection_effects_state {
 3192            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3193            state.effects.completions = effects.completions;
 3194            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3195            let (changed, result) = self.selections.change_with(cx, change);
 3196            state.changed |= changed;
 3197            return result;
 3198        }
 3199        let mut state = DeferredSelectionEffectsState {
 3200            changed: false,
 3201            effects,
 3202            old_cursor_position: self.selections.newest_anchor().head(),
 3203            history_entry: SelectionHistoryEntry {
 3204                selections: self.selections.disjoint_anchors(),
 3205                select_next_state: self.select_next_state.clone(),
 3206                select_prev_state: self.select_prev_state.clone(),
 3207                add_selections_state: self.add_selections_state.clone(),
 3208            },
 3209        };
 3210        let (changed, result) = self.selections.change_with(cx, change);
 3211        state.changed = state.changed || changed;
 3212        if self.defer_selection_effects {
 3213            self.deferred_selection_effects_state = Some(state);
 3214        } else {
 3215            self.apply_selection_effects(state, window, cx);
 3216        }
 3217        result
 3218    }
 3219
 3220    /// Defers the effects of selection change, so that the effects of multiple calls to
 3221    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3222    /// to selection history and the state of popovers based on selection position aren't
 3223    /// erroneously updated.
 3224    pub fn with_selection_effects_deferred<R>(
 3225        &mut self,
 3226        window: &mut Window,
 3227        cx: &mut Context<Self>,
 3228        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3229    ) -> R {
 3230        let already_deferred = self.defer_selection_effects;
 3231        self.defer_selection_effects = true;
 3232        let result = update(self, window, cx);
 3233        if !already_deferred {
 3234            self.defer_selection_effects = false;
 3235            if let Some(state) = self.deferred_selection_effects_state.take() {
 3236                self.apply_selection_effects(state, window, cx);
 3237            }
 3238        }
 3239        result
 3240    }
 3241
 3242    fn apply_selection_effects(
 3243        &mut self,
 3244        state: DeferredSelectionEffectsState,
 3245        window: &mut Window,
 3246        cx: &mut Context<Self>,
 3247    ) {
 3248        if state.changed {
 3249            self.selection_history.push(state.history_entry);
 3250
 3251            if let Some(autoscroll) = state.effects.scroll {
 3252                self.request_autoscroll(autoscroll, cx);
 3253            }
 3254
 3255            let old_cursor_position = &state.old_cursor_position;
 3256
 3257            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3258
 3259            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3260                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3261            }
 3262        }
 3263    }
 3264
 3265    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3266    where
 3267        I: IntoIterator<Item = (Range<S>, T)>,
 3268        S: ToOffset,
 3269        T: Into<Arc<str>>,
 3270    {
 3271        if self.read_only(cx) {
 3272            return;
 3273        }
 3274
 3275        self.buffer
 3276            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3277    }
 3278
 3279    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3280    where
 3281        I: IntoIterator<Item = (Range<S>, T)>,
 3282        S: ToOffset,
 3283        T: Into<Arc<str>>,
 3284    {
 3285        if self.read_only(cx) {
 3286            return;
 3287        }
 3288
 3289        self.buffer.update(cx, |buffer, cx| {
 3290            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3291        });
 3292    }
 3293
 3294    pub fn edit_with_block_indent<I, S, T>(
 3295        &mut self,
 3296        edits: I,
 3297        original_indent_columns: Vec<Option<u32>>,
 3298        cx: &mut Context<Self>,
 3299    ) where
 3300        I: IntoIterator<Item = (Range<S>, T)>,
 3301        S: ToOffset,
 3302        T: Into<Arc<str>>,
 3303    {
 3304        if self.read_only(cx) {
 3305            return;
 3306        }
 3307
 3308        self.buffer.update(cx, |buffer, cx| {
 3309            buffer.edit(
 3310                edits,
 3311                Some(AutoindentMode::Block {
 3312                    original_indent_columns,
 3313                }),
 3314                cx,
 3315            )
 3316        });
 3317    }
 3318
 3319    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3320        self.hide_context_menu(window, cx);
 3321
 3322        match phase {
 3323            SelectPhase::Begin {
 3324                position,
 3325                add,
 3326                click_count,
 3327            } => self.begin_selection(position, add, click_count, window, cx),
 3328            SelectPhase::BeginColumnar {
 3329                position,
 3330                goal_column,
 3331                reset,
 3332                mode,
 3333            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3334            SelectPhase::Extend {
 3335                position,
 3336                click_count,
 3337            } => self.extend_selection(position, click_count, window, cx),
 3338            SelectPhase::Update {
 3339                position,
 3340                goal_column,
 3341                scroll_delta,
 3342            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3343            SelectPhase::End => self.end_selection(window, cx),
 3344        }
 3345    }
 3346
 3347    fn extend_selection(
 3348        &mut self,
 3349        position: DisplayPoint,
 3350        click_count: usize,
 3351        window: &mut Window,
 3352        cx: &mut Context<Self>,
 3353    ) {
 3354        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3355        let tail = self.selections.newest::<usize>(cx).tail();
 3356        self.begin_selection(position, false, click_count, window, cx);
 3357
 3358        let position = position.to_offset(&display_map, Bias::Left);
 3359        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3360
 3361        let mut pending_selection = self
 3362            .selections
 3363            .pending_anchor()
 3364            .expect("extend_selection not called with pending selection");
 3365        if position >= tail {
 3366            pending_selection.start = tail_anchor;
 3367        } else {
 3368            pending_selection.end = tail_anchor;
 3369            pending_selection.reversed = true;
 3370        }
 3371
 3372        let mut pending_mode = self.selections.pending_mode().unwrap();
 3373        match &mut pending_mode {
 3374            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3375            _ => {}
 3376        }
 3377
 3378        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3379            SelectionEffects::scroll(Autoscroll::fit())
 3380        } else {
 3381            SelectionEffects::no_scroll()
 3382        };
 3383
 3384        self.change_selections(effects, window, cx, |s| {
 3385            s.set_pending(pending_selection, pending_mode)
 3386        });
 3387    }
 3388
 3389    fn begin_selection(
 3390        &mut self,
 3391        position: DisplayPoint,
 3392        add: bool,
 3393        click_count: usize,
 3394        window: &mut Window,
 3395        cx: &mut Context<Self>,
 3396    ) {
 3397        if !self.focus_handle.is_focused(window) {
 3398            self.last_focused_descendant = None;
 3399            window.focus(&self.focus_handle);
 3400        }
 3401
 3402        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3403        let buffer = &display_map.buffer_snapshot;
 3404        let position = display_map.clip_point(position, Bias::Left);
 3405
 3406        let start;
 3407        let end;
 3408        let mode;
 3409        let mut auto_scroll;
 3410        match click_count {
 3411            1 => {
 3412                start = buffer.anchor_before(position.to_point(&display_map));
 3413                end = start;
 3414                mode = SelectMode::Character;
 3415                auto_scroll = true;
 3416            }
 3417            2 => {
 3418                let position = display_map
 3419                    .clip_point(position, Bias::Left)
 3420                    .to_offset(&display_map, Bias::Left);
 3421                let (range, _) = buffer.surrounding_word(position, false);
 3422                start = buffer.anchor_before(range.start);
 3423                end = buffer.anchor_before(range.end);
 3424                mode = SelectMode::Word(start..end);
 3425                auto_scroll = true;
 3426            }
 3427            3 => {
 3428                let position = display_map
 3429                    .clip_point(position, Bias::Left)
 3430                    .to_point(&display_map);
 3431                let line_start = display_map.prev_line_boundary(position).0;
 3432                let next_line_start = buffer.clip_point(
 3433                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3434                    Bias::Left,
 3435                );
 3436                start = buffer.anchor_before(line_start);
 3437                end = buffer.anchor_before(next_line_start);
 3438                mode = SelectMode::Line(start..end);
 3439                auto_scroll = true;
 3440            }
 3441            _ => {
 3442                start = buffer.anchor_before(0);
 3443                end = buffer.anchor_before(buffer.len());
 3444                mode = SelectMode::All;
 3445                auto_scroll = false;
 3446            }
 3447        }
 3448        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3449
 3450        let point_to_delete: Option<usize> = {
 3451            let selected_points: Vec<Selection<Point>> =
 3452                self.selections.disjoint_in_range(start..end, cx);
 3453
 3454            if !add || click_count > 1 {
 3455                None
 3456            } else if !selected_points.is_empty() {
 3457                Some(selected_points[0].id)
 3458            } else {
 3459                let clicked_point_already_selected =
 3460                    self.selections.disjoint.iter().find(|selection| {
 3461                        selection.start.to_point(buffer) == start.to_point(buffer)
 3462                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3463                    });
 3464
 3465                clicked_point_already_selected.map(|selection| selection.id)
 3466            }
 3467        };
 3468
 3469        let selections_count = self.selections.count();
 3470        let effects = if auto_scroll {
 3471            SelectionEffects::default()
 3472        } else {
 3473            SelectionEffects::no_scroll()
 3474        };
 3475
 3476        self.change_selections(effects, window, cx, |s| {
 3477            if let Some(point_to_delete) = point_to_delete {
 3478                s.delete(point_to_delete);
 3479
 3480                if selections_count == 1 {
 3481                    s.set_pending_anchor_range(start..end, mode);
 3482                }
 3483            } else {
 3484                if !add {
 3485                    s.clear_disjoint();
 3486                }
 3487
 3488                s.set_pending_anchor_range(start..end, mode);
 3489            }
 3490        });
 3491    }
 3492
 3493    fn begin_columnar_selection(
 3494        &mut self,
 3495        position: DisplayPoint,
 3496        goal_column: u32,
 3497        reset: bool,
 3498        mode: ColumnarMode,
 3499        window: &mut Window,
 3500        cx: &mut Context<Self>,
 3501    ) {
 3502        if !self.focus_handle.is_focused(window) {
 3503            self.last_focused_descendant = None;
 3504            window.focus(&self.focus_handle);
 3505        }
 3506
 3507        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3508
 3509        if reset {
 3510            let pointer_position = display_map
 3511                .buffer_snapshot
 3512                .anchor_before(position.to_point(&display_map));
 3513
 3514            self.change_selections(
 3515                SelectionEffects::scroll(Autoscroll::newest()),
 3516                window,
 3517                cx,
 3518                |s| {
 3519                    s.clear_disjoint();
 3520                    s.set_pending_anchor_range(
 3521                        pointer_position..pointer_position,
 3522                        SelectMode::Character,
 3523                    );
 3524                },
 3525            );
 3526        };
 3527
 3528        let tail = self.selections.newest::<Point>(cx).tail();
 3529        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3530        self.columnar_selection_state = match mode {
 3531            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3532                selection_tail: selection_anchor,
 3533                display_point: if reset {
 3534                    if position.column() != goal_column {
 3535                        Some(DisplayPoint::new(position.row(), goal_column))
 3536                    } else {
 3537                        None
 3538                    }
 3539                } else {
 3540                    None
 3541                },
 3542            }),
 3543            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3544                selection_tail: selection_anchor,
 3545            }),
 3546        };
 3547
 3548        if !reset {
 3549            self.select_columns(position, goal_column, &display_map, window, cx);
 3550        }
 3551    }
 3552
 3553    fn update_selection(
 3554        &mut self,
 3555        position: DisplayPoint,
 3556        goal_column: u32,
 3557        scroll_delta: gpui::Point<f32>,
 3558        window: &mut Window,
 3559        cx: &mut Context<Self>,
 3560    ) {
 3561        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3562
 3563        if self.columnar_selection_state.is_some() {
 3564            self.select_columns(position, goal_column, &display_map, window, cx);
 3565        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3566            let buffer = &display_map.buffer_snapshot;
 3567            let head;
 3568            let tail;
 3569            let mode = self.selections.pending_mode().unwrap();
 3570            match &mode {
 3571                SelectMode::Character => {
 3572                    head = position.to_point(&display_map);
 3573                    tail = pending.tail().to_point(buffer);
 3574                }
 3575                SelectMode::Word(original_range) => {
 3576                    let offset = display_map
 3577                        .clip_point(position, Bias::Left)
 3578                        .to_offset(&display_map, Bias::Left);
 3579                    let original_range = original_range.to_offset(buffer);
 3580
 3581                    let head_offset = if buffer.is_inside_word(offset, false)
 3582                        || original_range.contains(&offset)
 3583                    {
 3584                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3585                        if word_range.start < original_range.start {
 3586                            word_range.start
 3587                        } else {
 3588                            word_range.end
 3589                        }
 3590                    } else {
 3591                        offset
 3592                    };
 3593
 3594                    head = head_offset.to_point(buffer);
 3595                    if head_offset <= original_range.start {
 3596                        tail = original_range.end.to_point(buffer);
 3597                    } else {
 3598                        tail = original_range.start.to_point(buffer);
 3599                    }
 3600                }
 3601                SelectMode::Line(original_range) => {
 3602                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3603
 3604                    let position = display_map
 3605                        .clip_point(position, Bias::Left)
 3606                        .to_point(&display_map);
 3607                    let line_start = display_map.prev_line_boundary(position).0;
 3608                    let next_line_start = buffer.clip_point(
 3609                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3610                        Bias::Left,
 3611                    );
 3612
 3613                    if line_start < original_range.start {
 3614                        head = line_start
 3615                    } else {
 3616                        head = next_line_start
 3617                    }
 3618
 3619                    if head <= original_range.start {
 3620                        tail = original_range.end;
 3621                    } else {
 3622                        tail = original_range.start;
 3623                    }
 3624                }
 3625                SelectMode::All => {
 3626                    return;
 3627                }
 3628            };
 3629
 3630            if head < tail {
 3631                pending.start = buffer.anchor_before(head);
 3632                pending.end = buffer.anchor_before(tail);
 3633                pending.reversed = true;
 3634            } else {
 3635                pending.start = buffer.anchor_before(tail);
 3636                pending.end = buffer.anchor_before(head);
 3637                pending.reversed = false;
 3638            }
 3639
 3640            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3641                s.set_pending(pending, mode);
 3642            });
 3643        } else {
 3644            log::error!("update_selection dispatched with no pending selection");
 3645            return;
 3646        }
 3647
 3648        self.apply_scroll_delta(scroll_delta, window, cx);
 3649        cx.notify();
 3650    }
 3651
 3652    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3653        self.columnar_selection_state.take();
 3654        if self.selections.pending_anchor().is_some() {
 3655            let selections = self.selections.all::<usize>(cx);
 3656            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3657                s.select(selections);
 3658                s.clear_pending();
 3659            });
 3660        }
 3661    }
 3662
 3663    fn select_columns(
 3664        &mut self,
 3665        head: DisplayPoint,
 3666        goal_column: u32,
 3667        display_map: &DisplaySnapshot,
 3668        window: &mut Window,
 3669        cx: &mut Context<Self>,
 3670    ) {
 3671        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3672            return;
 3673        };
 3674
 3675        let tail = match columnar_state {
 3676            ColumnarSelectionState::FromMouse {
 3677                selection_tail,
 3678                display_point,
 3679            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3680            ColumnarSelectionState::FromSelection { selection_tail } => {
 3681                selection_tail.to_display_point(&display_map)
 3682            }
 3683        };
 3684
 3685        let start_row = cmp::min(tail.row(), head.row());
 3686        let end_row = cmp::max(tail.row(), head.row());
 3687        let start_column = cmp::min(tail.column(), goal_column);
 3688        let end_column = cmp::max(tail.column(), goal_column);
 3689        let reversed = start_column < tail.column();
 3690
 3691        let selection_ranges = (start_row.0..=end_row.0)
 3692            .map(DisplayRow)
 3693            .filter_map(|row| {
 3694                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3695                    || start_column <= display_map.line_len(row))
 3696                    && !display_map.is_block_line(row)
 3697                {
 3698                    let start = display_map
 3699                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3700                        .to_point(display_map);
 3701                    let end = display_map
 3702                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3703                        .to_point(display_map);
 3704                    if reversed {
 3705                        Some(end..start)
 3706                    } else {
 3707                        Some(start..end)
 3708                    }
 3709                } else {
 3710                    None
 3711                }
 3712            })
 3713            .collect::<Vec<_>>();
 3714
 3715        let ranges = match columnar_state {
 3716            ColumnarSelectionState::FromMouse { .. } => {
 3717                let mut non_empty_ranges = selection_ranges
 3718                    .iter()
 3719                    .filter(|selection_range| selection_range.start != selection_range.end)
 3720                    .peekable();
 3721                if non_empty_ranges.peek().is_some() {
 3722                    non_empty_ranges.cloned().collect()
 3723                } else {
 3724                    selection_ranges
 3725                }
 3726            }
 3727            _ => selection_ranges,
 3728        };
 3729
 3730        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3731            s.select_ranges(ranges);
 3732        });
 3733        cx.notify();
 3734    }
 3735
 3736    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3737        self.selections
 3738            .all_adjusted(cx)
 3739            .iter()
 3740            .any(|selection| !selection.is_empty())
 3741    }
 3742
 3743    pub fn has_pending_nonempty_selection(&self) -> bool {
 3744        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3745            Some(Selection { start, end, .. }) => start != end,
 3746            None => false,
 3747        };
 3748
 3749        pending_nonempty_selection
 3750            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3751    }
 3752
 3753    pub fn has_pending_selection(&self) -> bool {
 3754        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3755    }
 3756
 3757    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3758        self.selection_mark_mode = false;
 3759        self.selection_drag_state = SelectionDragState::None;
 3760
 3761        if self.clear_expanded_diff_hunks(cx) {
 3762            cx.notify();
 3763            return;
 3764        }
 3765        if self.dismiss_menus_and_popups(true, window, cx) {
 3766            return;
 3767        }
 3768
 3769        if self.mode.is_full()
 3770            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3771        {
 3772            return;
 3773        }
 3774
 3775        cx.propagate();
 3776    }
 3777
 3778    pub fn dismiss_menus_and_popups(
 3779        &mut self,
 3780        is_user_requested: bool,
 3781        window: &mut Window,
 3782        cx: &mut Context<Self>,
 3783    ) -> bool {
 3784        if self.take_rename(false, window, cx).is_some() {
 3785            return true;
 3786        }
 3787
 3788        if hide_hover(self, cx) {
 3789            return true;
 3790        }
 3791
 3792        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3793            return true;
 3794        }
 3795
 3796        if self.hide_context_menu(window, cx).is_some() {
 3797            return true;
 3798        }
 3799
 3800        if self.mouse_context_menu.take().is_some() {
 3801            return true;
 3802        }
 3803
 3804        if is_user_requested && self.discard_inline_completion(true, cx) {
 3805            return true;
 3806        }
 3807
 3808        if self.snippet_stack.pop().is_some() {
 3809            return true;
 3810        }
 3811
 3812        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3813            self.dismiss_diagnostics(cx);
 3814            return true;
 3815        }
 3816
 3817        false
 3818    }
 3819
 3820    fn linked_editing_ranges_for(
 3821        &self,
 3822        selection: Range<text::Anchor>,
 3823        cx: &App,
 3824    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3825        if self.linked_edit_ranges.is_empty() {
 3826            return None;
 3827        }
 3828        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3829            selection.end.buffer_id.and_then(|end_buffer_id| {
 3830                if selection.start.buffer_id != Some(end_buffer_id) {
 3831                    return None;
 3832                }
 3833                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3834                let snapshot = buffer.read(cx).snapshot();
 3835                self.linked_edit_ranges
 3836                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3837                    .map(|ranges| (ranges, snapshot, buffer))
 3838            })?;
 3839        use text::ToOffset as TO;
 3840        // find offset from the start of current range to current cursor position
 3841        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3842
 3843        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3844        let start_difference = start_offset - start_byte_offset;
 3845        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3846        let end_difference = end_offset - start_byte_offset;
 3847        // Current range has associated linked ranges.
 3848        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3849        for range in linked_ranges.iter() {
 3850            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3851            let end_offset = start_offset + end_difference;
 3852            let start_offset = start_offset + start_difference;
 3853            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3854                continue;
 3855            }
 3856            if self.selections.disjoint_anchor_ranges().any(|s| {
 3857                if s.start.buffer_id != selection.start.buffer_id
 3858                    || s.end.buffer_id != selection.end.buffer_id
 3859                {
 3860                    return false;
 3861                }
 3862                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3863                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3864            }) {
 3865                continue;
 3866            }
 3867            let start = buffer_snapshot.anchor_after(start_offset);
 3868            let end = buffer_snapshot.anchor_after(end_offset);
 3869            linked_edits
 3870                .entry(buffer.clone())
 3871                .or_default()
 3872                .push(start..end);
 3873        }
 3874        Some(linked_edits)
 3875    }
 3876
 3877    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3878        let text: Arc<str> = text.into();
 3879
 3880        if self.read_only(cx) {
 3881            return;
 3882        }
 3883
 3884        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3885
 3886        let selections = self.selections.all_adjusted(cx);
 3887        let mut bracket_inserted = false;
 3888        let mut edits = Vec::new();
 3889        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3890        let mut new_selections = Vec::with_capacity(selections.len());
 3891        let mut new_autoclose_regions = Vec::new();
 3892        let snapshot = self.buffer.read(cx).read(cx);
 3893        let mut clear_linked_edit_ranges = false;
 3894
 3895        for (selection, autoclose_region) in
 3896            self.selections_with_autoclose_regions(selections, &snapshot)
 3897        {
 3898            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3899                // Determine if the inserted text matches the opening or closing
 3900                // bracket of any of this language's bracket pairs.
 3901                let mut bracket_pair = None;
 3902                let mut is_bracket_pair_start = false;
 3903                let mut is_bracket_pair_end = false;
 3904                if !text.is_empty() {
 3905                    let mut bracket_pair_matching_end = None;
 3906                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3907                    //  and they are removing the character that triggered IME popup.
 3908                    for (pair, enabled) in scope.brackets() {
 3909                        if !pair.close && !pair.surround {
 3910                            continue;
 3911                        }
 3912
 3913                        if enabled && pair.start.ends_with(text.as_ref()) {
 3914                            let prefix_len = pair.start.len() - text.len();
 3915                            let preceding_text_matches_prefix = prefix_len == 0
 3916                                || (selection.start.column >= (prefix_len as u32)
 3917                                    && snapshot.contains_str_at(
 3918                                        Point::new(
 3919                                            selection.start.row,
 3920                                            selection.start.column - (prefix_len as u32),
 3921                                        ),
 3922                                        &pair.start[..prefix_len],
 3923                                    ));
 3924                            if preceding_text_matches_prefix {
 3925                                bracket_pair = Some(pair.clone());
 3926                                is_bracket_pair_start = true;
 3927                                break;
 3928                            }
 3929                        }
 3930                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3931                        {
 3932                            // take first bracket pair matching end, but don't break in case a later bracket
 3933                            // pair matches start
 3934                            bracket_pair_matching_end = Some(pair.clone());
 3935                        }
 3936                    }
 3937                    if let Some(end) = bracket_pair_matching_end
 3938                        && bracket_pair.is_none()
 3939                    {
 3940                        bracket_pair = Some(end);
 3941                        is_bracket_pair_end = true;
 3942                    }
 3943                }
 3944
 3945                if let Some(bracket_pair) = bracket_pair {
 3946                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3947                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3948                    let auto_surround =
 3949                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3950                    if selection.is_empty() {
 3951                        if is_bracket_pair_start {
 3952                            // If the inserted text is a suffix of an opening bracket and the
 3953                            // selection is preceded by the rest of the opening bracket, then
 3954                            // insert the closing bracket.
 3955                            let following_text_allows_autoclose = snapshot
 3956                                .chars_at(selection.start)
 3957                                .next()
 3958                                .map_or(true, |c| scope.should_autoclose_before(c));
 3959
 3960                            let preceding_text_allows_autoclose = selection.start.column == 0
 3961                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3962                                    true,
 3963                                    |c| {
 3964                                        bracket_pair.start != bracket_pair.end
 3965                                            || !snapshot
 3966                                                .char_classifier_at(selection.start)
 3967                                                .is_word(c)
 3968                                    },
 3969                                );
 3970
 3971                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3972                                && bracket_pair.start.len() == 1
 3973                            {
 3974                                let target = bracket_pair.start.chars().next().unwrap();
 3975                                let current_line_count = snapshot
 3976                                    .reversed_chars_at(selection.start)
 3977                                    .take_while(|&c| c != '\n')
 3978                                    .filter(|&c| c == target)
 3979                                    .count();
 3980                                current_line_count % 2 == 1
 3981                            } else {
 3982                                false
 3983                            };
 3984
 3985                            if autoclose
 3986                                && bracket_pair.close
 3987                                && following_text_allows_autoclose
 3988                                && preceding_text_allows_autoclose
 3989                                && !is_closing_quote
 3990                            {
 3991                                let anchor = snapshot.anchor_before(selection.end);
 3992                                new_selections.push((selection.map(|_| anchor), text.len()));
 3993                                new_autoclose_regions.push((
 3994                                    anchor,
 3995                                    text.len(),
 3996                                    selection.id,
 3997                                    bracket_pair.clone(),
 3998                                ));
 3999                                edits.push((
 4000                                    selection.range(),
 4001                                    format!("{}{}", text, bracket_pair.end).into(),
 4002                                ));
 4003                                bracket_inserted = true;
 4004                                continue;
 4005                            }
 4006                        }
 4007
 4008                        if let Some(region) = autoclose_region {
 4009                            // If the selection is followed by an auto-inserted closing bracket,
 4010                            // then don't insert that closing bracket again; just move the selection
 4011                            // past the closing bracket.
 4012                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4013                                && text.as_ref() == region.pair.end.as_str();
 4014                            if should_skip {
 4015                                let anchor = snapshot.anchor_after(selection.end);
 4016                                new_selections
 4017                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4018                                continue;
 4019                            }
 4020                        }
 4021
 4022                        let always_treat_brackets_as_autoclosed = snapshot
 4023                            .language_settings_at(selection.start, cx)
 4024                            .always_treat_brackets_as_autoclosed;
 4025                        if always_treat_brackets_as_autoclosed
 4026                            && is_bracket_pair_end
 4027                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4028                        {
 4029                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4030                            // and the inserted text is a closing bracket and the selection is followed
 4031                            // by the closing bracket then move the selection past the closing bracket.
 4032                            let anchor = snapshot.anchor_after(selection.end);
 4033                            new_selections.push((selection.map(|_| anchor), text.len()));
 4034                            continue;
 4035                        }
 4036                    }
 4037                    // If an opening bracket is 1 character long and is typed while
 4038                    // text is selected, then surround that text with the bracket pair.
 4039                    else if auto_surround
 4040                        && bracket_pair.surround
 4041                        && is_bracket_pair_start
 4042                        && bracket_pair.start.chars().count() == 1
 4043                    {
 4044                        edits.push((selection.start..selection.start, text.clone()));
 4045                        edits.push((
 4046                            selection.end..selection.end,
 4047                            bracket_pair.end.as_str().into(),
 4048                        ));
 4049                        bracket_inserted = true;
 4050                        new_selections.push((
 4051                            Selection {
 4052                                id: selection.id,
 4053                                start: snapshot.anchor_after(selection.start),
 4054                                end: snapshot.anchor_before(selection.end),
 4055                                reversed: selection.reversed,
 4056                                goal: selection.goal,
 4057                            },
 4058                            0,
 4059                        ));
 4060                        continue;
 4061                    }
 4062                }
 4063            }
 4064
 4065            if self.auto_replace_emoji_shortcode
 4066                && selection.is_empty()
 4067                && text.as_ref().ends_with(':')
 4068            {
 4069                if let Some(possible_emoji_short_code) =
 4070                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4071                {
 4072                    if !possible_emoji_short_code.is_empty() {
 4073                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4074                            let emoji_shortcode_start = Point::new(
 4075                                selection.start.row,
 4076                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4077                            );
 4078
 4079                            // Remove shortcode from buffer
 4080                            edits.push((
 4081                                emoji_shortcode_start..selection.start,
 4082                                "".to_string().into(),
 4083                            ));
 4084                            new_selections.push((
 4085                                Selection {
 4086                                    id: selection.id,
 4087                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4088                                    end: snapshot.anchor_before(selection.start),
 4089                                    reversed: selection.reversed,
 4090                                    goal: selection.goal,
 4091                                },
 4092                                0,
 4093                            ));
 4094
 4095                            // Insert emoji
 4096                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4097                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4098                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4099
 4100                            continue;
 4101                        }
 4102                    }
 4103                }
 4104            }
 4105
 4106            // If not handling any auto-close operation, then just replace the selected
 4107            // text with the given input and move the selection to the end of the
 4108            // newly inserted text.
 4109            let anchor = snapshot.anchor_after(selection.end);
 4110            if !self.linked_edit_ranges.is_empty() {
 4111                let start_anchor = snapshot.anchor_before(selection.start);
 4112
 4113                let is_word_char = text.chars().next().map_or(true, |char| {
 4114                    let classifier = snapshot
 4115                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4116                        .ignore_punctuation(true);
 4117                    classifier.is_word(char)
 4118                });
 4119
 4120                if is_word_char {
 4121                    if let Some(ranges) = self
 4122                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4123                    {
 4124                        for (buffer, edits) in ranges {
 4125                            linked_edits
 4126                                .entry(buffer.clone())
 4127                                .or_default()
 4128                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4129                        }
 4130                    }
 4131                } else {
 4132                    clear_linked_edit_ranges = true;
 4133                }
 4134            }
 4135
 4136            new_selections.push((selection.map(|_| anchor), 0));
 4137            edits.push((selection.start..selection.end, text.clone()));
 4138        }
 4139
 4140        drop(snapshot);
 4141
 4142        self.transact(window, cx, |this, window, cx| {
 4143            if clear_linked_edit_ranges {
 4144                this.linked_edit_ranges.clear();
 4145            }
 4146            let initial_buffer_versions =
 4147                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4148
 4149            this.buffer.update(cx, |buffer, cx| {
 4150                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4151            });
 4152            for (buffer, edits) in linked_edits {
 4153                buffer.update(cx, |buffer, cx| {
 4154                    let snapshot = buffer.snapshot();
 4155                    let edits = edits
 4156                        .into_iter()
 4157                        .map(|(range, text)| {
 4158                            use text::ToPoint as TP;
 4159                            let end_point = TP::to_point(&range.end, &snapshot);
 4160                            let start_point = TP::to_point(&range.start, &snapshot);
 4161                            (start_point..end_point, text)
 4162                        })
 4163                        .sorted_by_key(|(range, _)| range.start);
 4164                    buffer.edit(edits, None, cx);
 4165                })
 4166            }
 4167            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4168            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4169            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4170            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4171                .zip(new_selection_deltas)
 4172                .map(|(selection, delta)| Selection {
 4173                    id: selection.id,
 4174                    start: selection.start + delta,
 4175                    end: selection.end + delta,
 4176                    reversed: selection.reversed,
 4177                    goal: SelectionGoal::None,
 4178                })
 4179                .collect::<Vec<_>>();
 4180
 4181            let mut i = 0;
 4182            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4183                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4184                let start = map.buffer_snapshot.anchor_before(position);
 4185                let end = map.buffer_snapshot.anchor_after(position);
 4186                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4187                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4188                        Ordering::Less => i += 1,
 4189                        Ordering::Greater => break,
 4190                        Ordering::Equal => {
 4191                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4192                                Ordering::Less => i += 1,
 4193                                Ordering::Equal => break,
 4194                                Ordering::Greater => break,
 4195                            }
 4196                        }
 4197                    }
 4198                }
 4199                this.autoclose_regions.insert(
 4200                    i,
 4201                    AutocloseRegion {
 4202                        selection_id,
 4203                        range: start..end,
 4204                        pair,
 4205                    },
 4206                );
 4207            }
 4208
 4209            let had_active_inline_completion = this.has_active_inline_completion();
 4210            this.change_selections(
 4211                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4212                window,
 4213                cx,
 4214                |s| s.select(new_selections),
 4215            );
 4216
 4217            if !bracket_inserted {
 4218                if let Some(on_type_format_task) =
 4219                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4220                {
 4221                    on_type_format_task.detach_and_log_err(cx);
 4222                }
 4223            }
 4224
 4225            let editor_settings = EditorSettings::get_global(cx);
 4226            if bracket_inserted
 4227                && (editor_settings.auto_signature_help
 4228                    || editor_settings.show_signature_help_after_edits)
 4229            {
 4230                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4231            }
 4232
 4233            let trigger_in_words =
 4234                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4235            if this.hard_wrap.is_some() {
 4236                let latest: Range<Point> = this.selections.newest(cx).range();
 4237                if latest.is_empty()
 4238                    && this
 4239                        .buffer()
 4240                        .read(cx)
 4241                        .snapshot(cx)
 4242                        .line_len(MultiBufferRow(latest.start.row))
 4243                        == latest.start.column
 4244                {
 4245                    this.rewrap_impl(
 4246                        RewrapOptions {
 4247                            override_language_settings: true,
 4248                            preserve_existing_whitespace: true,
 4249                        },
 4250                        cx,
 4251                    )
 4252                }
 4253            }
 4254            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4255            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4256            this.refresh_inline_completion(true, false, window, cx);
 4257            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4258        });
 4259    }
 4260
 4261    fn find_possible_emoji_shortcode_at_position(
 4262        snapshot: &MultiBufferSnapshot,
 4263        position: Point,
 4264    ) -> Option<String> {
 4265        let mut chars = Vec::new();
 4266        let mut found_colon = false;
 4267        for char in snapshot.reversed_chars_at(position).take(100) {
 4268            // Found a possible emoji shortcode in the middle of the buffer
 4269            if found_colon {
 4270                if char.is_whitespace() {
 4271                    chars.reverse();
 4272                    return Some(chars.iter().collect());
 4273                }
 4274                // If the previous character is not a whitespace, we are in the middle of a word
 4275                // and we only want to complete the shortcode if the word is made up of other emojis
 4276                let mut containing_word = String::new();
 4277                for ch in snapshot
 4278                    .reversed_chars_at(position)
 4279                    .skip(chars.len() + 1)
 4280                    .take(100)
 4281                {
 4282                    if ch.is_whitespace() {
 4283                        break;
 4284                    }
 4285                    containing_word.push(ch);
 4286                }
 4287                let containing_word = containing_word.chars().rev().collect::<String>();
 4288                if util::word_consists_of_emojis(containing_word.as_str()) {
 4289                    chars.reverse();
 4290                    return Some(chars.iter().collect());
 4291                }
 4292            }
 4293
 4294            if char.is_whitespace() || !char.is_ascii() {
 4295                return None;
 4296            }
 4297            if char == ':' {
 4298                found_colon = true;
 4299            } else {
 4300                chars.push(char);
 4301            }
 4302        }
 4303        // Found a possible emoji shortcode at the beginning of the buffer
 4304        chars.reverse();
 4305        Some(chars.iter().collect())
 4306    }
 4307
 4308    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4310        self.transact(window, cx, |this, window, cx| {
 4311            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4312                let selections = this.selections.all::<usize>(cx);
 4313                let multi_buffer = this.buffer.read(cx);
 4314                let buffer = multi_buffer.snapshot(cx);
 4315                selections
 4316                    .iter()
 4317                    .map(|selection| {
 4318                        let start_point = selection.start.to_point(&buffer);
 4319                        let mut existing_indent =
 4320                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4321                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4322                        let start = selection.start;
 4323                        let end = selection.end;
 4324                        let selection_is_empty = start == end;
 4325                        let language_scope = buffer.language_scope_at(start);
 4326                        let (
 4327                            comment_delimiter,
 4328                            doc_delimiter,
 4329                            insert_extra_newline,
 4330                            indent_on_newline,
 4331                            indent_on_extra_newline,
 4332                        ) = if let Some(language) = &language_scope {
 4333                            let mut insert_extra_newline =
 4334                                insert_extra_newline_brackets(&buffer, start..end, language)
 4335                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4336
 4337                            // Comment extension on newline is allowed only for cursor selections
 4338                            let comment_delimiter = maybe!({
 4339                                if !selection_is_empty {
 4340                                    return None;
 4341                                }
 4342
 4343                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4344                                    return None;
 4345                                }
 4346
 4347                                let delimiters = language.line_comment_prefixes();
 4348                                let max_len_of_delimiter =
 4349                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4350                                let (snapshot, range) =
 4351                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4352
 4353                                let num_of_whitespaces = snapshot
 4354                                    .chars_for_range(range.clone())
 4355                                    .take_while(|c| c.is_whitespace())
 4356                                    .count();
 4357                                let comment_candidate = snapshot
 4358                                    .chars_for_range(range)
 4359                                    .skip(num_of_whitespaces)
 4360                                    .take(max_len_of_delimiter)
 4361                                    .collect::<String>();
 4362                                let (delimiter, trimmed_len) = delimiters
 4363                                    .iter()
 4364                                    .filter_map(|delimiter| {
 4365                                        let prefix = delimiter.trim_end();
 4366                                        if comment_candidate.starts_with(prefix) {
 4367                                            Some((delimiter, prefix.len()))
 4368                                        } else {
 4369                                            None
 4370                                        }
 4371                                    })
 4372                                    .max_by_key(|(_, len)| *len)?;
 4373
 4374                                let cursor_is_placed_after_comment_marker =
 4375                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4376                                if cursor_is_placed_after_comment_marker {
 4377                                    Some(delimiter.clone())
 4378                                } else {
 4379                                    None
 4380                                }
 4381                            });
 4382
 4383                            let mut indent_on_newline = IndentSize::spaces(0);
 4384                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4385
 4386                            let doc_delimiter = maybe!({
 4387                                if !selection_is_empty {
 4388                                    return None;
 4389                                }
 4390
 4391                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4392                                    return None;
 4393                                }
 4394
 4395                                let DocumentationConfig {
 4396                                    start: start_tag,
 4397                                    end: end_tag,
 4398                                    prefix: delimiter,
 4399                                    tab_size: len,
 4400                                } = language.documentation()?;
 4401
 4402                                let is_within_block_comment = buffer
 4403                                    .language_scope_at(start_point)
 4404                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4405                                if !is_within_block_comment {
 4406                                    return None;
 4407                                }
 4408
 4409                                let (snapshot, range) =
 4410                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4411
 4412                                let num_of_whitespaces = snapshot
 4413                                    .chars_for_range(range.clone())
 4414                                    .take_while(|c| c.is_whitespace())
 4415                                    .count();
 4416
 4417                                // 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.
 4418                                let column = start_point.column;
 4419                                let cursor_is_after_start_tag = {
 4420                                    let start_tag_len = start_tag.len();
 4421                                    let start_tag_line = snapshot
 4422                                        .chars_for_range(range.clone())
 4423                                        .skip(num_of_whitespaces)
 4424                                        .take(start_tag_len)
 4425                                        .collect::<String>();
 4426                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4427                                        num_of_whitespaces + start_tag_len <= column as usize
 4428                                    } else {
 4429                                        false
 4430                                    }
 4431                                };
 4432
 4433                                let cursor_is_after_delimiter = {
 4434                                    let delimiter_trim = delimiter.trim_end();
 4435                                    let delimiter_line = snapshot
 4436                                        .chars_for_range(range.clone())
 4437                                        .skip(num_of_whitespaces)
 4438                                        .take(delimiter_trim.len())
 4439                                        .collect::<String>();
 4440                                    if delimiter_line.starts_with(delimiter_trim) {
 4441                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4442                                    } else {
 4443                                        false
 4444                                    }
 4445                                };
 4446
 4447                                let cursor_is_before_end_tag_if_exists = {
 4448                                    let mut char_position = 0u32;
 4449                                    let mut end_tag_offset = None;
 4450
 4451                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4452                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4453                                            let chars_before_match =
 4454                                                chunk[..byte_pos].chars().count() as u32;
 4455                                            end_tag_offset =
 4456                                                Some(char_position + chars_before_match);
 4457                                            break 'outer;
 4458                                        }
 4459                                        char_position += chunk.chars().count() as u32;
 4460                                    }
 4461
 4462                                    if let Some(end_tag_offset) = end_tag_offset {
 4463                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4464                                        if cursor_is_after_start_tag {
 4465                                            if cursor_is_before_end_tag {
 4466                                                insert_extra_newline = true;
 4467                                            }
 4468                                            let cursor_is_at_start_of_end_tag =
 4469                                                column == end_tag_offset;
 4470                                            if cursor_is_at_start_of_end_tag {
 4471                                                indent_on_extra_newline.len = (*len).into();
 4472                                            }
 4473                                        }
 4474                                        cursor_is_before_end_tag
 4475                                    } else {
 4476                                        true
 4477                                    }
 4478                                };
 4479
 4480                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4481                                    && cursor_is_before_end_tag_if_exists
 4482                                {
 4483                                    if cursor_is_after_start_tag {
 4484                                        indent_on_newline.len = (*len).into();
 4485                                    }
 4486                                    Some(delimiter.clone())
 4487                                } else {
 4488                                    None
 4489                                }
 4490                            });
 4491
 4492                            (
 4493                                comment_delimiter,
 4494                                doc_delimiter,
 4495                                insert_extra_newline,
 4496                                indent_on_newline,
 4497                                indent_on_extra_newline,
 4498                            )
 4499                        } else {
 4500                            (
 4501                                None,
 4502                                None,
 4503                                false,
 4504                                IndentSize::default(),
 4505                                IndentSize::default(),
 4506                            )
 4507                        };
 4508
 4509                        let prevent_auto_indent = doc_delimiter.is_some();
 4510                        let delimiter = comment_delimiter.or(doc_delimiter);
 4511
 4512                        let capacity_for_delimiter =
 4513                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4514                        let mut new_text = String::with_capacity(
 4515                            1 + capacity_for_delimiter
 4516                                + existing_indent.len as usize
 4517                                + indent_on_newline.len as usize
 4518                                + indent_on_extra_newline.len as usize,
 4519                        );
 4520                        new_text.push('\n');
 4521                        new_text.extend(existing_indent.chars());
 4522                        new_text.extend(indent_on_newline.chars());
 4523
 4524                        if let Some(delimiter) = &delimiter {
 4525                            new_text.push_str(delimiter);
 4526                        }
 4527
 4528                        if insert_extra_newline {
 4529                            new_text.push('\n');
 4530                            new_text.extend(existing_indent.chars());
 4531                            new_text.extend(indent_on_extra_newline.chars());
 4532                        }
 4533
 4534                        let anchor = buffer.anchor_after(end);
 4535                        let new_selection = selection.map(|_| anchor);
 4536                        (
 4537                            ((start..end, new_text), prevent_auto_indent),
 4538                            (insert_extra_newline, new_selection),
 4539                        )
 4540                    })
 4541                    .unzip()
 4542            };
 4543
 4544            let mut auto_indent_edits = Vec::new();
 4545            let mut edits = Vec::new();
 4546            for (edit, prevent_auto_indent) in edits_with_flags {
 4547                if prevent_auto_indent {
 4548                    edits.push(edit);
 4549                } else {
 4550                    auto_indent_edits.push(edit);
 4551                }
 4552            }
 4553            if !edits.is_empty() {
 4554                this.edit(edits, cx);
 4555            }
 4556            if !auto_indent_edits.is_empty() {
 4557                this.edit_with_autoindent(auto_indent_edits, cx);
 4558            }
 4559
 4560            let buffer = this.buffer.read(cx).snapshot(cx);
 4561            let new_selections = selection_info
 4562                .into_iter()
 4563                .map(|(extra_newline_inserted, new_selection)| {
 4564                    let mut cursor = new_selection.end.to_point(&buffer);
 4565                    if extra_newline_inserted {
 4566                        cursor.row -= 1;
 4567                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4568                    }
 4569                    new_selection.map(|_| cursor)
 4570                })
 4571                .collect();
 4572
 4573            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4574            this.refresh_inline_completion(true, false, window, cx);
 4575        });
 4576    }
 4577
 4578    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4579        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4580
 4581        let buffer = self.buffer.read(cx);
 4582        let snapshot = buffer.snapshot(cx);
 4583
 4584        let mut edits = Vec::new();
 4585        let mut rows = Vec::new();
 4586
 4587        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4588            let cursor = selection.head();
 4589            let row = cursor.row;
 4590
 4591            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4592
 4593            let newline = "\n".to_string();
 4594            edits.push((start_of_line..start_of_line, newline));
 4595
 4596            rows.push(row + rows_inserted as u32);
 4597        }
 4598
 4599        self.transact(window, cx, |editor, window, cx| {
 4600            editor.edit(edits, cx);
 4601
 4602            editor.change_selections(Default::default(), window, cx, |s| {
 4603                let mut index = 0;
 4604                s.move_cursors_with(|map, _, _| {
 4605                    let row = rows[index];
 4606                    index += 1;
 4607
 4608                    let point = Point::new(row, 0);
 4609                    let boundary = map.next_line_boundary(point).1;
 4610                    let clipped = map.clip_point(boundary, Bias::Left);
 4611
 4612                    (clipped, SelectionGoal::None)
 4613                });
 4614            });
 4615
 4616            let mut indent_edits = Vec::new();
 4617            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4618            for row in rows {
 4619                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4620                for (row, indent) in indents {
 4621                    if indent.len == 0 {
 4622                        continue;
 4623                    }
 4624
 4625                    let text = match indent.kind {
 4626                        IndentKind::Space => " ".repeat(indent.len as usize),
 4627                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4628                    };
 4629                    let point = Point::new(row.0, 0);
 4630                    indent_edits.push((point..point, text));
 4631                }
 4632            }
 4633            editor.edit(indent_edits, cx);
 4634        });
 4635    }
 4636
 4637    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4638        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4639
 4640        let buffer = self.buffer.read(cx);
 4641        let snapshot = buffer.snapshot(cx);
 4642
 4643        let mut edits = Vec::new();
 4644        let mut rows = Vec::new();
 4645        let mut rows_inserted = 0;
 4646
 4647        for selection in self.selections.all_adjusted(cx) {
 4648            let cursor = selection.head();
 4649            let row = cursor.row;
 4650
 4651            let point = Point::new(row + 1, 0);
 4652            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4653
 4654            let newline = "\n".to_string();
 4655            edits.push((start_of_line..start_of_line, newline));
 4656
 4657            rows_inserted += 1;
 4658            rows.push(row + rows_inserted);
 4659        }
 4660
 4661        self.transact(window, cx, |editor, window, cx| {
 4662            editor.edit(edits, cx);
 4663
 4664            editor.change_selections(Default::default(), window, cx, |s| {
 4665                let mut index = 0;
 4666                s.move_cursors_with(|map, _, _| {
 4667                    let row = rows[index];
 4668                    index += 1;
 4669
 4670                    let point = Point::new(row, 0);
 4671                    let boundary = map.next_line_boundary(point).1;
 4672                    let clipped = map.clip_point(boundary, Bias::Left);
 4673
 4674                    (clipped, SelectionGoal::None)
 4675                });
 4676            });
 4677
 4678            let mut indent_edits = Vec::new();
 4679            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4680            for row in rows {
 4681                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4682                for (row, indent) in indents {
 4683                    if indent.len == 0 {
 4684                        continue;
 4685                    }
 4686
 4687                    let text = match indent.kind {
 4688                        IndentKind::Space => " ".repeat(indent.len as usize),
 4689                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4690                    };
 4691                    let point = Point::new(row.0, 0);
 4692                    indent_edits.push((point..point, text));
 4693                }
 4694            }
 4695            editor.edit(indent_edits, cx);
 4696        });
 4697    }
 4698
 4699    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4700        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4701            original_indent_columns: Vec::new(),
 4702        });
 4703        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4704    }
 4705
 4706    fn insert_with_autoindent_mode(
 4707        &mut self,
 4708        text: &str,
 4709        autoindent_mode: Option<AutoindentMode>,
 4710        window: &mut Window,
 4711        cx: &mut Context<Self>,
 4712    ) {
 4713        if self.read_only(cx) {
 4714            return;
 4715        }
 4716
 4717        let text: Arc<str> = text.into();
 4718        self.transact(window, cx, |this, window, cx| {
 4719            let old_selections = this.selections.all_adjusted(cx);
 4720            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4721                let anchors = {
 4722                    let snapshot = buffer.read(cx);
 4723                    old_selections
 4724                        .iter()
 4725                        .map(|s| {
 4726                            let anchor = snapshot.anchor_after(s.head());
 4727                            s.map(|_| anchor)
 4728                        })
 4729                        .collect::<Vec<_>>()
 4730                };
 4731                buffer.edit(
 4732                    old_selections
 4733                        .iter()
 4734                        .map(|s| (s.start..s.end, text.clone())),
 4735                    autoindent_mode,
 4736                    cx,
 4737                );
 4738                anchors
 4739            });
 4740
 4741            this.change_selections(Default::default(), window, cx, |s| {
 4742                s.select_anchors(selection_anchors);
 4743            });
 4744
 4745            cx.notify();
 4746        });
 4747    }
 4748
 4749    fn trigger_completion_on_input(
 4750        &mut self,
 4751        text: &str,
 4752        trigger_in_words: bool,
 4753        window: &mut Window,
 4754        cx: &mut Context<Self>,
 4755    ) {
 4756        let completions_source = self
 4757            .context_menu
 4758            .borrow()
 4759            .as_ref()
 4760            .and_then(|menu| match menu {
 4761                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4762                CodeContextMenu::CodeActions(_) => None,
 4763            });
 4764
 4765        match completions_source {
 4766            Some(CompletionsMenuSource::Words) => {
 4767                self.show_word_completions(&ShowWordCompletions, window, cx)
 4768            }
 4769            Some(CompletionsMenuSource::Normal)
 4770            | Some(CompletionsMenuSource::SnippetChoices)
 4771            | None
 4772                if self.is_completion_trigger(
 4773                    text,
 4774                    trigger_in_words,
 4775                    completions_source.is_some(),
 4776                    cx,
 4777                ) =>
 4778            {
 4779                self.show_completions(
 4780                    &ShowCompletions {
 4781                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4782                    },
 4783                    window,
 4784                    cx,
 4785                )
 4786            }
 4787            _ => {
 4788                self.hide_context_menu(window, cx);
 4789            }
 4790        }
 4791    }
 4792
 4793    fn is_completion_trigger(
 4794        &self,
 4795        text: &str,
 4796        trigger_in_words: bool,
 4797        menu_is_open: bool,
 4798        cx: &mut Context<Self>,
 4799    ) -> bool {
 4800        let position = self.selections.newest_anchor().head();
 4801        let multibuffer = self.buffer.read(cx);
 4802        let Some(buffer) = position
 4803            .buffer_id
 4804            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4805        else {
 4806            return false;
 4807        };
 4808
 4809        if let Some(completion_provider) = &self.completion_provider {
 4810            completion_provider.is_completion_trigger(
 4811                &buffer,
 4812                position.text_anchor,
 4813                text,
 4814                trigger_in_words,
 4815                menu_is_open,
 4816                cx,
 4817            )
 4818        } else {
 4819            false
 4820        }
 4821    }
 4822
 4823    /// If any empty selections is touching the start of its innermost containing autoclose
 4824    /// region, expand it to select the brackets.
 4825    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4826        let selections = self.selections.all::<usize>(cx);
 4827        let buffer = self.buffer.read(cx).read(cx);
 4828        let new_selections = self
 4829            .selections_with_autoclose_regions(selections, &buffer)
 4830            .map(|(mut selection, region)| {
 4831                if !selection.is_empty() {
 4832                    return selection;
 4833                }
 4834
 4835                if let Some(region) = region {
 4836                    let mut range = region.range.to_offset(&buffer);
 4837                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4838                        range.start -= region.pair.start.len();
 4839                        if buffer.contains_str_at(range.start, &region.pair.start)
 4840                            && buffer.contains_str_at(range.end, &region.pair.end)
 4841                        {
 4842                            range.end += region.pair.end.len();
 4843                            selection.start = range.start;
 4844                            selection.end = range.end;
 4845
 4846                            return selection;
 4847                        }
 4848                    }
 4849                }
 4850
 4851                let always_treat_brackets_as_autoclosed = buffer
 4852                    .language_settings_at(selection.start, cx)
 4853                    .always_treat_brackets_as_autoclosed;
 4854
 4855                if !always_treat_brackets_as_autoclosed {
 4856                    return selection;
 4857                }
 4858
 4859                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4860                    for (pair, enabled) in scope.brackets() {
 4861                        if !enabled || !pair.close {
 4862                            continue;
 4863                        }
 4864
 4865                        if buffer.contains_str_at(selection.start, &pair.end) {
 4866                            let pair_start_len = pair.start.len();
 4867                            if buffer.contains_str_at(
 4868                                selection.start.saturating_sub(pair_start_len),
 4869                                &pair.start,
 4870                            ) {
 4871                                selection.start -= pair_start_len;
 4872                                selection.end += pair.end.len();
 4873
 4874                                return selection;
 4875                            }
 4876                        }
 4877                    }
 4878                }
 4879
 4880                selection
 4881            })
 4882            .collect();
 4883
 4884        drop(buffer);
 4885        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4886            selections.select(new_selections)
 4887        });
 4888    }
 4889
 4890    /// Iterate the given selections, and for each one, find the smallest surrounding
 4891    /// autoclose region. This uses the ordering of the selections and the autoclose
 4892    /// regions to avoid repeated comparisons.
 4893    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4894        &'a self,
 4895        selections: impl IntoIterator<Item = Selection<D>>,
 4896        buffer: &'a MultiBufferSnapshot,
 4897    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4898        let mut i = 0;
 4899        let mut regions = self.autoclose_regions.as_slice();
 4900        selections.into_iter().map(move |selection| {
 4901            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4902
 4903            let mut enclosing = None;
 4904            while let Some(pair_state) = regions.get(i) {
 4905                if pair_state.range.end.to_offset(buffer) < range.start {
 4906                    regions = &regions[i + 1..];
 4907                    i = 0;
 4908                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4909                    break;
 4910                } else {
 4911                    if pair_state.selection_id == selection.id {
 4912                        enclosing = Some(pair_state);
 4913                    }
 4914                    i += 1;
 4915                }
 4916            }
 4917
 4918            (selection, enclosing)
 4919        })
 4920    }
 4921
 4922    /// Remove any autoclose regions that no longer contain their selection.
 4923    fn invalidate_autoclose_regions(
 4924        &mut self,
 4925        mut selections: &[Selection<Anchor>],
 4926        buffer: &MultiBufferSnapshot,
 4927    ) {
 4928        self.autoclose_regions.retain(|state| {
 4929            let mut i = 0;
 4930            while let Some(selection) = selections.get(i) {
 4931                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4932                    selections = &selections[1..];
 4933                    continue;
 4934                }
 4935                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4936                    break;
 4937                }
 4938                if selection.id == state.selection_id {
 4939                    return true;
 4940                } else {
 4941                    i += 1;
 4942                }
 4943            }
 4944            false
 4945        });
 4946    }
 4947
 4948    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4949        let offset = position.to_offset(buffer);
 4950        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4951        if offset > word_range.start && kind == Some(CharKind::Word) {
 4952            Some(
 4953                buffer
 4954                    .text_for_range(word_range.start..offset)
 4955                    .collect::<String>(),
 4956            )
 4957        } else {
 4958            None
 4959        }
 4960    }
 4961
 4962    pub fn toggle_inline_values(
 4963        &mut self,
 4964        _: &ToggleInlineValues,
 4965        _: &mut Window,
 4966        cx: &mut Context<Self>,
 4967    ) {
 4968        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4969
 4970        self.refresh_inline_values(cx);
 4971    }
 4972
 4973    pub fn toggle_inlay_hints(
 4974        &mut self,
 4975        _: &ToggleInlayHints,
 4976        _: &mut Window,
 4977        cx: &mut Context<Self>,
 4978    ) {
 4979        self.refresh_inlay_hints(
 4980            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4981            cx,
 4982        );
 4983    }
 4984
 4985    pub fn inlay_hints_enabled(&self) -> bool {
 4986        self.inlay_hint_cache.enabled
 4987    }
 4988
 4989    pub fn inline_values_enabled(&self) -> bool {
 4990        self.inline_value_cache.enabled
 4991    }
 4992
 4993    #[cfg(any(test, feature = "test-support"))]
 4994    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4995        self.display_map
 4996            .read(cx)
 4997            .current_inlays()
 4998            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4999            .cloned()
 5000            .collect()
 5001    }
 5002
 5003    #[cfg(any(test, feature = "test-support"))]
 5004    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5005        self.display_map
 5006            .read(cx)
 5007            .current_inlays()
 5008            .cloned()
 5009            .collect()
 5010    }
 5011
 5012    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5013        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5014            return;
 5015        }
 5016
 5017        let reason_description = reason.description();
 5018        let ignore_debounce = matches!(
 5019            reason,
 5020            InlayHintRefreshReason::SettingsChange(_)
 5021                | InlayHintRefreshReason::Toggle(_)
 5022                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5023                | InlayHintRefreshReason::ModifiersChanged(_)
 5024        );
 5025        let (invalidate_cache, required_languages) = match reason {
 5026            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5027                match self.inlay_hint_cache.modifiers_override(enabled) {
 5028                    Some(enabled) => {
 5029                        if enabled {
 5030                            (InvalidationStrategy::RefreshRequested, None)
 5031                        } else {
 5032                            self.splice_inlays(
 5033                                &self
 5034                                    .visible_inlay_hints(cx)
 5035                                    .iter()
 5036                                    .map(|inlay| inlay.id)
 5037                                    .collect::<Vec<InlayId>>(),
 5038                                Vec::new(),
 5039                                cx,
 5040                            );
 5041                            return;
 5042                        }
 5043                    }
 5044                    None => return,
 5045                }
 5046            }
 5047            InlayHintRefreshReason::Toggle(enabled) => {
 5048                if self.inlay_hint_cache.toggle(enabled) {
 5049                    if enabled {
 5050                        (InvalidationStrategy::RefreshRequested, None)
 5051                    } else {
 5052                        self.splice_inlays(
 5053                            &self
 5054                                .visible_inlay_hints(cx)
 5055                                .iter()
 5056                                .map(|inlay| inlay.id)
 5057                                .collect::<Vec<InlayId>>(),
 5058                            Vec::new(),
 5059                            cx,
 5060                        );
 5061                        return;
 5062                    }
 5063                } else {
 5064                    return;
 5065                }
 5066            }
 5067            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5068                match self.inlay_hint_cache.update_settings(
 5069                    &self.buffer,
 5070                    new_settings,
 5071                    self.visible_inlay_hints(cx),
 5072                    cx,
 5073                ) {
 5074                    ControlFlow::Break(Some(InlaySplice {
 5075                        to_remove,
 5076                        to_insert,
 5077                    })) => {
 5078                        self.splice_inlays(&to_remove, to_insert, cx);
 5079                        return;
 5080                    }
 5081                    ControlFlow::Break(None) => return,
 5082                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5083                }
 5084            }
 5085            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5086                if let Some(InlaySplice {
 5087                    to_remove,
 5088                    to_insert,
 5089                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5090                {
 5091                    self.splice_inlays(&to_remove, to_insert, cx);
 5092                }
 5093                self.display_map.update(cx, |display_map, _| {
 5094                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5095                });
 5096                return;
 5097            }
 5098            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5099            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5100                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5101            }
 5102            InlayHintRefreshReason::RefreshRequested => {
 5103                (InvalidationStrategy::RefreshRequested, None)
 5104            }
 5105        };
 5106
 5107        if let Some(InlaySplice {
 5108            to_remove,
 5109            to_insert,
 5110        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5111            reason_description,
 5112            self.visible_excerpts(required_languages.as_ref(), cx),
 5113            invalidate_cache,
 5114            ignore_debounce,
 5115            cx,
 5116        ) {
 5117            self.splice_inlays(&to_remove, to_insert, cx);
 5118        }
 5119    }
 5120
 5121    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5122        self.display_map
 5123            .read(cx)
 5124            .current_inlays()
 5125            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5126            .cloned()
 5127            .collect()
 5128    }
 5129
 5130    pub fn visible_excerpts(
 5131        &self,
 5132        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5133        cx: &mut Context<Editor>,
 5134    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5135        let Some(project) = self.project.as_ref() else {
 5136            return HashMap::default();
 5137        };
 5138        let project = project.read(cx);
 5139        let multi_buffer = self.buffer().read(cx);
 5140        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5141        let multi_buffer_visible_start = self
 5142            .scroll_manager
 5143            .anchor()
 5144            .anchor
 5145            .to_point(&multi_buffer_snapshot);
 5146        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5147            multi_buffer_visible_start
 5148                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5149            Bias::Left,
 5150        );
 5151        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5152        multi_buffer_snapshot
 5153            .range_to_buffer_ranges(multi_buffer_visible_range)
 5154            .into_iter()
 5155            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5156            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5157                let buffer_file = project::File::from_dyn(buffer.file())?;
 5158                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5159                let worktree_entry = buffer_worktree
 5160                    .read(cx)
 5161                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5162                if worktree_entry.is_ignored {
 5163                    return None;
 5164                }
 5165
 5166                let language = buffer.language()?;
 5167                if let Some(restrict_to_languages) = restrict_to_languages {
 5168                    if !restrict_to_languages.contains(language) {
 5169                        return None;
 5170                    }
 5171                }
 5172                Some((
 5173                    excerpt_id,
 5174                    (
 5175                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5176                        buffer.version().clone(),
 5177                        excerpt_visible_range,
 5178                    ),
 5179                ))
 5180            })
 5181            .collect()
 5182    }
 5183
 5184    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5185        TextLayoutDetails {
 5186            text_system: window.text_system().clone(),
 5187            editor_style: self.style.clone().unwrap(),
 5188            rem_size: window.rem_size(),
 5189            scroll_anchor: self.scroll_manager.anchor(),
 5190            visible_rows: self.visible_line_count(),
 5191            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5192        }
 5193    }
 5194
 5195    pub fn splice_inlays(
 5196        &self,
 5197        to_remove: &[InlayId],
 5198        to_insert: Vec<Inlay>,
 5199        cx: &mut Context<Self>,
 5200    ) {
 5201        self.display_map.update(cx, |display_map, cx| {
 5202            display_map.splice_inlays(to_remove, to_insert, cx)
 5203        });
 5204        cx.notify();
 5205    }
 5206
 5207    fn trigger_on_type_formatting(
 5208        &self,
 5209        input: String,
 5210        window: &mut Window,
 5211        cx: &mut Context<Self>,
 5212    ) -> Option<Task<Result<()>>> {
 5213        if input.len() != 1 {
 5214            return None;
 5215        }
 5216
 5217        let project = self.project.as_ref()?;
 5218        let position = self.selections.newest_anchor().head();
 5219        let (buffer, buffer_position) = self
 5220            .buffer
 5221            .read(cx)
 5222            .text_anchor_for_position(position, cx)?;
 5223
 5224        let settings = language_settings::language_settings(
 5225            buffer
 5226                .read(cx)
 5227                .language_at(buffer_position)
 5228                .map(|l| l.name()),
 5229            buffer.read(cx).file(),
 5230            cx,
 5231        );
 5232        if !settings.use_on_type_format {
 5233            return None;
 5234        }
 5235
 5236        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5237        // hence we do LSP request & edit on host side only — add formats to host's history.
 5238        let push_to_lsp_host_history = true;
 5239        // If this is not the host, append its history with new edits.
 5240        let push_to_client_history = project.read(cx).is_via_collab();
 5241
 5242        let on_type_formatting = project.update(cx, |project, cx| {
 5243            project.on_type_format(
 5244                buffer.clone(),
 5245                buffer_position,
 5246                input,
 5247                push_to_lsp_host_history,
 5248                cx,
 5249            )
 5250        });
 5251        Some(cx.spawn_in(window, async move |editor, cx| {
 5252            if let Some(transaction) = on_type_formatting.await? {
 5253                if push_to_client_history {
 5254                    buffer
 5255                        .update(cx, |buffer, _| {
 5256                            buffer.push_transaction(transaction, Instant::now());
 5257                            buffer.finalize_last_transaction();
 5258                        })
 5259                        .ok();
 5260                }
 5261                editor.update(cx, |editor, cx| {
 5262                    editor.refresh_document_highlights(cx);
 5263                })?;
 5264            }
 5265            Ok(())
 5266        }))
 5267    }
 5268
 5269    pub fn show_word_completions(
 5270        &mut self,
 5271        _: &ShowWordCompletions,
 5272        window: &mut Window,
 5273        cx: &mut Context<Self>,
 5274    ) {
 5275        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5276    }
 5277
 5278    pub fn show_completions(
 5279        &mut self,
 5280        options: &ShowCompletions,
 5281        window: &mut Window,
 5282        cx: &mut Context<Self>,
 5283    ) {
 5284        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5285    }
 5286
 5287    fn open_or_update_completions_menu(
 5288        &mut self,
 5289        requested_source: Option<CompletionsMenuSource>,
 5290        trigger: Option<&str>,
 5291        window: &mut Window,
 5292        cx: &mut Context<Self>,
 5293    ) {
 5294        if self.pending_rename.is_some() {
 5295            return;
 5296        }
 5297
 5298        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5299
 5300        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5301        // inserted and selected. To handle that case, the start of the selection is used so that
 5302        // the menu starts with all choices.
 5303        let position = self
 5304            .selections
 5305            .newest_anchor()
 5306            .start
 5307            .bias_right(&multibuffer_snapshot);
 5308        if position.diff_base_anchor.is_some() {
 5309            return;
 5310        }
 5311        let (buffer, buffer_position) =
 5312            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5313                output
 5314            } else {
 5315                return;
 5316            };
 5317        let buffer_snapshot = buffer.read(cx).snapshot();
 5318
 5319        let query: Option<Arc<String>> =
 5320            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5321
 5322        drop(multibuffer_snapshot);
 5323
 5324        let provider = match requested_source {
 5325            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5326            Some(CompletionsMenuSource::Words) => None,
 5327            Some(CompletionsMenuSource::SnippetChoices) => {
 5328                log::error!("bug: SnippetChoices requested_source is not handled");
 5329                None
 5330            }
 5331        };
 5332
 5333        let sort_completions = provider
 5334            .as_ref()
 5335            .map_or(false, |provider| provider.sort_completions());
 5336
 5337        let filter_completions = provider
 5338            .as_ref()
 5339            .map_or(true, |provider| provider.filter_completions());
 5340
 5341        let trigger_kind = match trigger {
 5342            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5343                CompletionTriggerKind::TRIGGER_CHARACTER
 5344            }
 5345            _ => CompletionTriggerKind::INVOKED,
 5346        };
 5347        let completion_context = CompletionContext {
 5348            trigger_character: trigger.and_then(|trigger| {
 5349                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5350                    Some(String::from(trigger))
 5351                } else {
 5352                    None
 5353                }
 5354            }),
 5355            trigger_kind,
 5356        };
 5357
 5358        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5359        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5360        // involve trigger chars, so this is skipped in that case.
 5361        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5362        {
 5363            let menu_is_open = matches!(
 5364                self.context_menu.borrow().as_ref(),
 5365                Some(CodeContextMenu::Completions(_))
 5366            );
 5367            if menu_is_open {
 5368                self.hide_context_menu(window, cx);
 5369            }
 5370        }
 5371
 5372        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5373            if filter_completions {
 5374                menu.filter(query.clone(), provider.clone(), window, cx);
 5375            }
 5376            // When `is_incomplete` is false, no need to re-query completions when the current query
 5377            // is a suffix of the initial query.
 5378            if !menu.is_incomplete {
 5379                // If the new query is a suffix of the old query (typing more characters) and
 5380                // the previous result was complete, the existing completions can be filtered.
 5381                //
 5382                // Note that this is always true for snippet completions.
 5383                let query_matches = match (&menu.initial_query, &query) {
 5384                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5385                    (None, _) => true,
 5386                    _ => false,
 5387                };
 5388                if query_matches {
 5389                    let position_matches = if menu.initial_position == position {
 5390                        true
 5391                    } else {
 5392                        let snapshot = self.buffer.read(cx).read(cx);
 5393                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5394                    };
 5395                    if position_matches {
 5396                        return;
 5397                    }
 5398                }
 5399            }
 5400        };
 5401
 5402        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5403            buffer_snapshot.surrounding_word(buffer_position)
 5404        {
 5405            let word_to_exclude = buffer_snapshot
 5406                .text_for_range(word_range.clone())
 5407                .collect::<String>();
 5408            (
 5409                buffer_snapshot.anchor_before(word_range.start)
 5410                    ..buffer_snapshot.anchor_after(buffer_position),
 5411                Some(word_to_exclude),
 5412            )
 5413        } else {
 5414            (buffer_position..buffer_position, None)
 5415        };
 5416
 5417        let language = buffer_snapshot
 5418            .language_at(buffer_position)
 5419            .map(|language| language.name());
 5420
 5421        let completion_settings =
 5422            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5423
 5424        let show_completion_documentation = buffer_snapshot
 5425            .settings_at(buffer_position, cx)
 5426            .show_completion_documentation;
 5427
 5428        // The document can be large, so stay in reasonable bounds when searching for words,
 5429        // otherwise completion pop-up might be slow to appear.
 5430        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5431        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5432        let min_word_search = buffer_snapshot.clip_point(
 5433            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5434            Bias::Left,
 5435        );
 5436        let max_word_search = buffer_snapshot.clip_point(
 5437            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5438            Bias::Right,
 5439        );
 5440        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5441            ..buffer_snapshot.point_to_offset(max_word_search);
 5442
 5443        let skip_digits = query
 5444            .as_ref()
 5445            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5446
 5447        let (mut words, provider_responses) = match &provider {
 5448            Some(provider) => {
 5449                let provider_responses = provider.completions(
 5450                    position.excerpt_id,
 5451                    &buffer,
 5452                    buffer_position,
 5453                    completion_context,
 5454                    window,
 5455                    cx,
 5456                );
 5457
 5458                let words = match completion_settings.words {
 5459                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5460                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5461                        .background_spawn(async move {
 5462                            buffer_snapshot.words_in_range(WordsQuery {
 5463                                fuzzy_contents: None,
 5464                                range: word_search_range,
 5465                                skip_digits,
 5466                            })
 5467                        }),
 5468                };
 5469
 5470                (words, provider_responses)
 5471            }
 5472            None => (
 5473                cx.background_spawn(async move {
 5474                    buffer_snapshot.words_in_range(WordsQuery {
 5475                        fuzzy_contents: None,
 5476                        range: word_search_range,
 5477                        skip_digits,
 5478                    })
 5479                }),
 5480                Task::ready(Ok(Vec::new())),
 5481            ),
 5482        };
 5483
 5484        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5485
 5486        let id = post_inc(&mut self.next_completion_id);
 5487        let task = cx.spawn_in(window, async move |editor, cx| {
 5488            let Ok(()) = editor.update(cx, |this, _| {
 5489                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5490            }) else {
 5491                return;
 5492            };
 5493
 5494            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5495            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5496            let mut completions = Vec::new();
 5497            let mut is_incomplete = false;
 5498            if let Some(provider_responses) = provider_responses.await.log_err() {
 5499                if !provider_responses.is_empty() {
 5500                    for response in provider_responses {
 5501                        completions.extend(response.completions);
 5502                        is_incomplete = is_incomplete || response.is_incomplete;
 5503                    }
 5504                    if completion_settings.words == WordsCompletionMode::Fallback {
 5505                        words = Task::ready(BTreeMap::default());
 5506                    }
 5507                }
 5508            }
 5509
 5510            let mut words = words.await;
 5511            if let Some(word_to_exclude) = &word_to_exclude {
 5512                words.remove(word_to_exclude);
 5513            }
 5514            for lsp_completion in &completions {
 5515                words.remove(&lsp_completion.new_text);
 5516            }
 5517            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5518                replace_range: word_replace_range.clone(),
 5519                new_text: word.clone(),
 5520                label: CodeLabel::plain(word, None),
 5521                icon_path: None,
 5522                documentation: None,
 5523                source: CompletionSource::BufferWord {
 5524                    word_range,
 5525                    resolved: false,
 5526                },
 5527                insert_text_mode: Some(InsertTextMode::AS_IS),
 5528                confirm: None,
 5529            }));
 5530
 5531            let menu = if completions.is_empty() {
 5532                None
 5533            } else {
 5534                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5535                    let languages = editor
 5536                        .workspace
 5537                        .as_ref()
 5538                        .and_then(|(workspace, _)| workspace.upgrade())
 5539                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5540                    let menu = CompletionsMenu::new(
 5541                        id,
 5542                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5543                        sort_completions,
 5544                        show_completion_documentation,
 5545                        position,
 5546                        query.clone(),
 5547                        is_incomplete,
 5548                        buffer.clone(),
 5549                        completions.into(),
 5550                        snippet_sort_order,
 5551                        languages,
 5552                        language,
 5553                        cx,
 5554                    );
 5555
 5556                    let query = if filter_completions { query } else { None };
 5557                    let matches_task = if let Some(query) = query {
 5558                        menu.do_async_filtering(query, cx)
 5559                    } else {
 5560                        Task::ready(menu.unfiltered_matches())
 5561                    };
 5562                    (menu, matches_task)
 5563                }) else {
 5564                    return;
 5565                };
 5566
 5567                let matches = matches_task.await;
 5568
 5569                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5570                    // Newer menu already set, so exit.
 5571                    match editor.context_menu.borrow().as_ref() {
 5572                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5573                            if prev_menu.id > id {
 5574                                return;
 5575                            }
 5576                        }
 5577                        _ => {}
 5578                    };
 5579
 5580                    // Only valid to take prev_menu because it the new menu is immediately set
 5581                    // below, or the menu is hidden.
 5582                    match editor.context_menu.borrow_mut().take() {
 5583                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5584                            let position_matches =
 5585                                if prev_menu.initial_position == menu.initial_position {
 5586                                    true
 5587                                } else {
 5588                                    let snapshot = editor.buffer.read(cx).read(cx);
 5589                                    prev_menu.initial_position.to_offset(&snapshot)
 5590                                        == menu.initial_position.to_offset(&snapshot)
 5591                                };
 5592                            if position_matches {
 5593                                // Preserve markdown cache before `set_filter_results` because it will
 5594                                // try to populate the documentation cache.
 5595                                menu.preserve_markdown_cache(prev_menu);
 5596                            }
 5597                        }
 5598                        _ => {}
 5599                    };
 5600
 5601                    menu.set_filter_results(matches, provider, window, cx);
 5602                }) else {
 5603                    return;
 5604                };
 5605
 5606                menu.visible().then_some(menu)
 5607            };
 5608
 5609            editor
 5610                .update_in(cx, |editor, window, cx| {
 5611                    if editor.focus_handle.is_focused(window) {
 5612                        if let Some(menu) = menu {
 5613                            *editor.context_menu.borrow_mut() =
 5614                                Some(CodeContextMenu::Completions(menu));
 5615
 5616                            crate::hover_popover::hide_hover(editor, cx);
 5617                            if editor.show_edit_predictions_in_menu() {
 5618                                editor.update_visible_inline_completion(window, cx);
 5619                            } else {
 5620                                editor.discard_inline_completion(false, cx);
 5621                            }
 5622
 5623                            cx.notify();
 5624                            return;
 5625                        }
 5626                    }
 5627
 5628                    if editor.completion_tasks.len() <= 1 {
 5629                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5630                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5631                        // If it was already hidden and we don't show inline completions in the menu, we should
 5632                        // also show the inline-completion when available.
 5633                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5634                            editor.update_visible_inline_completion(window, cx);
 5635                        }
 5636                    }
 5637                })
 5638                .ok();
 5639        });
 5640
 5641        self.completion_tasks.push((id, task));
 5642    }
 5643
 5644    #[cfg(feature = "test-support")]
 5645    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5646        let menu = self.context_menu.borrow();
 5647        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5648            let completions = menu.completions.borrow();
 5649            Some(completions.to_vec())
 5650        } else {
 5651            None
 5652        }
 5653    }
 5654
 5655    pub fn with_completions_menu_matching_id<R>(
 5656        &self,
 5657        id: CompletionId,
 5658        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5659    ) -> R {
 5660        let mut context_menu = self.context_menu.borrow_mut();
 5661        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5662            return f(None);
 5663        };
 5664        if completions_menu.id != id {
 5665            return f(None);
 5666        }
 5667        f(Some(completions_menu))
 5668    }
 5669
 5670    pub fn confirm_completion(
 5671        &mut self,
 5672        action: &ConfirmCompletion,
 5673        window: &mut Window,
 5674        cx: &mut Context<Self>,
 5675    ) -> Option<Task<Result<()>>> {
 5676        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5677        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5678    }
 5679
 5680    pub fn confirm_completion_insert(
 5681        &mut self,
 5682        _: &ConfirmCompletionInsert,
 5683        window: &mut Window,
 5684        cx: &mut Context<Self>,
 5685    ) -> Option<Task<Result<()>>> {
 5686        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5687        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5688    }
 5689
 5690    pub fn confirm_completion_replace(
 5691        &mut self,
 5692        _: &ConfirmCompletionReplace,
 5693        window: &mut Window,
 5694        cx: &mut Context<Self>,
 5695    ) -> Option<Task<Result<()>>> {
 5696        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5697        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5698    }
 5699
 5700    pub fn compose_completion(
 5701        &mut self,
 5702        action: &ComposeCompletion,
 5703        window: &mut Window,
 5704        cx: &mut Context<Self>,
 5705    ) -> Option<Task<Result<()>>> {
 5706        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5707        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5708    }
 5709
 5710    fn do_completion(
 5711        &mut self,
 5712        item_ix: Option<usize>,
 5713        intent: CompletionIntent,
 5714        window: &mut Window,
 5715        cx: &mut Context<Editor>,
 5716    ) -> Option<Task<Result<()>>> {
 5717        use language::ToOffset as _;
 5718
 5719        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5720        else {
 5721            return None;
 5722        };
 5723
 5724        let candidate_id = {
 5725            let entries = completions_menu.entries.borrow();
 5726            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5727            if self.show_edit_predictions_in_menu() {
 5728                self.discard_inline_completion(true, cx);
 5729            }
 5730            mat.candidate_id
 5731        };
 5732
 5733        let completion = completions_menu
 5734            .completions
 5735            .borrow()
 5736            .get(candidate_id)?
 5737            .clone();
 5738        cx.stop_propagation();
 5739
 5740        let buffer_handle = completions_menu.buffer.clone();
 5741
 5742        let CompletionEdit {
 5743            new_text,
 5744            snippet,
 5745            replace_range,
 5746        } = process_completion_for_edit(
 5747            &completion,
 5748            intent,
 5749            &buffer_handle,
 5750            &completions_menu.initial_position.text_anchor,
 5751            cx,
 5752        );
 5753
 5754        let buffer = buffer_handle.read(cx);
 5755        let snapshot = self.buffer.read(cx).snapshot(cx);
 5756        let newest_anchor = self.selections.newest_anchor();
 5757        let replace_range_multibuffer = {
 5758            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5759            let multibuffer_anchor = snapshot
 5760                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5761                .unwrap()
 5762                ..snapshot
 5763                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5764                    .unwrap();
 5765            multibuffer_anchor.start.to_offset(&snapshot)
 5766                ..multibuffer_anchor.end.to_offset(&snapshot)
 5767        };
 5768        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5769            return None;
 5770        }
 5771
 5772        let old_text = buffer
 5773            .text_for_range(replace_range.clone())
 5774            .collect::<String>();
 5775        let lookbehind = newest_anchor
 5776            .start
 5777            .text_anchor
 5778            .to_offset(buffer)
 5779            .saturating_sub(replace_range.start);
 5780        let lookahead = replace_range
 5781            .end
 5782            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5783        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5784        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5785
 5786        let selections = self.selections.all::<usize>(cx);
 5787        let mut ranges = Vec::new();
 5788        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5789
 5790        for selection in &selections {
 5791            let range = if selection.id == newest_anchor.id {
 5792                replace_range_multibuffer.clone()
 5793            } else {
 5794                let mut range = selection.range();
 5795
 5796                // if prefix is present, don't duplicate it
 5797                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5798                    range.start = range.start.saturating_sub(lookbehind);
 5799
 5800                    // if suffix is also present, mimic the newest cursor and replace it
 5801                    if selection.id != newest_anchor.id
 5802                        && snapshot.contains_str_at(range.end, suffix)
 5803                    {
 5804                        range.end += lookahead;
 5805                    }
 5806                }
 5807                range
 5808            };
 5809
 5810            ranges.push(range.clone());
 5811
 5812            if !self.linked_edit_ranges.is_empty() {
 5813                let start_anchor = snapshot.anchor_before(range.start);
 5814                let end_anchor = snapshot.anchor_after(range.end);
 5815                if let Some(ranges) = self
 5816                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5817                {
 5818                    for (buffer, edits) in ranges {
 5819                        linked_edits
 5820                            .entry(buffer.clone())
 5821                            .or_default()
 5822                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5823                    }
 5824                }
 5825            }
 5826        }
 5827
 5828        let common_prefix_len = old_text
 5829            .chars()
 5830            .zip(new_text.chars())
 5831            .take_while(|(a, b)| a == b)
 5832            .map(|(a, _)| a.len_utf8())
 5833            .sum::<usize>();
 5834
 5835        cx.emit(EditorEvent::InputHandled {
 5836            utf16_range_to_replace: None,
 5837            text: new_text[common_prefix_len..].into(),
 5838        });
 5839
 5840        self.transact(window, cx, |this, window, cx| {
 5841            if let Some(mut snippet) = snippet {
 5842                snippet.text = new_text.to_string();
 5843                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5844            } else {
 5845                this.buffer.update(cx, |buffer, cx| {
 5846                    let auto_indent = match completion.insert_text_mode {
 5847                        Some(InsertTextMode::AS_IS) => None,
 5848                        _ => this.autoindent_mode.clone(),
 5849                    };
 5850                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5851                    buffer.edit(edits, auto_indent, cx);
 5852                });
 5853            }
 5854            for (buffer, edits) in linked_edits {
 5855                buffer.update(cx, |buffer, cx| {
 5856                    let snapshot = buffer.snapshot();
 5857                    let edits = edits
 5858                        .into_iter()
 5859                        .map(|(range, text)| {
 5860                            use text::ToPoint as TP;
 5861                            let end_point = TP::to_point(&range.end, &snapshot);
 5862                            let start_point = TP::to_point(&range.start, &snapshot);
 5863                            (start_point..end_point, text)
 5864                        })
 5865                        .sorted_by_key(|(range, _)| range.start);
 5866                    buffer.edit(edits, None, cx);
 5867                })
 5868            }
 5869
 5870            this.refresh_inline_completion(true, false, window, cx);
 5871        });
 5872
 5873        let show_new_completions_on_confirm = completion
 5874            .confirm
 5875            .as_ref()
 5876            .map_or(false, |confirm| confirm(intent, window, cx));
 5877        if show_new_completions_on_confirm {
 5878            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5879        }
 5880
 5881        let provider = self.completion_provider.as_ref()?;
 5882        drop(completion);
 5883        let apply_edits = provider.apply_additional_edits_for_completion(
 5884            buffer_handle,
 5885            completions_menu.completions.clone(),
 5886            candidate_id,
 5887            true,
 5888            cx,
 5889        );
 5890
 5891        let editor_settings = EditorSettings::get_global(cx);
 5892        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5893            // After the code completion is finished, users often want to know what signatures are needed.
 5894            // so we should automatically call signature_help
 5895            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5896        }
 5897
 5898        Some(cx.foreground_executor().spawn(async move {
 5899            apply_edits.await?;
 5900            Ok(())
 5901        }))
 5902    }
 5903
 5904    pub fn toggle_code_actions(
 5905        &mut self,
 5906        action: &ToggleCodeActions,
 5907        window: &mut Window,
 5908        cx: &mut Context<Self>,
 5909    ) {
 5910        let quick_launch = action.quick_launch;
 5911        let mut context_menu = self.context_menu.borrow_mut();
 5912        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5913            if code_actions.deployed_from == action.deployed_from {
 5914                // Toggle if we're selecting the same one
 5915                *context_menu = None;
 5916                cx.notify();
 5917                return;
 5918            } else {
 5919                // Otherwise, clear it and start a new one
 5920                *context_menu = None;
 5921                cx.notify();
 5922            }
 5923        }
 5924        drop(context_menu);
 5925        let snapshot = self.snapshot(window, cx);
 5926        let deployed_from = action.deployed_from.clone();
 5927        let action = action.clone();
 5928        self.completion_tasks.clear();
 5929        self.discard_inline_completion(false, cx);
 5930
 5931        let multibuffer_point = match &action.deployed_from {
 5932            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5933                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5934            }
 5935            _ => self.selections.newest::<Point>(cx).head(),
 5936        };
 5937        let Some((buffer, buffer_row)) = snapshot
 5938            .buffer_snapshot
 5939            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5940            .and_then(|(buffer_snapshot, range)| {
 5941                self.buffer()
 5942                    .read(cx)
 5943                    .buffer(buffer_snapshot.remote_id())
 5944                    .map(|buffer| (buffer, range.start.row))
 5945            })
 5946        else {
 5947            return;
 5948        };
 5949        let buffer_id = buffer.read(cx).remote_id();
 5950        let tasks = self
 5951            .tasks
 5952            .get(&(buffer_id, buffer_row))
 5953            .map(|t| Arc::new(t.to_owned()));
 5954
 5955        if !self.focus_handle.is_focused(window) {
 5956            return;
 5957        }
 5958        let project = self.project.clone();
 5959
 5960        let code_actions_task = match deployed_from {
 5961            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5962            _ => self.code_actions(buffer_row, window, cx),
 5963        };
 5964
 5965        let runnable_task = match deployed_from {
 5966            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5967            _ => {
 5968                let mut task_context_task = Task::ready(None);
 5969                if let Some(tasks) = &tasks {
 5970                    if let Some(project) = project {
 5971                        task_context_task =
 5972                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5973                    }
 5974                }
 5975
 5976                cx.spawn_in(window, {
 5977                    let buffer = buffer.clone();
 5978                    async move |editor, cx| {
 5979                        let task_context = task_context_task.await;
 5980
 5981                        let resolved_tasks =
 5982                            tasks
 5983                                .zip(task_context.clone())
 5984                                .map(|(tasks, task_context)| ResolvedTasks {
 5985                                    templates: tasks.resolve(&task_context).collect(),
 5986                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5987                                        multibuffer_point.row,
 5988                                        tasks.column,
 5989                                    )),
 5990                                });
 5991                        let debug_scenarios = editor
 5992                            .update(cx, |editor, cx| {
 5993                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5994                            })?
 5995                            .await;
 5996                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5997                    }
 5998                })
 5999            }
 6000        };
 6001
 6002        cx.spawn_in(window, async move |editor, cx| {
 6003            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6004            let code_actions = code_actions_task.await;
 6005            let spawn_straight_away = quick_launch
 6006                && resolved_tasks
 6007                    .as_ref()
 6008                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6009                && code_actions
 6010                    .as_ref()
 6011                    .map_or(true, |actions| actions.is_empty())
 6012                && debug_scenarios.is_empty();
 6013
 6014            editor.update_in(cx, |editor, window, cx| {
 6015                crate::hover_popover::hide_hover(editor, cx);
 6016                let actions = CodeActionContents::new(
 6017                    resolved_tasks,
 6018                    code_actions,
 6019                    debug_scenarios,
 6020                    task_context.unwrap_or_default(),
 6021                );
 6022
 6023                // Don't show the menu if there are no actions available
 6024                if actions.is_empty() {
 6025                    cx.notify();
 6026                    return Task::ready(Ok(()));
 6027                }
 6028
 6029                *editor.context_menu.borrow_mut() =
 6030                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6031                        buffer,
 6032                        actions,
 6033                        selected_item: Default::default(),
 6034                        scroll_handle: UniformListScrollHandle::default(),
 6035                        deployed_from,
 6036                    }));
 6037                cx.notify();
 6038                if spawn_straight_away {
 6039                    if let Some(task) = editor.confirm_code_action(
 6040                        &ConfirmCodeAction { item_ix: Some(0) },
 6041                        window,
 6042                        cx,
 6043                    ) {
 6044                        return task;
 6045                    }
 6046                }
 6047
 6048                Task::ready(Ok(()))
 6049            })
 6050        })
 6051        .detach_and_log_err(cx);
 6052    }
 6053
 6054    fn debug_scenarios(
 6055        &mut self,
 6056        resolved_tasks: &Option<ResolvedTasks>,
 6057        buffer: &Entity<Buffer>,
 6058        cx: &mut App,
 6059    ) -> Task<Vec<task::DebugScenario>> {
 6060        maybe!({
 6061            let project = self.project.as_ref()?;
 6062            let dap_store = project.read(cx).dap_store();
 6063            let mut scenarios = vec![];
 6064            let resolved_tasks = resolved_tasks.as_ref()?;
 6065            let buffer = buffer.read(cx);
 6066            let language = buffer.language()?;
 6067            let file = buffer.file();
 6068            let debug_adapter = language_settings(language.name().into(), file, cx)
 6069                .debuggers
 6070                .first()
 6071                .map(SharedString::from)
 6072                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6073
 6074            dap_store.update(cx, |dap_store, cx| {
 6075                for (_, task) in &resolved_tasks.templates {
 6076                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6077                        task.original_task().clone(),
 6078                        debug_adapter.clone().into(),
 6079                        task.display_label().to_owned().into(),
 6080                        cx,
 6081                    );
 6082                    scenarios.push(maybe_scenario);
 6083                }
 6084            });
 6085            Some(cx.background_spawn(async move {
 6086                let scenarios = futures::future::join_all(scenarios)
 6087                    .await
 6088                    .into_iter()
 6089                    .flatten()
 6090                    .collect::<Vec<_>>();
 6091                scenarios
 6092            }))
 6093        })
 6094        .unwrap_or_else(|| Task::ready(vec![]))
 6095    }
 6096
 6097    fn code_actions(
 6098        &mut self,
 6099        buffer_row: u32,
 6100        window: &mut Window,
 6101        cx: &mut Context<Self>,
 6102    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6103        let mut task = self.code_actions_task.take();
 6104        cx.spawn_in(window, async move |editor, cx| {
 6105            while let Some(prev_task) = task {
 6106                prev_task.await.log_err();
 6107                task = editor
 6108                    .update(cx, |this, _| this.code_actions_task.take())
 6109                    .ok()?;
 6110            }
 6111
 6112            editor
 6113                .update(cx, |editor, cx| {
 6114                    editor
 6115                        .available_code_actions
 6116                        .clone()
 6117                        .and_then(|(location, code_actions)| {
 6118                            let snapshot = location.buffer.read(cx).snapshot();
 6119                            let point_range = location.range.to_point(&snapshot);
 6120                            let point_range = point_range.start.row..=point_range.end.row;
 6121                            if point_range.contains(&buffer_row) {
 6122                                Some(code_actions)
 6123                            } else {
 6124                                None
 6125                            }
 6126                        })
 6127                })
 6128                .ok()
 6129                .flatten()
 6130        })
 6131    }
 6132
 6133    pub fn confirm_code_action(
 6134        &mut self,
 6135        action: &ConfirmCodeAction,
 6136        window: &mut Window,
 6137        cx: &mut Context<Self>,
 6138    ) -> Option<Task<Result<()>>> {
 6139        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6140
 6141        let actions_menu =
 6142            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6143                menu
 6144            } else {
 6145                return None;
 6146            };
 6147
 6148        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6149        let action = actions_menu.actions.get(action_ix)?;
 6150        let title = action.label();
 6151        let buffer = actions_menu.buffer;
 6152        let workspace = self.workspace()?;
 6153
 6154        match action {
 6155            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6156                workspace.update(cx, |workspace, cx| {
 6157                    workspace.schedule_resolved_task(
 6158                        task_source_kind,
 6159                        resolved_task,
 6160                        false,
 6161                        window,
 6162                        cx,
 6163                    );
 6164
 6165                    Some(Task::ready(Ok(())))
 6166                })
 6167            }
 6168            CodeActionsItem::CodeAction {
 6169                excerpt_id,
 6170                action,
 6171                provider,
 6172            } => {
 6173                let apply_code_action =
 6174                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6175                let workspace = workspace.downgrade();
 6176                Some(cx.spawn_in(window, async move |editor, cx| {
 6177                    let project_transaction = apply_code_action.await?;
 6178                    Self::open_project_transaction(
 6179                        &editor,
 6180                        workspace,
 6181                        project_transaction,
 6182                        title,
 6183                        cx,
 6184                    )
 6185                    .await
 6186                }))
 6187            }
 6188            CodeActionsItem::DebugScenario(scenario) => {
 6189                let context = actions_menu.actions.context.clone();
 6190
 6191                workspace.update(cx, |workspace, cx| {
 6192                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6193                    workspace.start_debug_session(
 6194                        scenario,
 6195                        context,
 6196                        Some(buffer),
 6197                        None,
 6198                        window,
 6199                        cx,
 6200                    );
 6201                });
 6202                Some(Task::ready(Ok(())))
 6203            }
 6204        }
 6205    }
 6206
 6207    pub async fn open_project_transaction(
 6208        this: &WeakEntity<Editor>,
 6209        workspace: WeakEntity<Workspace>,
 6210        transaction: ProjectTransaction,
 6211        title: String,
 6212        cx: &mut AsyncWindowContext,
 6213    ) -> Result<()> {
 6214        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6215        cx.update(|_, cx| {
 6216            entries.sort_unstable_by_key(|(buffer, _)| {
 6217                buffer.read(cx).file().map(|f| f.path().clone())
 6218            });
 6219        })?;
 6220
 6221        // If the project transaction's edits are all contained within this editor, then
 6222        // avoid opening a new editor to display them.
 6223
 6224        if let Some((buffer, transaction)) = entries.first() {
 6225            if entries.len() == 1 {
 6226                let excerpt = this.update(cx, |editor, cx| {
 6227                    editor
 6228                        .buffer()
 6229                        .read(cx)
 6230                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6231                })?;
 6232                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6233                    if excerpted_buffer == *buffer {
 6234                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6235                            let excerpt_range = excerpt_range.to_offset(buffer);
 6236                            buffer
 6237                                .edited_ranges_for_transaction::<usize>(transaction)
 6238                                .all(|range| {
 6239                                    excerpt_range.start <= range.start
 6240                                        && excerpt_range.end >= range.end
 6241                                })
 6242                        })?;
 6243
 6244                        if all_edits_within_excerpt {
 6245                            return Ok(());
 6246                        }
 6247                    }
 6248                }
 6249            }
 6250        } else {
 6251            return Ok(());
 6252        }
 6253
 6254        let mut ranges_to_highlight = Vec::new();
 6255        let excerpt_buffer = cx.new(|cx| {
 6256            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6257            for (buffer_handle, transaction) in &entries {
 6258                let edited_ranges = buffer_handle
 6259                    .read(cx)
 6260                    .edited_ranges_for_transaction::<Point>(transaction)
 6261                    .collect::<Vec<_>>();
 6262                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6263                    PathKey::for_buffer(buffer_handle, cx),
 6264                    buffer_handle.clone(),
 6265                    edited_ranges,
 6266                    DEFAULT_MULTIBUFFER_CONTEXT,
 6267                    cx,
 6268                );
 6269
 6270                ranges_to_highlight.extend(ranges);
 6271            }
 6272            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6273            multibuffer
 6274        })?;
 6275
 6276        workspace.update_in(cx, |workspace, window, cx| {
 6277            let project = workspace.project().clone();
 6278            let editor =
 6279                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6280            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6281            editor.update(cx, |editor, cx| {
 6282                editor.highlight_background::<Self>(
 6283                    &ranges_to_highlight,
 6284                    |theme| theme.colors().editor_highlighted_line_background,
 6285                    cx,
 6286                );
 6287            });
 6288        })?;
 6289
 6290        Ok(())
 6291    }
 6292
 6293    pub fn clear_code_action_providers(&mut self) {
 6294        self.code_action_providers.clear();
 6295        self.available_code_actions.take();
 6296    }
 6297
 6298    pub fn add_code_action_provider(
 6299        &mut self,
 6300        provider: Rc<dyn CodeActionProvider>,
 6301        window: &mut Window,
 6302        cx: &mut Context<Self>,
 6303    ) {
 6304        if self
 6305            .code_action_providers
 6306            .iter()
 6307            .any(|existing_provider| existing_provider.id() == provider.id())
 6308        {
 6309            return;
 6310        }
 6311
 6312        self.code_action_providers.push(provider);
 6313        self.refresh_code_actions(window, cx);
 6314    }
 6315
 6316    pub fn remove_code_action_provider(
 6317        &mut self,
 6318        id: Arc<str>,
 6319        window: &mut Window,
 6320        cx: &mut Context<Self>,
 6321    ) {
 6322        self.code_action_providers
 6323            .retain(|provider| provider.id() != id);
 6324        self.refresh_code_actions(window, cx);
 6325    }
 6326
 6327    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6328        !self.code_action_providers.is_empty()
 6329            && EditorSettings::get_global(cx).toolbar.code_actions
 6330    }
 6331
 6332    pub fn has_available_code_actions(&self) -> bool {
 6333        self.available_code_actions
 6334            .as_ref()
 6335            .is_some_and(|(_, actions)| !actions.is_empty())
 6336    }
 6337
 6338    fn render_inline_code_actions(
 6339        &self,
 6340        icon_size: ui::IconSize,
 6341        display_row: DisplayRow,
 6342        is_active: bool,
 6343        cx: &mut Context<Self>,
 6344    ) -> AnyElement {
 6345        let show_tooltip = !self.context_menu_visible();
 6346        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6347            .icon_size(icon_size)
 6348            .shape(ui::IconButtonShape::Square)
 6349            .style(ButtonStyle::Transparent)
 6350            .icon_color(ui::Color::Hidden)
 6351            .toggle_state(is_active)
 6352            .when(show_tooltip, |this| {
 6353                this.tooltip({
 6354                    let focus_handle = self.focus_handle.clone();
 6355                    move |window, cx| {
 6356                        Tooltip::for_action_in(
 6357                            "Toggle Code Actions",
 6358                            &ToggleCodeActions {
 6359                                deployed_from: None,
 6360                                quick_launch: false,
 6361                            },
 6362                            &focus_handle,
 6363                            window,
 6364                            cx,
 6365                        )
 6366                    }
 6367                })
 6368            })
 6369            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6370                window.focus(&editor.focus_handle(cx));
 6371                editor.toggle_code_actions(
 6372                    &crate::actions::ToggleCodeActions {
 6373                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6374                            display_row,
 6375                        )),
 6376                        quick_launch: false,
 6377                    },
 6378                    window,
 6379                    cx,
 6380                );
 6381            }))
 6382            .into_any_element()
 6383    }
 6384
 6385    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6386        &self.context_menu
 6387    }
 6388
 6389    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6390        let newest_selection = self.selections.newest_anchor().clone();
 6391        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6392        let buffer = self.buffer.read(cx);
 6393        if newest_selection.head().diff_base_anchor.is_some() {
 6394            return None;
 6395        }
 6396        let (start_buffer, start) =
 6397            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6398        let (end_buffer, end) =
 6399            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6400        if start_buffer != end_buffer {
 6401            return None;
 6402        }
 6403
 6404        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6405            cx.background_executor()
 6406                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6407                .await;
 6408
 6409            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6410                let providers = this.code_action_providers.clone();
 6411                let tasks = this
 6412                    .code_action_providers
 6413                    .iter()
 6414                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6415                    .collect::<Vec<_>>();
 6416                (providers, tasks)
 6417            })?;
 6418
 6419            let mut actions = Vec::new();
 6420            for (provider, provider_actions) in
 6421                providers.into_iter().zip(future::join_all(tasks).await)
 6422            {
 6423                if let Some(provider_actions) = provider_actions.log_err() {
 6424                    actions.extend(provider_actions.into_iter().map(|action| {
 6425                        AvailableCodeAction {
 6426                            excerpt_id: newest_selection.start.excerpt_id,
 6427                            action,
 6428                            provider: provider.clone(),
 6429                        }
 6430                    }));
 6431                }
 6432            }
 6433
 6434            this.update(cx, |this, cx| {
 6435                this.available_code_actions = if actions.is_empty() {
 6436                    None
 6437                } else {
 6438                    Some((
 6439                        Location {
 6440                            buffer: start_buffer,
 6441                            range: start..end,
 6442                        },
 6443                        actions.into(),
 6444                    ))
 6445                };
 6446                cx.notify();
 6447            })
 6448        }));
 6449        None
 6450    }
 6451
 6452    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6453        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6454            self.show_git_blame_inline = false;
 6455
 6456            self.show_git_blame_inline_delay_task =
 6457                Some(cx.spawn_in(window, async move |this, cx| {
 6458                    cx.background_executor().timer(delay).await;
 6459
 6460                    this.update(cx, |this, cx| {
 6461                        this.show_git_blame_inline = true;
 6462                        cx.notify();
 6463                    })
 6464                    .log_err();
 6465                }));
 6466        }
 6467    }
 6468
 6469    fn show_blame_popover(
 6470        &mut self,
 6471        blame_entry: &BlameEntry,
 6472        position: gpui::Point<Pixels>,
 6473        cx: &mut Context<Self>,
 6474    ) {
 6475        if let Some(state) = &mut self.inline_blame_popover {
 6476            state.hide_task.take();
 6477        } else {
 6478            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6479            let blame_entry = blame_entry.clone();
 6480            let show_task = cx.spawn(async move |editor, cx| {
 6481                cx.background_executor()
 6482                    .timer(std::time::Duration::from_millis(delay))
 6483                    .await;
 6484                editor
 6485                    .update(cx, |editor, cx| {
 6486                        editor.inline_blame_popover_show_task.take();
 6487                        let Some(blame) = editor.blame.as_ref() else {
 6488                            return;
 6489                        };
 6490                        let blame = blame.read(cx);
 6491                        let details = blame.details_for_entry(&blame_entry);
 6492                        let markdown = cx.new(|cx| {
 6493                            Markdown::new(
 6494                                details
 6495                                    .as_ref()
 6496                                    .map(|message| message.message.clone())
 6497                                    .unwrap_or_default(),
 6498                                None,
 6499                                None,
 6500                                cx,
 6501                            )
 6502                        });
 6503                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6504                            position,
 6505                            hide_task: None,
 6506                            popover_bounds: None,
 6507                            popover_state: InlineBlamePopoverState {
 6508                                scroll_handle: ScrollHandle::new(),
 6509                                commit_message: details,
 6510                                markdown,
 6511                            },
 6512                        });
 6513                        cx.notify();
 6514                    })
 6515                    .ok();
 6516            });
 6517            self.inline_blame_popover_show_task = Some(show_task);
 6518        }
 6519    }
 6520
 6521    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6522        self.inline_blame_popover_show_task.take();
 6523        if let Some(state) = &mut self.inline_blame_popover {
 6524            let hide_task = cx.spawn(async move |editor, cx| {
 6525                cx.background_executor()
 6526                    .timer(std::time::Duration::from_millis(100))
 6527                    .await;
 6528                editor
 6529                    .update(cx, |editor, cx| {
 6530                        editor.inline_blame_popover.take();
 6531                        cx.notify();
 6532                    })
 6533                    .ok();
 6534            });
 6535            state.hide_task = Some(hide_task);
 6536        }
 6537    }
 6538
 6539    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6540        if self.pending_rename.is_some() {
 6541            return None;
 6542        }
 6543
 6544        let provider = self.semantics_provider.clone()?;
 6545        let buffer = self.buffer.read(cx);
 6546        let newest_selection = self.selections.newest_anchor().clone();
 6547        let cursor_position = newest_selection.head();
 6548        let (cursor_buffer, cursor_buffer_position) =
 6549            buffer.text_anchor_for_position(cursor_position, cx)?;
 6550        let (tail_buffer, tail_buffer_position) =
 6551            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6552        if cursor_buffer != tail_buffer {
 6553            return None;
 6554        }
 6555
 6556        let snapshot = cursor_buffer.read(cx).snapshot();
 6557        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6558        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6559        if start_word_range != end_word_range {
 6560            self.document_highlights_task.take();
 6561            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6562            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6563            return None;
 6564        }
 6565
 6566        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6567        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6568            cx.background_executor()
 6569                .timer(Duration::from_millis(debounce))
 6570                .await;
 6571
 6572            let highlights = if let Some(highlights) = cx
 6573                .update(|cx| {
 6574                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6575                })
 6576                .ok()
 6577                .flatten()
 6578            {
 6579                highlights.await.log_err()
 6580            } else {
 6581                None
 6582            };
 6583
 6584            if let Some(highlights) = highlights {
 6585                this.update(cx, |this, cx| {
 6586                    if this.pending_rename.is_some() {
 6587                        return;
 6588                    }
 6589
 6590                    let buffer_id = cursor_position.buffer_id;
 6591                    let buffer = this.buffer.read(cx);
 6592                    if !buffer
 6593                        .text_anchor_for_position(cursor_position, cx)
 6594                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6595                    {
 6596                        return;
 6597                    }
 6598
 6599                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6600                    let mut write_ranges = Vec::new();
 6601                    let mut read_ranges = Vec::new();
 6602                    for highlight in highlights {
 6603                        for (excerpt_id, excerpt_range) in
 6604                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6605                        {
 6606                            let start = highlight
 6607                                .range
 6608                                .start
 6609                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6610                            let end = highlight
 6611                                .range
 6612                                .end
 6613                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6614                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6615                                continue;
 6616                            }
 6617
 6618                            let range = Anchor {
 6619                                buffer_id,
 6620                                excerpt_id,
 6621                                text_anchor: start,
 6622                                diff_base_anchor: None,
 6623                            }..Anchor {
 6624                                buffer_id,
 6625                                excerpt_id,
 6626                                text_anchor: end,
 6627                                diff_base_anchor: None,
 6628                            };
 6629                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6630                                write_ranges.push(range);
 6631                            } else {
 6632                                read_ranges.push(range);
 6633                            }
 6634                        }
 6635                    }
 6636
 6637                    this.highlight_background::<DocumentHighlightRead>(
 6638                        &read_ranges,
 6639                        |theme| theme.colors().editor_document_highlight_read_background,
 6640                        cx,
 6641                    );
 6642                    this.highlight_background::<DocumentHighlightWrite>(
 6643                        &write_ranges,
 6644                        |theme| theme.colors().editor_document_highlight_write_background,
 6645                        cx,
 6646                    );
 6647                    cx.notify();
 6648                })
 6649                .log_err();
 6650            }
 6651        }));
 6652        None
 6653    }
 6654
 6655    fn prepare_highlight_query_from_selection(
 6656        &mut self,
 6657        cx: &mut Context<Editor>,
 6658    ) -> Option<(String, Range<Anchor>)> {
 6659        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6660            return None;
 6661        }
 6662        if !EditorSettings::get_global(cx).selection_highlight {
 6663            return None;
 6664        }
 6665        if self.selections.count() != 1 || self.selections.line_mode {
 6666            return None;
 6667        }
 6668        let selection = self.selections.newest::<Point>(cx);
 6669        if selection.is_empty() || selection.start.row != selection.end.row {
 6670            return None;
 6671        }
 6672        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6673        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6674        let query = multi_buffer_snapshot
 6675            .text_for_range(selection_anchor_range.clone())
 6676            .collect::<String>();
 6677        if query.trim().is_empty() {
 6678            return None;
 6679        }
 6680        Some((query, selection_anchor_range))
 6681    }
 6682
 6683    fn update_selection_occurrence_highlights(
 6684        &mut self,
 6685        query_text: String,
 6686        query_range: Range<Anchor>,
 6687        multi_buffer_range_to_query: Range<Point>,
 6688        use_debounce: bool,
 6689        window: &mut Window,
 6690        cx: &mut Context<Editor>,
 6691    ) -> Task<()> {
 6692        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6693        cx.spawn_in(window, async move |editor, cx| {
 6694            if use_debounce {
 6695                cx.background_executor()
 6696                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6697                    .await;
 6698            }
 6699            let match_task = cx.background_spawn(async move {
 6700                let buffer_ranges = multi_buffer_snapshot
 6701                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6702                    .into_iter()
 6703                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6704                let mut match_ranges = Vec::new();
 6705                let Ok(regex) = project::search::SearchQuery::text(
 6706                    query_text.clone(),
 6707                    false,
 6708                    false,
 6709                    false,
 6710                    Default::default(),
 6711                    Default::default(),
 6712                    false,
 6713                    None,
 6714                ) else {
 6715                    return Vec::default();
 6716                };
 6717                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6718                    match_ranges.extend(
 6719                        regex
 6720                            .search(&buffer_snapshot, Some(search_range.clone()))
 6721                            .await
 6722                            .into_iter()
 6723                            .filter_map(|match_range| {
 6724                                let match_start = buffer_snapshot
 6725                                    .anchor_after(search_range.start + match_range.start);
 6726                                let match_end = buffer_snapshot
 6727                                    .anchor_before(search_range.start + match_range.end);
 6728                                let match_anchor_range = Anchor::range_in_buffer(
 6729                                    excerpt_id,
 6730                                    buffer_snapshot.remote_id(),
 6731                                    match_start..match_end,
 6732                                );
 6733                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6734                            }),
 6735                    );
 6736                }
 6737                match_ranges
 6738            });
 6739            let match_ranges = match_task.await;
 6740            editor
 6741                .update_in(cx, |editor, _, cx| {
 6742                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6743                    if !match_ranges.is_empty() {
 6744                        editor.highlight_background::<SelectedTextHighlight>(
 6745                            &match_ranges,
 6746                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6747                            cx,
 6748                        )
 6749                    }
 6750                })
 6751                .log_err();
 6752        })
 6753    }
 6754
 6755    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6756        struct NewlineFold;
 6757        let type_id = std::any::TypeId::of::<NewlineFold>();
 6758        if !self.mode.is_single_line() {
 6759            return;
 6760        }
 6761        let snapshot = self.snapshot(window, cx);
 6762        if snapshot.buffer_snapshot.max_point().row == 0 {
 6763            return;
 6764        }
 6765        let task = cx.background_spawn(async move {
 6766            let new_newlines = snapshot
 6767                .buffer_chars_at(0)
 6768                .filter_map(|(c, i)| {
 6769                    if c == '\n' {
 6770                        Some(
 6771                            snapshot.buffer_snapshot.anchor_after(i)
 6772                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6773                        )
 6774                    } else {
 6775                        None
 6776                    }
 6777                })
 6778                .collect::<Vec<_>>();
 6779            let existing_newlines = snapshot
 6780                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6781                .filter_map(|fold| {
 6782                    if fold.placeholder.type_tag == Some(type_id) {
 6783                        Some(fold.range.start..fold.range.end)
 6784                    } else {
 6785                        None
 6786                    }
 6787                })
 6788                .collect::<Vec<_>>();
 6789
 6790            (new_newlines, existing_newlines)
 6791        });
 6792        self.folding_newlines = cx.spawn(async move |this, cx| {
 6793            let (new_newlines, existing_newlines) = task.await;
 6794            if new_newlines == existing_newlines {
 6795                return;
 6796            }
 6797            let placeholder = FoldPlaceholder {
 6798                render: Arc::new(move |_, _, cx| {
 6799                    div()
 6800                        .bg(cx.theme().status().hint_background)
 6801                        .border_b_1()
 6802                        .size_full()
 6803                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6804                        .border_color(cx.theme().status().hint)
 6805                        .child("\\n")
 6806                        .into_any()
 6807                }),
 6808                constrain_width: false,
 6809                merge_adjacent: false,
 6810                type_tag: Some(type_id),
 6811            };
 6812            let creases = new_newlines
 6813                .into_iter()
 6814                .map(|range| Crease::simple(range, placeholder.clone()))
 6815                .collect();
 6816            this.update(cx, |this, cx| {
 6817                this.display_map.update(cx, |display_map, cx| {
 6818                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6819                    display_map.fold(creases, cx);
 6820                });
 6821            })
 6822            .ok();
 6823        });
 6824    }
 6825
 6826    fn refresh_selected_text_highlights(
 6827        &mut self,
 6828        on_buffer_edit: bool,
 6829        window: &mut Window,
 6830        cx: &mut Context<Editor>,
 6831    ) {
 6832        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6833        else {
 6834            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6835            self.quick_selection_highlight_task.take();
 6836            self.debounced_selection_highlight_task.take();
 6837            return;
 6838        };
 6839        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6840        if on_buffer_edit
 6841            || self
 6842                .quick_selection_highlight_task
 6843                .as_ref()
 6844                .map_or(true, |(prev_anchor_range, _)| {
 6845                    prev_anchor_range != &query_range
 6846                })
 6847        {
 6848            let multi_buffer_visible_start = self
 6849                .scroll_manager
 6850                .anchor()
 6851                .anchor
 6852                .to_point(&multi_buffer_snapshot);
 6853            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6854                multi_buffer_visible_start
 6855                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6856                Bias::Left,
 6857            );
 6858            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6859            self.quick_selection_highlight_task = Some((
 6860                query_range.clone(),
 6861                self.update_selection_occurrence_highlights(
 6862                    query_text.clone(),
 6863                    query_range.clone(),
 6864                    multi_buffer_visible_range,
 6865                    false,
 6866                    window,
 6867                    cx,
 6868                ),
 6869            ));
 6870        }
 6871        if on_buffer_edit
 6872            || self
 6873                .debounced_selection_highlight_task
 6874                .as_ref()
 6875                .map_or(true, |(prev_anchor_range, _)| {
 6876                    prev_anchor_range != &query_range
 6877                })
 6878        {
 6879            let multi_buffer_start = multi_buffer_snapshot
 6880                .anchor_before(0)
 6881                .to_point(&multi_buffer_snapshot);
 6882            let multi_buffer_end = multi_buffer_snapshot
 6883                .anchor_after(multi_buffer_snapshot.len())
 6884                .to_point(&multi_buffer_snapshot);
 6885            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6886            self.debounced_selection_highlight_task = Some((
 6887                query_range.clone(),
 6888                self.update_selection_occurrence_highlights(
 6889                    query_text,
 6890                    query_range,
 6891                    multi_buffer_full_range,
 6892                    true,
 6893                    window,
 6894                    cx,
 6895                ),
 6896            ));
 6897        }
 6898    }
 6899
 6900    pub fn refresh_inline_completion(
 6901        &mut self,
 6902        debounce: bool,
 6903        user_requested: bool,
 6904        window: &mut Window,
 6905        cx: &mut Context<Self>,
 6906    ) -> Option<()> {
 6907        let provider = self.edit_prediction_provider()?;
 6908        let cursor = self.selections.newest_anchor().head();
 6909        let (buffer, cursor_buffer_position) =
 6910            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6911
 6912        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6913            self.discard_inline_completion(false, cx);
 6914            return None;
 6915        }
 6916
 6917        if !user_requested
 6918            && (!self.should_show_edit_predictions()
 6919                || !self.is_focused(window)
 6920                || buffer.read(cx).is_empty())
 6921        {
 6922            self.discard_inline_completion(false, cx);
 6923            return None;
 6924        }
 6925
 6926        self.update_visible_inline_completion(window, cx);
 6927        provider.refresh(
 6928            self.project.clone(),
 6929            buffer,
 6930            cursor_buffer_position,
 6931            debounce,
 6932            cx,
 6933        );
 6934        Some(())
 6935    }
 6936
 6937    fn show_edit_predictions_in_menu(&self) -> bool {
 6938        match self.edit_prediction_settings {
 6939            EditPredictionSettings::Disabled => false,
 6940            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6941        }
 6942    }
 6943
 6944    pub fn edit_predictions_enabled(&self) -> bool {
 6945        match self.edit_prediction_settings {
 6946            EditPredictionSettings::Disabled => false,
 6947            EditPredictionSettings::Enabled { .. } => true,
 6948        }
 6949    }
 6950
 6951    fn edit_prediction_requires_modifier(&self) -> bool {
 6952        match self.edit_prediction_settings {
 6953            EditPredictionSettings::Disabled => false,
 6954            EditPredictionSettings::Enabled {
 6955                preview_requires_modifier,
 6956                ..
 6957            } => preview_requires_modifier,
 6958        }
 6959    }
 6960
 6961    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6962        if self.edit_prediction_provider.is_none() {
 6963            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6964        } else {
 6965            let selection = self.selections.newest_anchor();
 6966            let cursor = selection.head();
 6967
 6968            if let Some((buffer, cursor_buffer_position)) =
 6969                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6970            {
 6971                self.edit_prediction_settings =
 6972                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6973            }
 6974        }
 6975    }
 6976
 6977    fn edit_prediction_settings_at_position(
 6978        &self,
 6979        buffer: &Entity<Buffer>,
 6980        buffer_position: language::Anchor,
 6981        cx: &App,
 6982    ) -> EditPredictionSettings {
 6983        if !self.mode.is_full()
 6984            || !self.show_inline_completions_override.unwrap_or(true)
 6985            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6986        {
 6987            return EditPredictionSettings::Disabled;
 6988        }
 6989
 6990        let buffer = buffer.read(cx);
 6991
 6992        let file = buffer.file();
 6993
 6994        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6995            return EditPredictionSettings::Disabled;
 6996        };
 6997
 6998        let by_provider = matches!(
 6999            self.menu_inline_completions_policy,
 7000            MenuInlineCompletionsPolicy::ByProvider
 7001        );
 7002
 7003        let show_in_menu = by_provider
 7004            && self
 7005                .edit_prediction_provider
 7006                .as_ref()
 7007                .map_or(false, |provider| {
 7008                    provider.provider.show_completions_in_menu()
 7009                });
 7010
 7011        let preview_requires_modifier =
 7012            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7013
 7014        EditPredictionSettings::Enabled {
 7015            show_in_menu,
 7016            preview_requires_modifier,
 7017        }
 7018    }
 7019
 7020    fn should_show_edit_predictions(&self) -> bool {
 7021        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7022    }
 7023
 7024    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7025        matches!(
 7026            self.edit_prediction_preview,
 7027            EditPredictionPreview::Active { .. }
 7028        )
 7029    }
 7030
 7031    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7032        let cursor = self.selections.newest_anchor().head();
 7033        if let Some((buffer, cursor_position)) =
 7034            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7035        {
 7036            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7037        } else {
 7038            false
 7039        }
 7040    }
 7041
 7042    pub fn supports_minimap(&self, cx: &App) -> bool {
 7043        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7044    }
 7045
 7046    fn edit_predictions_enabled_in_buffer(
 7047        &self,
 7048        buffer: &Entity<Buffer>,
 7049        buffer_position: language::Anchor,
 7050        cx: &App,
 7051    ) -> bool {
 7052        maybe!({
 7053            if self.read_only(cx) {
 7054                return Some(false);
 7055            }
 7056            let provider = self.edit_prediction_provider()?;
 7057            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7058                return Some(false);
 7059            }
 7060            let buffer = buffer.read(cx);
 7061            let Some(file) = buffer.file() else {
 7062                return Some(true);
 7063            };
 7064            let settings = all_language_settings(Some(file), cx);
 7065            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7066        })
 7067        .unwrap_or(false)
 7068    }
 7069
 7070    fn cycle_inline_completion(
 7071        &mut self,
 7072        direction: Direction,
 7073        window: &mut Window,
 7074        cx: &mut Context<Self>,
 7075    ) -> Option<()> {
 7076        let provider = self.edit_prediction_provider()?;
 7077        let cursor = self.selections.newest_anchor().head();
 7078        let (buffer, cursor_buffer_position) =
 7079            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7080        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7081            return None;
 7082        }
 7083
 7084        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7085        self.update_visible_inline_completion(window, cx);
 7086
 7087        Some(())
 7088    }
 7089
 7090    pub fn show_inline_completion(
 7091        &mut self,
 7092        _: &ShowEditPrediction,
 7093        window: &mut Window,
 7094        cx: &mut Context<Self>,
 7095    ) {
 7096        if !self.has_active_inline_completion() {
 7097            self.refresh_inline_completion(false, true, window, cx);
 7098            return;
 7099        }
 7100
 7101        self.update_visible_inline_completion(window, cx);
 7102    }
 7103
 7104    pub fn display_cursor_names(
 7105        &mut self,
 7106        _: &DisplayCursorNames,
 7107        window: &mut Window,
 7108        cx: &mut Context<Self>,
 7109    ) {
 7110        self.show_cursor_names(window, cx);
 7111    }
 7112
 7113    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7114        self.show_cursor_names = true;
 7115        cx.notify();
 7116        cx.spawn_in(window, async move |this, cx| {
 7117            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7118            this.update(cx, |this, cx| {
 7119                this.show_cursor_names = false;
 7120                cx.notify()
 7121            })
 7122            .ok()
 7123        })
 7124        .detach();
 7125    }
 7126
 7127    pub fn next_edit_prediction(
 7128        &mut self,
 7129        _: &NextEditPrediction,
 7130        window: &mut Window,
 7131        cx: &mut Context<Self>,
 7132    ) {
 7133        if self.has_active_inline_completion() {
 7134            self.cycle_inline_completion(Direction::Next, window, cx);
 7135        } else {
 7136            let is_copilot_disabled = self
 7137                .refresh_inline_completion(false, true, window, cx)
 7138                .is_none();
 7139            if is_copilot_disabled {
 7140                cx.propagate();
 7141            }
 7142        }
 7143    }
 7144
 7145    pub fn previous_edit_prediction(
 7146        &mut self,
 7147        _: &PreviousEditPrediction,
 7148        window: &mut Window,
 7149        cx: &mut Context<Self>,
 7150    ) {
 7151        if self.has_active_inline_completion() {
 7152            self.cycle_inline_completion(Direction::Prev, window, cx);
 7153        } else {
 7154            let is_copilot_disabled = self
 7155                .refresh_inline_completion(false, true, window, cx)
 7156                .is_none();
 7157            if is_copilot_disabled {
 7158                cx.propagate();
 7159            }
 7160        }
 7161    }
 7162
 7163    pub fn accept_edit_prediction(
 7164        &mut self,
 7165        _: &AcceptEditPrediction,
 7166        window: &mut Window,
 7167        cx: &mut Context<Self>,
 7168    ) {
 7169        if self.show_edit_predictions_in_menu() {
 7170            self.hide_context_menu(window, cx);
 7171        }
 7172
 7173        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7174            return;
 7175        };
 7176
 7177        self.report_inline_completion_event(
 7178            active_inline_completion.completion_id.clone(),
 7179            true,
 7180            cx,
 7181        );
 7182
 7183        match &active_inline_completion.completion {
 7184            InlineCompletion::Move { target, .. } => {
 7185                let target = *target;
 7186
 7187                if let Some(position_map) = &self.last_position_map {
 7188                    if position_map
 7189                        .visible_row_range
 7190                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7191                        || !self.edit_prediction_requires_modifier()
 7192                    {
 7193                        self.unfold_ranges(&[target..target], true, false, cx);
 7194                        // Note that this is also done in vim's handler of the Tab action.
 7195                        self.change_selections(
 7196                            SelectionEffects::scroll(Autoscroll::newest()),
 7197                            window,
 7198                            cx,
 7199                            |selections| {
 7200                                selections.select_anchor_ranges([target..target]);
 7201                            },
 7202                        );
 7203                        self.clear_row_highlights::<EditPredictionPreview>();
 7204
 7205                        self.edit_prediction_preview
 7206                            .set_previous_scroll_position(None);
 7207                    } else {
 7208                        self.edit_prediction_preview
 7209                            .set_previous_scroll_position(Some(
 7210                                position_map.snapshot.scroll_anchor,
 7211                            ));
 7212
 7213                        self.highlight_rows::<EditPredictionPreview>(
 7214                            target..target,
 7215                            cx.theme().colors().editor_highlighted_line_background,
 7216                            RowHighlightOptions {
 7217                                autoscroll: true,
 7218                                ..Default::default()
 7219                            },
 7220                            cx,
 7221                        );
 7222                        self.request_autoscroll(Autoscroll::fit(), cx);
 7223                    }
 7224                }
 7225            }
 7226            InlineCompletion::Edit { edits, .. } => {
 7227                if let Some(provider) = self.edit_prediction_provider() {
 7228                    provider.accept(cx);
 7229                }
 7230
 7231                // Store the transaction ID and selections before applying the edit
 7232                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7233
 7234                let snapshot = self.buffer.read(cx).snapshot(cx);
 7235                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7236
 7237                self.buffer.update(cx, |buffer, cx| {
 7238                    buffer.edit(edits.iter().cloned(), None, cx)
 7239                });
 7240
 7241                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7242                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7243                });
 7244
 7245                let selections = self.selections.disjoint_anchors();
 7246                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7247                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7248                    if has_new_transaction {
 7249                        self.selection_history
 7250                            .insert_transaction(transaction_id_now, selections);
 7251                    }
 7252                }
 7253
 7254                self.update_visible_inline_completion(window, cx);
 7255                if self.active_inline_completion.is_none() {
 7256                    self.refresh_inline_completion(true, true, window, cx);
 7257                }
 7258
 7259                cx.notify();
 7260            }
 7261        }
 7262
 7263        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7264    }
 7265
 7266    pub fn accept_partial_inline_completion(
 7267        &mut self,
 7268        _: &AcceptPartialEditPrediction,
 7269        window: &mut Window,
 7270        cx: &mut Context<Self>,
 7271    ) {
 7272        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7273            return;
 7274        };
 7275        if self.selections.count() != 1 {
 7276            return;
 7277        }
 7278
 7279        self.report_inline_completion_event(
 7280            active_inline_completion.completion_id.clone(),
 7281            true,
 7282            cx,
 7283        );
 7284
 7285        match &active_inline_completion.completion {
 7286            InlineCompletion::Move { target, .. } => {
 7287                let target = *target;
 7288                self.change_selections(
 7289                    SelectionEffects::scroll(Autoscroll::newest()),
 7290                    window,
 7291                    cx,
 7292                    |selections| {
 7293                        selections.select_anchor_ranges([target..target]);
 7294                    },
 7295                );
 7296            }
 7297            InlineCompletion::Edit { edits, .. } => {
 7298                // Find an insertion that starts at the cursor position.
 7299                let snapshot = self.buffer.read(cx).snapshot(cx);
 7300                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7301                let insertion = edits.iter().find_map(|(range, text)| {
 7302                    let range = range.to_offset(&snapshot);
 7303                    if range.is_empty() && range.start == cursor_offset {
 7304                        Some(text)
 7305                    } else {
 7306                        None
 7307                    }
 7308                });
 7309
 7310                if let Some(text) = insertion {
 7311                    let mut partial_completion = text
 7312                        .chars()
 7313                        .by_ref()
 7314                        .take_while(|c| c.is_alphabetic())
 7315                        .collect::<String>();
 7316                    if partial_completion.is_empty() {
 7317                        partial_completion = text
 7318                            .chars()
 7319                            .by_ref()
 7320                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7321                            .collect::<String>();
 7322                    }
 7323
 7324                    cx.emit(EditorEvent::InputHandled {
 7325                        utf16_range_to_replace: None,
 7326                        text: partial_completion.clone().into(),
 7327                    });
 7328
 7329                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7330
 7331                    self.refresh_inline_completion(true, true, window, cx);
 7332                    cx.notify();
 7333                } else {
 7334                    self.accept_edit_prediction(&Default::default(), window, cx);
 7335                }
 7336            }
 7337        }
 7338    }
 7339
 7340    fn discard_inline_completion(
 7341        &mut self,
 7342        should_report_inline_completion_event: bool,
 7343        cx: &mut Context<Self>,
 7344    ) -> bool {
 7345        if should_report_inline_completion_event {
 7346            let completion_id = self
 7347                .active_inline_completion
 7348                .as_ref()
 7349                .and_then(|active_completion| active_completion.completion_id.clone());
 7350
 7351            self.report_inline_completion_event(completion_id, false, cx);
 7352        }
 7353
 7354        if let Some(provider) = self.edit_prediction_provider() {
 7355            provider.discard(cx);
 7356        }
 7357
 7358        self.take_active_inline_completion(cx)
 7359    }
 7360
 7361    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7362        let Some(provider) = self.edit_prediction_provider() else {
 7363            return;
 7364        };
 7365
 7366        let Some((_, buffer, _)) = self
 7367            .buffer
 7368            .read(cx)
 7369            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7370        else {
 7371            return;
 7372        };
 7373
 7374        let extension = buffer
 7375            .read(cx)
 7376            .file()
 7377            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7378
 7379        let event_type = match accepted {
 7380            true => "Edit Prediction Accepted",
 7381            false => "Edit Prediction Discarded",
 7382        };
 7383        telemetry::event!(
 7384            event_type,
 7385            provider = provider.name(),
 7386            prediction_id = id,
 7387            suggestion_accepted = accepted,
 7388            file_extension = extension,
 7389        );
 7390    }
 7391
 7392    pub fn has_active_inline_completion(&self) -> bool {
 7393        self.active_inline_completion.is_some()
 7394    }
 7395
 7396    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7397        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7398            return false;
 7399        };
 7400
 7401        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7402        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7403        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7404        true
 7405    }
 7406
 7407    /// Returns true when we're displaying the edit prediction popover below the cursor
 7408    /// like we are not previewing and the LSP autocomplete menu is visible
 7409    /// or we are in `when_holding_modifier` mode.
 7410    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7411        if self.edit_prediction_preview_is_active()
 7412            || !self.show_edit_predictions_in_menu()
 7413            || !self.edit_predictions_enabled()
 7414        {
 7415            return false;
 7416        }
 7417
 7418        if self.has_visible_completions_menu() {
 7419            return true;
 7420        }
 7421
 7422        has_completion && self.edit_prediction_requires_modifier()
 7423    }
 7424
 7425    fn handle_modifiers_changed(
 7426        &mut self,
 7427        modifiers: Modifiers,
 7428        position_map: &PositionMap,
 7429        window: &mut Window,
 7430        cx: &mut Context<Self>,
 7431    ) {
 7432        if self.show_edit_predictions_in_menu() {
 7433            self.update_edit_prediction_preview(&modifiers, window, cx);
 7434        }
 7435
 7436        self.update_selection_mode(&modifiers, position_map, window, cx);
 7437
 7438        let mouse_position = window.mouse_position();
 7439        if !position_map.text_hitbox.is_hovered(window) {
 7440            return;
 7441        }
 7442
 7443        self.update_hovered_link(
 7444            position_map.point_for_position(mouse_position),
 7445            &position_map.snapshot,
 7446            modifiers,
 7447            window,
 7448            cx,
 7449        )
 7450    }
 7451
 7452    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7453        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7454        if invert {
 7455            match multi_cursor_setting {
 7456                MultiCursorModifier::Alt => modifiers.alt,
 7457                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7458            }
 7459        } else {
 7460            match multi_cursor_setting {
 7461                MultiCursorModifier::Alt => modifiers.secondary(),
 7462                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7463            }
 7464        }
 7465    }
 7466
 7467    fn columnar_selection_mode(
 7468        modifiers: &Modifiers,
 7469        cx: &mut Context<Self>,
 7470    ) -> Option<ColumnarMode> {
 7471        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7472            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7473                Some(ColumnarMode::FromMouse)
 7474            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7475                Some(ColumnarMode::FromSelection)
 7476            } else {
 7477                None
 7478            }
 7479        } else {
 7480            None
 7481        }
 7482    }
 7483
 7484    fn update_selection_mode(
 7485        &mut self,
 7486        modifiers: &Modifiers,
 7487        position_map: &PositionMap,
 7488        window: &mut Window,
 7489        cx: &mut Context<Self>,
 7490    ) {
 7491        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7492            return;
 7493        };
 7494        if self.selections.pending.is_none() {
 7495            return;
 7496        }
 7497
 7498        let mouse_position = window.mouse_position();
 7499        let point_for_position = position_map.point_for_position(mouse_position);
 7500        let position = point_for_position.previous_valid;
 7501
 7502        self.select(
 7503            SelectPhase::BeginColumnar {
 7504                position,
 7505                reset: false,
 7506                mode,
 7507                goal_column: point_for_position.exact_unclipped.column(),
 7508            },
 7509            window,
 7510            cx,
 7511        );
 7512    }
 7513
 7514    fn update_edit_prediction_preview(
 7515        &mut self,
 7516        modifiers: &Modifiers,
 7517        window: &mut Window,
 7518        cx: &mut Context<Self>,
 7519    ) {
 7520        let mut modifiers_held = false;
 7521        if let Some(accept_keystroke) = self
 7522            .accept_edit_prediction_keybind(false, window, cx)
 7523            .keystroke()
 7524        {
 7525            modifiers_held = modifiers_held
 7526                || (&accept_keystroke.modifiers == modifiers
 7527                    && accept_keystroke.modifiers.modified());
 7528        };
 7529        if let Some(accept_partial_keystroke) = self
 7530            .accept_edit_prediction_keybind(true, window, cx)
 7531            .keystroke()
 7532        {
 7533            modifiers_held = modifiers_held
 7534                || (&accept_partial_keystroke.modifiers == modifiers
 7535                    && accept_partial_keystroke.modifiers.modified());
 7536        }
 7537
 7538        if modifiers_held {
 7539            if matches!(
 7540                self.edit_prediction_preview,
 7541                EditPredictionPreview::Inactive { .. }
 7542            ) {
 7543                self.edit_prediction_preview = EditPredictionPreview::Active {
 7544                    previous_scroll_position: None,
 7545                    since: Instant::now(),
 7546                };
 7547
 7548                self.update_visible_inline_completion(window, cx);
 7549                cx.notify();
 7550            }
 7551        } else if let EditPredictionPreview::Active {
 7552            previous_scroll_position,
 7553            since,
 7554        } = self.edit_prediction_preview
 7555        {
 7556            if let (Some(previous_scroll_position), Some(position_map)) =
 7557                (previous_scroll_position, self.last_position_map.as_ref())
 7558            {
 7559                self.set_scroll_position(
 7560                    previous_scroll_position
 7561                        .scroll_position(&position_map.snapshot.display_snapshot),
 7562                    window,
 7563                    cx,
 7564                );
 7565            }
 7566
 7567            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7568                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7569            };
 7570            self.clear_row_highlights::<EditPredictionPreview>();
 7571            self.update_visible_inline_completion(window, cx);
 7572            cx.notify();
 7573        }
 7574    }
 7575
 7576    fn update_visible_inline_completion(
 7577        &mut self,
 7578        _window: &mut Window,
 7579        cx: &mut Context<Self>,
 7580    ) -> Option<()> {
 7581        let selection = self.selections.newest_anchor();
 7582        let cursor = selection.head();
 7583        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7584        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7585        let excerpt_id = cursor.excerpt_id;
 7586
 7587        let show_in_menu = self.show_edit_predictions_in_menu();
 7588        let completions_menu_has_precedence = !show_in_menu
 7589            && (self.context_menu.borrow().is_some()
 7590                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7591
 7592        if completions_menu_has_precedence
 7593            || !offset_selection.is_empty()
 7594            || self
 7595                .active_inline_completion
 7596                .as_ref()
 7597                .map_or(false, |completion| {
 7598                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7599                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7600                    !invalidation_range.contains(&offset_selection.head())
 7601                })
 7602        {
 7603            self.discard_inline_completion(false, cx);
 7604            return None;
 7605        }
 7606
 7607        self.take_active_inline_completion(cx);
 7608        let Some(provider) = self.edit_prediction_provider() else {
 7609            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7610            return None;
 7611        };
 7612
 7613        let (buffer, cursor_buffer_position) =
 7614            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7615
 7616        self.edit_prediction_settings =
 7617            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7618
 7619        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7620
 7621        if self.edit_prediction_indent_conflict {
 7622            let cursor_point = cursor.to_point(&multibuffer);
 7623
 7624            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7625
 7626            if let Some((_, indent)) = indents.iter().next() {
 7627                if indent.len == cursor_point.column {
 7628                    self.edit_prediction_indent_conflict = false;
 7629                }
 7630            }
 7631        }
 7632
 7633        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7634        let edits = inline_completion
 7635            .edits
 7636            .into_iter()
 7637            .flat_map(|(range, new_text)| {
 7638                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7639                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7640                Some((start..end, new_text))
 7641            })
 7642            .collect::<Vec<_>>();
 7643        if edits.is_empty() {
 7644            return None;
 7645        }
 7646
 7647        let first_edit_start = edits.first().unwrap().0.start;
 7648        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7649        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7650
 7651        let last_edit_end = edits.last().unwrap().0.end;
 7652        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7653        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7654
 7655        let cursor_row = cursor.to_point(&multibuffer).row;
 7656
 7657        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7658
 7659        let mut inlay_ids = Vec::new();
 7660        let invalidation_row_range;
 7661        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7662            Some(cursor_row..edit_end_row)
 7663        } else if cursor_row > edit_end_row {
 7664            Some(edit_start_row..cursor_row)
 7665        } else {
 7666            None
 7667        };
 7668        let is_move =
 7669            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7670        let completion = if is_move {
 7671            invalidation_row_range =
 7672                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7673            let target = first_edit_start;
 7674            InlineCompletion::Move { target, snapshot }
 7675        } else {
 7676            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7677                && !self.inline_completions_hidden_for_vim_mode;
 7678
 7679            if show_completions_in_buffer {
 7680                if edits
 7681                    .iter()
 7682                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7683                {
 7684                    let mut inlays = Vec::new();
 7685                    for (range, new_text) in &edits {
 7686                        let inlay = Inlay::inline_completion(
 7687                            post_inc(&mut self.next_inlay_id),
 7688                            range.start,
 7689                            new_text.as_str(),
 7690                        );
 7691                        inlay_ids.push(inlay.id);
 7692                        inlays.push(inlay);
 7693                    }
 7694
 7695                    self.splice_inlays(&[], inlays, cx);
 7696                } else {
 7697                    let background_color = cx.theme().status().deleted_background;
 7698                    self.highlight_text::<InlineCompletionHighlight>(
 7699                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7700                        HighlightStyle {
 7701                            background_color: Some(background_color),
 7702                            ..Default::default()
 7703                        },
 7704                        cx,
 7705                    );
 7706                }
 7707            }
 7708
 7709            invalidation_row_range = edit_start_row..edit_end_row;
 7710
 7711            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7712                if provider.show_tab_accept_marker() {
 7713                    EditDisplayMode::TabAccept
 7714                } else {
 7715                    EditDisplayMode::Inline
 7716                }
 7717            } else {
 7718                EditDisplayMode::DiffPopover
 7719            };
 7720
 7721            InlineCompletion::Edit {
 7722                edits,
 7723                edit_preview: inline_completion.edit_preview,
 7724                display_mode,
 7725                snapshot,
 7726            }
 7727        };
 7728
 7729        let invalidation_range = multibuffer
 7730            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7731            ..multibuffer.anchor_after(Point::new(
 7732                invalidation_row_range.end,
 7733                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7734            ));
 7735
 7736        self.stale_inline_completion_in_menu = None;
 7737        self.active_inline_completion = Some(InlineCompletionState {
 7738            inlay_ids,
 7739            completion,
 7740            completion_id: inline_completion.id,
 7741            invalidation_range,
 7742        });
 7743
 7744        cx.notify();
 7745
 7746        Some(())
 7747    }
 7748
 7749    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7750        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7751    }
 7752
 7753    fn clear_tasks(&mut self) {
 7754        self.tasks.clear()
 7755    }
 7756
 7757    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7758        if self.tasks.insert(key, value).is_some() {
 7759            // This case should hopefully be rare, but just in case...
 7760            log::error!(
 7761                "multiple different run targets found on a single line, only the last target will be rendered"
 7762            )
 7763        }
 7764    }
 7765
 7766    /// Get all display points of breakpoints that will be rendered within editor
 7767    ///
 7768    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7769    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7770    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7771    fn active_breakpoints(
 7772        &self,
 7773        range: Range<DisplayRow>,
 7774        window: &mut Window,
 7775        cx: &mut Context<Self>,
 7776    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7777        let mut breakpoint_display_points = HashMap::default();
 7778
 7779        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7780            return breakpoint_display_points;
 7781        };
 7782
 7783        let snapshot = self.snapshot(window, cx);
 7784
 7785        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7786        let Some(project) = self.project.as_ref() else {
 7787            return breakpoint_display_points;
 7788        };
 7789
 7790        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7791            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7792
 7793        for (buffer_snapshot, range, excerpt_id) in
 7794            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7795        {
 7796            let Some(buffer) = project
 7797                .read(cx)
 7798                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7799            else {
 7800                continue;
 7801            };
 7802            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7803                &buffer,
 7804                Some(
 7805                    buffer_snapshot.anchor_before(range.start)
 7806                        ..buffer_snapshot.anchor_after(range.end),
 7807                ),
 7808                buffer_snapshot,
 7809                cx,
 7810            );
 7811            for (breakpoint, state) in breakpoints {
 7812                let multi_buffer_anchor =
 7813                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7814                let position = multi_buffer_anchor
 7815                    .to_point(&multi_buffer_snapshot)
 7816                    .to_display_point(&snapshot);
 7817
 7818                breakpoint_display_points.insert(
 7819                    position.row(),
 7820                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7821                );
 7822            }
 7823        }
 7824
 7825        breakpoint_display_points
 7826    }
 7827
 7828    fn breakpoint_context_menu(
 7829        &self,
 7830        anchor: Anchor,
 7831        window: &mut Window,
 7832        cx: &mut Context<Self>,
 7833    ) -> Entity<ui::ContextMenu> {
 7834        let weak_editor = cx.weak_entity();
 7835        let focus_handle = self.focus_handle(cx);
 7836
 7837        let row = self
 7838            .buffer
 7839            .read(cx)
 7840            .snapshot(cx)
 7841            .summary_for_anchor::<Point>(&anchor)
 7842            .row;
 7843
 7844        let breakpoint = self
 7845            .breakpoint_at_row(row, window, cx)
 7846            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7847
 7848        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7849            "Edit Log Breakpoint"
 7850        } else {
 7851            "Set Log Breakpoint"
 7852        };
 7853
 7854        let condition_breakpoint_msg = if breakpoint
 7855            .as_ref()
 7856            .is_some_and(|bp| bp.1.condition.is_some())
 7857        {
 7858            "Edit Condition Breakpoint"
 7859        } else {
 7860            "Set Condition Breakpoint"
 7861        };
 7862
 7863        let hit_condition_breakpoint_msg = if breakpoint
 7864            .as_ref()
 7865            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7866        {
 7867            "Edit Hit Condition Breakpoint"
 7868        } else {
 7869            "Set Hit Condition Breakpoint"
 7870        };
 7871
 7872        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7873            "Unset Breakpoint"
 7874        } else {
 7875            "Set Breakpoint"
 7876        };
 7877
 7878        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7879
 7880        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7881            BreakpointState::Enabled => Some("Disable"),
 7882            BreakpointState::Disabled => Some("Enable"),
 7883        });
 7884
 7885        let (anchor, breakpoint) =
 7886            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7887
 7888        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7889            menu.on_blur_subscription(Subscription::new(|| {}))
 7890                .context(focus_handle)
 7891                .when(run_to_cursor, |this| {
 7892                    let weak_editor = weak_editor.clone();
 7893                    this.entry("Run to cursor", None, move |window, cx| {
 7894                        weak_editor
 7895                            .update(cx, |editor, cx| {
 7896                                editor.change_selections(
 7897                                    SelectionEffects::no_scroll(),
 7898                                    window,
 7899                                    cx,
 7900                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7901                                );
 7902                            })
 7903                            .ok();
 7904
 7905                        window.dispatch_action(Box::new(RunToCursor), cx);
 7906                    })
 7907                    .separator()
 7908                })
 7909                .when_some(toggle_state_msg, |this, msg| {
 7910                    this.entry(msg, None, {
 7911                        let weak_editor = weak_editor.clone();
 7912                        let breakpoint = breakpoint.clone();
 7913                        move |_window, cx| {
 7914                            weak_editor
 7915                                .update(cx, |this, cx| {
 7916                                    this.edit_breakpoint_at_anchor(
 7917                                        anchor,
 7918                                        breakpoint.as_ref().clone(),
 7919                                        BreakpointEditAction::InvertState,
 7920                                        cx,
 7921                                    );
 7922                                })
 7923                                .log_err();
 7924                        }
 7925                    })
 7926                })
 7927                .entry(set_breakpoint_msg, None, {
 7928                    let weak_editor = weak_editor.clone();
 7929                    let breakpoint = breakpoint.clone();
 7930                    move |_window, cx| {
 7931                        weak_editor
 7932                            .update(cx, |this, cx| {
 7933                                this.edit_breakpoint_at_anchor(
 7934                                    anchor,
 7935                                    breakpoint.as_ref().clone(),
 7936                                    BreakpointEditAction::Toggle,
 7937                                    cx,
 7938                                );
 7939                            })
 7940                            .log_err();
 7941                    }
 7942                })
 7943                .entry(log_breakpoint_msg, None, {
 7944                    let breakpoint = breakpoint.clone();
 7945                    let weak_editor = weak_editor.clone();
 7946                    move |window, cx| {
 7947                        weak_editor
 7948                            .update(cx, |this, cx| {
 7949                                this.add_edit_breakpoint_block(
 7950                                    anchor,
 7951                                    breakpoint.as_ref(),
 7952                                    BreakpointPromptEditAction::Log,
 7953                                    window,
 7954                                    cx,
 7955                                );
 7956                            })
 7957                            .log_err();
 7958                    }
 7959                })
 7960                .entry(condition_breakpoint_msg, None, {
 7961                    let breakpoint = breakpoint.clone();
 7962                    let weak_editor = weak_editor.clone();
 7963                    move |window, cx| {
 7964                        weak_editor
 7965                            .update(cx, |this, cx| {
 7966                                this.add_edit_breakpoint_block(
 7967                                    anchor,
 7968                                    breakpoint.as_ref(),
 7969                                    BreakpointPromptEditAction::Condition,
 7970                                    window,
 7971                                    cx,
 7972                                );
 7973                            })
 7974                            .log_err();
 7975                    }
 7976                })
 7977                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7978                    weak_editor
 7979                        .update(cx, |this, cx| {
 7980                            this.add_edit_breakpoint_block(
 7981                                anchor,
 7982                                breakpoint.as_ref(),
 7983                                BreakpointPromptEditAction::HitCondition,
 7984                                window,
 7985                                cx,
 7986                            );
 7987                        })
 7988                        .log_err();
 7989                })
 7990        })
 7991    }
 7992
 7993    fn render_breakpoint(
 7994        &self,
 7995        position: Anchor,
 7996        row: DisplayRow,
 7997        breakpoint: &Breakpoint,
 7998        state: Option<BreakpointSessionState>,
 7999        cx: &mut Context<Self>,
 8000    ) -> IconButton {
 8001        let is_rejected = state.is_some_and(|s| !s.verified);
 8002        // Is it a breakpoint that shows up when hovering over gutter?
 8003        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8004            (false, false),
 8005            |PhantomBreakpointIndicator {
 8006                 is_active,
 8007                 display_row,
 8008                 collides_with_existing_breakpoint,
 8009             }| {
 8010                (
 8011                    is_active && display_row == row,
 8012                    collides_with_existing_breakpoint,
 8013                )
 8014            },
 8015        );
 8016
 8017        let (color, icon) = {
 8018            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8019                (false, false) => ui::IconName::DebugBreakpoint,
 8020                (true, false) => ui::IconName::DebugLogBreakpoint,
 8021                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8022                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8023            };
 8024
 8025            let color = if is_phantom {
 8026                Color::Hint
 8027            } else if is_rejected {
 8028                Color::Disabled
 8029            } else {
 8030                Color::Debugger
 8031            };
 8032
 8033            (color, icon)
 8034        };
 8035
 8036        let breakpoint = Arc::from(breakpoint.clone());
 8037
 8038        let alt_as_text = gpui::Keystroke {
 8039            modifiers: Modifiers::secondary_key(),
 8040            ..Default::default()
 8041        };
 8042        let primary_action_text = if breakpoint.is_disabled() {
 8043            "Enable breakpoint"
 8044        } else if is_phantom && !collides_with_existing {
 8045            "Set breakpoint"
 8046        } else {
 8047            "Unset breakpoint"
 8048        };
 8049        let focus_handle = self.focus_handle.clone();
 8050
 8051        let meta = if is_rejected {
 8052            SharedString::from("No executable code is associated with this line.")
 8053        } else if collides_with_existing && !breakpoint.is_disabled() {
 8054            SharedString::from(format!(
 8055                "{alt_as_text}-click to disable,\nright-click for more options."
 8056            ))
 8057        } else {
 8058            SharedString::from("Right-click for more options.")
 8059        };
 8060        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8061            .icon_size(IconSize::XSmall)
 8062            .size(ui::ButtonSize::None)
 8063            .when(is_rejected, |this| {
 8064                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8065            })
 8066            .icon_color(color)
 8067            .style(ButtonStyle::Transparent)
 8068            .on_click(cx.listener({
 8069                let breakpoint = breakpoint.clone();
 8070
 8071                move |editor, event: &ClickEvent, window, cx| {
 8072                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8073                        BreakpointEditAction::InvertState
 8074                    } else {
 8075                        BreakpointEditAction::Toggle
 8076                    };
 8077
 8078                    window.focus(&editor.focus_handle(cx));
 8079                    editor.edit_breakpoint_at_anchor(
 8080                        position,
 8081                        breakpoint.as_ref().clone(),
 8082                        edit_action,
 8083                        cx,
 8084                    );
 8085                }
 8086            }))
 8087            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8088                editor.set_breakpoint_context_menu(
 8089                    row,
 8090                    Some(position),
 8091                    event.down.position,
 8092                    window,
 8093                    cx,
 8094                );
 8095            }))
 8096            .tooltip(move |window, cx| {
 8097                Tooltip::with_meta_in(
 8098                    primary_action_text,
 8099                    Some(&ToggleBreakpoint),
 8100                    meta.clone(),
 8101                    &focus_handle,
 8102                    window,
 8103                    cx,
 8104                )
 8105            })
 8106    }
 8107
 8108    fn build_tasks_context(
 8109        project: &Entity<Project>,
 8110        buffer: &Entity<Buffer>,
 8111        buffer_row: u32,
 8112        tasks: &Arc<RunnableTasks>,
 8113        cx: &mut Context<Self>,
 8114    ) -> Task<Option<task::TaskContext>> {
 8115        let position = Point::new(buffer_row, tasks.column);
 8116        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8117        let location = Location {
 8118            buffer: buffer.clone(),
 8119            range: range_start..range_start,
 8120        };
 8121        // Fill in the environmental variables from the tree-sitter captures
 8122        let mut captured_task_variables = TaskVariables::default();
 8123        for (capture_name, value) in tasks.extra_variables.clone() {
 8124            captured_task_variables.insert(
 8125                task::VariableName::Custom(capture_name.into()),
 8126                value.clone(),
 8127            );
 8128        }
 8129        project.update(cx, |project, cx| {
 8130            project.task_store().update(cx, |task_store, cx| {
 8131                task_store.task_context_for_location(captured_task_variables, location, cx)
 8132            })
 8133        })
 8134    }
 8135
 8136    pub fn spawn_nearest_task(
 8137        &mut self,
 8138        action: &SpawnNearestTask,
 8139        window: &mut Window,
 8140        cx: &mut Context<Self>,
 8141    ) {
 8142        let Some((workspace, _)) = self.workspace.clone() else {
 8143            return;
 8144        };
 8145        let Some(project) = self.project.clone() else {
 8146            return;
 8147        };
 8148
 8149        // Try to find a closest, enclosing node using tree-sitter that has a
 8150        // task
 8151        let Some((buffer, buffer_row, tasks)) = self
 8152            .find_enclosing_node_task(cx)
 8153            // Or find the task that's closest in row-distance.
 8154            .or_else(|| self.find_closest_task(cx))
 8155        else {
 8156            return;
 8157        };
 8158
 8159        let reveal_strategy = action.reveal;
 8160        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8161        cx.spawn_in(window, async move |_, cx| {
 8162            let context = task_context.await?;
 8163            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8164
 8165            let resolved = &mut resolved_task.resolved;
 8166            resolved.reveal = reveal_strategy;
 8167
 8168            workspace
 8169                .update_in(cx, |workspace, window, cx| {
 8170                    workspace.schedule_resolved_task(
 8171                        task_source_kind,
 8172                        resolved_task,
 8173                        false,
 8174                        window,
 8175                        cx,
 8176                    );
 8177                })
 8178                .ok()
 8179        })
 8180        .detach();
 8181    }
 8182
 8183    fn find_closest_task(
 8184        &mut self,
 8185        cx: &mut Context<Self>,
 8186    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8187        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8188
 8189        let ((buffer_id, row), tasks) = self
 8190            .tasks
 8191            .iter()
 8192            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8193
 8194        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8195        let tasks = Arc::new(tasks.to_owned());
 8196        Some((buffer, *row, tasks))
 8197    }
 8198
 8199    fn find_enclosing_node_task(
 8200        &mut self,
 8201        cx: &mut Context<Self>,
 8202    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8203        let snapshot = self.buffer.read(cx).snapshot(cx);
 8204        let offset = self.selections.newest::<usize>(cx).head();
 8205        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8206        let buffer_id = excerpt.buffer().remote_id();
 8207
 8208        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8209        let mut cursor = layer.node().walk();
 8210
 8211        while cursor.goto_first_child_for_byte(offset).is_some() {
 8212            if cursor.node().end_byte() == offset {
 8213                cursor.goto_next_sibling();
 8214            }
 8215        }
 8216
 8217        // Ascend to the smallest ancestor that contains the range and has a task.
 8218        loop {
 8219            let node = cursor.node();
 8220            let node_range = node.byte_range();
 8221            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8222
 8223            // Check if this node contains our offset
 8224            if node_range.start <= offset && node_range.end >= offset {
 8225                // If it contains offset, check for task
 8226                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8227                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8228                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8229                }
 8230            }
 8231
 8232            if !cursor.goto_parent() {
 8233                break;
 8234            }
 8235        }
 8236        None
 8237    }
 8238
 8239    fn render_run_indicator(
 8240        &self,
 8241        _style: &EditorStyle,
 8242        is_active: bool,
 8243        row: DisplayRow,
 8244        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8245        cx: &mut Context<Self>,
 8246    ) -> IconButton {
 8247        let color = Color::Muted;
 8248        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8249
 8250        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8251            .shape(ui::IconButtonShape::Square)
 8252            .icon_size(IconSize::XSmall)
 8253            .icon_color(color)
 8254            .toggle_state(is_active)
 8255            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8256                let quick_launch = e.down.button == MouseButton::Left;
 8257                window.focus(&editor.focus_handle(cx));
 8258                editor.toggle_code_actions(
 8259                    &ToggleCodeActions {
 8260                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8261                        quick_launch,
 8262                    },
 8263                    window,
 8264                    cx,
 8265                );
 8266            }))
 8267            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8268                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8269            }))
 8270    }
 8271
 8272    pub fn context_menu_visible(&self) -> bool {
 8273        !self.edit_prediction_preview_is_active()
 8274            && self
 8275                .context_menu
 8276                .borrow()
 8277                .as_ref()
 8278                .map_or(false, |menu| menu.visible())
 8279    }
 8280
 8281    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8282        self.context_menu
 8283            .borrow()
 8284            .as_ref()
 8285            .map(|menu| menu.origin())
 8286    }
 8287
 8288    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8289        self.context_menu_options = Some(options);
 8290    }
 8291
 8292    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8293    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8294
 8295    fn render_edit_prediction_popover(
 8296        &mut self,
 8297        text_bounds: &Bounds<Pixels>,
 8298        content_origin: gpui::Point<Pixels>,
 8299        right_margin: Pixels,
 8300        editor_snapshot: &EditorSnapshot,
 8301        visible_row_range: Range<DisplayRow>,
 8302        scroll_top: f32,
 8303        scroll_bottom: f32,
 8304        line_layouts: &[LineWithInvisibles],
 8305        line_height: Pixels,
 8306        scroll_pixel_position: gpui::Point<Pixels>,
 8307        newest_selection_head: Option<DisplayPoint>,
 8308        editor_width: Pixels,
 8309        style: &EditorStyle,
 8310        window: &mut Window,
 8311        cx: &mut App,
 8312    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8313        if self.mode().is_minimap() {
 8314            return None;
 8315        }
 8316        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8317
 8318        if self.edit_prediction_visible_in_cursor_popover(true) {
 8319            return None;
 8320        }
 8321
 8322        match &active_inline_completion.completion {
 8323            InlineCompletion::Move { target, .. } => {
 8324                let target_display_point = target.to_display_point(editor_snapshot);
 8325
 8326                if self.edit_prediction_requires_modifier() {
 8327                    if !self.edit_prediction_preview_is_active() {
 8328                        return None;
 8329                    }
 8330
 8331                    self.render_edit_prediction_modifier_jump_popover(
 8332                        text_bounds,
 8333                        content_origin,
 8334                        visible_row_range,
 8335                        line_layouts,
 8336                        line_height,
 8337                        scroll_pixel_position,
 8338                        newest_selection_head,
 8339                        target_display_point,
 8340                        window,
 8341                        cx,
 8342                    )
 8343                } else {
 8344                    self.render_edit_prediction_eager_jump_popover(
 8345                        text_bounds,
 8346                        content_origin,
 8347                        editor_snapshot,
 8348                        visible_row_range,
 8349                        scroll_top,
 8350                        scroll_bottom,
 8351                        line_height,
 8352                        scroll_pixel_position,
 8353                        target_display_point,
 8354                        editor_width,
 8355                        window,
 8356                        cx,
 8357                    )
 8358                }
 8359            }
 8360            InlineCompletion::Edit {
 8361                display_mode: EditDisplayMode::Inline,
 8362                ..
 8363            } => None,
 8364            InlineCompletion::Edit {
 8365                display_mode: EditDisplayMode::TabAccept,
 8366                edits,
 8367                ..
 8368            } => {
 8369                let range = &edits.first()?.0;
 8370                let target_display_point = range.end.to_display_point(editor_snapshot);
 8371
 8372                self.render_edit_prediction_end_of_line_popover(
 8373                    "Accept",
 8374                    editor_snapshot,
 8375                    visible_row_range,
 8376                    target_display_point,
 8377                    line_height,
 8378                    scroll_pixel_position,
 8379                    content_origin,
 8380                    editor_width,
 8381                    window,
 8382                    cx,
 8383                )
 8384            }
 8385            InlineCompletion::Edit {
 8386                edits,
 8387                edit_preview,
 8388                display_mode: EditDisplayMode::DiffPopover,
 8389                snapshot,
 8390            } => self.render_edit_prediction_diff_popover(
 8391                text_bounds,
 8392                content_origin,
 8393                right_margin,
 8394                editor_snapshot,
 8395                visible_row_range,
 8396                line_layouts,
 8397                line_height,
 8398                scroll_pixel_position,
 8399                newest_selection_head,
 8400                editor_width,
 8401                style,
 8402                edits,
 8403                edit_preview,
 8404                snapshot,
 8405                window,
 8406                cx,
 8407            ),
 8408        }
 8409    }
 8410
 8411    fn render_edit_prediction_modifier_jump_popover(
 8412        &mut self,
 8413        text_bounds: &Bounds<Pixels>,
 8414        content_origin: gpui::Point<Pixels>,
 8415        visible_row_range: Range<DisplayRow>,
 8416        line_layouts: &[LineWithInvisibles],
 8417        line_height: Pixels,
 8418        scroll_pixel_position: gpui::Point<Pixels>,
 8419        newest_selection_head: Option<DisplayPoint>,
 8420        target_display_point: DisplayPoint,
 8421        window: &mut Window,
 8422        cx: &mut App,
 8423    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8424        let scrolled_content_origin =
 8425            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8426
 8427        const SCROLL_PADDING_Y: Pixels = px(12.);
 8428
 8429        if target_display_point.row() < visible_row_range.start {
 8430            return self.render_edit_prediction_scroll_popover(
 8431                |_| SCROLL_PADDING_Y,
 8432                IconName::ArrowUp,
 8433                visible_row_range,
 8434                line_layouts,
 8435                newest_selection_head,
 8436                scrolled_content_origin,
 8437                window,
 8438                cx,
 8439            );
 8440        } else if target_display_point.row() >= visible_row_range.end {
 8441            return self.render_edit_prediction_scroll_popover(
 8442                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8443                IconName::ArrowDown,
 8444                visible_row_range,
 8445                line_layouts,
 8446                newest_selection_head,
 8447                scrolled_content_origin,
 8448                window,
 8449                cx,
 8450            );
 8451        }
 8452
 8453        const POLE_WIDTH: Pixels = px(2.);
 8454
 8455        let line_layout =
 8456            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8457        let target_column = target_display_point.column() as usize;
 8458
 8459        let target_x = line_layout.x_for_index(target_column);
 8460        let target_y =
 8461            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8462
 8463        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8464
 8465        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8466        border_color.l += 0.001;
 8467
 8468        let mut element = v_flex()
 8469            .items_end()
 8470            .when(flag_on_right, |el| el.items_start())
 8471            .child(if flag_on_right {
 8472                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8473                    .rounded_bl(px(0.))
 8474                    .rounded_tl(px(0.))
 8475                    .border_l_2()
 8476                    .border_color(border_color)
 8477            } else {
 8478                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8479                    .rounded_br(px(0.))
 8480                    .rounded_tr(px(0.))
 8481                    .border_r_2()
 8482                    .border_color(border_color)
 8483            })
 8484            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8485            .into_any();
 8486
 8487        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8488
 8489        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8490            - point(
 8491                if flag_on_right {
 8492                    POLE_WIDTH
 8493                } else {
 8494                    size.width - POLE_WIDTH
 8495                },
 8496                size.height - line_height,
 8497            );
 8498
 8499        origin.x = origin.x.max(content_origin.x);
 8500
 8501        element.prepaint_at(origin, window, cx);
 8502
 8503        Some((element, origin))
 8504    }
 8505
 8506    fn render_edit_prediction_scroll_popover(
 8507        &mut self,
 8508        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8509        scroll_icon: IconName,
 8510        visible_row_range: Range<DisplayRow>,
 8511        line_layouts: &[LineWithInvisibles],
 8512        newest_selection_head: Option<DisplayPoint>,
 8513        scrolled_content_origin: gpui::Point<Pixels>,
 8514        window: &mut Window,
 8515        cx: &mut App,
 8516    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8517        let mut element = self
 8518            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8519            .into_any();
 8520
 8521        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8522
 8523        let cursor = newest_selection_head?;
 8524        let cursor_row_layout =
 8525            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8526        let cursor_column = cursor.column() as usize;
 8527
 8528        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8529
 8530        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8531
 8532        element.prepaint_at(origin, window, cx);
 8533        Some((element, origin))
 8534    }
 8535
 8536    fn render_edit_prediction_eager_jump_popover(
 8537        &mut self,
 8538        text_bounds: &Bounds<Pixels>,
 8539        content_origin: gpui::Point<Pixels>,
 8540        editor_snapshot: &EditorSnapshot,
 8541        visible_row_range: Range<DisplayRow>,
 8542        scroll_top: f32,
 8543        scroll_bottom: f32,
 8544        line_height: Pixels,
 8545        scroll_pixel_position: gpui::Point<Pixels>,
 8546        target_display_point: DisplayPoint,
 8547        editor_width: Pixels,
 8548        window: &mut Window,
 8549        cx: &mut App,
 8550    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8551        if target_display_point.row().as_f32() < scroll_top {
 8552            let mut element = self
 8553                .render_edit_prediction_line_popover(
 8554                    "Jump to Edit",
 8555                    Some(IconName::ArrowUp),
 8556                    window,
 8557                    cx,
 8558                )?
 8559                .into_any();
 8560
 8561            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8562            let offset = point(
 8563                (text_bounds.size.width - size.width) / 2.,
 8564                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8565            );
 8566
 8567            let origin = text_bounds.origin + offset;
 8568            element.prepaint_at(origin, window, cx);
 8569            Some((element, origin))
 8570        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8571            let mut element = self
 8572                .render_edit_prediction_line_popover(
 8573                    "Jump to Edit",
 8574                    Some(IconName::ArrowDown),
 8575                    window,
 8576                    cx,
 8577                )?
 8578                .into_any();
 8579
 8580            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8581            let offset = point(
 8582                (text_bounds.size.width - size.width) / 2.,
 8583                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8584            );
 8585
 8586            let origin = text_bounds.origin + offset;
 8587            element.prepaint_at(origin, window, cx);
 8588            Some((element, origin))
 8589        } else {
 8590            self.render_edit_prediction_end_of_line_popover(
 8591                "Jump to Edit",
 8592                editor_snapshot,
 8593                visible_row_range,
 8594                target_display_point,
 8595                line_height,
 8596                scroll_pixel_position,
 8597                content_origin,
 8598                editor_width,
 8599                window,
 8600                cx,
 8601            )
 8602        }
 8603    }
 8604
 8605    fn render_edit_prediction_end_of_line_popover(
 8606        self: &mut Editor,
 8607        label: &'static str,
 8608        editor_snapshot: &EditorSnapshot,
 8609        visible_row_range: Range<DisplayRow>,
 8610        target_display_point: DisplayPoint,
 8611        line_height: Pixels,
 8612        scroll_pixel_position: gpui::Point<Pixels>,
 8613        content_origin: gpui::Point<Pixels>,
 8614        editor_width: Pixels,
 8615        window: &mut Window,
 8616        cx: &mut App,
 8617    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8618        let target_line_end = DisplayPoint::new(
 8619            target_display_point.row(),
 8620            editor_snapshot.line_len(target_display_point.row()),
 8621        );
 8622
 8623        let mut element = self
 8624            .render_edit_prediction_line_popover(label, None, window, cx)?
 8625            .into_any();
 8626
 8627        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8628
 8629        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8630
 8631        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8632        let mut origin = start_point
 8633            + line_origin
 8634            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8635        origin.x = origin.x.max(content_origin.x);
 8636
 8637        let max_x = content_origin.x + editor_width - size.width;
 8638
 8639        if origin.x > max_x {
 8640            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8641
 8642            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8643                origin.y += offset;
 8644                IconName::ArrowUp
 8645            } else {
 8646                origin.y -= offset;
 8647                IconName::ArrowDown
 8648            };
 8649
 8650            element = self
 8651                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8652                .into_any();
 8653
 8654            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8655
 8656            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8657        }
 8658
 8659        element.prepaint_at(origin, window, cx);
 8660        Some((element, origin))
 8661    }
 8662
 8663    fn render_edit_prediction_diff_popover(
 8664        self: &Editor,
 8665        text_bounds: &Bounds<Pixels>,
 8666        content_origin: gpui::Point<Pixels>,
 8667        right_margin: Pixels,
 8668        editor_snapshot: &EditorSnapshot,
 8669        visible_row_range: Range<DisplayRow>,
 8670        line_layouts: &[LineWithInvisibles],
 8671        line_height: Pixels,
 8672        scroll_pixel_position: gpui::Point<Pixels>,
 8673        newest_selection_head: Option<DisplayPoint>,
 8674        editor_width: Pixels,
 8675        style: &EditorStyle,
 8676        edits: &Vec<(Range<Anchor>, String)>,
 8677        edit_preview: &Option<language::EditPreview>,
 8678        snapshot: &language::BufferSnapshot,
 8679        window: &mut Window,
 8680        cx: &mut App,
 8681    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8682        let edit_start = edits
 8683            .first()
 8684            .unwrap()
 8685            .0
 8686            .start
 8687            .to_display_point(editor_snapshot);
 8688        let edit_end = edits
 8689            .last()
 8690            .unwrap()
 8691            .0
 8692            .end
 8693            .to_display_point(editor_snapshot);
 8694
 8695        let is_visible = visible_row_range.contains(&edit_start.row())
 8696            || visible_row_range.contains(&edit_end.row());
 8697        if !is_visible {
 8698            return None;
 8699        }
 8700
 8701        let highlighted_edits =
 8702            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8703
 8704        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8705        let line_count = highlighted_edits.text.lines().count();
 8706
 8707        const BORDER_WIDTH: Pixels = px(1.);
 8708
 8709        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8710        let has_keybind = keybind.is_some();
 8711
 8712        let mut element = h_flex()
 8713            .items_start()
 8714            .child(
 8715                h_flex()
 8716                    .bg(cx.theme().colors().editor_background)
 8717                    .border(BORDER_WIDTH)
 8718                    .shadow_sm()
 8719                    .border_color(cx.theme().colors().border)
 8720                    .rounded_l_lg()
 8721                    .when(line_count > 1, |el| el.rounded_br_lg())
 8722                    .pr_1()
 8723                    .child(styled_text),
 8724            )
 8725            .child(
 8726                h_flex()
 8727                    .h(line_height + BORDER_WIDTH * 2.)
 8728                    .px_1p5()
 8729                    .gap_1()
 8730                    // Workaround: For some reason, there's a gap if we don't do this
 8731                    .ml(-BORDER_WIDTH)
 8732                    .shadow(vec![gpui::BoxShadow {
 8733                        color: gpui::black().opacity(0.05),
 8734                        offset: point(px(1.), px(1.)),
 8735                        blur_radius: px(2.),
 8736                        spread_radius: px(0.),
 8737                    }])
 8738                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8739                    .border(BORDER_WIDTH)
 8740                    .border_color(cx.theme().colors().border)
 8741                    .rounded_r_lg()
 8742                    .id("edit_prediction_diff_popover_keybind")
 8743                    .when(!has_keybind, |el| {
 8744                        let status_colors = cx.theme().status();
 8745
 8746                        el.bg(status_colors.error_background)
 8747                            .border_color(status_colors.error.opacity(0.6))
 8748                            .child(Icon::new(IconName::Info).color(Color::Error))
 8749                            .cursor_default()
 8750                            .hoverable_tooltip(move |_window, cx| {
 8751                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8752                            })
 8753                    })
 8754                    .children(keybind),
 8755            )
 8756            .into_any();
 8757
 8758        let longest_row =
 8759            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8760        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8761            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8762        } else {
 8763            layout_line(
 8764                longest_row,
 8765                editor_snapshot,
 8766                style,
 8767                editor_width,
 8768                |_| false,
 8769                window,
 8770                cx,
 8771            )
 8772            .width
 8773        };
 8774
 8775        let viewport_bounds =
 8776            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8777                right: -right_margin,
 8778                ..Default::default()
 8779            });
 8780
 8781        let x_after_longest =
 8782            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8783                - scroll_pixel_position.x;
 8784
 8785        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8786
 8787        // Fully visible if it can be displayed within the window (allow overlapping other
 8788        // panes). However, this is only allowed if the popover starts within text_bounds.
 8789        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8790            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8791
 8792        let mut origin = if can_position_to_the_right {
 8793            point(
 8794                x_after_longest,
 8795                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8796                    - scroll_pixel_position.y,
 8797            )
 8798        } else {
 8799            let cursor_row = newest_selection_head.map(|head| head.row());
 8800            let above_edit = edit_start
 8801                .row()
 8802                .0
 8803                .checked_sub(line_count as u32)
 8804                .map(DisplayRow);
 8805            let below_edit = Some(edit_end.row() + 1);
 8806            let above_cursor =
 8807                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8808            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8809
 8810            // Place the edit popover adjacent to the edit if there is a location
 8811            // available that is onscreen and does not obscure the cursor. Otherwise,
 8812            // place it adjacent to the cursor.
 8813            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8814                .into_iter()
 8815                .flatten()
 8816                .find(|&start_row| {
 8817                    let end_row = start_row + line_count as u32;
 8818                    visible_row_range.contains(&start_row)
 8819                        && visible_row_range.contains(&end_row)
 8820                        && cursor_row.map_or(true, |cursor_row| {
 8821                            !((start_row..end_row).contains(&cursor_row))
 8822                        })
 8823                })?;
 8824
 8825            content_origin
 8826                + point(
 8827                    -scroll_pixel_position.x,
 8828                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8829                )
 8830        };
 8831
 8832        origin.x -= BORDER_WIDTH;
 8833
 8834        window.defer_draw(element, origin, 1);
 8835
 8836        // Do not return an element, since it will already be drawn due to defer_draw.
 8837        None
 8838    }
 8839
 8840    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8841        px(30.)
 8842    }
 8843
 8844    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8845        if self.read_only(cx) {
 8846            cx.theme().players().read_only()
 8847        } else {
 8848            self.style.as_ref().unwrap().local_player
 8849        }
 8850    }
 8851
 8852    fn render_edit_prediction_accept_keybind(
 8853        &self,
 8854        window: &mut Window,
 8855        cx: &App,
 8856    ) -> Option<AnyElement> {
 8857        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8858        let accept_keystroke = accept_binding.keystroke()?;
 8859
 8860        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8861
 8862        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8863            Color::Accent
 8864        } else {
 8865            Color::Muted
 8866        };
 8867
 8868        h_flex()
 8869            .px_0p5()
 8870            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8871            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8872            .text_size(TextSize::XSmall.rems(cx))
 8873            .child(h_flex().children(ui::render_modifiers(
 8874                &accept_keystroke.modifiers,
 8875                PlatformStyle::platform(),
 8876                Some(modifiers_color),
 8877                Some(IconSize::XSmall.rems().into()),
 8878                true,
 8879            )))
 8880            .when(is_platform_style_mac, |parent| {
 8881                parent.child(accept_keystroke.key.clone())
 8882            })
 8883            .when(!is_platform_style_mac, |parent| {
 8884                parent.child(
 8885                    Key::new(
 8886                        util::capitalize(&accept_keystroke.key),
 8887                        Some(Color::Default),
 8888                    )
 8889                    .size(Some(IconSize::XSmall.rems().into())),
 8890                )
 8891            })
 8892            .into_any()
 8893            .into()
 8894    }
 8895
 8896    fn render_edit_prediction_line_popover(
 8897        &self,
 8898        label: impl Into<SharedString>,
 8899        icon: Option<IconName>,
 8900        window: &mut Window,
 8901        cx: &App,
 8902    ) -> Option<Stateful<Div>> {
 8903        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8904
 8905        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8906        let has_keybind = keybind.is_some();
 8907
 8908        let result = h_flex()
 8909            .id("ep-line-popover")
 8910            .py_0p5()
 8911            .pl_1()
 8912            .pr(padding_right)
 8913            .gap_1()
 8914            .rounded_md()
 8915            .border_1()
 8916            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8917            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8918            .shadow_sm()
 8919            .when(!has_keybind, |el| {
 8920                let status_colors = cx.theme().status();
 8921
 8922                el.bg(status_colors.error_background)
 8923                    .border_color(status_colors.error.opacity(0.6))
 8924                    .pl_2()
 8925                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8926                    .cursor_default()
 8927                    .hoverable_tooltip(move |_window, cx| {
 8928                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8929                    })
 8930            })
 8931            .children(keybind)
 8932            .child(
 8933                Label::new(label)
 8934                    .size(LabelSize::Small)
 8935                    .when(!has_keybind, |el| {
 8936                        el.color(cx.theme().status().error.into()).strikethrough()
 8937                    }),
 8938            )
 8939            .when(!has_keybind, |el| {
 8940                el.child(
 8941                    h_flex().ml_1().child(
 8942                        Icon::new(IconName::Info)
 8943                            .size(IconSize::Small)
 8944                            .color(cx.theme().status().error.into()),
 8945                    ),
 8946                )
 8947            })
 8948            .when_some(icon, |element, icon| {
 8949                element.child(
 8950                    div()
 8951                        .mt(px(1.5))
 8952                        .child(Icon::new(icon).size(IconSize::Small)),
 8953                )
 8954            });
 8955
 8956        Some(result)
 8957    }
 8958
 8959    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8960        let accent_color = cx.theme().colors().text_accent;
 8961        let editor_bg_color = cx.theme().colors().editor_background;
 8962        editor_bg_color.blend(accent_color.opacity(0.1))
 8963    }
 8964
 8965    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8966        let accent_color = cx.theme().colors().text_accent;
 8967        let editor_bg_color = cx.theme().colors().editor_background;
 8968        editor_bg_color.blend(accent_color.opacity(0.6))
 8969    }
 8970
 8971    fn render_edit_prediction_cursor_popover(
 8972        &self,
 8973        min_width: Pixels,
 8974        max_width: Pixels,
 8975        cursor_point: Point,
 8976        style: &EditorStyle,
 8977        accept_keystroke: Option<&gpui::Keystroke>,
 8978        _window: &Window,
 8979        cx: &mut Context<Editor>,
 8980    ) -> Option<AnyElement> {
 8981        let provider = self.edit_prediction_provider.as_ref()?;
 8982
 8983        if provider.provider.needs_terms_acceptance(cx) {
 8984            return Some(
 8985                h_flex()
 8986                    .min_w(min_width)
 8987                    .flex_1()
 8988                    .px_2()
 8989                    .py_1()
 8990                    .gap_3()
 8991                    .elevation_2(cx)
 8992                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8993                    .id("accept-terms")
 8994                    .cursor_pointer()
 8995                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8996                    .on_click(cx.listener(|this, _event, window, cx| {
 8997                        cx.stop_propagation();
 8998                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8999                        window.dispatch_action(
 9000                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9001                            cx,
 9002                        );
 9003                    }))
 9004                    .child(
 9005                        h_flex()
 9006                            .flex_1()
 9007                            .gap_2()
 9008                            .child(Icon::new(IconName::ZedPredict))
 9009                            .child(Label::new("Accept Terms of Service"))
 9010                            .child(div().w_full())
 9011                            .child(
 9012                                Icon::new(IconName::ArrowUpRight)
 9013                                    .color(Color::Muted)
 9014                                    .size(IconSize::Small),
 9015                            )
 9016                            .into_any_element(),
 9017                    )
 9018                    .into_any(),
 9019            );
 9020        }
 9021
 9022        let is_refreshing = provider.provider.is_refreshing(cx);
 9023
 9024        fn pending_completion_container() -> Div {
 9025            h_flex()
 9026                .h_full()
 9027                .flex_1()
 9028                .gap_2()
 9029                .child(Icon::new(IconName::ZedPredict))
 9030        }
 9031
 9032        let completion = match &self.active_inline_completion {
 9033            Some(prediction) => {
 9034                if !self.has_visible_completions_menu() {
 9035                    const RADIUS: Pixels = px(6.);
 9036                    const BORDER_WIDTH: Pixels = px(1.);
 9037
 9038                    return Some(
 9039                        h_flex()
 9040                            .elevation_2(cx)
 9041                            .border(BORDER_WIDTH)
 9042                            .border_color(cx.theme().colors().border)
 9043                            .when(accept_keystroke.is_none(), |el| {
 9044                                el.border_color(cx.theme().status().error)
 9045                            })
 9046                            .rounded(RADIUS)
 9047                            .rounded_tl(px(0.))
 9048                            .overflow_hidden()
 9049                            .child(div().px_1p5().child(match &prediction.completion {
 9050                                InlineCompletion::Move { target, snapshot } => {
 9051                                    use text::ToPoint as _;
 9052                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9053                                    {
 9054                                        Icon::new(IconName::ZedPredictDown)
 9055                                    } else {
 9056                                        Icon::new(IconName::ZedPredictUp)
 9057                                    }
 9058                                }
 9059                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9060                            }))
 9061                            .child(
 9062                                h_flex()
 9063                                    .gap_1()
 9064                                    .py_1()
 9065                                    .px_2()
 9066                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9067                                    .border_l_1()
 9068                                    .border_color(cx.theme().colors().border)
 9069                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9070                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9071                                        el.child(
 9072                                            Label::new("Hold")
 9073                                                .size(LabelSize::Small)
 9074                                                .when(accept_keystroke.is_none(), |el| {
 9075                                                    el.strikethrough()
 9076                                                })
 9077                                                .line_height_style(LineHeightStyle::UiLabel),
 9078                                        )
 9079                                    })
 9080                                    .id("edit_prediction_cursor_popover_keybind")
 9081                                    .when(accept_keystroke.is_none(), |el| {
 9082                                        let status_colors = cx.theme().status();
 9083
 9084                                        el.bg(status_colors.error_background)
 9085                                            .border_color(status_colors.error.opacity(0.6))
 9086                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9087                                            .cursor_default()
 9088                                            .hoverable_tooltip(move |_window, cx| {
 9089                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9090                                                    .into()
 9091                                            })
 9092                                    })
 9093                                    .when_some(
 9094                                        accept_keystroke.as_ref(),
 9095                                        |el, accept_keystroke| {
 9096                                            el.child(h_flex().children(ui::render_modifiers(
 9097                                                &accept_keystroke.modifiers,
 9098                                                PlatformStyle::platform(),
 9099                                                Some(Color::Default),
 9100                                                Some(IconSize::XSmall.rems().into()),
 9101                                                false,
 9102                                            )))
 9103                                        },
 9104                                    ),
 9105                            )
 9106                            .into_any(),
 9107                    );
 9108                }
 9109
 9110                self.render_edit_prediction_cursor_popover_preview(
 9111                    prediction,
 9112                    cursor_point,
 9113                    style,
 9114                    cx,
 9115                )?
 9116            }
 9117
 9118            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9119                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9120                    stale_completion,
 9121                    cursor_point,
 9122                    style,
 9123                    cx,
 9124                )?,
 9125
 9126                None => {
 9127                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9128                }
 9129            },
 9130
 9131            None => pending_completion_container().child(Label::new("No Prediction")),
 9132        };
 9133
 9134        let completion = if is_refreshing {
 9135            completion
 9136                .with_animation(
 9137                    "loading-completion",
 9138                    Animation::new(Duration::from_secs(2))
 9139                        .repeat()
 9140                        .with_easing(pulsating_between(0.4, 0.8)),
 9141                    |label, delta| label.opacity(delta),
 9142                )
 9143                .into_any_element()
 9144        } else {
 9145            completion.into_any_element()
 9146        };
 9147
 9148        let has_completion = self.active_inline_completion.is_some();
 9149
 9150        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9151        Some(
 9152            h_flex()
 9153                .min_w(min_width)
 9154                .max_w(max_width)
 9155                .flex_1()
 9156                .elevation_2(cx)
 9157                .border_color(cx.theme().colors().border)
 9158                .child(
 9159                    div()
 9160                        .flex_1()
 9161                        .py_1()
 9162                        .px_2()
 9163                        .overflow_hidden()
 9164                        .child(completion),
 9165                )
 9166                .when_some(accept_keystroke, |el, accept_keystroke| {
 9167                    if !accept_keystroke.modifiers.modified() {
 9168                        return el;
 9169                    }
 9170
 9171                    el.child(
 9172                        h_flex()
 9173                            .h_full()
 9174                            .border_l_1()
 9175                            .rounded_r_lg()
 9176                            .border_color(cx.theme().colors().border)
 9177                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9178                            .gap_1()
 9179                            .py_1()
 9180                            .px_2()
 9181                            .child(
 9182                                h_flex()
 9183                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9184                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9185                                    .child(h_flex().children(ui::render_modifiers(
 9186                                        &accept_keystroke.modifiers,
 9187                                        PlatformStyle::platform(),
 9188                                        Some(if !has_completion {
 9189                                            Color::Muted
 9190                                        } else {
 9191                                            Color::Default
 9192                                        }),
 9193                                        None,
 9194                                        false,
 9195                                    ))),
 9196                            )
 9197                            .child(Label::new("Preview").into_any_element())
 9198                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9199                    )
 9200                })
 9201                .into_any(),
 9202        )
 9203    }
 9204
 9205    fn render_edit_prediction_cursor_popover_preview(
 9206        &self,
 9207        completion: &InlineCompletionState,
 9208        cursor_point: Point,
 9209        style: &EditorStyle,
 9210        cx: &mut Context<Editor>,
 9211    ) -> Option<Div> {
 9212        use text::ToPoint as _;
 9213
 9214        fn render_relative_row_jump(
 9215            prefix: impl Into<String>,
 9216            current_row: u32,
 9217            target_row: u32,
 9218        ) -> Div {
 9219            let (row_diff, arrow) = if target_row < current_row {
 9220                (current_row - target_row, IconName::ArrowUp)
 9221            } else {
 9222                (target_row - current_row, IconName::ArrowDown)
 9223            };
 9224
 9225            h_flex()
 9226                .child(
 9227                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9228                        .color(Color::Muted)
 9229                        .size(LabelSize::Small),
 9230                )
 9231                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9232        }
 9233
 9234        match &completion.completion {
 9235            InlineCompletion::Move {
 9236                target, snapshot, ..
 9237            } => Some(
 9238                h_flex()
 9239                    .px_2()
 9240                    .gap_2()
 9241                    .flex_1()
 9242                    .child(
 9243                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9244                            Icon::new(IconName::ZedPredictDown)
 9245                        } else {
 9246                            Icon::new(IconName::ZedPredictUp)
 9247                        },
 9248                    )
 9249                    .child(Label::new("Jump to Edit")),
 9250            ),
 9251
 9252            InlineCompletion::Edit {
 9253                edits,
 9254                edit_preview,
 9255                snapshot,
 9256                display_mode: _,
 9257            } => {
 9258                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9259
 9260                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9261                    &snapshot,
 9262                    &edits,
 9263                    edit_preview.as_ref()?,
 9264                    true,
 9265                    cx,
 9266                )
 9267                .first_line_preview();
 9268
 9269                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9270                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9271
 9272                let preview = h_flex()
 9273                    .gap_1()
 9274                    .min_w_16()
 9275                    .child(styled_text)
 9276                    .when(has_more_lines, |parent| parent.child(""));
 9277
 9278                let left = if first_edit_row != cursor_point.row {
 9279                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9280                        .into_any_element()
 9281                } else {
 9282                    Icon::new(IconName::ZedPredict).into_any_element()
 9283                };
 9284
 9285                Some(
 9286                    h_flex()
 9287                        .h_full()
 9288                        .flex_1()
 9289                        .gap_2()
 9290                        .pr_1()
 9291                        .overflow_x_hidden()
 9292                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9293                        .child(left)
 9294                        .child(preview),
 9295                )
 9296            }
 9297        }
 9298    }
 9299
 9300    pub fn render_context_menu(
 9301        &self,
 9302        style: &EditorStyle,
 9303        max_height_in_lines: u32,
 9304        window: &mut Window,
 9305        cx: &mut Context<Editor>,
 9306    ) -> Option<AnyElement> {
 9307        let menu = self.context_menu.borrow();
 9308        let menu = menu.as_ref()?;
 9309        if !menu.visible() {
 9310            return None;
 9311        };
 9312        Some(menu.render(style, max_height_in_lines, window, cx))
 9313    }
 9314
 9315    fn render_context_menu_aside(
 9316        &mut self,
 9317        max_size: Size<Pixels>,
 9318        window: &mut Window,
 9319        cx: &mut Context<Editor>,
 9320    ) -> Option<AnyElement> {
 9321        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9322            if menu.visible() {
 9323                menu.render_aside(max_size, window, cx)
 9324            } else {
 9325                None
 9326            }
 9327        })
 9328    }
 9329
 9330    fn hide_context_menu(
 9331        &mut self,
 9332        window: &mut Window,
 9333        cx: &mut Context<Self>,
 9334    ) -> Option<CodeContextMenu> {
 9335        cx.notify();
 9336        self.completion_tasks.clear();
 9337        let context_menu = self.context_menu.borrow_mut().take();
 9338        self.stale_inline_completion_in_menu.take();
 9339        self.update_visible_inline_completion(window, cx);
 9340        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9341            if let Some(completion_provider) = &self.completion_provider {
 9342                completion_provider.selection_changed(None, window, cx);
 9343            }
 9344        }
 9345        context_menu
 9346    }
 9347
 9348    fn show_snippet_choices(
 9349        &mut self,
 9350        choices: &Vec<String>,
 9351        selection: Range<Anchor>,
 9352        cx: &mut Context<Self>,
 9353    ) {
 9354        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9355            (Some(a), Some(b)) if a == b => a,
 9356            _ => {
 9357                log::error!("expected anchor range to have matching buffer IDs");
 9358                return;
 9359            }
 9360        };
 9361        let multi_buffer = self.buffer().read(cx);
 9362        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9363            return;
 9364        };
 9365
 9366        let id = post_inc(&mut self.next_completion_id);
 9367        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9368        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9369            CompletionsMenu::new_snippet_choices(
 9370                id,
 9371                true,
 9372                choices,
 9373                selection,
 9374                buffer,
 9375                snippet_sort_order,
 9376            ),
 9377        ));
 9378    }
 9379
 9380    pub fn insert_snippet(
 9381        &mut self,
 9382        insertion_ranges: &[Range<usize>],
 9383        snippet: Snippet,
 9384        window: &mut Window,
 9385        cx: &mut Context<Self>,
 9386    ) -> Result<()> {
 9387        struct Tabstop<T> {
 9388            is_end_tabstop: bool,
 9389            ranges: Vec<Range<T>>,
 9390            choices: Option<Vec<String>>,
 9391        }
 9392
 9393        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9394            let snippet_text: Arc<str> = snippet.text.clone().into();
 9395            let edits = insertion_ranges
 9396                .iter()
 9397                .cloned()
 9398                .map(|range| (range, snippet_text.clone()));
 9399            let autoindent_mode = AutoindentMode::Block {
 9400                original_indent_columns: Vec::new(),
 9401            };
 9402            buffer.edit(edits, Some(autoindent_mode), cx);
 9403
 9404            let snapshot = &*buffer.read(cx);
 9405            let snippet = &snippet;
 9406            snippet
 9407                .tabstops
 9408                .iter()
 9409                .map(|tabstop| {
 9410                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9411                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9412                    });
 9413                    let mut tabstop_ranges = tabstop
 9414                        .ranges
 9415                        .iter()
 9416                        .flat_map(|tabstop_range| {
 9417                            let mut delta = 0_isize;
 9418                            insertion_ranges.iter().map(move |insertion_range| {
 9419                                let insertion_start = insertion_range.start as isize + delta;
 9420                                delta +=
 9421                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9422
 9423                                let start = ((insertion_start + tabstop_range.start) as usize)
 9424                                    .min(snapshot.len());
 9425                                let end = ((insertion_start + tabstop_range.end) as usize)
 9426                                    .min(snapshot.len());
 9427                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9428                            })
 9429                        })
 9430                        .collect::<Vec<_>>();
 9431                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9432
 9433                    Tabstop {
 9434                        is_end_tabstop,
 9435                        ranges: tabstop_ranges,
 9436                        choices: tabstop.choices.clone(),
 9437                    }
 9438                })
 9439                .collect::<Vec<_>>()
 9440        });
 9441        if let Some(tabstop) = tabstops.first() {
 9442            self.change_selections(Default::default(), window, cx, |s| {
 9443                // Reverse order so that the first range is the newest created selection.
 9444                // Completions will use it and autoscroll will prioritize it.
 9445                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9446            });
 9447
 9448            if let Some(choices) = &tabstop.choices {
 9449                if let Some(selection) = tabstop.ranges.first() {
 9450                    self.show_snippet_choices(choices, selection.clone(), cx)
 9451                }
 9452            }
 9453
 9454            // If we're already at the last tabstop and it's at the end of the snippet,
 9455            // we're done, we don't need to keep the state around.
 9456            if !tabstop.is_end_tabstop {
 9457                let choices = tabstops
 9458                    .iter()
 9459                    .map(|tabstop| tabstop.choices.clone())
 9460                    .collect();
 9461
 9462                let ranges = tabstops
 9463                    .into_iter()
 9464                    .map(|tabstop| tabstop.ranges)
 9465                    .collect::<Vec<_>>();
 9466
 9467                self.snippet_stack.push(SnippetState {
 9468                    active_index: 0,
 9469                    ranges,
 9470                    choices,
 9471                });
 9472            }
 9473
 9474            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9475            if self.autoclose_regions.is_empty() {
 9476                let snapshot = self.buffer.read(cx).snapshot(cx);
 9477                for selection in &mut self.selections.all::<Point>(cx) {
 9478                    let selection_head = selection.head();
 9479                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9480                        continue;
 9481                    };
 9482
 9483                    let mut bracket_pair = None;
 9484                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9485                    let prev_chars = snapshot
 9486                        .reversed_chars_at(selection_head)
 9487                        .collect::<String>();
 9488                    for (pair, enabled) in scope.brackets() {
 9489                        if enabled
 9490                            && pair.close
 9491                            && prev_chars.starts_with(pair.start.as_str())
 9492                            && next_chars.starts_with(pair.end.as_str())
 9493                        {
 9494                            bracket_pair = Some(pair.clone());
 9495                            break;
 9496                        }
 9497                    }
 9498                    if let Some(pair) = bracket_pair {
 9499                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9500                        let autoclose_enabled =
 9501                            self.use_autoclose && snapshot_settings.use_autoclose;
 9502                        if autoclose_enabled {
 9503                            let start = snapshot.anchor_after(selection_head);
 9504                            let end = snapshot.anchor_after(selection_head);
 9505                            self.autoclose_regions.push(AutocloseRegion {
 9506                                selection_id: selection.id,
 9507                                range: start..end,
 9508                                pair,
 9509                            });
 9510                        }
 9511                    }
 9512                }
 9513            }
 9514        }
 9515        Ok(())
 9516    }
 9517
 9518    pub fn move_to_next_snippet_tabstop(
 9519        &mut self,
 9520        window: &mut Window,
 9521        cx: &mut Context<Self>,
 9522    ) -> bool {
 9523        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9524    }
 9525
 9526    pub fn move_to_prev_snippet_tabstop(
 9527        &mut self,
 9528        window: &mut Window,
 9529        cx: &mut Context<Self>,
 9530    ) -> bool {
 9531        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9532    }
 9533
 9534    pub fn move_to_snippet_tabstop(
 9535        &mut self,
 9536        bias: Bias,
 9537        window: &mut Window,
 9538        cx: &mut Context<Self>,
 9539    ) -> bool {
 9540        if let Some(mut snippet) = self.snippet_stack.pop() {
 9541            match bias {
 9542                Bias::Left => {
 9543                    if snippet.active_index > 0 {
 9544                        snippet.active_index -= 1;
 9545                    } else {
 9546                        self.snippet_stack.push(snippet);
 9547                        return false;
 9548                    }
 9549                }
 9550                Bias::Right => {
 9551                    if snippet.active_index + 1 < snippet.ranges.len() {
 9552                        snippet.active_index += 1;
 9553                    } else {
 9554                        self.snippet_stack.push(snippet);
 9555                        return false;
 9556                    }
 9557                }
 9558            }
 9559            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9560                self.change_selections(Default::default(), window, cx, |s| {
 9561                    // Reverse order so that the first range is the newest created selection.
 9562                    // Completions will use it and autoscroll will prioritize it.
 9563                    s.select_ranges(current_ranges.iter().rev().cloned())
 9564                });
 9565
 9566                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9567                    if let Some(selection) = current_ranges.first() {
 9568                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9569                    }
 9570                }
 9571
 9572                // If snippet state is not at the last tabstop, push it back on the stack
 9573                if snippet.active_index + 1 < snippet.ranges.len() {
 9574                    self.snippet_stack.push(snippet);
 9575                }
 9576                return true;
 9577            }
 9578        }
 9579
 9580        false
 9581    }
 9582
 9583    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9584        self.transact(window, cx, |this, window, cx| {
 9585            this.select_all(&SelectAll, window, cx);
 9586            this.insert("", window, cx);
 9587        });
 9588    }
 9589
 9590    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9591        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9592        self.transact(window, cx, |this, window, cx| {
 9593            this.select_autoclose_pair(window, cx);
 9594            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9595            if !this.linked_edit_ranges.is_empty() {
 9596                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9597                let snapshot = this.buffer.read(cx).snapshot(cx);
 9598
 9599                for selection in selections.iter() {
 9600                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9601                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9602                    if selection_start.buffer_id != selection_end.buffer_id {
 9603                        continue;
 9604                    }
 9605                    if let Some(ranges) =
 9606                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9607                    {
 9608                        for (buffer, entries) in ranges {
 9609                            linked_ranges.entry(buffer).or_default().extend(entries);
 9610                        }
 9611                    }
 9612                }
 9613            }
 9614
 9615            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9616            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9617            for selection in &mut selections {
 9618                if selection.is_empty() {
 9619                    let old_head = selection.head();
 9620                    let mut new_head =
 9621                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9622                            .to_point(&display_map);
 9623                    if let Some((buffer, line_buffer_range)) = display_map
 9624                        .buffer_snapshot
 9625                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9626                    {
 9627                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9628                        let indent_len = match indent_size.kind {
 9629                            IndentKind::Space => {
 9630                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9631                            }
 9632                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9633                        };
 9634                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9635                            let indent_len = indent_len.get();
 9636                            new_head = cmp::min(
 9637                                new_head,
 9638                                MultiBufferPoint::new(
 9639                                    old_head.row,
 9640                                    ((old_head.column - 1) / indent_len) * indent_len,
 9641                                ),
 9642                            );
 9643                        }
 9644                    }
 9645
 9646                    selection.set_head(new_head, SelectionGoal::None);
 9647                }
 9648            }
 9649
 9650            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9651            this.insert("", window, cx);
 9652            let empty_str: Arc<str> = Arc::from("");
 9653            for (buffer, edits) in linked_ranges {
 9654                let snapshot = buffer.read(cx).snapshot();
 9655                use text::ToPoint as TP;
 9656
 9657                let edits = edits
 9658                    .into_iter()
 9659                    .map(|range| {
 9660                        let end_point = TP::to_point(&range.end, &snapshot);
 9661                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9662
 9663                        if end_point == start_point {
 9664                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9665                                .saturating_sub(1);
 9666                            start_point =
 9667                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9668                        };
 9669
 9670                        (start_point..end_point, empty_str.clone())
 9671                    })
 9672                    .sorted_by_key(|(range, _)| range.start)
 9673                    .collect::<Vec<_>>();
 9674                buffer.update(cx, |this, cx| {
 9675                    this.edit(edits, None, cx);
 9676                })
 9677            }
 9678            this.refresh_inline_completion(true, false, window, cx);
 9679            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9680        });
 9681    }
 9682
 9683    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9684        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9685        self.transact(window, cx, |this, window, cx| {
 9686            this.change_selections(Default::default(), window, cx, |s| {
 9687                s.move_with(|map, selection| {
 9688                    if selection.is_empty() {
 9689                        let cursor = movement::right(map, selection.head());
 9690                        selection.end = cursor;
 9691                        selection.reversed = true;
 9692                        selection.goal = SelectionGoal::None;
 9693                    }
 9694                })
 9695            });
 9696            this.insert("", window, cx);
 9697            this.refresh_inline_completion(true, false, window, cx);
 9698        });
 9699    }
 9700
 9701    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9702        if self.mode.is_single_line() {
 9703            cx.propagate();
 9704            return;
 9705        }
 9706
 9707        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9708        if self.move_to_prev_snippet_tabstop(window, cx) {
 9709            return;
 9710        }
 9711        self.outdent(&Outdent, window, cx);
 9712    }
 9713
 9714    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9715        if self.mode.is_single_line() {
 9716            cx.propagate();
 9717            return;
 9718        }
 9719
 9720        if self.move_to_next_snippet_tabstop(window, cx) {
 9721            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9722            return;
 9723        }
 9724        if self.read_only(cx) {
 9725            return;
 9726        }
 9727        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9728        let mut selections = self.selections.all_adjusted(cx);
 9729        let buffer = self.buffer.read(cx);
 9730        let snapshot = buffer.snapshot(cx);
 9731        let rows_iter = selections.iter().map(|s| s.head().row);
 9732        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9733
 9734        let has_some_cursor_in_whitespace = selections
 9735            .iter()
 9736            .filter(|selection| selection.is_empty())
 9737            .any(|selection| {
 9738                let cursor = selection.head();
 9739                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9740                cursor.column < current_indent.len
 9741            });
 9742
 9743        let mut edits = Vec::new();
 9744        let mut prev_edited_row = 0;
 9745        let mut row_delta = 0;
 9746        for selection in &mut selections {
 9747            if selection.start.row != prev_edited_row {
 9748                row_delta = 0;
 9749            }
 9750            prev_edited_row = selection.end.row;
 9751
 9752            // If the selection is non-empty, then increase the indentation of the selected lines.
 9753            if !selection.is_empty() {
 9754                row_delta =
 9755                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9756                continue;
 9757            }
 9758
 9759            let cursor = selection.head();
 9760            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9761            if let Some(suggested_indent) =
 9762                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9763            {
 9764                // Don't do anything if already at suggested indent
 9765                // and there is any other cursor which is not
 9766                if has_some_cursor_in_whitespace
 9767                    && cursor.column == current_indent.len
 9768                    && current_indent.len == suggested_indent.len
 9769                {
 9770                    continue;
 9771                }
 9772
 9773                // Adjust line and move cursor to suggested indent
 9774                // if cursor is not at suggested indent
 9775                if cursor.column < suggested_indent.len
 9776                    && cursor.column <= current_indent.len
 9777                    && current_indent.len <= suggested_indent.len
 9778                {
 9779                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9780                    selection.end = selection.start;
 9781                    if row_delta == 0 {
 9782                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9783                            cursor.row,
 9784                            current_indent,
 9785                            suggested_indent,
 9786                        ));
 9787                        row_delta = suggested_indent.len - current_indent.len;
 9788                    }
 9789                    continue;
 9790                }
 9791
 9792                // If current indent is more than suggested indent
 9793                // only move cursor to current indent and skip indent
 9794                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9795                    selection.start = Point::new(cursor.row, current_indent.len);
 9796                    selection.end = selection.start;
 9797                    continue;
 9798                }
 9799            }
 9800
 9801            // Otherwise, insert a hard or soft tab.
 9802            let settings = buffer.language_settings_at(cursor, cx);
 9803            let tab_size = if settings.hard_tabs {
 9804                IndentSize::tab()
 9805            } else {
 9806                let tab_size = settings.tab_size.get();
 9807                let indent_remainder = snapshot
 9808                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9809                    .flat_map(str::chars)
 9810                    .fold(row_delta % tab_size, |counter: u32, c| {
 9811                        if c == '\t' {
 9812                            0
 9813                        } else {
 9814                            (counter + 1) % tab_size
 9815                        }
 9816                    });
 9817
 9818                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9819                IndentSize::spaces(chars_to_next_tab_stop)
 9820            };
 9821            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9822            selection.end = selection.start;
 9823            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9824            row_delta += tab_size.len;
 9825        }
 9826
 9827        self.transact(window, cx, |this, window, cx| {
 9828            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9829            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9830            this.refresh_inline_completion(true, false, window, cx);
 9831        });
 9832    }
 9833
 9834    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9835        if self.read_only(cx) {
 9836            return;
 9837        }
 9838        if self.mode.is_single_line() {
 9839            cx.propagate();
 9840            return;
 9841        }
 9842
 9843        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9844        let mut selections = self.selections.all::<Point>(cx);
 9845        let mut prev_edited_row = 0;
 9846        let mut row_delta = 0;
 9847        let mut edits = Vec::new();
 9848        let buffer = self.buffer.read(cx);
 9849        let snapshot = buffer.snapshot(cx);
 9850        for selection in &mut selections {
 9851            if selection.start.row != prev_edited_row {
 9852                row_delta = 0;
 9853            }
 9854            prev_edited_row = selection.end.row;
 9855
 9856            row_delta =
 9857                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9858        }
 9859
 9860        self.transact(window, cx, |this, window, cx| {
 9861            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9862            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9863        });
 9864    }
 9865
 9866    fn indent_selection(
 9867        buffer: &MultiBuffer,
 9868        snapshot: &MultiBufferSnapshot,
 9869        selection: &mut Selection<Point>,
 9870        edits: &mut Vec<(Range<Point>, String)>,
 9871        delta_for_start_row: u32,
 9872        cx: &App,
 9873    ) -> u32 {
 9874        let settings = buffer.language_settings_at(selection.start, cx);
 9875        let tab_size = settings.tab_size.get();
 9876        let indent_kind = if settings.hard_tabs {
 9877            IndentKind::Tab
 9878        } else {
 9879            IndentKind::Space
 9880        };
 9881        let mut start_row = selection.start.row;
 9882        let mut end_row = selection.end.row + 1;
 9883
 9884        // If a selection ends at the beginning of a line, don't indent
 9885        // that last line.
 9886        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9887            end_row -= 1;
 9888        }
 9889
 9890        // Avoid re-indenting a row that has already been indented by a
 9891        // previous selection, but still update this selection's column
 9892        // to reflect that indentation.
 9893        if delta_for_start_row > 0 {
 9894            start_row += 1;
 9895            selection.start.column += delta_for_start_row;
 9896            if selection.end.row == selection.start.row {
 9897                selection.end.column += delta_for_start_row;
 9898            }
 9899        }
 9900
 9901        let mut delta_for_end_row = 0;
 9902        let has_multiple_rows = start_row + 1 != end_row;
 9903        for row in start_row..end_row {
 9904            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9905            let indent_delta = match (current_indent.kind, indent_kind) {
 9906                (IndentKind::Space, IndentKind::Space) => {
 9907                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9908                    IndentSize::spaces(columns_to_next_tab_stop)
 9909                }
 9910                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9911                (_, IndentKind::Tab) => IndentSize::tab(),
 9912            };
 9913
 9914            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9915                0
 9916            } else {
 9917                selection.start.column
 9918            };
 9919            let row_start = Point::new(row, start);
 9920            edits.push((
 9921                row_start..row_start,
 9922                indent_delta.chars().collect::<String>(),
 9923            ));
 9924
 9925            // Update this selection's endpoints to reflect the indentation.
 9926            if row == selection.start.row {
 9927                selection.start.column += indent_delta.len;
 9928            }
 9929            if row == selection.end.row {
 9930                selection.end.column += indent_delta.len;
 9931                delta_for_end_row = indent_delta.len;
 9932            }
 9933        }
 9934
 9935        if selection.start.row == selection.end.row {
 9936            delta_for_start_row + delta_for_end_row
 9937        } else {
 9938            delta_for_end_row
 9939        }
 9940    }
 9941
 9942    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9943        if self.read_only(cx) {
 9944            return;
 9945        }
 9946        if self.mode.is_single_line() {
 9947            cx.propagate();
 9948            return;
 9949        }
 9950
 9951        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9952        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9953        let selections = self.selections.all::<Point>(cx);
 9954        let mut deletion_ranges = Vec::new();
 9955        let mut last_outdent = None;
 9956        {
 9957            let buffer = self.buffer.read(cx);
 9958            let snapshot = buffer.snapshot(cx);
 9959            for selection in &selections {
 9960                let settings = buffer.language_settings_at(selection.start, cx);
 9961                let tab_size = settings.tab_size.get();
 9962                let mut rows = selection.spanned_rows(false, &display_map);
 9963
 9964                // Avoid re-outdenting a row that has already been outdented by a
 9965                // previous selection.
 9966                if let Some(last_row) = last_outdent {
 9967                    if last_row == rows.start {
 9968                        rows.start = rows.start.next_row();
 9969                    }
 9970                }
 9971                let has_multiple_rows = rows.len() > 1;
 9972                for row in rows.iter_rows() {
 9973                    let indent_size = snapshot.indent_size_for_line(row);
 9974                    if indent_size.len > 0 {
 9975                        let deletion_len = match indent_size.kind {
 9976                            IndentKind::Space => {
 9977                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9978                                if columns_to_prev_tab_stop == 0 {
 9979                                    tab_size
 9980                                } else {
 9981                                    columns_to_prev_tab_stop
 9982                                }
 9983                            }
 9984                            IndentKind::Tab => 1,
 9985                        };
 9986                        let start = if has_multiple_rows
 9987                            || deletion_len > selection.start.column
 9988                            || indent_size.len < selection.start.column
 9989                        {
 9990                            0
 9991                        } else {
 9992                            selection.start.column - deletion_len
 9993                        };
 9994                        deletion_ranges.push(
 9995                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9996                        );
 9997                        last_outdent = Some(row);
 9998                    }
 9999                }
10000            }
10001        }
10002
10003        self.transact(window, cx, |this, window, cx| {
10004            this.buffer.update(cx, |buffer, cx| {
10005                let empty_str: Arc<str> = Arc::default();
10006                buffer.edit(
10007                    deletion_ranges
10008                        .into_iter()
10009                        .map(|range| (range, empty_str.clone())),
10010                    None,
10011                    cx,
10012                );
10013            });
10014            let selections = this.selections.all::<usize>(cx);
10015            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10016        });
10017    }
10018
10019    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10020        if self.read_only(cx) {
10021            return;
10022        }
10023        if self.mode.is_single_line() {
10024            cx.propagate();
10025            return;
10026        }
10027
10028        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10029        let selections = self
10030            .selections
10031            .all::<usize>(cx)
10032            .into_iter()
10033            .map(|s| s.range());
10034
10035        self.transact(window, cx, |this, window, cx| {
10036            this.buffer.update(cx, |buffer, cx| {
10037                buffer.autoindent_ranges(selections, cx);
10038            });
10039            let selections = this.selections.all::<usize>(cx);
10040            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10041        });
10042    }
10043
10044    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10045        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10046        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10047        let selections = self.selections.all::<Point>(cx);
10048
10049        let mut new_cursors = Vec::new();
10050        let mut edit_ranges = Vec::new();
10051        let mut selections = selections.iter().peekable();
10052        while let Some(selection) = selections.next() {
10053            let mut rows = selection.spanned_rows(false, &display_map);
10054            let goal_display_column = selection.head().to_display_point(&display_map).column();
10055
10056            // Accumulate contiguous regions of rows that we want to delete.
10057            while let Some(next_selection) = selections.peek() {
10058                let next_rows = next_selection.spanned_rows(false, &display_map);
10059                if next_rows.start <= rows.end {
10060                    rows.end = next_rows.end;
10061                    selections.next().unwrap();
10062                } else {
10063                    break;
10064                }
10065            }
10066
10067            let buffer = &display_map.buffer_snapshot;
10068            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10069            let edit_end;
10070            let cursor_buffer_row;
10071            if buffer.max_point().row >= rows.end.0 {
10072                // If there's a line after the range, delete the \n from the end of the row range
10073                // and position the cursor on the next line.
10074                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10075                cursor_buffer_row = rows.end;
10076            } else {
10077                // If there isn't a line after the range, delete the \n from the line before the
10078                // start of the row range and position the cursor there.
10079                edit_start = edit_start.saturating_sub(1);
10080                edit_end = buffer.len();
10081                cursor_buffer_row = rows.start.previous_row();
10082            }
10083
10084            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10085            *cursor.column_mut() =
10086                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10087
10088            new_cursors.push((
10089                selection.id,
10090                buffer.anchor_after(cursor.to_point(&display_map)),
10091            ));
10092            edit_ranges.push(edit_start..edit_end);
10093        }
10094
10095        self.transact(window, cx, |this, window, cx| {
10096            let buffer = this.buffer.update(cx, |buffer, cx| {
10097                let empty_str: Arc<str> = Arc::default();
10098                buffer.edit(
10099                    edit_ranges
10100                        .into_iter()
10101                        .map(|range| (range, empty_str.clone())),
10102                    None,
10103                    cx,
10104                );
10105                buffer.snapshot(cx)
10106            });
10107            let new_selections = new_cursors
10108                .into_iter()
10109                .map(|(id, cursor)| {
10110                    let cursor = cursor.to_point(&buffer);
10111                    Selection {
10112                        id,
10113                        start: cursor,
10114                        end: cursor,
10115                        reversed: false,
10116                        goal: SelectionGoal::None,
10117                    }
10118                })
10119                .collect();
10120
10121            this.change_selections(Default::default(), window, cx, |s| {
10122                s.select(new_selections);
10123            });
10124        });
10125    }
10126
10127    pub fn join_lines_impl(
10128        &mut self,
10129        insert_whitespace: bool,
10130        window: &mut Window,
10131        cx: &mut Context<Self>,
10132    ) {
10133        if self.read_only(cx) {
10134            return;
10135        }
10136        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10137        for selection in self.selections.all::<Point>(cx) {
10138            let start = MultiBufferRow(selection.start.row);
10139            // Treat single line selections as if they include the next line. Otherwise this action
10140            // would do nothing for single line selections individual cursors.
10141            let end = if selection.start.row == selection.end.row {
10142                MultiBufferRow(selection.start.row + 1)
10143            } else {
10144                MultiBufferRow(selection.end.row)
10145            };
10146
10147            if let Some(last_row_range) = row_ranges.last_mut() {
10148                if start <= last_row_range.end {
10149                    last_row_range.end = end;
10150                    continue;
10151                }
10152            }
10153            row_ranges.push(start..end);
10154        }
10155
10156        let snapshot = self.buffer.read(cx).snapshot(cx);
10157        let mut cursor_positions = Vec::new();
10158        for row_range in &row_ranges {
10159            let anchor = snapshot.anchor_before(Point::new(
10160                row_range.end.previous_row().0,
10161                snapshot.line_len(row_range.end.previous_row()),
10162            ));
10163            cursor_positions.push(anchor..anchor);
10164        }
10165
10166        self.transact(window, cx, |this, window, cx| {
10167            for row_range in row_ranges.into_iter().rev() {
10168                for row in row_range.iter_rows().rev() {
10169                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10170                    let next_line_row = row.next_row();
10171                    let indent = snapshot.indent_size_for_line(next_line_row);
10172                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10173
10174                    let replace =
10175                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10176                            " "
10177                        } else {
10178                            ""
10179                        };
10180
10181                    this.buffer.update(cx, |buffer, cx| {
10182                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10183                    });
10184                }
10185            }
10186
10187            this.change_selections(Default::default(), window, cx, |s| {
10188                s.select_anchor_ranges(cursor_positions)
10189            });
10190        });
10191    }
10192
10193    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10194        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10195        self.join_lines_impl(true, window, cx);
10196    }
10197
10198    pub fn sort_lines_case_sensitive(
10199        &mut self,
10200        _: &SortLinesCaseSensitive,
10201        window: &mut Window,
10202        cx: &mut Context<Self>,
10203    ) {
10204        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10205    }
10206
10207    pub fn sort_lines_case_insensitive(
10208        &mut self,
10209        _: &SortLinesCaseInsensitive,
10210        window: &mut Window,
10211        cx: &mut Context<Self>,
10212    ) {
10213        self.manipulate_immutable_lines(window, cx, |lines| {
10214            lines.sort_by_key(|line| line.to_lowercase())
10215        })
10216    }
10217
10218    pub fn unique_lines_case_insensitive(
10219        &mut self,
10220        _: &UniqueLinesCaseInsensitive,
10221        window: &mut Window,
10222        cx: &mut Context<Self>,
10223    ) {
10224        self.manipulate_immutable_lines(window, cx, |lines| {
10225            let mut seen = HashSet::default();
10226            lines.retain(|line| seen.insert(line.to_lowercase()));
10227        })
10228    }
10229
10230    pub fn unique_lines_case_sensitive(
10231        &mut self,
10232        _: &UniqueLinesCaseSensitive,
10233        window: &mut Window,
10234        cx: &mut Context<Self>,
10235    ) {
10236        self.manipulate_immutable_lines(window, cx, |lines| {
10237            let mut seen = HashSet::default();
10238            lines.retain(|line| seen.insert(*line));
10239        })
10240    }
10241
10242    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10243        let Some(project) = self.project.clone() else {
10244            return;
10245        };
10246        self.reload(project, window, cx)
10247            .detach_and_notify_err(window, cx);
10248    }
10249
10250    pub fn restore_file(
10251        &mut self,
10252        _: &::git::RestoreFile,
10253        window: &mut Window,
10254        cx: &mut Context<Self>,
10255    ) {
10256        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10257        let mut buffer_ids = HashSet::default();
10258        let snapshot = self.buffer().read(cx).snapshot(cx);
10259        for selection in self.selections.all::<usize>(cx) {
10260            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10261        }
10262
10263        let buffer = self.buffer().read(cx);
10264        let ranges = buffer_ids
10265            .into_iter()
10266            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10267            .collect::<Vec<_>>();
10268
10269        self.restore_hunks_in_ranges(ranges, window, cx);
10270    }
10271
10272    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10273        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10274        let selections = self
10275            .selections
10276            .all(cx)
10277            .into_iter()
10278            .map(|s| s.range())
10279            .collect();
10280        self.restore_hunks_in_ranges(selections, window, cx);
10281    }
10282
10283    pub fn restore_hunks_in_ranges(
10284        &mut self,
10285        ranges: Vec<Range<Point>>,
10286        window: &mut Window,
10287        cx: &mut Context<Editor>,
10288    ) {
10289        let mut revert_changes = HashMap::default();
10290        let chunk_by = self
10291            .snapshot(window, cx)
10292            .hunks_for_ranges(ranges)
10293            .into_iter()
10294            .chunk_by(|hunk| hunk.buffer_id);
10295        for (buffer_id, hunks) in &chunk_by {
10296            let hunks = hunks.collect::<Vec<_>>();
10297            for hunk in &hunks {
10298                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10299            }
10300            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10301        }
10302        drop(chunk_by);
10303        if !revert_changes.is_empty() {
10304            self.transact(window, cx, |editor, window, cx| {
10305                editor.restore(revert_changes, window, cx);
10306            });
10307        }
10308    }
10309
10310    pub fn open_active_item_in_terminal(
10311        &mut self,
10312        _: &OpenInTerminal,
10313        window: &mut Window,
10314        cx: &mut Context<Self>,
10315    ) {
10316        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10317            let project_path = buffer.read(cx).project_path(cx)?;
10318            let project = self.project.as_ref()?.read(cx);
10319            let entry = project.entry_for_path(&project_path, cx)?;
10320            let parent = match &entry.canonical_path {
10321                Some(canonical_path) => canonical_path.to_path_buf(),
10322                None => project.absolute_path(&project_path, cx)?,
10323            }
10324            .parent()?
10325            .to_path_buf();
10326            Some(parent)
10327        }) {
10328            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10329        }
10330    }
10331
10332    fn set_breakpoint_context_menu(
10333        &mut self,
10334        display_row: DisplayRow,
10335        position: Option<Anchor>,
10336        clicked_point: gpui::Point<Pixels>,
10337        window: &mut Window,
10338        cx: &mut Context<Self>,
10339    ) {
10340        let source = self
10341            .buffer
10342            .read(cx)
10343            .snapshot(cx)
10344            .anchor_before(Point::new(display_row.0, 0u32));
10345
10346        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10347
10348        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10349            self,
10350            source,
10351            clicked_point,
10352            context_menu,
10353            window,
10354            cx,
10355        );
10356    }
10357
10358    fn add_edit_breakpoint_block(
10359        &mut self,
10360        anchor: Anchor,
10361        breakpoint: &Breakpoint,
10362        edit_action: BreakpointPromptEditAction,
10363        window: &mut Window,
10364        cx: &mut Context<Self>,
10365    ) {
10366        let weak_editor = cx.weak_entity();
10367        let bp_prompt = cx.new(|cx| {
10368            BreakpointPromptEditor::new(
10369                weak_editor,
10370                anchor,
10371                breakpoint.clone(),
10372                edit_action,
10373                window,
10374                cx,
10375            )
10376        });
10377
10378        let height = bp_prompt.update(cx, |this, cx| {
10379            this.prompt
10380                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10381        });
10382        let cloned_prompt = bp_prompt.clone();
10383        let blocks = vec![BlockProperties {
10384            style: BlockStyle::Sticky,
10385            placement: BlockPlacement::Above(anchor),
10386            height: Some(height),
10387            render: Arc::new(move |cx| {
10388                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10389                cloned_prompt.clone().into_any_element()
10390            }),
10391            priority: 0,
10392            render_in_minimap: true,
10393        }];
10394
10395        let focus_handle = bp_prompt.focus_handle(cx);
10396        window.focus(&focus_handle);
10397
10398        let block_ids = self.insert_blocks(blocks, None, cx);
10399        bp_prompt.update(cx, |prompt, _| {
10400            prompt.add_block_ids(block_ids);
10401        });
10402    }
10403
10404    pub(crate) fn breakpoint_at_row(
10405        &self,
10406        row: u32,
10407        window: &mut Window,
10408        cx: &mut Context<Self>,
10409    ) -> Option<(Anchor, Breakpoint)> {
10410        let snapshot = self.snapshot(window, cx);
10411        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10412
10413        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10414    }
10415
10416    pub(crate) fn breakpoint_at_anchor(
10417        &self,
10418        breakpoint_position: Anchor,
10419        snapshot: &EditorSnapshot,
10420        cx: &mut Context<Self>,
10421    ) -> Option<(Anchor, Breakpoint)> {
10422        let project = self.project.clone()?;
10423
10424        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10425            snapshot
10426                .buffer_snapshot
10427                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10428        })?;
10429
10430        let enclosing_excerpt = breakpoint_position.excerpt_id;
10431        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10432        let buffer_snapshot = buffer.read(cx).snapshot();
10433
10434        let row = buffer_snapshot
10435            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10436            .row;
10437
10438        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10439        let anchor_end = snapshot
10440            .buffer_snapshot
10441            .anchor_after(Point::new(row, line_len));
10442
10443        let bp = self
10444            .breakpoint_store
10445            .as_ref()?
10446            .read_with(cx, |breakpoint_store, cx| {
10447                breakpoint_store
10448                    .breakpoints(
10449                        &buffer,
10450                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10451                        &buffer_snapshot,
10452                        cx,
10453                    )
10454                    .next()
10455                    .and_then(|(bp, _)| {
10456                        let breakpoint_row = buffer_snapshot
10457                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10458                            .row;
10459
10460                        if breakpoint_row == row {
10461                            snapshot
10462                                .buffer_snapshot
10463                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10464                                .map(|position| (position, bp.bp.clone()))
10465                        } else {
10466                            None
10467                        }
10468                    })
10469            });
10470        bp
10471    }
10472
10473    pub fn edit_log_breakpoint(
10474        &mut self,
10475        _: &EditLogBreakpoint,
10476        window: &mut Window,
10477        cx: &mut Context<Self>,
10478    ) {
10479        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10480            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10481                message: None,
10482                state: BreakpointState::Enabled,
10483                condition: None,
10484                hit_condition: None,
10485            });
10486
10487            self.add_edit_breakpoint_block(
10488                anchor,
10489                &breakpoint,
10490                BreakpointPromptEditAction::Log,
10491                window,
10492                cx,
10493            );
10494        }
10495    }
10496
10497    fn breakpoints_at_cursors(
10498        &self,
10499        window: &mut Window,
10500        cx: &mut Context<Self>,
10501    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10502        let snapshot = self.snapshot(window, cx);
10503        let cursors = self
10504            .selections
10505            .disjoint_anchors()
10506            .into_iter()
10507            .map(|selection| {
10508                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10509
10510                let breakpoint_position = self
10511                    .breakpoint_at_row(cursor_position.row, window, cx)
10512                    .map(|bp| bp.0)
10513                    .unwrap_or_else(|| {
10514                        snapshot
10515                            .display_snapshot
10516                            .buffer_snapshot
10517                            .anchor_after(Point::new(cursor_position.row, 0))
10518                    });
10519
10520                let breakpoint = self
10521                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10522                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10523
10524                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10525            })
10526            // 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.
10527            .collect::<HashMap<Anchor, _>>();
10528
10529        cursors.into_iter().collect()
10530    }
10531
10532    pub fn enable_breakpoint(
10533        &mut self,
10534        _: &crate::actions::EnableBreakpoint,
10535        window: &mut Window,
10536        cx: &mut Context<Self>,
10537    ) {
10538        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10539            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10540                continue;
10541            };
10542            self.edit_breakpoint_at_anchor(
10543                anchor,
10544                breakpoint,
10545                BreakpointEditAction::InvertState,
10546                cx,
10547            );
10548        }
10549    }
10550
10551    pub fn disable_breakpoint(
10552        &mut self,
10553        _: &crate::actions::DisableBreakpoint,
10554        window: &mut Window,
10555        cx: &mut Context<Self>,
10556    ) {
10557        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10558            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10559                continue;
10560            };
10561            self.edit_breakpoint_at_anchor(
10562                anchor,
10563                breakpoint,
10564                BreakpointEditAction::InvertState,
10565                cx,
10566            );
10567        }
10568    }
10569
10570    pub fn toggle_breakpoint(
10571        &mut self,
10572        _: &crate::actions::ToggleBreakpoint,
10573        window: &mut Window,
10574        cx: &mut Context<Self>,
10575    ) {
10576        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10577            if let Some(breakpoint) = breakpoint {
10578                self.edit_breakpoint_at_anchor(
10579                    anchor,
10580                    breakpoint,
10581                    BreakpointEditAction::Toggle,
10582                    cx,
10583                );
10584            } else {
10585                self.edit_breakpoint_at_anchor(
10586                    anchor,
10587                    Breakpoint::new_standard(),
10588                    BreakpointEditAction::Toggle,
10589                    cx,
10590                );
10591            }
10592        }
10593    }
10594
10595    pub fn edit_breakpoint_at_anchor(
10596        &mut self,
10597        breakpoint_position: Anchor,
10598        breakpoint: Breakpoint,
10599        edit_action: BreakpointEditAction,
10600        cx: &mut Context<Self>,
10601    ) {
10602        let Some(breakpoint_store) = &self.breakpoint_store else {
10603            return;
10604        };
10605
10606        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10607            if breakpoint_position == Anchor::min() {
10608                self.buffer()
10609                    .read(cx)
10610                    .excerpt_buffer_ids()
10611                    .into_iter()
10612                    .next()
10613            } else {
10614                None
10615            }
10616        }) else {
10617            return;
10618        };
10619
10620        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10621            return;
10622        };
10623
10624        breakpoint_store.update(cx, |breakpoint_store, cx| {
10625            breakpoint_store.toggle_breakpoint(
10626                buffer,
10627                BreakpointWithPosition {
10628                    position: breakpoint_position.text_anchor,
10629                    bp: breakpoint,
10630                },
10631                edit_action,
10632                cx,
10633            );
10634        });
10635
10636        cx.notify();
10637    }
10638
10639    #[cfg(any(test, feature = "test-support"))]
10640    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10641        self.breakpoint_store.clone()
10642    }
10643
10644    pub fn prepare_restore_change(
10645        &self,
10646        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10647        hunk: &MultiBufferDiffHunk,
10648        cx: &mut App,
10649    ) -> Option<()> {
10650        if hunk.is_created_file() {
10651            return None;
10652        }
10653        let buffer = self.buffer.read(cx);
10654        let diff = buffer.diff_for(hunk.buffer_id)?;
10655        let buffer = buffer.buffer(hunk.buffer_id)?;
10656        let buffer = buffer.read(cx);
10657        let original_text = diff
10658            .read(cx)
10659            .base_text()
10660            .as_rope()
10661            .slice(hunk.diff_base_byte_range.clone());
10662        let buffer_snapshot = buffer.snapshot();
10663        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10664        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10665            probe
10666                .0
10667                .start
10668                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10669                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10670        }) {
10671            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10672            Some(())
10673        } else {
10674            None
10675        }
10676    }
10677
10678    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10679        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10680    }
10681
10682    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10683        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10684    }
10685
10686    fn manipulate_lines<M>(
10687        &mut self,
10688        window: &mut Window,
10689        cx: &mut Context<Self>,
10690        mut manipulate: M,
10691    ) where
10692        M: FnMut(&str) -> LineManipulationResult,
10693    {
10694        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10695
10696        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10697        let buffer = self.buffer.read(cx).snapshot(cx);
10698
10699        let mut edits = Vec::new();
10700
10701        let selections = self.selections.all::<Point>(cx);
10702        let mut selections = selections.iter().peekable();
10703        let mut contiguous_row_selections = Vec::new();
10704        let mut new_selections = Vec::new();
10705        let mut added_lines = 0;
10706        let mut removed_lines = 0;
10707
10708        while let Some(selection) = selections.next() {
10709            let (start_row, end_row) = consume_contiguous_rows(
10710                &mut contiguous_row_selections,
10711                selection,
10712                &display_map,
10713                &mut selections,
10714            );
10715
10716            let start_point = Point::new(start_row.0, 0);
10717            let end_point = Point::new(
10718                end_row.previous_row().0,
10719                buffer.line_len(end_row.previous_row()),
10720            );
10721            let text = buffer
10722                .text_for_range(start_point..end_point)
10723                .collect::<String>();
10724
10725            let LineManipulationResult {
10726                new_text,
10727                line_count_before,
10728                line_count_after,
10729            } = manipulate(&text);
10730
10731            edits.push((start_point..end_point, new_text));
10732
10733            // Selections must change based on added and removed line count
10734            let start_row =
10735                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10736            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10737            new_selections.push(Selection {
10738                id: selection.id,
10739                start: start_row,
10740                end: end_row,
10741                goal: SelectionGoal::None,
10742                reversed: selection.reversed,
10743            });
10744
10745            if line_count_after > line_count_before {
10746                added_lines += line_count_after - line_count_before;
10747            } else if line_count_before > line_count_after {
10748                removed_lines += line_count_before - line_count_after;
10749            }
10750        }
10751
10752        self.transact(window, cx, |this, window, cx| {
10753            let buffer = this.buffer.update(cx, |buffer, cx| {
10754                buffer.edit(edits, None, cx);
10755                buffer.snapshot(cx)
10756            });
10757
10758            // Recalculate offsets on newly edited buffer
10759            let new_selections = new_selections
10760                .iter()
10761                .map(|s| {
10762                    let start_point = Point::new(s.start.0, 0);
10763                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10764                    Selection {
10765                        id: s.id,
10766                        start: buffer.point_to_offset(start_point),
10767                        end: buffer.point_to_offset(end_point),
10768                        goal: s.goal,
10769                        reversed: s.reversed,
10770                    }
10771                })
10772                .collect();
10773
10774            this.change_selections(Default::default(), window, cx, |s| {
10775                s.select(new_selections);
10776            });
10777
10778            this.request_autoscroll(Autoscroll::fit(), cx);
10779        });
10780    }
10781
10782    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10783        self.manipulate_text(window, cx, |text| {
10784            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10785            if has_upper_case_characters {
10786                text.to_lowercase()
10787            } else {
10788                text.to_uppercase()
10789            }
10790        })
10791    }
10792
10793    fn manipulate_immutable_lines<Fn>(
10794        &mut self,
10795        window: &mut Window,
10796        cx: &mut Context<Self>,
10797        mut callback: Fn,
10798    ) where
10799        Fn: FnMut(&mut Vec<&str>),
10800    {
10801        self.manipulate_lines(window, cx, |text| {
10802            let mut lines: Vec<&str> = text.split('\n').collect();
10803            let line_count_before = lines.len();
10804
10805            callback(&mut lines);
10806
10807            LineManipulationResult {
10808                new_text: lines.join("\n"),
10809                line_count_before,
10810                line_count_after: lines.len(),
10811            }
10812        });
10813    }
10814
10815    fn manipulate_mutable_lines<Fn>(
10816        &mut self,
10817        window: &mut Window,
10818        cx: &mut Context<Self>,
10819        mut callback: Fn,
10820    ) where
10821        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10822    {
10823        self.manipulate_lines(window, cx, |text| {
10824            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10825            let line_count_before = lines.len();
10826
10827            callback(&mut lines);
10828
10829            LineManipulationResult {
10830                new_text: lines.join("\n"),
10831                line_count_before,
10832                line_count_after: lines.len(),
10833            }
10834        });
10835    }
10836
10837    pub fn convert_indentation_to_spaces(
10838        &mut self,
10839        _: &ConvertIndentationToSpaces,
10840        window: &mut Window,
10841        cx: &mut Context<Self>,
10842    ) {
10843        let settings = self.buffer.read(cx).language_settings(cx);
10844        let tab_size = settings.tab_size.get() as usize;
10845
10846        self.manipulate_mutable_lines(window, cx, |lines| {
10847            // Allocates a reasonably sized scratch buffer once for the whole loop
10848            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10849            // Avoids recomputing spaces that could be inserted many times
10850            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10851                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10852                .collect();
10853
10854            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10855                let mut chars = line.as_ref().chars();
10856                let mut col = 0;
10857                let mut changed = false;
10858
10859                while let Some(ch) = chars.next() {
10860                    match ch {
10861                        ' ' => {
10862                            reindented_line.push(' ');
10863                            col += 1;
10864                        }
10865                        '\t' => {
10866                            // \t are converted to spaces depending on the current column
10867                            let spaces_len = tab_size - (col % tab_size);
10868                            reindented_line.extend(&space_cache[spaces_len - 1]);
10869                            col += spaces_len;
10870                            changed = true;
10871                        }
10872                        _ => {
10873                            // If we dont append before break, the character is consumed
10874                            reindented_line.push(ch);
10875                            break;
10876                        }
10877                    }
10878                }
10879
10880                if !changed {
10881                    reindented_line.clear();
10882                    continue;
10883                }
10884                // Append the rest of the line and replace old reference with new one
10885                reindented_line.extend(chars);
10886                *line = Cow::Owned(reindented_line.clone());
10887                reindented_line.clear();
10888            }
10889        });
10890    }
10891
10892    pub fn convert_indentation_to_tabs(
10893        &mut self,
10894        _: &ConvertIndentationToTabs,
10895        window: &mut Window,
10896        cx: &mut Context<Self>,
10897    ) {
10898        let settings = self.buffer.read(cx).language_settings(cx);
10899        let tab_size = settings.tab_size.get() as usize;
10900
10901        self.manipulate_mutable_lines(window, cx, |lines| {
10902            // Allocates a reasonably sized buffer once for the whole loop
10903            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10904            // Avoids recomputing spaces that could be inserted many times
10905            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10906                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10907                .collect();
10908
10909            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10910                let mut chars = line.chars();
10911                let mut spaces_count = 0;
10912                let mut first_non_indent_char = None;
10913                let mut changed = false;
10914
10915                while let Some(ch) = chars.next() {
10916                    match ch {
10917                        ' ' => {
10918                            // Keep track of spaces. Append \t when we reach tab_size
10919                            spaces_count += 1;
10920                            changed = true;
10921                            if spaces_count == tab_size {
10922                                reindented_line.push('\t');
10923                                spaces_count = 0;
10924                            }
10925                        }
10926                        '\t' => {
10927                            reindented_line.push('\t');
10928                            spaces_count = 0;
10929                        }
10930                        _ => {
10931                            // Dont append it yet, we might have remaining spaces
10932                            first_non_indent_char = Some(ch);
10933                            break;
10934                        }
10935                    }
10936                }
10937
10938                if !changed {
10939                    reindented_line.clear();
10940                    continue;
10941                }
10942                // Remaining spaces that didn't make a full tab stop
10943                if spaces_count > 0 {
10944                    reindented_line.extend(&space_cache[spaces_count - 1]);
10945                }
10946                // If we consume an extra character that was not indentation, add it back
10947                if let Some(extra_char) = first_non_indent_char {
10948                    reindented_line.push(extra_char);
10949                }
10950                // Append the rest of the line and replace old reference with new one
10951                reindented_line.extend(chars);
10952                *line = Cow::Owned(reindented_line.clone());
10953                reindented_line.clear();
10954            }
10955        });
10956    }
10957
10958    pub fn convert_to_upper_case(
10959        &mut self,
10960        _: &ConvertToUpperCase,
10961        window: &mut Window,
10962        cx: &mut Context<Self>,
10963    ) {
10964        self.manipulate_text(window, cx, |text| text.to_uppercase())
10965    }
10966
10967    pub fn convert_to_lower_case(
10968        &mut self,
10969        _: &ConvertToLowerCase,
10970        window: &mut Window,
10971        cx: &mut Context<Self>,
10972    ) {
10973        self.manipulate_text(window, cx, |text| text.to_lowercase())
10974    }
10975
10976    pub fn convert_to_title_case(
10977        &mut self,
10978        _: &ConvertToTitleCase,
10979        window: &mut Window,
10980        cx: &mut Context<Self>,
10981    ) {
10982        self.manipulate_text(window, cx, |text| {
10983            text.split('\n')
10984                .map(|line| line.to_case(Case::Title))
10985                .join("\n")
10986        })
10987    }
10988
10989    pub fn convert_to_snake_case(
10990        &mut self,
10991        _: &ConvertToSnakeCase,
10992        window: &mut Window,
10993        cx: &mut Context<Self>,
10994    ) {
10995        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10996    }
10997
10998    pub fn convert_to_kebab_case(
10999        &mut self,
11000        _: &ConvertToKebabCase,
11001        window: &mut Window,
11002        cx: &mut Context<Self>,
11003    ) {
11004        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11005    }
11006
11007    pub fn convert_to_upper_camel_case(
11008        &mut self,
11009        _: &ConvertToUpperCamelCase,
11010        window: &mut Window,
11011        cx: &mut Context<Self>,
11012    ) {
11013        self.manipulate_text(window, cx, |text| {
11014            text.split('\n')
11015                .map(|line| line.to_case(Case::UpperCamel))
11016                .join("\n")
11017        })
11018    }
11019
11020    pub fn convert_to_lower_camel_case(
11021        &mut self,
11022        _: &ConvertToLowerCamelCase,
11023        window: &mut Window,
11024        cx: &mut Context<Self>,
11025    ) {
11026        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11027    }
11028
11029    pub fn convert_to_opposite_case(
11030        &mut self,
11031        _: &ConvertToOppositeCase,
11032        window: &mut Window,
11033        cx: &mut Context<Self>,
11034    ) {
11035        self.manipulate_text(window, cx, |text| {
11036            text.chars()
11037                .fold(String::with_capacity(text.len()), |mut t, c| {
11038                    if c.is_uppercase() {
11039                        t.extend(c.to_lowercase());
11040                    } else {
11041                        t.extend(c.to_uppercase());
11042                    }
11043                    t
11044                })
11045        })
11046    }
11047
11048    pub fn convert_to_rot13(
11049        &mut self,
11050        _: &ConvertToRot13,
11051        window: &mut Window,
11052        cx: &mut Context<Self>,
11053    ) {
11054        self.manipulate_text(window, cx, |text| {
11055            text.chars()
11056                .map(|c| match c {
11057                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11058                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11059                    _ => c,
11060                })
11061                .collect()
11062        })
11063    }
11064
11065    pub fn convert_to_rot47(
11066        &mut self,
11067        _: &ConvertToRot47,
11068        window: &mut Window,
11069        cx: &mut Context<Self>,
11070    ) {
11071        self.manipulate_text(window, cx, |text| {
11072            text.chars()
11073                .map(|c| {
11074                    let code_point = c as u32;
11075                    if code_point >= 33 && code_point <= 126 {
11076                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11077                    }
11078                    c
11079                })
11080                .collect()
11081        })
11082    }
11083
11084    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11085    where
11086        Fn: FnMut(&str) -> String,
11087    {
11088        let buffer = self.buffer.read(cx).snapshot(cx);
11089
11090        let mut new_selections = Vec::new();
11091        let mut edits = Vec::new();
11092        let mut selection_adjustment = 0i32;
11093
11094        for selection in self.selections.all::<usize>(cx) {
11095            let selection_is_empty = selection.is_empty();
11096
11097            let (start, end) = if selection_is_empty {
11098                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11099                (word_range.start, word_range.end)
11100            } else {
11101                (selection.start, selection.end)
11102            };
11103
11104            let text = buffer.text_for_range(start..end).collect::<String>();
11105            let old_length = text.len() as i32;
11106            let text = callback(&text);
11107
11108            new_selections.push(Selection {
11109                start: (start as i32 - selection_adjustment) as usize,
11110                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11111                goal: SelectionGoal::None,
11112                ..selection
11113            });
11114
11115            selection_adjustment += old_length - text.len() as i32;
11116
11117            edits.push((start..end, text));
11118        }
11119
11120        self.transact(window, cx, |this, window, cx| {
11121            this.buffer.update(cx, |buffer, cx| {
11122                buffer.edit(edits, None, cx);
11123            });
11124
11125            this.change_selections(Default::default(), window, cx, |s| {
11126                s.select(new_selections);
11127            });
11128
11129            this.request_autoscroll(Autoscroll::fit(), cx);
11130        });
11131    }
11132
11133    pub fn move_selection_on_drop(
11134        &mut self,
11135        selection: &Selection<Anchor>,
11136        target: DisplayPoint,
11137        is_cut: bool,
11138        window: &mut Window,
11139        cx: &mut Context<Self>,
11140    ) {
11141        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11142        let buffer = &display_map.buffer_snapshot;
11143        let mut edits = Vec::new();
11144        let insert_point = display_map
11145            .clip_point(target, Bias::Left)
11146            .to_point(&display_map);
11147        let text = buffer
11148            .text_for_range(selection.start..selection.end)
11149            .collect::<String>();
11150        if is_cut {
11151            edits.push(((selection.start..selection.end), String::new()));
11152        }
11153        let insert_anchor = buffer.anchor_before(insert_point);
11154        edits.push(((insert_anchor..insert_anchor), text));
11155        let last_edit_start = insert_anchor.bias_left(buffer);
11156        let last_edit_end = insert_anchor.bias_right(buffer);
11157        self.transact(window, cx, |this, window, cx| {
11158            this.buffer.update(cx, |buffer, cx| {
11159                buffer.edit(edits, None, cx);
11160            });
11161            this.change_selections(Default::default(), window, cx, |s| {
11162                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11163            });
11164        });
11165    }
11166
11167    pub fn clear_selection_drag_state(&mut self) {
11168        self.selection_drag_state = SelectionDragState::None;
11169    }
11170
11171    pub fn duplicate(
11172        &mut self,
11173        upwards: bool,
11174        whole_lines: bool,
11175        window: &mut Window,
11176        cx: &mut Context<Self>,
11177    ) {
11178        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11179
11180        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11181        let buffer = &display_map.buffer_snapshot;
11182        let selections = self.selections.all::<Point>(cx);
11183
11184        let mut edits = Vec::new();
11185        let mut selections_iter = selections.iter().peekable();
11186        while let Some(selection) = selections_iter.next() {
11187            let mut rows = selection.spanned_rows(false, &display_map);
11188            // duplicate line-wise
11189            if whole_lines || selection.start == selection.end {
11190                // Avoid duplicating the same lines twice.
11191                while let Some(next_selection) = selections_iter.peek() {
11192                    let next_rows = next_selection.spanned_rows(false, &display_map);
11193                    if next_rows.start < rows.end {
11194                        rows.end = next_rows.end;
11195                        selections_iter.next().unwrap();
11196                    } else {
11197                        break;
11198                    }
11199                }
11200
11201                // Copy the text from the selected row region and splice it either at the start
11202                // or end of the region.
11203                let start = Point::new(rows.start.0, 0);
11204                let end = Point::new(
11205                    rows.end.previous_row().0,
11206                    buffer.line_len(rows.end.previous_row()),
11207                );
11208                let text = buffer
11209                    .text_for_range(start..end)
11210                    .chain(Some("\n"))
11211                    .collect::<String>();
11212                let insert_location = if upwards {
11213                    Point::new(rows.end.0, 0)
11214                } else {
11215                    start
11216                };
11217                edits.push((insert_location..insert_location, text));
11218            } else {
11219                // duplicate character-wise
11220                let start = selection.start;
11221                let end = selection.end;
11222                let text = buffer.text_for_range(start..end).collect::<String>();
11223                edits.push((selection.end..selection.end, text));
11224            }
11225        }
11226
11227        self.transact(window, cx, |this, _, cx| {
11228            this.buffer.update(cx, |buffer, cx| {
11229                buffer.edit(edits, None, cx);
11230            });
11231
11232            this.request_autoscroll(Autoscroll::fit(), cx);
11233        });
11234    }
11235
11236    pub fn duplicate_line_up(
11237        &mut self,
11238        _: &DuplicateLineUp,
11239        window: &mut Window,
11240        cx: &mut Context<Self>,
11241    ) {
11242        self.duplicate(true, true, window, cx);
11243    }
11244
11245    pub fn duplicate_line_down(
11246        &mut self,
11247        _: &DuplicateLineDown,
11248        window: &mut Window,
11249        cx: &mut Context<Self>,
11250    ) {
11251        self.duplicate(false, true, window, cx);
11252    }
11253
11254    pub fn duplicate_selection(
11255        &mut self,
11256        _: &DuplicateSelection,
11257        window: &mut Window,
11258        cx: &mut Context<Self>,
11259    ) {
11260        self.duplicate(false, false, window, cx);
11261    }
11262
11263    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11264        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11265        if self.mode.is_single_line() {
11266            cx.propagate();
11267            return;
11268        }
11269
11270        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11271        let buffer = self.buffer.read(cx).snapshot(cx);
11272
11273        let mut edits = Vec::new();
11274        let mut unfold_ranges = Vec::new();
11275        let mut refold_creases = Vec::new();
11276
11277        let selections = self.selections.all::<Point>(cx);
11278        let mut selections = selections.iter().peekable();
11279        let mut contiguous_row_selections = Vec::new();
11280        let mut new_selections = Vec::new();
11281
11282        while let Some(selection) = selections.next() {
11283            // Find all the selections that span a contiguous row range
11284            let (start_row, end_row) = consume_contiguous_rows(
11285                &mut contiguous_row_selections,
11286                selection,
11287                &display_map,
11288                &mut selections,
11289            );
11290
11291            // Move the text spanned by the row range to be before the line preceding the row range
11292            if start_row.0 > 0 {
11293                let range_to_move = Point::new(
11294                    start_row.previous_row().0,
11295                    buffer.line_len(start_row.previous_row()),
11296                )
11297                    ..Point::new(
11298                        end_row.previous_row().0,
11299                        buffer.line_len(end_row.previous_row()),
11300                    );
11301                let insertion_point = display_map
11302                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11303                    .0;
11304
11305                // Don't move lines across excerpts
11306                if buffer
11307                    .excerpt_containing(insertion_point..range_to_move.end)
11308                    .is_some()
11309                {
11310                    let text = buffer
11311                        .text_for_range(range_to_move.clone())
11312                        .flat_map(|s| s.chars())
11313                        .skip(1)
11314                        .chain(['\n'])
11315                        .collect::<String>();
11316
11317                    edits.push((
11318                        buffer.anchor_after(range_to_move.start)
11319                            ..buffer.anchor_before(range_to_move.end),
11320                        String::new(),
11321                    ));
11322                    let insertion_anchor = buffer.anchor_after(insertion_point);
11323                    edits.push((insertion_anchor..insertion_anchor, text));
11324
11325                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11326
11327                    // Move selections up
11328                    new_selections.extend(contiguous_row_selections.drain(..).map(
11329                        |mut selection| {
11330                            selection.start.row -= row_delta;
11331                            selection.end.row -= row_delta;
11332                            selection
11333                        },
11334                    ));
11335
11336                    // Move folds up
11337                    unfold_ranges.push(range_to_move.clone());
11338                    for fold in display_map.folds_in_range(
11339                        buffer.anchor_before(range_to_move.start)
11340                            ..buffer.anchor_after(range_to_move.end),
11341                    ) {
11342                        let mut start = fold.range.start.to_point(&buffer);
11343                        let mut end = fold.range.end.to_point(&buffer);
11344                        start.row -= row_delta;
11345                        end.row -= row_delta;
11346                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11347                    }
11348                }
11349            }
11350
11351            // If we didn't move line(s), preserve the existing selections
11352            new_selections.append(&mut contiguous_row_selections);
11353        }
11354
11355        self.transact(window, cx, |this, window, cx| {
11356            this.unfold_ranges(&unfold_ranges, true, true, cx);
11357            this.buffer.update(cx, |buffer, cx| {
11358                for (range, text) in edits {
11359                    buffer.edit([(range, text)], None, cx);
11360                }
11361            });
11362            this.fold_creases(refold_creases, true, window, cx);
11363            this.change_selections(Default::default(), window, cx, |s| {
11364                s.select(new_selections);
11365            })
11366        });
11367    }
11368
11369    pub fn move_line_down(
11370        &mut self,
11371        _: &MoveLineDown,
11372        window: &mut Window,
11373        cx: &mut Context<Self>,
11374    ) {
11375        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11376        if self.mode.is_single_line() {
11377            cx.propagate();
11378            return;
11379        }
11380
11381        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11382        let buffer = self.buffer.read(cx).snapshot(cx);
11383
11384        let mut edits = Vec::new();
11385        let mut unfold_ranges = Vec::new();
11386        let mut refold_creases = Vec::new();
11387
11388        let selections = self.selections.all::<Point>(cx);
11389        let mut selections = selections.iter().peekable();
11390        let mut contiguous_row_selections = Vec::new();
11391        let mut new_selections = Vec::new();
11392
11393        while let Some(selection) = selections.next() {
11394            // Find all the selections that span a contiguous row range
11395            let (start_row, end_row) = consume_contiguous_rows(
11396                &mut contiguous_row_selections,
11397                selection,
11398                &display_map,
11399                &mut selections,
11400            );
11401
11402            // Move the text spanned by the row range to be after the last line of the row range
11403            if end_row.0 <= buffer.max_point().row {
11404                let range_to_move =
11405                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11406                let insertion_point = display_map
11407                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11408                    .0;
11409
11410                // Don't move lines across excerpt boundaries
11411                if buffer
11412                    .excerpt_containing(range_to_move.start..insertion_point)
11413                    .is_some()
11414                {
11415                    let mut text = String::from("\n");
11416                    text.extend(buffer.text_for_range(range_to_move.clone()));
11417                    text.pop(); // Drop trailing newline
11418                    edits.push((
11419                        buffer.anchor_after(range_to_move.start)
11420                            ..buffer.anchor_before(range_to_move.end),
11421                        String::new(),
11422                    ));
11423                    let insertion_anchor = buffer.anchor_after(insertion_point);
11424                    edits.push((insertion_anchor..insertion_anchor, text));
11425
11426                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11427
11428                    // Move selections down
11429                    new_selections.extend(contiguous_row_selections.drain(..).map(
11430                        |mut selection| {
11431                            selection.start.row += row_delta;
11432                            selection.end.row += row_delta;
11433                            selection
11434                        },
11435                    ));
11436
11437                    // Move folds down
11438                    unfold_ranges.push(range_to_move.clone());
11439                    for fold in display_map.folds_in_range(
11440                        buffer.anchor_before(range_to_move.start)
11441                            ..buffer.anchor_after(range_to_move.end),
11442                    ) {
11443                        let mut start = fold.range.start.to_point(&buffer);
11444                        let mut end = fold.range.end.to_point(&buffer);
11445                        start.row += row_delta;
11446                        end.row += row_delta;
11447                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11448                    }
11449                }
11450            }
11451
11452            // If we didn't move line(s), preserve the existing selections
11453            new_selections.append(&mut contiguous_row_selections);
11454        }
11455
11456        self.transact(window, cx, |this, window, cx| {
11457            this.unfold_ranges(&unfold_ranges, true, true, cx);
11458            this.buffer.update(cx, |buffer, cx| {
11459                for (range, text) in edits {
11460                    buffer.edit([(range, text)], None, cx);
11461                }
11462            });
11463            this.fold_creases(refold_creases, true, window, cx);
11464            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11465        });
11466    }
11467
11468    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11470        let text_layout_details = &self.text_layout_details(window);
11471        self.transact(window, cx, |this, window, cx| {
11472            let edits = this.change_selections(Default::default(), window, cx, |s| {
11473                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11474                s.move_with(|display_map, selection| {
11475                    if !selection.is_empty() {
11476                        return;
11477                    }
11478
11479                    let mut head = selection.head();
11480                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11481                    if head.column() == display_map.line_len(head.row()) {
11482                        transpose_offset = display_map
11483                            .buffer_snapshot
11484                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11485                    }
11486
11487                    if transpose_offset == 0 {
11488                        return;
11489                    }
11490
11491                    *head.column_mut() += 1;
11492                    head = display_map.clip_point(head, Bias::Right);
11493                    let goal = SelectionGoal::HorizontalPosition(
11494                        display_map
11495                            .x_for_display_point(head, text_layout_details)
11496                            .into(),
11497                    );
11498                    selection.collapse_to(head, goal);
11499
11500                    let transpose_start = display_map
11501                        .buffer_snapshot
11502                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11503                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11504                        let transpose_end = display_map
11505                            .buffer_snapshot
11506                            .clip_offset(transpose_offset + 1, Bias::Right);
11507                        if let Some(ch) =
11508                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11509                        {
11510                            edits.push((transpose_start..transpose_offset, String::new()));
11511                            edits.push((transpose_end..transpose_end, ch.to_string()));
11512                        }
11513                    }
11514                });
11515                edits
11516            });
11517            this.buffer
11518                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11519            let selections = this.selections.all::<usize>(cx);
11520            this.change_selections(Default::default(), window, cx, |s| {
11521                s.select(selections);
11522            });
11523        });
11524    }
11525
11526    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11527        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11528        if self.mode.is_single_line() {
11529            cx.propagate();
11530            return;
11531        }
11532
11533        self.rewrap_impl(RewrapOptions::default(), cx)
11534    }
11535
11536    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11537        let buffer = self.buffer.read(cx).snapshot(cx);
11538        let selections = self.selections.all::<Point>(cx);
11539
11540        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11541        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11542            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11543                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11544                .peekable();
11545
11546            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11547                row
11548            } else {
11549                return Vec::new();
11550            };
11551
11552            let language_settings = buffer.language_settings_at(selection.head(), cx);
11553            let language_scope = buffer.language_scope_at(selection.head());
11554
11555            let indent_and_prefix_for_row =
11556                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11557                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11558                    let (comment_prefix, rewrap_prefix) =
11559                        if let Some(language_scope) = &language_scope {
11560                            let indent_end = Point::new(row, indent.len);
11561                            let comment_prefix = language_scope
11562                                .line_comment_prefixes()
11563                                .iter()
11564                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11565                                .map(|prefix| prefix.to_string());
11566                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11567                            let line_text_after_indent = buffer
11568                                .text_for_range(indent_end..line_end)
11569                                .collect::<String>();
11570                            let rewrap_prefix = language_scope
11571                                .rewrap_prefixes()
11572                                .iter()
11573                                .find_map(|prefix_regex| {
11574                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11575                                        if mat.start() == 0 {
11576                                            Some(mat.as_str().to_string())
11577                                        } else {
11578                                            None
11579                                        }
11580                                    })
11581                                })
11582                                .flatten();
11583                            (comment_prefix, rewrap_prefix)
11584                        } else {
11585                            (None, None)
11586                        };
11587                    (indent, comment_prefix, rewrap_prefix)
11588                };
11589
11590            let mut ranges = Vec::new();
11591            let from_empty_selection = selection.is_empty();
11592
11593            let mut current_range_start = first_row;
11594            let mut prev_row = first_row;
11595            let (
11596                mut current_range_indent,
11597                mut current_range_comment_prefix,
11598                mut current_range_rewrap_prefix,
11599            ) = indent_and_prefix_for_row(first_row);
11600
11601            for row in non_blank_rows_iter.skip(1) {
11602                let has_paragraph_break = row > prev_row + 1;
11603
11604                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11605                    indent_and_prefix_for_row(row);
11606
11607                let has_indent_change = row_indent != current_range_indent;
11608                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11609
11610                let has_boundary_change = has_comment_change
11611                    || row_rewrap_prefix.is_some()
11612                    || (has_indent_change && current_range_comment_prefix.is_some());
11613
11614                if has_paragraph_break || has_boundary_change {
11615                    ranges.push((
11616                        language_settings.clone(),
11617                        Point::new(current_range_start, 0)
11618                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11619                        current_range_indent,
11620                        current_range_comment_prefix.clone(),
11621                        current_range_rewrap_prefix.clone(),
11622                        from_empty_selection,
11623                    ));
11624                    current_range_start = row;
11625                    current_range_indent = row_indent;
11626                    current_range_comment_prefix = row_comment_prefix;
11627                    current_range_rewrap_prefix = row_rewrap_prefix;
11628                }
11629                prev_row = row;
11630            }
11631
11632            ranges.push((
11633                language_settings.clone(),
11634                Point::new(current_range_start, 0)
11635                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11636                current_range_indent,
11637                current_range_comment_prefix,
11638                current_range_rewrap_prefix,
11639                from_empty_selection,
11640            ));
11641
11642            ranges
11643        });
11644
11645        let mut edits = Vec::new();
11646        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11647
11648        for (
11649            language_settings,
11650            wrap_range,
11651            indent_size,
11652            comment_prefix,
11653            rewrap_prefix,
11654            from_empty_selection,
11655        ) in wrap_ranges
11656        {
11657            let mut start_row = wrap_range.start.row;
11658            let mut end_row = wrap_range.end.row;
11659
11660            // Skip selections that overlap with a range that has already been rewrapped.
11661            let selection_range = start_row..end_row;
11662            if rewrapped_row_ranges
11663                .iter()
11664                .any(|range| range.overlaps(&selection_range))
11665            {
11666                continue;
11667            }
11668
11669            let tab_size = language_settings.tab_size;
11670
11671            let indent_prefix = indent_size.chars().collect::<String>();
11672            let mut line_prefix = indent_prefix.clone();
11673            let mut inside_comment = false;
11674            if let Some(prefix) = &comment_prefix {
11675                line_prefix.push_str(prefix);
11676                inside_comment = true;
11677            }
11678            if let Some(prefix) = &rewrap_prefix {
11679                line_prefix.push_str(prefix);
11680            }
11681
11682            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11683                RewrapBehavior::InComments => inside_comment,
11684                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11685                RewrapBehavior::Anywhere => true,
11686            };
11687
11688            let should_rewrap = options.override_language_settings
11689                || allow_rewrap_based_on_language
11690                || self.hard_wrap.is_some();
11691            if !should_rewrap {
11692                continue;
11693            }
11694
11695            if from_empty_selection {
11696                'expand_upwards: while start_row > 0 {
11697                    let prev_row = start_row - 1;
11698                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11699                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11700                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11701                    {
11702                        start_row = prev_row;
11703                    } else {
11704                        break 'expand_upwards;
11705                    }
11706                }
11707
11708                'expand_downwards: while end_row < buffer.max_point().row {
11709                    let next_row = end_row + 1;
11710                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11711                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11712                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11713                    {
11714                        end_row = next_row;
11715                    } else {
11716                        break 'expand_downwards;
11717                    }
11718                }
11719            }
11720
11721            let start = Point::new(start_row, 0);
11722            let start_offset = start.to_offset(&buffer);
11723            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11724            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11725            let Some(lines_without_prefixes) = selection_text
11726                .lines()
11727                .enumerate()
11728                .map(|(ix, line)| {
11729                    let line_trimmed = line.trim_start();
11730                    if rewrap_prefix.is_some() && ix > 0 {
11731                        Ok(line_trimmed)
11732                    } else {
11733                        line_trimmed
11734                            .strip_prefix(&line_prefix.trim_start())
11735                            .with_context(|| {
11736                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11737                            })
11738                    }
11739                })
11740                .collect::<Result<Vec<_>, _>>()
11741                .log_err()
11742            else {
11743                continue;
11744            };
11745
11746            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11747                buffer
11748                    .language_settings_at(Point::new(start_row, 0), cx)
11749                    .preferred_line_length as usize
11750            });
11751
11752            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11753                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11754            } else {
11755                line_prefix.clone()
11756            };
11757
11758            let wrapped_text = wrap_with_prefix(
11759                line_prefix,
11760                subsequent_lines_prefix,
11761                lines_without_prefixes.join("\n"),
11762                wrap_column,
11763                tab_size,
11764                options.preserve_existing_whitespace,
11765            );
11766
11767            // TODO: should always use char-based diff while still supporting cursor behavior that
11768            // matches vim.
11769            let mut diff_options = DiffOptions::default();
11770            if options.override_language_settings {
11771                diff_options.max_word_diff_len = 0;
11772                diff_options.max_word_diff_line_count = 0;
11773            } else {
11774                diff_options.max_word_diff_len = usize::MAX;
11775                diff_options.max_word_diff_line_count = usize::MAX;
11776            }
11777
11778            for (old_range, new_text) in
11779                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11780            {
11781                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11782                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11783                edits.push((edit_start..edit_end, new_text));
11784            }
11785
11786            rewrapped_row_ranges.push(start_row..=end_row);
11787        }
11788
11789        self.buffer
11790            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11791    }
11792
11793    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11794        let mut text = String::new();
11795        let buffer = self.buffer.read(cx).snapshot(cx);
11796        let mut selections = self.selections.all::<Point>(cx);
11797        let mut clipboard_selections = Vec::with_capacity(selections.len());
11798        {
11799            let max_point = buffer.max_point();
11800            let mut is_first = true;
11801            for selection in &mut selections {
11802                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11803                if is_entire_line {
11804                    selection.start = Point::new(selection.start.row, 0);
11805                    if !selection.is_empty() && selection.end.column == 0 {
11806                        selection.end = cmp::min(max_point, selection.end);
11807                    } else {
11808                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11809                    }
11810                    selection.goal = SelectionGoal::None;
11811                }
11812                if is_first {
11813                    is_first = false;
11814                } else {
11815                    text += "\n";
11816                }
11817                let mut len = 0;
11818                for chunk in buffer.text_for_range(selection.start..selection.end) {
11819                    text.push_str(chunk);
11820                    len += chunk.len();
11821                }
11822                clipboard_selections.push(ClipboardSelection {
11823                    len,
11824                    is_entire_line,
11825                    first_line_indent: buffer
11826                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11827                        .len,
11828                });
11829            }
11830        }
11831
11832        self.transact(window, cx, |this, window, cx| {
11833            this.change_selections(Default::default(), window, cx, |s| {
11834                s.select(selections);
11835            });
11836            this.insert("", window, cx);
11837        });
11838        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11839    }
11840
11841    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11842        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11843        let item = self.cut_common(window, cx);
11844        cx.write_to_clipboard(item);
11845    }
11846
11847    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11848        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11849        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11850            s.move_with(|snapshot, sel| {
11851                if sel.is_empty() {
11852                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11853                }
11854            });
11855        });
11856        let item = self.cut_common(window, cx);
11857        cx.set_global(KillRing(item))
11858    }
11859
11860    pub fn kill_ring_yank(
11861        &mut self,
11862        _: &KillRingYank,
11863        window: &mut Window,
11864        cx: &mut Context<Self>,
11865    ) {
11866        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11867        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11868            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11869                (kill_ring.text().to_string(), kill_ring.metadata_json())
11870            } else {
11871                return;
11872            }
11873        } else {
11874            return;
11875        };
11876        self.do_paste(&text, metadata, false, window, cx);
11877    }
11878
11879    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11880        self.do_copy(true, cx);
11881    }
11882
11883    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11884        self.do_copy(false, cx);
11885    }
11886
11887    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11888        let selections = self.selections.all::<Point>(cx);
11889        let buffer = self.buffer.read(cx).read(cx);
11890        let mut text = String::new();
11891
11892        let mut clipboard_selections = Vec::with_capacity(selections.len());
11893        {
11894            let max_point = buffer.max_point();
11895            let mut is_first = true;
11896            for selection in &selections {
11897                let mut start = selection.start;
11898                let mut end = selection.end;
11899                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11900                if is_entire_line {
11901                    start = Point::new(start.row, 0);
11902                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11903                }
11904
11905                let mut trimmed_selections = Vec::new();
11906                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11907                    let row = MultiBufferRow(start.row);
11908                    let first_indent = buffer.indent_size_for_line(row);
11909                    if first_indent.len == 0 || start.column > first_indent.len {
11910                        trimmed_selections.push(start..end);
11911                    } else {
11912                        trimmed_selections.push(
11913                            Point::new(row.0, first_indent.len)
11914                                ..Point::new(row.0, buffer.line_len(row)),
11915                        );
11916                        for row in start.row + 1..=end.row {
11917                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11918                            if row == end.row {
11919                                line_len = end.column;
11920                            }
11921                            if line_len == 0 {
11922                                trimmed_selections
11923                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11924                                continue;
11925                            }
11926                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11927                            if row_indent_size.len >= first_indent.len {
11928                                trimmed_selections.push(
11929                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11930                                );
11931                            } else {
11932                                trimmed_selections.clear();
11933                                trimmed_selections.push(start..end);
11934                                break;
11935                            }
11936                        }
11937                    }
11938                } else {
11939                    trimmed_selections.push(start..end);
11940                }
11941
11942                for trimmed_range in trimmed_selections {
11943                    if is_first {
11944                        is_first = false;
11945                    } else {
11946                        text += "\n";
11947                    }
11948                    let mut len = 0;
11949                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11950                        text.push_str(chunk);
11951                        len += chunk.len();
11952                    }
11953                    clipboard_selections.push(ClipboardSelection {
11954                        len,
11955                        is_entire_line,
11956                        first_line_indent: buffer
11957                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11958                            .len,
11959                    });
11960                }
11961            }
11962        }
11963
11964        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11965            text,
11966            clipboard_selections,
11967        ));
11968    }
11969
11970    pub fn do_paste(
11971        &mut self,
11972        text: &String,
11973        clipboard_selections: Option<Vec<ClipboardSelection>>,
11974        handle_entire_lines: bool,
11975        window: &mut Window,
11976        cx: &mut Context<Self>,
11977    ) {
11978        if self.read_only(cx) {
11979            return;
11980        }
11981
11982        let clipboard_text = Cow::Borrowed(text);
11983
11984        self.transact(window, cx, |this, window, cx| {
11985            if let Some(mut clipboard_selections) = clipboard_selections {
11986                let old_selections = this.selections.all::<usize>(cx);
11987                let all_selections_were_entire_line =
11988                    clipboard_selections.iter().all(|s| s.is_entire_line);
11989                let first_selection_indent_column =
11990                    clipboard_selections.first().map(|s| s.first_line_indent);
11991                if clipboard_selections.len() != old_selections.len() {
11992                    clipboard_selections.drain(..);
11993                }
11994                let cursor_offset = this.selections.last::<usize>(cx).head();
11995                let mut auto_indent_on_paste = true;
11996
11997                this.buffer.update(cx, |buffer, cx| {
11998                    let snapshot = buffer.read(cx);
11999                    auto_indent_on_paste = snapshot
12000                        .language_settings_at(cursor_offset, cx)
12001                        .auto_indent_on_paste;
12002
12003                    let mut start_offset = 0;
12004                    let mut edits = Vec::new();
12005                    let mut original_indent_columns = Vec::new();
12006                    for (ix, selection) in old_selections.iter().enumerate() {
12007                        let to_insert;
12008                        let entire_line;
12009                        let original_indent_column;
12010                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12011                            let end_offset = start_offset + clipboard_selection.len;
12012                            to_insert = &clipboard_text[start_offset..end_offset];
12013                            entire_line = clipboard_selection.is_entire_line;
12014                            start_offset = end_offset + 1;
12015                            original_indent_column = Some(clipboard_selection.first_line_indent);
12016                        } else {
12017                            to_insert = clipboard_text.as_str();
12018                            entire_line = all_selections_were_entire_line;
12019                            original_indent_column = first_selection_indent_column
12020                        }
12021
12022                        // If the corresponding selection was empty when this slice of the
12023                        // clipboard text was written, then the entire line containing the
12024                        // selection was copied. If this selection is also currently empty,
12025                        // then paste the line before the current line of the buffer.
12026                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12027                            let column = selection.start.to_point(&snapshot).column as usize;
12028                            let line_start = selection.start - column;
12029                            line_start..line_start
12030                        } else {
12031                            selection.range()
12032                        };
12033
12034                        edits.push((range, to_insert));
12035                        original_indent_columns.push(original_indent_column);
12036                    }
12037                    drop(snapshot);
12038
12039                    buffer.edit(
12040                        edits,
12041                        if auto_indent_on_paste {
12042                            Some(AutoindentMode::Block {
12043                                original_indent_columns,
12044                            })
12045                        } else {
12046                            None
12047                        },
12048                        cx,
12049                    );
12050                });
12051
12052                let selections = this.selections.all::<usize>(cx);
12053                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12054            } else {
12055                this.insert(&clipboard_text, window, cx);
12056            }
12057        });
12058    }
12059
12060    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12061        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12062        if let Some(item) = cx.read_from_clipboard() {
12063            let entries = item.entries();
12064
12065            match entries.first() {
12066                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12067                // of all the pasted entries.
12068                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12069                    .do_paste(
12070                        clipboard_string.text(),
12071                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12072                        true,
12073                        window,
12074                        cx,
12075                    ),
12076                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12077            }
12078        }
12079    }
12080
12081    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12082        if self.read_only(cx) {
12083            return;
12084        }
12085
12086        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12087
12088        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12089            if let Some((selections, _)) =
12090                self.selection_history.transaction(transaction_id).cloned()
12091            {
12092                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12093                    s.select_anchors(selections.to_vec());
12094                });
12095            } else {
12096                log::error!(
12097                    "No entry in selection_history found for undo. \
12098                     This may correspond to a bug where undo does not update the selection. \
12099                     If this is occurring, please add details to \
12100                     https://github.com/zed-industries/zed/issues/22692"
12101                );
12102            }
12103            self.request_autoscroll(Autoscroll::fit(), cx);
12104            self.unmark_text(window, cx);
12105            self.refresh_inline_completion(true, false, window, cx);
12106            cx.emit(EditorEvent::Edited { transaction_id });
12107            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12108        }
12109    }
12110
12111    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12112        if self.read_only(cx) {
12113            return;
12114        }
12115
12116        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12117
12118        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12119            if let Some((_, Some(selections))) =
12120                self.selection_history.transaction(transaction_id).cloned()
12121            {
12122                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12123                    s.select_anchors(selections.to_vec());
12124                });
12125            } else {
12126                log::error!(
12127                    "No entry in selection_history found for redo. \
12128                     This may correspond to a bug where undo does not update the selection. \
12129                     If this is occurring, please add details to \
12130                     https://github.com/zed-industries/zed/issues/22692"
12131                );
12132            }
12133            self.request_autoscroll(Autoscroll::fit(), cx);
12134            self.unmark_text(window, cx);
12135            self.refresh_inline_completion(true, false, window, cx);
12136            cx.emit(EditorEvent::Edited { transaction_id });
12137        }
12138    }
12139
12140    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12141        self.buffer
12142            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12143    }
12144
12145    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12146        self.buffer
12147            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12148    }
12149
12150    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12151        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12152        self.change_selections(Default::default(), window, cx, |s| {
12153            s.move_with(|map, selection| {
12154                let cursor = if selection.is_empty() {
12155                    movement::left(map, selection.start)
12156                } else {
12157                    selection.start
12158                };
12159                selection.collapse_to(cursor, SelectionGoal::None);
12160            });
12161        })
12162    }
12163
12164    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12165        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12166        self.change_selections(Default::default(), window, cx, |s| {
12167            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12168        })
12169    }
12170
12171    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12173        self.change_selections(Default::default(), window, cx, |s| {
12174            s.move_with(|map, selection| {
12175                let cursor = if selection.is_empty() {
12176                    movement::right(map, selection.end)
12177                } else {
12178                    selection.end
12179                };
12180                selection.collapse_to(cursor, SelectionGoal::None)
12181            });
12182        })
12183    }
12184
12185    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12187        self.change_selections(Default::default(), window, cx, |s| {
12188            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12189        })
12190    }
12191
12192    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12193        if self.take_rename(true, window, cx).is_some() {
12194            return;
12195        }
12196
12197        if self.mode.is_single_line() {
12198            cx.propagate();
12199            return;
12200        }
12201
12202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12203
12204        let text_layout_details = &self.text_layout_details(window);
12205        let selection_count = self.selections.count();
12206        let first_selection = self.selections.first_anchor();
12207
12208        self.change_selections(Default::default(), window, cx, |s| {
12209            s.move_with(|map, selection| {
12210                if !selection.is_empty() {
12211                    selection.goal = SelectionGoal::None;
12212                }
12213                let (cursor, goal) = movement::up(
12214                    map,
12215                    selection.start,
12216                    selection.goal,
12217                    false,
12218                    text_layout_details,
12219                );
12220                selection.collapse_to(cursor, goal);
12221            });
12222        });
12223
12224        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12225        {
12226            cx.propagate();
12227        }
12228    }
12229
12230    pub fn move_up_by_lines(
12231        &mut self,
12232        action: &MoveUpByLines,
12233        window: &mut Window,
12234        cx: &mut Context<Self>,
12235    ) {
12236        if self.take_rename(true, window, cx).is_some() {
12237            return;
12238        }
12239
12240        if self.mode.is_single_line() {
12241            cx.propagate();
12242            return;
12243        }
12244
12245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12246
12247        let text_layout_details = &self.text_layout_details(window);
12248
12249        self.change_selections(Default::default(), window, cx, |s| {
12250            s.move_with(|map, selection| {
12251                if !selection.is_empty() {
12252                    selection.goal = SelectionGoal::None;
12253                }
12254                let (cursor, goal) = movement::up_by_rows(
12255                    map,
12256                    selection.start,
12257                    action.lines,
12258                    selection.goal,
12259                    false,
12260                    text_layout_details,
12261                );
12262                selection.collapse_to(cursor, goal);
12263            });
12264        })
12265    }
12266
12267    pub fn move_down_by_lines(
12268        &mut self,
12269        action: &MoveDownByLines,
12270        window: &mut Window,
12271        cx: &mut Context<Self>,
12272    ) {
12273        if self.take_rename(true, window, cx).is_some() {
12274            return;
12275        }
12276
12277        if self.mode.is_single_line() {
12278            cx.propagate();
12279            return;
12280        }
12281
12282        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12283
12284        let text_layout_details = &self.text_layout_details(window);
12285
12286        self.change_selections(Default::default(), window, cx, |s| {
12287            s.move_with(|map, selection| {
12288                if !selection.is_empty() {
12289                    selection.goal = SelectionGoal::None;
12290                }
12291                let (cursor, goal) = movement::down_by_rows(
12292                    map,
12293                    selection.start,
12294                    action.lines,
12295                    selection.goal,
12296                    false,
12297                    text_layout_details,
12298                );
12299                selection.collapse_to(cursor, goal);
12300            });
12301        })
12302    }
12303
12304    pub fn select_down_by_lines(
12305        &mut self,
12306        action: &SelectDownByLines,
12307        window: &mut Window,
12308        cx: &mut Context<Self>,
12309    ) {
12310        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12311        let text_layout_details = &self.text_layout_details(window);
12312        self.change_selections(Default::default(), window, cx, |s| {
12313            s.move_heads_with(|map, head, goal| {
12314                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12315            })
12316        })
12317    }
12318
12319    pub fn select_up_by_lines(
12320        &mut self,
12321        action: &SelectUpByLines,
12322        window: &mut Window,
12323        cx: &mut Context<Self>,
12324    ) {
12325        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12326        let text_layout_details = &self.text_layout_details(window);
12327        self.change_selections(Default::default(), window, cx, |s| {
12328            s.move_heads_with(|map, head, goal| {
12329                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12330            })
12331        })
12332    }
12333
12334    pub fn select_page_up(
12335        &mut self,
12336        _: &SelectPageUp,
12337        window: &mut Window,
12338        cx: &mut Context<Self>,
12339    ) {
12340        let Some(row_count) = self.visible_row_count() else {
12341            return;
12342        };
12343
12344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12345
12346        let text_layout_details = &self.text_layout_details(window);
12347
12348        self.change_selections(Default::default(), window, cx, |s| {
12349            s.move_heads_with(|map, head, goal| {
12350                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12351            })
12352        })
12353    }
12354
12355    pub fn move_page_up(
12356        &mut self,
12357        action: &MovePageUp,
12358        window: &mut Window,
12359        cx: &mut Context<Self>,
12360    ) {
12361        if self.take_rename(true, window, cx).is_some() {
12362            return;
12363        }
12364
12365        if self
12366            .context_menu
12367            .borrow_mut()
12368            .as_mut()
12369            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12370            .unwrap_or(false)
12371        {
12372            return;
12373        }
12374
12375        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12376            cx.propagate();
12377            return;
12378        }
12379
12380        let Some(row_count) = self.visible_row_count() else {
12381            return;
12382        };
12383
12384        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12385
12386        let effects = if action.center_cursor {
12387            SelectionEffects::scroll(Autoscroll::center())
12388        } else {
12389            SelectionEffects::default()
12390        };
12391
12392        let text_layout_details = &self.text_layout_details(window);
12393
12394        self.change_selections(effects, window, cx, |s| {
12395            s.move_with(|map, selection| {
12396                if !selection.is_empty() {
12397                    selection.goal = SelectionGoal::None;
12398                }
12399                let (cursor, goal) = movement::up_by_rows(
12400                    map,
12401                    selection.end,
12402                    row_count,
12403                    selection.goal,
12404                    false,
12405                    text_layout_details,
12406                );
12407                selection.collapse_to(cursor, goal);
12408            });
12409        });
12410    }
12411
12412    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12413        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12414        let text_layout_details = &self.text_layout_details(window);
12415        self.change_selections(Default::default(), window, cx, |s| {
12416            s.move_heads_with(|map, head, goal| {
12417                movement::up(map, head, goal, false, text_layout_details)
12418            })
12419        })
12420    }
12421
12422    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12423        self.take_rename(true, window, cx);
12424
12425        if self.mode.is_single_line() {
12426            cx.propagate();
12427            return;
12428        }
12429
12430        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12431
12432        let text_layout_details = &self.text_layout_details(window);
12433        let selection_count = self.selections.count();
12434        let first_selection = self.selections.first_anchor();
12435
12436        self.change_selections(Default::default(), window, cx, |s| {
12437            s.move_with(|map, selection| {
12438                if !selection.is_empty() {
12439                    selection.goal = SelectionGoal::None;
12440                }
12441                let (cursor, goal) = movement::down(
12442                    map,
12443                    selection.end,
12444                    selection.goal,
12445                    false,
12446                    text_layout_details,
12447                );
12448                selection.collapse_to(cursor, goal);
12449            });
12450        });
12451
12452        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12453        {
12454            cx.propagate();
12455        }
12456    }
12457
12458    pub fn select_page_down(
12459        &mut self,
12460        _: &SelectPageDown,
12461        window: &mut Window,
12462        cx: &mut Context<Self>,
12463    ) {
12464        let Some(row_count) = self.visible_row_count() else {
12465            return;
12466        };
12467
12468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12469
12470        let text_layout_details = &self.text_layout_details(window);
12471
12472        self.change_selections(Default::default(), window, cx, |s| {
12473            s.move_heads_with(|map, head, goal| {
12474                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12475            })
12476        })
12477    }
12478
12479    pub fn move_page_down(
12480        &mut self,
12481        action: &MovePageDown,
12482        window: &mut Window,
12483        cx: &mut Context<Self>,
12484    ) {
12485        if self.take_rename(true, window, cx).is_some() {
12486            return;
12487        }
12488
12489        if self
12490            .context_menu
12491            .borrow_mut()
12492            .as_mut()
12493            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12494            .unwrap_or(false)
12495        {
12496            return;
12497        }
12498
12499        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12500            cx.propagate();
12501            return;
12502        }
12503
12504        let Some(row_count) = self.visible_row_count() else {
12505            return;
12506        };
12507
12508        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12509
12510        let effects = if action.center_cursor {
12511            SelectionEffects::scroll(Autoscroll::center())
12512        } else {
12513            SelectionEffects::default()
12514        };
12515
12516        let text_layout_details = &self.text_layout_details(window);
12517        self.change_selections(effects, window, cx, |s| {
12518            s.move_with(|map, selection| {
12519                if !selection.is_empty() {
12520                    selection.goal = SelectionGoal::None;
12521                }
12522                let (cursor, goal) = movement::down_by_rows(
12523                    map,
12524                    selection.end,
12525                    row_count,
12526                    selection.goal,
12527                    false,
12528                    text_layout_details,
12529                );
12530                selection.collapse_to(cursor, goal);
12531            });
12532        });
12533    }
12534
12535    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12536        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12537        let text_layout_details = &self.text_layout_details(window);
12538        self.change_selections(Default::default(), window, cx, |s| {
12539            s.move_heads_with(|map, head, goal| {
12540                movement::down(map, head, goal, false, text_layout_details)
12541            })
12542        });
12543    }
12544
12545    pub fn context_menu_first(
12546        &mut self,
12547        _: &ContextMenuFirst,
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_first(self.completion_provider.as_deref(), window, cx);
12553        }
12554    }
12555
12556    pub fn context_menu_prev(
12557        &mut self,
12558        _: &ContextMenuPrevious,
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_prev(self.completion_provider.as_deref(), window, cx);
12564        }
12565    }
12566
12567    pub fn context_menu_next(
12568        &mut self,
12569        _: &ContextMenuNext,
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_next(self.completion_provider.as_deref(), window, cx);
12575        }
12576    }
12577
12578    pub fn context_menu_last(
12579        &mut self,
12580        _: &ContextMenuLast,
12581        window: &mut Window,
12582        cx: &mut Context<Self>,
12583    ) {
12584        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12585            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12586        }
12587    }
12588
12589    pub fn signature_help_prev(
12590        &mut self,
12591        _: &SignatureHelpPrevious,
12592        _: &mut Window,
12593        cx: &mut Context<Self>,
12594    ) {
12595        if let Some(popover) = self.signature_help_state.popover_mut() {
12596            if popover.current_signature == 0 {
12597                popover.current_signature = popover.signatures.len() - 1;
12598            } else {
12599                popover.current_signature -= 1;
12600            }
12601            cx.notify();
12602        }
12603    }
12604
12605    pub fn signature_help_next(
12606        &mut self,
12607        _: &SignatureHelpNext,
12608        _: &mut Window,
12609        cx: &mut Context<Self>,
12610    ) {
12611        if let Some(popover) = self.signature_help_state.popover_mut() {
12612            if popover.current_signature + 1 == popover.signatures.len() {
12613                popover.current_signature = 0;
12614            } else {
12615                popover.current_signature += 1;
12616            }
12617            cx.notify();
12618        }
12619    }
12620
12621    pub fn move_to_previous_word_start(
12622        &mut self,
12623        _: &MoveToPreviousWordStart,
12624        window: &mut Window,
12625        cx: &mut Context<Self>,
12626    ) {
12627        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12628        self.change_selections(Default::default(), window, cx, |s| {
12629            s.move_cursors_with(|map, head, _| {
12630                (
12631                    movement::previous_word_start(map, head),
12632                    SelectionGoal::None,
12633                )
12634            });
12635        })
12636    }
12637
12638    pub fn move_to_previous_subword_start(
12639        &mut self,
12640        _: &MoveToPreviousSubwordStart,
12641        window: &mut Window,
12642        cx: &mut Context<Self>,
12643    ) {
12644        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12645        self.change_selections(Default::default(), window, cx, |s| {
12646            s.move_cursors_with(|map, head, _| {
12647                (
12648                    movement::previous_subword_start(map, head),
12649                    SelectionGoal::None,
12650                )
12651            });
12652        })
12653    }
12654
12655    pub fn select_to_previous_word_start(
12656        &mut self,
12657        _: &SelectToPreviousWordStart,
12658        window: &mut Window,
12659        cx: &mut Context<Self>,
12660    ) {
12661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12662        self.change_selections(Default::default(), window, cx, |s| {
12663            s.move_heads_with(|map, head, _| {
12664                (
12665                    movement::previous_word_start(map, head),
12666                    SelectionGoal::None,
12667                )
12668            });
12669        })
12670    }
12671
12672    pub fn select_to_previous_subword_start(
12673        &mut self,
12674        _: &SelectToPreviousSubwordStart,
12675        window: &mut Window,
12676        cx: &mut Context<Self>,
12677    ) {
12678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12679        self.change_selections(Default::default(), window, cx, |s| {
12680            s.move_heads_with(|map, head, _| {
12681                (
12682                    movement::previous_subword_start(map, head),
12683                    SelectionGoal::None,
12684                )
12685            });
12686        })
12687    }
12688
12689    pub fn delete_to_previous_word_start(
12690        &mut self,
12691        action: &DeleteToPreviousWordStart,
12692        window: &mut Window,
12693        cx: &mut Context<Self>,
12694    ) {
12695        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12696        self.transact(window, cx, |this, window, cx| {
12697            this.select_autoclose_pair(window, cx);
12698            this.change_selections(Default::default(), window, cx, |s| {
12699                s.move_with(|map, selection| {
12700                    if selection.is_empty() {
12701                        let cursor = if action.ignore_newlines {
12702                            movement::previous_word_start(map, selection.head())
12703                        } else {
12704                            movement::previous_word_start_or_newline(map, selection.head())
12705                        };
12706                        selection.set_head(cursor, SelectionGoal::None);
12707                    }
12708                });
12709            });
12710            this.insert("", window, cx);
12711        });
12712    }
12713
12714    pub fn delete_to_previous_subword_start(
12715        &mut self,
12716        _: &DeleteToPreviousSubwordStart,
12717        window: &mut Window,
12718        cx: &mut Context<Self>,
12719    ) {
12720        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12721        self.transact(window, cx, |this, window, cx| {
12722            this.select_autoclose_pair(window, cx);
12723            this.change_selections(Default::default(), window, cx, |s| {
12724                s.move_with(|map, selection| {
12725                    if selection.is_empty() {
12726                        let cursor = movement::previous_subword_start(map, selection.head());
12727                        selection.set_head(cursor, SelectionGoal::None);
12728                    }
12729                });
12730            });
12731            this.insert("", window, cx);
12732        });
12733    }
12734
12735    pub fn move_to_next_word_end(
12736        &mut self,
12737        _: &MoveToNextWordEnd,
12738        window: &mut Window,
12739        cx: &mut Context<Self>,
12740    ) {
12741        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12742        self.change_selections(Default::default(), window, cx, |s| {
12743            s.move_cursors_with(|map, head, _| {
12744                (movement::next_word_end(map, head), SelectionGoal::None)
12745            });
12746        })
12747    }
12748
12749    pub fn move_to_next_subword_end(
12750        &mut self,
12751        _: &MoveToNextSubwordEnd,
12752        window: &mut Window,
12753        cx: &mut Context<Self>,
12754    ) {
12755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12756        self.change_selections(Default::default(), window, cx, |s| {
12757            s.move_cursors_with(|map, head, _| {
12758                (movement::next_subword_end(map, head), SelectionGoal::None)
12759            });
12760        })
12761    }
12762
12763    pub fn select_to_next_word_end(
12764        &mut self,
12765        _: &SelectToNextWordEnd,
12766        window: &mut Window,
12767        cx: &mut Context<Self>,
12768    ) {
12769        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12770        self.change_selections(Default::default(), window, cx, |s| {
12771            s.move_heads_with(|map, head, _| {
12772                (movement::next_word_end(map, head), SelectionGoal::None)
12773            });
12774        })
12775    }
12776
12777    pub fn select_to_next_subword_end(
12778        &mut self,
12779        _: &SelectToNextSubwordEnd,
12780        window: &mut Window,
12781        cx: &mut Context<Self>,
12782    ) {
12783        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12784        self.change_selections(Default::default(), window, cx, |s| {
12785            s.move_heads_with(|map, head, _| {
12786                (movement::next_subword_end(map, head), SelectionGoal::None)
12787            });
12788        })
12789    }
12790
12791    pub fn delete_to_next_word_end(
12792        &mut self,
12793        action: &DeleteToNextWordEnd,
12794        window: &mut Window,
12795        cx: &mut Context<Self>,
12796    ) {
12797        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12798        self.transact(window, cx, |this, window, cx| {
12799            this.change_selections(Default::default(), window, cx, |s| {
12800                s.move_with(|map, selection| {
12801                    if selection.is_empty() {
12802                        let cursor = if action.ignore_newlines {
12803                            movement::next_word_end(map, selection.head())
12804                        } else {
12805                            movement::next_word_end_or_newline(map, selection.head())
12806                        };
12807                        selection.set_head(cursor, SelectionGoal::None);
12808                    }
12809                });
12810            });
12811            this.insert("", window, cx);
12812        });
12813    }
12814
12815    pub fn delete_to_next_subword_end(
12816        &mut self,
12817        _: &DeleteToNextSubwordEnd,
12818        window: &mut Window,
12819        cx: &mut Context<Self>,
12820    ) {
12821        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12822        self.transact(window, cx, |this, window, cx| {
12823            this.change_selections(Default::default(), window, cx, |s| {
12824                s.move_with(|map, selection| {
12825                    if selection.is_empty() {
12826                        let cursor = movement::next_subword_end(map, selection.head());
12827                        selection.set_head(cursor, SelectionGoal::None);
12828                    }
12829                });
12830            });
12831            this.insert("", window, cx);
12832        });
12833    }
12834
12835    pub fn move_to_beginning_of_line(
12836        &mut self,
12837        action: &MoveToBeginningOfLine,
12838        window: &mut Window,
12839        cx: &mut Context<Self>,
12840    ) {
12841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12842        self.change_selections(Default::default(), window, cx, |s| {
12843            s.move_cursors_with(|map, head, _| {
12844                (
12845                    movement::indented_line_beginning(
12846                        map,
12847                        head,
12848                        action.stop_at_soft_wraps,
12849                        action.stop_at_indent,
12850                    ),
12851                    SelectionGoal::None,
12852                )
12853            });
12854        })
12855    }
12856
12857    pub fn select_to_beginning_of_line(
12858        &mut self,
12859        action: &SelectToBeginningOfLine,
12860        window: &mut Window,
12861        cx: &mut Context<Self>,
12862    ) {
12863        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12864        self.change_selections(Default::default(), window, cx, |s| {
12865            s.move_heads_with(|map, head, _| {
12866                (
12867                    movement::indented_line_beginning(
12868                        map,
12869                        head,
12870                        action.stop_at_soft_wraps,
12871                        action.stop_at_indent,
12872                    ),
12873                    SelectionGoal::None,
12874                )
12875            });
12876        });
12877    }
12878
12879    pub fn delete_to_beginning_of_line(
12880        &mut self,
12881        action: &DeleteToBeginningOfLine,
12882        window: &mut Window,
12883        cx: &mut Context<Self>,
12884    ) {
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12886        self.transact(window, cx, |this, window, cx| {
12887            this.change_selections(Default::default(), window, cx, |s| {
12888                s.move_with(|_, selection| {
12889                    selection.reversed = true;
12890                });
12891            });
12892
12893            this.select_to_beginning_of_line(
12894                &SelectToBeginningOfLine {
12895                    stop_at_soft_wraps: false,
12896                    stop_at_indent: action.stop_at_indent,
12897                },
12898                window,
12899                cx,
12900            );
12901            this.backspace(&Backspace, window, cx);
12902        });
12903    }
12904
12905    pub fn move_to_end_of_line(
12906        &mut self,
12907        action: &MoveToEndOfLine,
12908        window: &mut Window,
12909        cx: &mut Context<Self>,
12910    ) {
12911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12912        self.change_selections(Default::default(), window, cx, |s| {
12913            s.move_cursors_with(|map, head, _| {
12914                (
12915                    movement::line_end(map, head, action.stop_at_soft_wraps),
12916                    SelectionGoal::None,
12917                )
12918            });
12919        })
12920    }
12921
12922    pub fn select_to_end_of_line(
12923        &mut self,
12924        action: &SelectToEndOfLine,
12925        window: &mut Window,
12926        cx: &mut Context<Self>,
12927    ) {
12928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12929        self.change_selections(Default::default(), window, cx, |s| {
12930            s.move_heads_with(|map, head, _| {
12931                (
12932                    movement::line_end(map, head, action.stop_at_soft_wraps),
12933                    SelectionGoal::None,
12934                )
12935            });
12936        })
12937    }
12938
12939    pub fn delete_to_end_of_line(
12940        &mut self,
12941        _: &DeleteToEndOfLine,
12942        window: &mut Window,
12943        cx: &mut Context<Self>,
12944    ) {
12945        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12946        self.transact(window, cx, |this, window, cx| {
12947            this.select_to_end_of_line(
12948                &SelectToEndOfLine {
12949                    stop_at_soft_wraps: false,
12950                },
12951                window,
12952                cx,
12953            );
12954            this.delete(&Delete, window, cx);
12955        });
12956    }
12957
12958    pub fn cut_to_end_of_line(
12959        &mut self,
12960        _: &CutToEndOfLine,
12961        window: &mut Window,
12962        cx: &mut Context<Self>,
12963    ) {
12964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12965        self.transact(window, cx, |this, window, cx| {
12966            this.select_to_end_of_line(
12967                &SelectToEndOfLine {
12968                    stop_at_soft_wraps: false,
12969                },
12970                window,
12971                cx,
12972            );
12973            this.cut(&Cut, window, cx);
12974        });
12975    }
12976
12977    pub fn move_to_start_of_paragraph(
12978        &mut self,
12979        _: &MoveToStartOfParagraph,
12980        window: &mut Window,
12981        cx: &mut Context<Self>,
12982    ) {
12983        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12984            cx.propagate();
12985            return;
12986        }
12987        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12988        self.change_selections(Default::default(), window, cx, |s| {
12989            s.move_with(|map, selection| {
12990                selection.collapse_to(
12991                    movement::start_of_paragraph(map, selection.head(), 1),
12992                    SelectionGoal::None,
12993                )
12994            });
12995        })
12996    }
12997
12998    pub fn move_to_end_of_paragraph(
12999        &mut self,
13000        _: &MoveToEndOfParagraph,
13001        window: &mut Window,
13002        cx: &mut Context<Self>,
13003    ) {
13004        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13005            cx.propagate();
13006            return;
13007        }
13008        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13009        self.change_selections(Default::default(), window, cx, |s| {
13010            s.move_with(|map, selection| {
13011                selection.collapse_to(
13012                    movement::end_of_paragraph(map, selection.head(), 1),
13013                    SelectionGoal::None,
13014                )
13015            });
13016        })
13017    }
13018
13019    pub fn select_to_start_of_paragraph(
13020        &mut self,
13021        _: &SelectToStartOfParagraph,
13022        window: &mut Window,
13023        cx: &mut Context<Self>,
13024    ) {
13025        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13026            cx.propagate();
13027            return;
13028        }
13029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13030        self.change_selections(Default::default(), window, cx, |s| {
13031            s.move_heads_with(|map, head, _| {
13032                (
13033                    movement::start_of_paragraph(map, head, 1),
13034                    SelectionGoal::None,
13035                )
13036            });
13037        })
13038    }
13039
13040    pub fn select_to_end_of_paragraph(
13041        &mut self,
13042        _: &SelectToEndOfParagraph,
13043        window: &mut Window,
13044        cx: &mut Context<Self>,
13045    ) {
13046        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13047            cx.propagate();
13048            return;
13049        }
13050        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13051        self.change_selections(Default::default(), window, cx, |s| {
13052            s.move_heads_with(|map, head, _| {
13053                (
13054                    movement::end_of_paragraph(map, head, 1),
13055                    SelectionGoal::None,
13056                )
13057            });
13058        })
13059    }
13060
13061    pub fn move_to_start_of_excerpt(
13062        &mut self,
13063        _: &MoveToStartOfExcerpt,
13064        window: &mut Window,
13065        cx: &mut Context<Self>,
13066    ) {
13067        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13068            cx.propagate();
13069            return;
13070        }
13071        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13072        self.change_selections(Default::default(), window, cx, |s| {
13073            s.move_with(|map, selection| {
13074                selection.collapse_to(
13075                    movement::start_of_excerpt(
13076                        map,
13077                        selection.head(),
13078                        workspace::searchable::Direction::Prev,
13079                    ),
13080                    SelectionGoal::None,
13081                )
13082            });
13083        })
13084    }
13085
13086    pub fn move_to_start_of_next_excerpt(
13087        &mut self,
13088        _: &MoveToStartOfNextExcerpt,
13089        window: &mut Window,
13090        cx: &mut Context<Self>,
13091    ) {
13092        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13093            cx.propagate();
13094            return;
13095        }
13096
13097        self.change_selections(Default::default(), window, cx, |s| {
13098            s.move_with(|map, selection| {
13099                selection.collapse_to(
13100                    movement::start_of_excerpt(
13101                        map,
13102                        selection.head(),
13103                        workspace::searchable::Direction::Next,
13104                    ),
13105                    SelectionGoal::None,
13106                )
13107            });
13108        })
13109    }
13110
13111    pub fn move_to_end_of_excerpt(
13112        &mut self,
13113        _: &MoveToEndOfExcerpt,
13114        window: &mut Window,
13115        cx: &mut Context<Self>,
13116    ) {
13117        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13118            cx.propagate();
13119            return;
13120        }
13121        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13122        self.change_selections(Default::default(), window, cx, |s| {
13123            s.move_with(|map, selection| {
13124                selection.collapse_to(
13125                    movement::end_of_excerpt(
13126                        map,
13127                        selection.head(),
13128                        workspace::searchable::Direction::Next,
13129                    ),
13130                    SelectionGoal::None,
13131                )
13132            });
13133        })
13134    }
13135
13136    pub fn move_to_end_of_previous_excerpt(
13137        &mut self,
13138        _: &MoveToEndOfPreviousExcerpt,
13139        window: &mut Window,
13140        cx: &mut Context<Self>,
13141    ) {
13142        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13143            cx.propagate();
13144            return;
13145        }
13146        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13147        self.change_selections(Default::default(), window, cx, |s| {
13148            s.move_with(|map, selection| {
13149                selection.collapse_to(
13150                    movement::end_of_excerpt(
13151                        map,
13152                        selection.head(),
13153                        workspace::searchable::Direction::Prev,
13154                    ),
13155                    SelectionGoal::None,
13156                )
13157            });
13158        })
13159    }
13160
13161    pub fn select_to_start_of_excerpt(
13162        &mut self,
13163        _: &SelectToStartOfExcerpt,
13164        window: &mut Window,
13165        cx: &mut Context<Self>,
13166    ) {
13167        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13168            cx.propagate();
13169            return;
13170        }
13171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13172        self.change_selections(Default::default(), window, cx, |s| {
13173            s.move_heads_with(|map, head, _| {
13174                (
13175                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13176                    SelectionGoal::None,
13177                )
13178            });
13179        })
13180    }
13181
13182    pub fn select_to_start_of_next_excerpt(
13183        &mut self,
13184        _: &SelectToStartOfNextExcerpt,
13185        window: &mut Window,
13186        cx: &mut Context<Self>,
13187    ) {
13188        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13189            cx.propagate();
13190            return;
13191        }
13192        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13193        self.change_selections(Default::default(), window, cx, |s| {
13194            s.move_heads_with(|map, head, _| {
13195                (
13196                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13197                    SelectionGoal::None,
13198                )
13199            });
13200        })
13201    }
13202
13203    pub fn select_to_end_of_excerpt(
13204        &mut self,
13205        _: &SelectToEndOfExcerpt,
13206        window: &mut Window,
13207        cx: &mut Context<Self>,
13208    ) {
13209        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13210            cx.propagate();
13211            return;
13212        }
13213        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13214        self.change_selections(Default::default(), window, cx, |s| {
13215            s.move_heads_with(|map, head, _| {
13216                (
13217                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13218                    SelectionGoal::None,
13219                )
13220            });
13221        })
13222    }
13223
13224    pub fn select_to_end_of_previous_excerpt(
13225        &mut self,
13226        _: &SelectToEndOfPreviousExcerpt,
13227        window: &mut Window,
13228        cx: &mut Context<Self>,
13229    ) {
13230        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13231            cx.propagate();
13232            return;
13233        }
13234        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13235        self.change_selections(Default::default(), window, cx, |s| {
13236            s.move_heads_with(|map, head, _| {
13237                (
13238                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13239                    SelectionGoal::None,
13240                )
13241            });
13242        })
13243    }
13244
13245    pub fn move_to_beginning(
13246        &mut self,
13247        _: &MoveToBeginning,
13248        window: &mut Window,
13249        cx: &mut Context<Self>,
13250    ) {
13251        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13252            cx.propagate();
13253            return;
13254        }
13255        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13256        self.change_selections(Default::default(), window, cx, |s| {
13257            s.select_ranges(vec![0..0]);
13258        });
13259    }
13260
13261    pub fn select_to_beginning(
13262        &mut self,
13263        _: &SelectToBeginning,
13264        window: &mut Window,
13265        cx: &mut Context<Self>,
13266    ) {
13267        let mut selection = self.selections.last::<Point>(cx);
13268        selection.set_head(Point::zero(), SelectionGoal::None);
13269        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13270        self.change_selections(Default::default(), window, cx, |s| {
13271            s.select(vec![selection]);
13272        });
13273    }
13274
13275    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13276        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13277            cx.propagate();
13278            return;
13279        }
13280        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13281        let cursor = self.buffer.read(cx).read(cx).len();
13282        self.change_selections(Default::default(), window, cx, |s| {
13283            s.select_ranges(vec![cursor..cursor])
13284        });
13285    }
13286
13287    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13288        self.nav_history = nav_history;
13289    }
13290
13291    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13292        self.nav_history.as_ref()
13293    }
13294
13295    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13296        self.push_to_nav_history(
13297            self.selections.newest_anchor().head(),
13298            None,
13299            false,
13300            true,
13301            cx,
13302        );
13303    }
13304
13305    fn push_to_nav_history(
13306        &mut self,
13307        cursor_anchor: Anchor,
13308        new_position: Option<Point>,
13309        is_deactivate: bool,
13310        always: bool,
13311        cx: &mut Context<Self>,
13312    ) {
13313        if let Some(nav_history) = self.nav_history.as_mut() {
13314            let buffer = self.buffer.read(cx).read(cx);
13315            let cursor_position = cursor_anchor.to_point(&buffer);
13316            let scroll_state = self.scroll_manager.anchor();
13317            let scroll_top_row = scroll_state.top_row(&buffer);
13318            drop(buffer);
13319
13320            if let Some(new_position) = new_position {
13321                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13322                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13323                    return;
13324                }
13325            }
13326
13327            nav_history.push(
13328                Some(NavigationData {
13329                    cursor_anchor,
13330                    cursor_position,
13331                    scroll_anchor: scroll_state,
13332                    scroll_top_row,
13333                }),
13334                cx,
13335            );
13336            cx.emit(EditorEvent::PushedToNavHistory {
13337                anchor: cursor_anchor,
13338                is_deactivate,
13339            })
13340        }
13341    }
13342
13343    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13345        let buffer = self.buffer.read(cx).snapshot(cx);
13346        let mut selection = self.selections.first::<usize>(cx);
13347        selection.set_head(buffer.len(), SelectionGoal::None);
13348        self.change_selections(Default::default(), window, cx, |s| {
13349            s.select(vec![selection]);
13350        });
13351    }
13352
13353    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13354        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13355        let end = self.buffer.read(cx).read(cx).len();
13356        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13357            s.select_ranges(vec![0..end]);
13358        });
13359    }
13360
13361    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13363        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13364        let mut selections = self.selections.all::<Point>(cx);
13365        let max_point = display_map.buffer_snapshot.max_point();
13366        for selection in &mut selections {
13367            let rows = selection.spanned_rows(true, &display_map);
13368            selection.start = Point::new(rows.start.0, 0);
13369            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13370            selection.reversed = false;
13371        }
13372        self.change_selections(Default::default(), window, cx, |s| {
13373            s.select(selections);
13374        });
13375    }
13376
13377    pub fn split_selection_into_lines(
13378        &mut self,
13379        _: &SplitSelectionIntoLines,
13380        window: &mut Window,
13381        cx: &mut Context<Self>,
13382    ) {
13383        let selections = self
13384            .selections
13385            .all::<Point>(cx)
13386            .into_iter()
13387            .map(|selection| selection.start..selection.end)
13388            .collect::<Vec<_>>();
13389        self.unfold_ranges(&selections, true, true, cx);
13390
13391        let mut new_selection_ranges = Vec::new();
13392        {
13393            let buffer = self.buffer.read(cx).read(cx);
13394            for selection in selections {
13395                for row in selection.start.row..selection.end.row {
13396                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13397                    new_selection_ranges.push(cursor..cursor);
13398                }
13399
13400                let is_multiline_selection = selection.start.row != selection.end.row;
13401                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13402                // so this action feels more ergonomic when paired with other selection operations
13403                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13404                if !should_skip_last {
13405                    new_selection_ranges.push(selection.end..selection.end);
13406                }
13407            }
13408        }
13409        self.change_selections(Default::default(), window, cx, |s| {
13410            s.select_ranges(new_selection_ranges);
13411        });
13412    }
13413
13414    pub fn add_selection_above(
13415        &mut self,
13416        _: &AddSelectionAbove,
13417        window: &mut Window,
13418        cx: &mut Context<Self>,
13419    ) {
13420        self.add_selection(true, window, cx);
13421    }
13422
13423    pub fn add_selection_below(
13424        &mut self,
13425        _: &AddSelectionBelow,
13426        window: &mut Window,
13427        cx: &mut Context<Self>,
13428    ) {
13429        self.add_selection(false, window, cx);
13430    }
13431
13432    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13433        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13434
13435        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13436        let all_selections = self.selections.all::<Point>(cx);
13437        let text_layout_details = self.text_layout_details(window);
13438
13439        let (mut columnar_selections, new_selections_to_columnarize) = {
13440            if let Some(state) = self.add_selections_state.as_ref() {
13441                let columnar_selection_ids: HashSet<_> = state
13442                    .groups
13443                    .iter()
13444                    .flat_map(|group| group.stack.iter())
13445                    .copied()
13446                    .collect();
13447
13448                all_selections
13449                    .into_iter()
13450                    .partition(|s| columnar_selection_ids.contains(&s.id))
13451            } else {
13452                (Vec::new(), all_selections)
13453            }
13454        };
13455
13456        let mut state = self
13457            .add_selections_state
13458            .take()
13459            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13460
13461        for selection in new_selections_to_columnarize {
13462            let range = selection.display_range(&display_map).sorted();
13463            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13464            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13465            let positions = start_x.min(end_x)..start_x.max(end_x);
13466            let mut stack = Vec::new();
13467            for row in range.start.row().0..=range.end.row().0 {
13468                if let Some(selection) = self.selections.build_columnar_selection(
13469                    &display_map,
13470                    DisplayRow(row),
13471                    &positions,
13472                    selection.reversed,
13473                    &text_layout_details,
13474                ) {
13475                    stack.push(selection.id);
13476                    columnar_selections.push(selection);
13477                }
13478            }
13479            if !stack.is_empty() {
13480                if above {
13481                    stack.reverse();
13482                }
13483                state.groups.push(AddSelectionsGroup { above, stack });
13484            }
13485        }
13486
13487        let mut final_selections = Vec::new();
13488        let end_row = if above {
13489            DisplayRow(0)
13490        } else {
13491            display_map.max_point().row()
13492        };
13493
13494        let mut last_added_item_per_group = HashMap::default();
13495        for group in state.groups.iter_mut() {
13496            if let Some(last_id) = group.stack.last() {
13497                last_added_item_per_group.insert(*last_id, group);
13498            }
13499        }
13500
13501        for selection in columnar_selections {
13502            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13503                if above == group.above {
13504                    let range = selection.display_range(&display_map).sorted();
13505                    debug_assert_eq!(range.start.row(), range.end.row());
13506                    let mut row = range.start.row();
13507                    let positions =
13508                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13509                            px(start)..px(end)
13510                        } else {
13511                            let start_x =
13512                                display_map.x_for_display_point(range.start, &text_layout_details);
13513                            let end_x =
13514                                display_map.x_for_display_point(range.end, &text_layout_details);
13515                            start_x.min(end_x)..start_x.max(end_x)
13516                        };
13517
13518                    let mut maybe_new_selection = None;
13519                    while row != end_row {
13520                        if above {
13521                            row.0 -= 1;
13522                        } else {
13523                            row.0 += 1;
13524                        }
13525                        if let Some(new_selection) = self.selections.build_columnar_selection(
13526                            &display_map,
13527                            row,
13528                            &positions,
13529                            selection.reversed,
13530                            &text_layout_details,
13531                        ) {
13532                            maybe_new_selection = Some(new_selection);
13533                            break;
13534                        }
13535                    }
13536
13537                    if let Some(new_selection) = maybe_new_selection {
13538                        group.stack.push(new_selection.id);
13539                        if above {
13540                            final_selections.push(new_selection);
13541                            final_selections.push(selection);
13542                        } else {
13543                            final_selections.push(selection);
13544                            final_selections.push(new_selection);
13545                        }
13546                    } else {
13547                        final_selections.push(selection);
13548                    }
13549                } else {
13550                    group.stack.pop();
13551                }
13552            } else {
13553                final_selections.push(selection);
13554            }
13555        }
13556
13557        self.change_selections(Default::default(), window, cx, |s| {
13558            s.select(final_selections);
13559        });
13560
13561        let final_selection_ids: HashSet<_> = self
13562            .selections
13563            .all::<Point>(cx)
13564            .iter()
13565            .map(|s| s.id)
13566            .collect();
13567        state.groups.retain_mut(|group| {
13568            // selections might get merged above so we remove invalid items from stacks
13569            group.stack.retain(|id| final_selection_ids.contains(id));
13570
13571            // single selection in stack can be treated as initial state
13572            group.stack.len() > 1
13573        });
13574
13575        if !state.groups.is_empty() {
13576            self.add_selections_state = Some(state);
13577        }
13578    }
13579
13580    fn select_match_ranges(
13581        &mut self,
13582        range: Range<usize>,
13583        reversed: bool,
13584        replace_newest: bool,
13585        auto_scroll: Option<Autoscroll>,
13586        window: &mut Window,
13587        cx: &mut Context<Editor>,
13588    ) {
13589        self.unfold_ranges(
13590            std::slice::from_ref(&range),
13591            false,
13592            auto_scroll.is_some(),
13593            cx,
13594        );
13595        let effects = if let Some(scroll) = auto_scroll {
13596            SelectionEffects::scroll(scroll)
13597        } else {
13598            SelectionEffects::no_scroll()
13599        };
13600        self.change_selections(effects, window, cx, |s| {
13601            if replace_newest {
13602                s.delete(s.newest_anchor().id);
13603            }
13604            if reversed {
13605                s.insert_range(range.end..range.start);
13606            } else {
13607                s.insert_range(range);
13608            }
13609        });
13610    }
13611
13612    pub fn select_next_match_internal(
13613        &mut self,
13614        display_map: &DisplaySnapshot,
13615        replace_newest: bool,
13616        autoscroll: Option<Autoscroll>,
13617        window: &mut Window,
13618        cx: &mut Context<Self>,
13619    ) -> Result<()> {
13620        let buffer = &display_map.buffer_snapshot;
13621        let mut selections = self.selections.all::<usize>(cx);
13622        if let Some(mut select_next_state) = self.select_next_state.take() {
13623            let query = &select_next_state.query;
13624            if !select_next_state.done {
13625                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13626                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13627                let mut next_selected_range = None;
13628
13629                let bytes_after_last_selection =
13630                    buffer.bytes_in_range(last_selection.end..buffer.len());
13631                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13632                let query_matches = query
13633                    .stream_find_iter(bytes_after_last_selection)
13634                    .map(|result| (last_selection.end, result))
13635                    .chain(
13636                        query
13637                            .stream_find_iter(bytes_before_first_selection)
13638                            .map(|result| (0, result)),
13639                    );
13640
13641                for (start_offset, query_match) in query_matches {
13642                    let query_match = query_match.unwrap(); // can only fail due to I/O
13643                    let offset_range =
13644                        start_offset + query_match.start()..start_offset + query_match.end();
13645
13646                    if !select_next_state.wordwise
13647                        || (!buffer.is_inside_word(offset_range.start, false)
13648                            && !buffer.is_inside_word(offset_range.end, false))
13649                    {
13650                        // TODO: This is n^2, because we might check all the selections
13651                        if !selections
13652                            .iter()
13653                            .any(|selection| selection.range().overlaps(&offset_range))
13654                        {
13655                            next_selected_range = Some(offset_range);
13656                            break;
13657                        }
13658                    }
13659                }
13660
13661                if let Some(next_selected_range) = next_selected_range {
13662                    self.select_match_ranges(
13663                        next_selected_range,
13664                        last_selection.reversed,
13665                        replace_newest,
13666                        autoscroll,
13667                        window,
13668                        cx,
13669                    );
13670                } else {
13671                    select_next_state.done = true;
13672                }
13673            }
13674
13675            self.select_next_state = Some(select_next_state);
13676        } else {
13677            let mut only_carets = true;
13678            let mut same_text_selected = true;
13679            let mut selected_text = None;
13680
13681            let mut selections_iter = selections.iter().peekable();
13682            while let Some(selection) = selections_iter.next() {
13683                if selection.start != selection.end {
13684                    only_carets = false;
13685                }
13686
13687                if same_text_selected {
13688                    if selected_text.is_none() {
13689                        selected_text =
13690                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13691                    }
13692
13693                    if let Some(next_selection) = selections_iter.peek() {
13694                        if next_selection.range().len() == selection.range().len() {
13695                            let next_selected_text = buffer
13696                                .text_for_range(next_selection.range())
13697                                .collect::<String>();
13698                            if Some(next_selected_text) != selected_text {
13699                                same_text_selected = false;
13700                                selected_text = None;
13701                            }
13702                        } else {
13703                            same_text_selected = false;
13704                            selected_text = None;
13705                        }
13706                    }
13707                }
13708            }
13709
13710            if only_carets {
13711                for selection in &mut selections {
13712                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13713                    selection.start = word_range.start;
13714                    selection.end = word_range.end;
13715                    selection.goal = SelectionGoal::None;
13716                    selection.reversed = false;
13717                    self.select_match_ranges(
13718                        selection.start..selection.end,
13719                        selection.reversed,
13720                        replace_newest,
13721                        autoscroll,
13722                        window,
13723                        cx,
13724                    );
13725                }
13726
13727                if selections.len() == 1 {
13728                    let selection = selections
13729                        .last()
13730                        .expect("ensured that there's only one selection");
13731                    let query = buffer
13732                        .text_for_range(selection.start..selection.end)
13733                        .collect::<String>();
13734                    let is_empty = query.is_empty();
13735                    let select_state = SelectNextState {
13736                        query: AhoCorasick::new(&[query])?,
13737                        wordwise: true,
13738                        done: is_empty,
13739                    };
13740                    self.select_next_state = Some(select_state);
13741                } else {
13742                    self.select_next_state = None;
13743                }
13744            } else if let Some(selected_text) = selected_text {
13745                self.select_next_state = Some(SelectNextState {
13746                    query: AhoCorasick::new(&[selected_text])?,
13747                    wordwise: false,
13748                    done: false,
13749                });
13750                self.select_next_match_internal(
13751                    display_map,
13752                    replace_newest,
13753                    autoscroll,
13754                    window,
13755                    cx,
13756                )?;
13757            }
13758        }
13759        Ok(())
13760    }
13761
13762    pub fn select_all_matches(
13763        &mut self,
13764        _action: &SelectAllMatches,
13765        window: &mut Window,
13766        cx: &mut Context<Self>,
13767    ) -> Result<()> {
13768        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13769
13770        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13771
13772        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13773        let Some(select_next_state) = self.select_next_state.as_mut() else {
13774            return Ok(());
13775        };
13776        if select_next_state.done {
13777            return Ok(());
13778        }
13779
13780        let mut new_selections = Vec::new();
13781
13782        let reversed = self.selections.oldest::<usize>(cx).reversed;
13783        let buffer = &display_map.buffer_snapshot;
13784        let query_matches = select_next_state
13785            .query
13786            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13787
13788        for query_match in query_matches.into_iter() {
13789            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13790            let offset_range = if reversed {
13791                query_match.end()..query_match.start()
13792            } else {
13793                query_match.start()..query_match.end()
13794            };
13795
13796            if !select_next_state.wordwise
13797                || (!buffer.is_inside_word(offset_range.start, false)
13798                    && !buffer.is_inside_word(offset_range.end, false))
13799            {
13800                new_selections.push(offset_range.start..offset_range.end);
13801            }
13802        }
13803
13804        select_next_state.done = true;
13805
13806        if new_selections.is_empty() {
13807            log::error!("bug: new_selections is empty in select_all_matches");
13808            return Ok(());
13809        }
13810
13811        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13812        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13813            selections.select_ranges(new_selections)
13814        });
13815
13816        Ok(())
13817    }
13818
13819    pub fn select_next(
13820        &mut self,
13821        action: &SelectNext,
13822        window: &mut Window,
13823        cx: &mut Context<Self>,
13824    ) -> Result<()> {
13825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13826        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13827        self.select_next_match_internal(
13828            &display_map,
13829            action.replace_newest,
13830            Some(Autoscroll::newest()),
13831            window,
13832            cx,
13833        )?;
13834        Ok(())
13835    }
13836
13837    pub fn select_previous(
13838        &mut self,
13839        action: &SelectPrevious,
13840        window: &mut Window,
13841        cx: &mut Context<Self>,
13842    ) -> Result<()> {
13843        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13844        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13845        let buffer = &display_map.buffer_snapshot;
13846        let mut selections = self.selections.all::<usize>(cx);
13847        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13848            let query = &select_prev_state.query;
13849            if !select_prev_state.done {
13850                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13851                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13852                let mut next_selected_range = None;
13853                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13854                let bytes_before_last_selection =
13855                    buffer.reversed_bytes_in_range(0..last_selection.start);
13856                let bytes_after_first_selection =
13857                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13858                let query_matches = query
13859                    .stream_find_iter(bytes_before_last_selection)
13860                    .map(|result| (last_selection.start, result))
13861                    .chain(
13862                        query
13863                            .stream_find_iter(bytes_after_first_selection)
13864                            .map(|result| (buffer.len(), result)),
13865                    );
13866                for (end_offset, query_match) in query_matches {
13867                    let query_match = query_match.unwrap(); // can only fail due to I/O
13868                    let offset_range =
13869                        end_offset - query_match.end()..end_offset - query_match.start();
13870
13871                    if !select_prev_state.wordwise
13872                        || (!buffer.is_inside_word(offset_range.start, false)
13873                            && !buffer.is_inside_word(offset_range.end, false))
13874                    {
13875                        next_selected_range = Some(offset_range);
13876                        break;
13877                    }
13878                }
13879
13880                if let Some(next_selected_range) = next_selected_range {
13881                    self.select_match_ranges(
13882                        next_selected_range,
13883                        last_selection.reversed,
13884                        action.replace_newest,
13885                        Some(Autoscroll::newest()),
13886                        window,
13887                        cx,
13888                    );
13889                } else {
13890                    select_prev_state.done = true;
13891                }
13892            }
13893
13894            self.select_prev_state = Some(select_prev_state);
13895        } else {
13896            let mut only_carets = true;
13897            let mut same_text_selected = true;
13898            let mut selected_text = None;
13899
13900            let mut selections_iter = selections.iter().peekable();
13901            while let Some(selection) = selections_iter.next() {
13902                if selection.start != selection.end {
13903                    only_carets = false;
13904                }
13905
13906                if same_text_selected {
13907                    if selected_text.is_none() {
13908                        selected_text =
13909                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13910                    }
13911
13912                    if let Some(next_selection) = selections_iter.peek() {
13913                        if next_selection.range().len() == selection.range().len() {
13914                            let next_selected_text = buffer
13915                                .text_for_range(next_selection.range())
13916                                .collect::<String>();
13917                            if Some(next_selected_text) != selected_text {
13918                                same_text_selected = false;
13919                                selected_text = None;
13920                            }
13921                        } else {
13922                            same_text_selected = false;
13923                            selected_text = None;
13924                        }
13925                    }
13926                }
13927            }
13928
13929            if only_carets {
13930                for selection in &mut selections {
13931                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13932                    selection.start = word_range.start;
13933                    selection.end = word_range.end;
13934                    selection.goal = SelectionGoal::None;
13935                    selection.reversed = false;
13936                    self.select_match_ranges(
13937                        selection.start..selection.end,
13938                        selection.reversed,
13939                        action.replace_newest,
13940                        Some(Autoscroll::newest()),
13941                        window,
13942                        cx,
13943                    );
13944                }
13945                if selections.len() == 1 {
13946                    let selection = selections
13947                        .last()
13948                        .expect("ensured that there's only one selection");
13949                    let query = buffer
13950                        .text_for_range(selection.start..selection.end)
13951                        .collect::<String>();
13952                    let is_empty = query.is_empty();
13953                    let select_state = SelectNextState {
13954                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13955                        wordwise: true,
13956                        done: is_empty,
13957                    };
13958                    self.select_prev_state = Some(select_state);
13959                } else {
13960                    self.select_prev_state = None;
13961                }
13962            } else if let Some(selected_text) = selected_text {
13963                self.select_prev_state = Some(SelectNextState {
13964                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13965                    wordwise: false,
13966                    done: false,
13967                });
13968                self.select_previous(action, window, cx)?;
13969            }
13970        }
13971        Ok(())
13972    }
13973
13974    pub fn find_next_match(
13975        &mut self,
13976        _: &FindNextMatch,
13977        window: &mut Window,
13978        cx: &mut Context<Self>,
13979    ) -> Result<()> {
13980        let selections = self.selections.disjoint_anchors();
13981        match selections.first() {
13982            Some(first) if selections.len() >= 2 => {
13983                self.change_selections(Default::default(), window, cx, |s| {
13984                    s.select_ranges([first.range()]);
13985                });
13986            }
13987            _ => self.select_next(
13988                &SelectNext {
13989                    replace_newest: true,
13990                },
13991                window,
13992                cx,
13993            )?,
13994        }
13995        Ok(())
13996    }
13997
13998    pub fn find_previous_match(
13999        &mut self,
14000        _: &FindPreviousMatch,
14001        window: &mut Window,
14002        cx: &mut Context<Self>,
14003    ) -> Result<()> {
14004        let selections = self.selections.disjoint_anchors();
14005        match selections.last() {
14006            Some(last) if selections.len() >= 2 => {
14007                self.change_selections(Default::default(), window, cx, |s| {
14008                    s.select_ranges([last.range()]);
14009                });
14010            }
14011            _ => self.select_previous(
14012                &SelectPrevious {
14013                    replace_newest: true,
14014                },
14015                window,
14016                cx,
14017            )?,
14018        }
14019        Ok(())
14020    }
14021
14022    pub fn toggle_comments(
14023        &mut self,
14024        action: &ToggleComments,
14025        window: &mut Window,
14026        cx: &mut Context<Self>,
14027    ) {
14028        if self.read_only(cx) {
14029            return;
14030        }
14031        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14032        let text_layout_details = &self.text_layout_details(window);
14033        self.transact(window, cx, |this, window, cx| {
14034            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14035            let mut edits = Vec::new();
14036            let mut selection_edit_ranges = Vec::new();
14037            let mut last_toggled_row = None;
14038            let snapshot = this.buffer.read(cx).read(cx);
14039            let empty_str: Arc<str> = Arc::default();
14040            let mut suffixes_inserted = Vec::new();
14041            let ignore_indent = action.ignore_indent;
14042
14043            fn comment_prefix_range(
14044                snapshot: &MultiBufferSnapshot,
14045                row: MultiBufferRow,
14046                comment_prefix: &str,
14047                comment_prefix_whitespace: &str,
14048                ignore_indent: bool,
14049            ) -> Range<Point> {
14050                let indent_size = if ignore_indent {
14051                    0
14052                } else {
14053                    snapshot.indent_size_for_line(row).len
14054                };
14055
14056                let start = Point::new(row.0, indent_size);
14057
14058                let mut line_bytes = snapshot
14059                    .bytes_in_range(start..snapshot.max_point())
14060                    .flatten()
14061                    .copied();
14062
14063                // If this line currently begins with the line comment prefix, then record
14064                // the range containing the prefix.
14065                if line_bytes
14066                    .by_ref()
14067                    .take(comment_prefix.len())
14068                    .eq(comment_prefix.bytes())
14069                {
14070                    // Include any whitespace that matches the comment prefix.
14071                    let matching_whitespace_len = line_bytes
14072                        .zip(comment_prefix_whitespace.bytes())
14073                        .take_while(|(a, b)| a == b)
14074                        .count() as u32;
14075                    let end = Point::new(
14076                        start.row,
14077                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14078                    );
14079                    start..end
14080                } else {
14081                    start..start
14082                }
14083            }
14084
14085            fn comment_suffix_range(
14086                snapshot: &MultiBufferSnapshot,
14087                row: MultiBufferRow,
14088                comment_suffix: &str,
14089                comment_suffix_has_leading_space: bool,
14090            ) -> Range<Point> {
14091                let end = Point::new(row.0, snapshot.line_len(row));
14092                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14093
14094                let mut line_end_bytes = snapshot
14095                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14096                    .flatten()
14097                    .copied();
14098
14099                let leading_space_len = if suffix_start_column > 0
14100                    && line_end_bytes.next() == Some(b' ')
14101                    && comment_suffix_has_leading_space
14102                {
14103                    1
14104                } else {
14105                    0
14106                };
14107
14108                // If this line currently begins with the line comment prefix, then record
14109                // the range containing the prefix.
14110                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14111                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14112                    start..end
14113                } else {
14114                    end..end
14115                }
14116            }
14117
14118            // TODO: Handle selections that cross excerpts
14119            for selection in &mut selections {
14120                let start_column = snapshot
14121                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14122                    .len;
14123                let language = if let Some(language) =
14124                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14125                {
14126                    language
14127                } else {
14128                    continue;
14129                };
14130
14131                selection_edit_ranges.clear();
14132
14133                // If multiple selections contain a given row, avoid processing that
14134                // row more than once.
14135                let mut start_row = MultiBufferRow(selection.start.row);
14136                if last_toggled_row == Some(start_row) {
14137                    start_row = start_row.next_row();
14138                }
14139                let end_row =
14140                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14141                        MultiBufferRow(selection.end.row - 1)
14142                    } else {
14143                        MultiBufferRow(selection.end.row)
14144                    };
14145                last_toggled_row = Some(end_row);
14146
14147                if start_row > end_row {
14148                    continue;
14149                }
14150
14151                // If the language has line comments, toggle those.
14152                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14153
14154                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14155                if ignore_indent {
14156                    full_comment_prefixes = full_comment_prefixes
14157                        .into_iter()
14158                        .map(|s| Arc::from(s.trim_end()))
14159                        .collect();
14160                }
14161
14162                if !full_comment_prefixes.is_empty() {
14163                    let first_prefix = full_comment_prefixes
14164                        .first()
14165                        .expect("prefixes is non-empty");
14166                    let prefix_trimmed_lengths = full_comment_prefixes
14167                        .iter()
14168                        .map(|p| p.trim_end_matches(' ').len())
14169                        .collect::<SmallVec<[usize; 4]>>();
14170
14171                    let mut all_selection_lines_are_comments = true;
14172
14173                    for row in start_row.0..=end_row.0 {
14174                        let row = MultiBufferRow(row);
14175                        if start_row < end_row && snapshot.is_line_blank(row) {
14176                            continue;
14177                        }
14178
14179                        let prefix_range = full_comment_prefixes
14180                            .iter()
14181                            .zip(prefix_trimmed_lengths.iter().copied())
14182                            .map(|(prefix, trimmed_prefix_len)| {
14183                                comment_prefix_range(
14184                                    snapshot.deref(),
14185                                    row,
14186                                    &prefix[..trimmed_prefix_len],
14187                                    &prefix[trimmed_prefix_len..],
14188                                    ignore_indent,
14189                                )
14190                            })
14191                            .max_by_key(|range| range.end.column - range.start.column)
14192                            .expect("prefixes is non-empty");
14193
14194                        if prefix_range.is_empty() {
14195                            all_selection_lines_are_comments = false;
14196                        }
14197
14198                        selection_edit_ranges.push(prefix_range);
14199                    }
14200
14201                    if all_selection_lines_are_comments {
14202                        edits.extend(
14203                            selection_edit_ranges
14204                                .iter()
14205                                .cloned()
14206                                .map(|range| (range, empty_str.clone())),
14207                        );
14208                    } else {
14209                        let min_column = selection_edit_ranges
14210                            .iter()
14211                            .map(|range| range.start.column)
14212                            .min()
14213                            .unwrap_or(0);
14214                        edits.extend(selection_edit_ranges.iter().map(|range| {
14215                            let position = Point::new(range.start.row, min_column);
14216                            (position..position, first_prefix.clone())
14217                        }));
14218                    }
14219                } else if let Some((full_comment_prefix, comment_suffix)) =
14220                    language.block_comment_delimiters()
14221                {
14222                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14223                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14224                    let prefix_range = comment_prefix_range(
14225                        snapshot.deref(),
14226                        start_row,
14227                        comment_prefix,
14228                        comment_prefix_whitespace,
14229                        ignore_indent,
14230                    );
14231                    let suffix_range = comment_suffix_range(
14232                        snapshot.deref(),
14233                        end_row,
14234                        comment_suffix.trim_start_matches(' '),
14235                        comment_suffix.starts_with(' '),
14236                    );
14237
14238                    if prefix_range.is_empty() || suffix_range.is_empty() {
14239                        edits.push((
14240                            prefix_range.start..prefix_range.start,
14241                            full_comment_prefix.clone(),
14242                        ));
14243                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14244                        suffixes_inserted.push((end_row, comment_suffix.len()));
14245                    } else {
14246                        edits.push((prefix_range, empty_str.clone()));
14247                        edits.push((suffix_range, empty_str.clone()));
14248                    }
14249                } else {
14250                    continue;
14251                }
14252            }
14253
14254            drop(snapshot);
14255            this.buffer.update(cx, |buffer, cx| {
14256                buffer.edit(edits, None, cx);
14257            });
14258
14259            // Adjust selections so that they end before any comment suffixes that
14260            // were inserted.
14261            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14262            let mut selections = this.selections.all::<Point>(cx);
14263            let snapshot = this.buffer.read(cx).read(cx);
14264            for selection in &mut selections {
14265                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14266                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14267                        Ordering::Less => {
14268                            suffixes_inserted.next();
14269                            continue;
14270                        }
14271                        Ordering::Greater => break,
14272                        Ordering::Equal => {
14273                            if selection.end.column == snapshot.line_len(row) {
14274                                if selection.is_empty() {
14275                                    selection.start.column -= suffix_len as u32;
14276                                }
14277                                selection.end.column -= suffix_len as u32;
14278                            }
14279                            break;
14280                        }
14281                    }
14282                }
14283            }
14284
14285            drop(snapshot);
14286            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14287
14288            let selections = this.selections.all::<Point>(cx);
14289            let selections_on_single_row = selections.windows(2).all(|selections| {
14290                selections[0].start.row == selections[1].start.row
14291                    && selections[0].end.row == selections[1].end.row
14292                    && selections[0].start.row == selections[0].end.row
14293            });
14294            let selections_selecting = selections
14295                .iter()
14296                .any(|selection| selection.start != selection.end);
14297            let advance_downwards = action.advance_downwards
14298                && selections_on_single_row
14299                && !selections_selecting
14300                && !matches!(this.mode, EditorMode::SingleLine { .. });
14301
14302            if advance_downwards {
14303                let snapshot = this.buffer.read(cx).snapshot(cx);
14304
14305                this.change_selections(Default::default(), window, cx, |s| {
14306                    s.move_cursors_with(|display_snapshot, display_point, _| {
14307                        let mut point = display_point.to_point(display_snapshot);
14308                        point.row += 1;
14309                        point = snapshot.clip_point(point, Bias::Left);
14310                        let display_point = point.to_display_point(display_snapshot);
14311                        let goal = SelectionGoal::HorizontalPosition(
14312                            display_snapshot
14313                                .x_for_display_point(display_point, text_layout_details)
14314                                .into(),
14315                        );
14316                        (display_point, goal)
14317                    })
14318                });
14319            }
14320        });
14321    }
14322
14323    pub fn select_enclosing_symbol(
14324        &mut self,
14325        _: &SelectEnclosingSymbol,
14326        window: &mut Window,
14327        cx: &mut Context<Self>,
14328    ) {
14329        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14330
14331        let buffer = self.buffer.read(cx).snapshot(cx);
14332        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14333
14334        fn update_selection(
14335            selection: &Selection<usize>,
14336            buffer_snap: &MultiBufferSnapshot,
14337        ) -> Option<Selection<usize>> {
14338            let cursor = selection.head();
14339            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14340            for symbol in symbols.iter().rev() {
14341                let start = symbol.range.start.to_offset(buffer_snap);
14342                let end = symbol.range.end.to_offset(buffer_snap);
14343                let new_range = start..end;
14344                if start < selection.start || end > selection.end {
14345                    return Some(Selection {
14346                        id: selection.id,
14347                        start: new_range.start,
14348                        end: new_range.end,
14349                        goal: SelectionGoal::None,
14350                        reversed: selection.reversed,
14351                    });
14352                }
14353            }
14354            None
14355        }
14356
14357        let mut selected_larger_symbol = false;
14358        let new_selections = old_selections
14359            .iter()
14360            .map(|selection| match update_selection(selection, &buffer) {
14361                Some(new_selection) => {
14362                    if new_selection.range() != selection.range() {
14363                        selected_larger_symbol = true;
14364                    }
14365                    new_selection
14366                }
14367                None => selection.clone(),
14368            })
14369            .collect::<Vec<_>>();
14370
14371        if selected_larger_symbol {
14372            self.change_selections(Default::default(), window, cx, |s| {
14373                s.select(new_selections);
14374            });
14375        }
14376    }
14377
14378    pub fn select_larger_syntax_node(
14379        &mut self,
14380        _: &SelectLargerSyntaxNode,
14381        window: &mut Window,
14382        cx: &mut Context<Self>,
14383    ) {
14384        let Some(visible_row_count) = self.visible_row_count() else {
14385            return;
14386        };
14387        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14388        if old_selections.is_empty() {
14389            return;
14390        }
14391
14392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14393
14394        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14395        let buffer = self.buffer.read(cx).snapshot(cx);
14396
14397        let mut selected_larger_node = false;
14398        let mut new_selections = old_selections
14399            .iter()
14400            .map(|selection| {
14401                let old_range = selection.start..selection.end;
14402
14403                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14404                    // manually select word at selection
14405                    if ["string_content", "inline"].contains(&node.kind()) {
14406                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14407                        // ignore if word is already selected
14408                        if !word_range.is_empty() && old_range != word_range {
14409                            let (last_word_range, _) =
14410                                buffer.surrounding_word(old_range.end, false);
14411                            // only select word if start and end point belongs to same word
14412                            if word_range == last_word_range {
14413                                selected_larger_node = true;
14414                                return Selection {
14415                                    id: selection.id,
14416                                    start: word_range.start,
14417                                    end: word_range.end,
14418                                    goal: SelectionGoal::None,
14419                                    reversed: selection.reversed,
14420                                };
14421                            }
14422                        }
14423                    }
14424                }
14425
14426                let mut new_range = old_range.clone();
14427                while let Some((_node, containing_range)) =
14428                    buffer.syntax_ancestor(new_range.clone())
14429                {
14430                    new_range = match containing_range {
14431                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14432                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14433                    };
14434                    if !display_map.intersects_fold(new_range.start)
14435                        && !display_map.intersects_fold(new_range.end)
14436                    {
14437                        break;
14438                    }
14439                }
14440
14441                selected_larger_node |= new_range != old_range;
14442                Selection {
14443                    id: selection.id,
14444                    start: new_range.start,
14445                    end: new_range.end,
14446                    goal: SelectionGoal::None,
14447                    reversed: selection.reversed,
14448                }
14449            })
14450            .collect::<Vec<_>>();
14451
14452        if !selected_larger_node {
14453            return; // don't put this call in the history
14454        }
14455
14456        // scroll based on transformation done to the last selection created by the user
14457        let (last_old, last_new) = old_selections
14458            .last()
14459            .zip(new_selections.last().cloned())
14460            .expect("old_selections isn't empty");
14461
14462        // revert selection
14463        let is_selection_reversed = {
14464            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14465            new_selections.last_mut().expect("checked above").reversed =
14466                should_newest_selection_be_reversed;
14467            should_newest_selection_be_reversed
14468        };
14469
14470        if selected_larger_node {
14471            self.select_syntax_node_history.disable_clearing = true;
14472            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14473                s.select(new_selections.clone());
14474            });
14475            self.select_syntax_node_history.disable_clearing = false;
14476        }
14477
14478        let start_row = last_new.start.to_display_point(&display_map).row().0;
14479        let end_row = last_new.end.to_display_point(&display_map).row().0;
14480        let selection_height = end_row - start_row + 1;
14481        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14482
14483        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14484        let scroll_behavior = if fits_on_the_screen {
14485            self.request_autoscroll(Autoscroll::fit(), cx);
14486            SelectSyntaxNodeScrollBehavior::FitSelection
14487        } else if is_selection_reversed {
14488            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14489            SelectSyntaxNodeScrollBehavior::CursorTop
14490        } else {
14491            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14492            SelectSyntaxNodeScrollBehavior::CursorBottom
14493        };
14494
14495        self.select_syntax_node_history.push((
14496            old_selections,
14497            scroll_behavior,
14498            is_selection_reversed,
14499        ));
14500    }
14501
14502    pub fn select_smaller_syntax_node(
14503        &mut self,
14504        _: &SelectSmallerSyntaxNode,
14505        window: &mut Window,
14506        cx: &mut Context<Self>,
14507    ) {
14508        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14509
14510        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14511            self.select_syntax_node_history.pop()
14512        {
14513            if let Some(selection) = selections.last_mut() {
14514                selection.reversed = is_selection_reversed;
14515            }
14516
14517            self.select_syntax_node_history.disable_clearing = true;
14518            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14519                s.select(selections.to_vec());
14520            });
14521            self.select_syntax_node_history.disable_clearing = false;
14522
14523            match scroll_behavior {
14524                SelectSyntaxNodeScrollBehavior::CursorTop => {
14525                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14526                }
14527                SelectSyntaxNodeScrollBehavior::FitSelection => {
14528                    self.request_autoscroll(Autoscroll::fit(), cx);
14529                }
14530                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14531                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14532                }
14533            }
14534        }
14535    }
14536
14537    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14538        if !EditorSettings::get_global(cx).gutter.runnables {
14539            self.clear_tasks();
14540            return Task::ready(());
14541        }
14542        let project = self.project.as_ref().map(Entity::downgrade);
14543        let task_sources = self.lsp_task_sources(cx);
14544        let multi_buffer = self.buffer.downgrade();
14545        cx.spawn_in(window, async move |editor, cx| {
14546            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14547            let Some(project) = project.and_then(|p| p.upgrade()) else {
14548                return;
14549            };
14550            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14551                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14552            }) else {
14553                return;
14554            };
14555
14556            let hide_runnables = project
14557                .update(cx, |project, cx| {
14558                    // Do not display any test indicators in non-dev server remote projects.
14559                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14560                })
14561                .unwrap_or(true);
14562            if hide_runnables {
14563                return;
14564            }
14565            let new_rows =
14566                cx.background_spawn({
14567                    let snapshot = display_snapshot.clone();
14568                    async move {
14569                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14570                    }
14571                })
14572                    .await;
14573            let Ok(lsp_tasks) =
14574                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14575            else {
14576                return;
14577            };
14578            let lsp_tasks = lsp_tasks.await;
14579
14580            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14581                lsp_tasks
14582                    .into_iter()
14583                    .flat_map(|(kind, tasks)| {
14584                        tasks.into_iter().filter_map(move |(location, task)| {
14585                            Some((kind.clone(), location?, task))
14586                        })
14587                    })
14588                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14589                        let buffer = location.target.buffer;
14590                        let buffer_snapshot = buffer.read(cx).snapshot();
14591                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14592                            |(excerpt_id, snapshot, _)| {
14593                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14594                                    display_snapshot
14595                                        .buffer_snapshot
14596                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14597                                } else {
14598                                    None
14599                                }
14600                            },
14601                        );
14602                        if let Some(offset) = offset {
14603                            let task_buffer_range =
14604                                location.target.range.to_point(&buffer_snapshot);
14605                            let context_buffer_range =
14606                                task_buffer_range.to_offset(&buffer_snapshot);
14607                            let context_range = BufferOffset(context_buffer_range.start)
14608                                ..BufferOffset(context_buffer_range.end);
14609
14610                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14611                                .or_insert_with(|| RunnableTasks {
14612                                    templates: Vec::new(),
14613                                    offset,
14614                                    column: task_buffer_range.start.column,
14615                                    extra_variables: HashMap::default(),
14616                                    context_range,
14617                                })
14618                                .templates
14619                                .push((kind, task.original_task().clone()));
14620                        }
14621
14622                        acc
14623                    })
14624            }) else {
14625                return;
14626            };
14627
14628            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14629                buffer.language_settings(cx).tasks.prefer_lsp
14630            }) else {
14631                return;
14632            };
14633
14634            let rows = Self::runnable_rows(
14635                project,
14636                display_snapshot,
14637                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14638                new_rows,
14639                cx.clone(),
14640            )
14641            .await;
14642            editor
14643                .update(cx, |editor, _| {
14644                    editor.clear_tasks();
14645                    for (key, mut value) in rows {
14646                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14647                            value.templates.extend(lsp_tasks.templates);
14648                        }
14649
14650                        editor.insert_tasks(key, value);
14651                    }
14652                    for (key, value) in lsp_tasks_by_rows {
14653                        editor.insert_tasks(key, value);
14654                    }
14655                })
14656                .ok();
14657        })
14658    }
14659    fn fetch_runnable_ranges(
14660        snapshot: &DisplaySnapshot,
14661        range: Range<Anchor>,
14662    ) -> Vec<language::RunnableRange> {
14663        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14664    }
14665
14666    fn runnable_rows(
14667        project: Entity<Project>,
14668        snapshot: DisplaySnapshot,
14669        prefer_lsp: bool,
14670        runnable_ranges: Vec<RunnableRange>,
14671        cx: AsyncWindowContext,
14672    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14673        cx.spawn(async move |cx| {
14674            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14675            for mut runnable in runnable_ranges {
14676                let Some(tasks) = cx
14677                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14678                    .ok()
14679                else {
14680                    continue;
14681                };
14682                let mut tasks = tasks.await;
14683
14684                if prefer_lsp {
14685                    tasks.retain(|(task_kind, _)| {
14686                        !matches!(task_kind, TaskSourceKind::Language { .. })
14687                    });
14688                }
14689                if tasks.is_empty() {
14690                    continue;
14691                }
14692
14693                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14694                let Some(row) = snapshot
14695                    .buffer_snapshot
14696                    .buffer_line_for_row(MultiBufferRow(point.row))
14697                    .map(|(_, range)| range.start.row)
14698                else {
14699                    continue;
14700                };
14701
14702                let context_range =
14703                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14704                runnable_rows.push((
14705                    (runnable.buffer_id, row),
14706                    RunnableTasks {
14707                        templates: tasks,
14708                        offset: snapshot
14709                            .buffer_snapshot
14710                            .anchor_before(runnable.run_range.start),
14711                        context_range,
14712                        column: point.column,
14713                        extra_variables: runnable.extra_captures,
14714                    },
14715                ));
14716            }
14717            runnable_rows
14718        })
14719    }
14720
14721    fn templates_with_tags(
14722        project: &Entity<Project>,
14723        runnable: &mut Runnable,
14724        cx: &mut App,
14725    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14726        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14727            let (worktree_id, file) = project
14728                .buffer_for_id(runnable.buffer, cx)
14729                .and_then(|buffer| buffer.read(cx).file())
14730                .map(|file| (file.worktree_id(cx), file.clone()))
14731                .unzip();
14732
14733            (
14734                project.task_store().read(cx).task_inventory().cloned(),
14735                worktree_id,
14736                file,
14737            )
14738        });
14739
14740        let tags = mem::take(&mut runnable.tags);
14741        let language = runnable.language.clone();
14742        cx.spawn(async move |cx| {
14743            let mut templates_with_tags = Vec::new();
14744            if let Some(inventory) = inventory {
14745                for RunnableTag(tag) in tags {
14746                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14747                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14748                    }) else {
14749                        return templates_with_tags;
14750                    };
14751                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14752                        move |(_, template)| {
14753                            template.tags.iter().any(|source_tag| source_tag == &tag)
14754                        },
14755                    ));
14756                }
14757            }
14758            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14759
14760            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14761                // Strongest source wins; if we have worktree tag binding, prefer that to
14762                // global and language bindings;
14763                // if we have a global binding, prefer that to language binding.
14764                let first_mismatch = templates_with_tags
14765                    .iter()
14766                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14767                if let Some(index) = first_mismatch {
14768                    templates_with_tags.truncate(index);
14769                }
14770            }
14771
14772            templates_with_tags
14773        })
14774    }
14775
14776    pub fn move_to_enclosing_bracket(
14777        &mut self,
14778        _: &MoveToEnclosingBracket,
14779        window: &mut Window,
14780        cx: &mut Context<Self>,
14781    ) {
14782        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14783        self.change_selections(Default::default(), window, cx, |s| {
14784            s.move_offsets_with(|snapshot, selection| {
14785                let Some(enclosing_bracket_ranges) =
14786                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14787                else {
14788                    return;
14789                };
14790
14791                let mut best_length = usize::MAX;
14792                let mut best_inside = false;
14793                let mut best_in_bracket_range = false;
14794                let mut best_destination = None;
14795                for (open, close) in enclosing_bracket_ranges {
14796                    let close = close.to_inclusive();
14797                    let length = close.end() - open.start;
14798                    let inside = selection.start >= open.end && selection.end <= *close.start();
14799                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14800                        || close.contains(&selection.head());
14801
14802                    // If best is next to a bracket and current isn't, skip
14803                    if !in_bracket_range && best_in_bracket_range {
14804                        continue;
14805                    }
14806
14807                    // Prefer smaller lengths unless best is inside and current isn't
14808                    if length > best_length && (best_inside || !inside) {
14809                        continue;
14810                    }
14811
14812                    best_length = length;
14813                    best_inside = inside;
14814                    best_in_bracket_range = in_bracket_range;
14815                    best_destination = Some(
14816                        if close.contains(&selection.start) && close.contains(&selection.end) {
14817                            if inside { open.end } else { open.start }
14818                        } else if inside {
14819                            *close.start()
14820                        } else {
14821                            *close.end()
14822                        },
14823                    );
14824                }
14825
14826                if let Some(destination) = best_destination {
14827                    selection.collapse_to(destination, SelectionGoal::None);
14828                }
14829            })
14830        });
14831    }
14832
14833    pub fn undo_selection(
14834        &mut self,
14835        _: &UndoSelection,
14836        window: &mut Window,
14837        cx: &mut Context<Self>,
14838    ) {
14839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14840        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14841            self.selection_history.mode = SelectionHistoryMode::Undoing;
14842            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14843                this.end_selection(window, cx);
14844                this.change_selections(
14845                    SelectionEffects::scroll(Autoscroll::newest()),
14846                    window,
14847                    cx,
14848                    |s| s.select_anchors(entry.selections.to_vec()),
14849                );
14850            });
14851            self.selection_history.mode = SelectionHistoryMode::Normal;
14852
14853            self.select_next_state = entry.select_next_state;
14854            self.select_prev_state = entry.select_prev_state;
14855            self.add_selections_state = entry.add_selections_state;
14856        }
14857    }
14858
14859    pub fn redo_selection(
14860        &mut self,
14861        _: &RedoSelection,
14862        window: &mut Window,
14863        cx: &mut Context<Self>,
14864    ) {
14865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14866        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14867            self.selection_history.mode = SelectionHistoryMode::Redoing;
14868            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14869                this.end_selection(window, cx);
14870                this.change_selections(
14871                    SelectionEffects::scroll(Autoscroll::newest()),
14872                    window,
14873                    cx,
14874                    |s| s.select_anchors(entry.selections.to_vec()),
14875                );
14876            });
14877            self.selection_history.mode = SelectionHistoryMode::Normal;
14878
14879            self.select_next_state = entry.select_next_state;
14880            self.select_prev_state = entry.select_prev_state;
14881            self.add_selections_state = entry.add_selections_state;
14882        }
14883    }
14884
14885    pub fn expand_excerpts(
14886        &mut self,
14887        action: &ExpandExcerpts,
14888        _: &mut Window,
14889        cx: &mut Context<Self>,
14890    ) {
14891        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14892    }
14893
14894    pub fn expand_excerpts_down(
14895        &mut self,
14896        action: &ExpandExcerptsDown,
14897        _: &mut Window,
14898        cx: &mut Context<Self>,
14899    ) {
14900        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14901    }
14902
14903    pub fn expand_excerpts_up(
14904        &mut self,
14905        action: &ExpandExcerptsUp,
14906        _: &mut Window,
14907        cx: &mut Context<Self>,
14908    ) {
14909        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14910    }
14911
14912    pub fn expand_excerpts_for_direction(
14913        &mut self,
14914        lines: u32,
14915        direction: ExpandExcerptDirection,
14916
14917        cx: &mut Context<Self>,
14918    ) {
14919        let selections = self.selections.disjoint_anchors();
14920
14921        let lines = if lines == 0 {
14922            EditorSettings::get_global(cx).expand_excerpt_lines
14923        } else {
14924            lines
14925        };
14926
14927        self.buffer.update(cx, |buffer, cx| {
14928            let snapshot = buffer.snapshot(cx);
14929            let mut excerpt_ids = selections
14930                .iter()
14931                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14932                .collect::<Vec<_>>();
14933            excerpt_ids.sort();
14934            excerpt_ids.dedup();
14935            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14936        })
14937    }
14938
14939    pub fn expand_excerpt(
14940        &mut self,
14941        excerpt: ExcerptId,
14942        direction: ExpandExcerptDirection,
14943        window: &mut Window,
14944        cx: &mut Context<Self>,
14945    ) {
14946        let current_scroll_position = self.scroll_position(cx);
14947        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14948        let mut should_scroll_up = false;
14949
14950        if direction == ExpandExcerptDirection::Down {
14951            let multi_buffer = self.buffer.read(cx);
14952            let snapshot = multi_buffer.snapshot(cx);
14953            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14954                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14955                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14956                        let buffer_snapshot = buffer.read(cx).snapshot();
14957                        let excerpt_end_row =
14958                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14959                        let last_row = buffer_snapshot.max_point().row;
14960                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14961                        should_scroll_up = lines_below >= lines_to_expand;
14962                    }
14963                }
14964            }
14965        }
14966
14967        self.buffer.update(cx, |buffer, cx| {
14968            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14969        });
14970
14971        if should_scroll_up {
14972            let new_scroll_position =
14973                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14974            self.set_scroll_position(new_scroll_position, window, cx);
14975        }
14976    }
14977
14978    pub fn go_to_singleton_buffer_point(
14979        &mut self,
14980        point: Point,
14981        window: &mut Window,
14982        cx: &mut Context<Self>,
14983    ) {
14984        self.go_to_singleton_buffer_range(point..point, window, cx);
14985    }
14986
14987    pub fn go_to_singleton_buffer_range(
14988        &mut self,
14989        range: Range<Point>,
14990        window: &mut Window,
14991        cx: &mut Context<Self>,
14992    ) {
14993        let multibuffer = self.buffer().read(cx);
14994        let Some(buffer) = multibuffer.as_singleton() else {
14995            return;
14996        };
14997        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14998            return;
14999        };
15000        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15001            return;
15002        };
15003        self.change_selections(
15004            SelectionEffects::default().nav_history(true),
15005            window,
15006            cx,
15007            |s| s.select_anchor_ranges([start..end]),
15008        );
15009    }
15010
15011    pub fn go_to_diagnostic(
15012        &mut self,
15013        _: &GoToDiagnostic,
15014        window: &mut Window,
15015        cx: &mut Context<Self>,
15016    ) {
15017        if !self.diagnostics_enabled() {
15018            return;
15019        }
15020        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15021        self.go_to_diagnostic_impl(Direction::Next, window, cx)
15022    }
15023
15024    pub fn go_to_prev_diagnostic(
15025        &mut self,
15026        _: &GoToPreviousDiagnostic,
15027        window: &mut Window,
15028        cx: &mut Context<Self>,
15029    ) {
15030        if !self.diagnostics_enabled() {
15031            return;
15032        }
15033        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15034        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
15035    }
15036
15037    pub fn go_to_diagnostic_impl(
15038        &mut self,
15039        direction: Direction,
15040        window: &mut Window,
15041        cx: &mut Context<Self>,
15042    ) {
15043        let buffer = self.buffer.read(cx).snapshot(cx);
15044        let selection = self.selections.newest::<usize>(cx);
15045
15046        let mut active_group_id = None;
15047        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15048            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15049                active_group_id = Some(active_group.group_id);
15050            }
15051        }
15052
15053        fn filtered(
15054            snapshot: EditorSnapshot,
15055            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15056        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15057            diagnostics
15058                .filter(|entry| entry.range.start != entry.range.end)
15059                .filter(|entry| !entry.diagnostic.is_unnecessary)
15060                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15061        }
15062
15063        let snapshot = self.snapshot(window, cx);
15064        let before = filtered(
15065            snapshot.clone(),
15066            buffer
15067                .diagnostics_in_range(0..selection.start)
15068                .filter(|entry| entry.range.start <= selection.start),
15069        );
15070        let after = filtered(
15071            snapshot,
15072            buffer
15073                .diagnostics_in_range(selection.start..buffer.len())
15074                .filter(|entry| entry.range.start >= selection.start),
15075        );
15076
15077        let mut found: Option<DiagnosticEntry<usize>> = None;
15078        if direction == Direction::Prev {
15079            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15080            {
15081                for diagnostic in prev_diagnostics.into_iter().rev() {
15082                    if diagnostic.range.start != selection.start
15083                        || active_group_id
15084                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15085                    {
15086                        found = Some(diagnostic);
15087                        break 'outer;
15088                    }
15089                }
15090            }
15091        } else {
15092            for diagnostic in after.chain(before) {
15093                if diagnostic.range.start != selection.start
15094                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15095                {
15096                    found = Some(diagnostic);
15097                    break;
15098                }
15099            }
15100        }
15101        let Some(next_diagnostic) = found else {
15102            return;
15103        };
15104
15105        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15106            return;
15107        };
15108        self.change_selections(Default::default(), window, cx, |s| {
15109            s.select_ranges(vec![
15110                next_diagnostic.range.start..next_diagnostic.range.start,
15111            ])
15112        });
15113        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15114        self.refresh_inline_completion(false, true, window, cx);
15115    }
15116
15117    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15119        let snapshot = self.snapshot(window, cx);
15120        let selection = self.selections.newest::<Point>(cx);
15121        self.go_to_hunk_before_or_after_position(
15122            &snapshot,
15123            selection.head(),
15124            Direction::Next,
15125            window,
15126            cx,
15127        );
15128    }
15129
15130    pub fn go_to_hunk_before_or_after_position(
15131        &mut self,
15132        snapshot: &EditorSnapshot,
15133        position: Point,
15134        direction: Direction,
15135        window: &mut Window,
15136        cx: &mut Context<Editor>,
15137    ) {
15138        let row = if direction == Direction::Next {
15139            self.hunk_after_position(snapshot, position)
15140                .map(|hunk| hunk.row_range.start)
15141        } else {
15142            self.hunk_before_position(snapshot, position)
15143        };
15144
15145        if let Some(row) = row {
15146            let destination = Point::new(row.0, 0);
15147            let autoscroll = Autoscroll::center();
15148
15149            self.unfold_ranges(&[destination..destination], false, false, cx);
15150            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15151                s.select_ranges([destination..destination]);
15152            });
15153        }
15154    }
15155
15156    fn hunk_after_position(
15157        &mut self,
15158        snapshot: &EditorSnapshot,
15159        position: Point,
15160    ) -> Option<MultiBufferDiffHunk> {
15161        snapshot
15162            .buffer_snapshot
15163            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15164            .find(|hunk| hunk.row_range.start.0 > position.row)
15165            .or_else(|| {
15166                snapshot
15167                    .buffer_snapshot
15168                    .diff_hunks_in_range(Point::zero()..position)
15169                    .find(|hunk| hunk.row_range.end.0 < position.row)
15170            })
15171    }
15172
15173    fn go_to_prev_hunk(
15174        &mut self,
15175        _: &GoToPreviousHunk,
15176        window: &mut Window,
15177        cx: &mut Context<Self>,
15178    ) {
15179        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15180        let snapshot = self.snapshot(window, cx);
15181        let selection = self.selections.newest::<Point>(cx);
15182        self.go_to_hunk_before_or_after_position(
15183            &snapshot,
15184            selection.head(),
15185            Direction::Prev,
15186            window,
15187            cx,
15188        );
15189    }
15190
15191    fn hunk_before_position(
15192        &mut self,
15193        snapshot: &EditorSnapshot,
15194        position: Point,
15195    ) -> Option<MultiBufferRow> {
15196        snapshot
15197            .buffer_snapshot
15198            .diff_hunk_before(position)
15199            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15200    }
15201
15202    fn go_to_next_change(
15203        &mut self,
15204        _: &GoToNextChange,
15205        window: &mut Window,
15206        cx: &mut Context<Self>,
15207    ) {
15208        if let Some(selections) = self
15209            .change_list
15210            .next_change(1, Direction::Next)
15211            .map(|s| s.to_vec())
15212        {
15213            self.change_selections(Default::default(), window, cx, |s| {
15214                let map = s.display_map();
15215                s.select_display_ranges(selections.iter().map(|a| {
15216                    let point = a.to_display_point(&map);
15217                    point..point
15218                }))
15219            })
15220        }
15221    }
15222
15223    fn go_to_previous_change(
15224        &mut self,
15225        _: &GoToPreviousChange,
15226        window: &mut Window,
15227        cx: &mut Context<Self>,
15228    ) {
15229        if let Some(selections) = self
15230            .change_list
15231            .next_change(1, Direction::Prev)
15232            .map(|s| s.to_vec())
15233        {
15234            self.change_selections(Default::default(), window, cx, |s| {
15235                let map = s.display_map();
15236                s.select_display_ranges(selections.iter().map(|a| {
15237                    let point = a.to_display_point(&map);
15238                    point..point
15239                }))
15240            })
15241        }
15242    }
15243
15244    fn go_to_line<T: 'static>(
15245        &mut self,
15246        position: Anchor,
15247        highlight_color: Option<Hsla>,
15248        window: &mut Window,
15249        cx: &mut Context<Self>,
15250    ) {
15251        let snapshot = self.snapshot(window, cx).display_snapshot;
15252        let position = position.to_point(&snapshot.buffer_snapshot);
15253        let start = snapshot
15254            .buffer_snapshot
15255            .clip_point(Point::new(position.row, 0), Bias::Left);
15256        let end = start + Point::new(1, 0);
15257        let start = snapshot.buffer_snapshot.anchor_before(start);
15258        let end = snapshot.buffer_snapshot.anchor_before(end);
15259
15260        self.highlight_rows::<T>(
15261            start..end,
15262            highlight_color
15263                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15264            Default::default(),
15265            cx,
15266        );
15267
15268        if self.buffer.read(cx).is_singleton() {
15269            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15270        }
15271    }
15272
15273    pub fn go_to_definition(
15274        &mut self,
15275        _: &GoToDefinition,
15276        window: &mut Window,
15277        cx: &mut Context<Self>,
15278    ) -> Task<Result<Navigated>> {
15279        let definition =
15280            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15281        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15282        cx.spawn_in(window, async move |editor, cx| {
15283            if definition.await? == Navigated::Yes {
15284                return Ok(Navigated::Yes);
15285            }
15286            match fallback_strategy {
15287                GoToDefinitionFallback::None => Ok(Navigated::No),
15288                GoToDefinitionFallback::FindAllReferences => {
15289                    match editor.update_in(cx, |editor, window, cx| {
15290                        editor.find_all_references(&FindAllReferences, window, cx)
15291                    })? {
15292                        Some(references) => references.await,
15293                        None => Ok(Navigated::No),
15294                    }
15295                }
15296            }
15297        })
15298    }
15299
15300    pub fn go_to_declaration(
15301        &mut self,
15302        _: &GoToDeclaration,
15303        window: &mut Window,
15304        cx: &mut Context<Self>,
15305    ) -> Task<Result<Navigated>> {
15306        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15307    }
15308
15309    pub fn go_to_declaration_split(
15310        &mut self,
15311        _: &GoToDeclaration,
15312        window: &mut Window,
15313        cx: &mut Context<Self>,
15314    ) -> Task<Result<Navigated>> {
15315        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15316    }
15317
15318    pub fn go_to_implementation(
15319        &mut self,
15320        _: &GoToImplementation,
15321        window: &mut Window,
15322        cx: &mut Context<Self>,
15323    ) -> Task<Result<Navigated>> {
15324        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15325    }
15326
15327    pub fn go_to_implementation_split(
15328        &mut self,
15329        _: &GoToImplementationSplit,
15330        window: &mut Window,
15331        cx: &mut Context<Self>,
15332    ) -> Task<Result<Navigated>> {
15333        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15334    }
15335
15336    pub fn go_to_type_definition(
15337        &mut self,
15338        _: &GoToTypeDefinition,
15339        window: &mut Window,
15340        cx: &mut Context<Self>,
15341    ) -> Task<Result<Navigated>> {
15342        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15343    }
15344
15345    pub fn go_to_definition_split(
15346        &mut self,
15347        _: &GoToDefinitionSplit,
15348        window: &mut Window,
15349        cx: &mut Context<Self>,
15350    ) -> Task<Result<Navigated>> {
15351        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15352    }
15353
15354    pub fn go_to_type_definition_split(
15355        &mut self,
15356        _: &GoToTypeDefinitionSplit,
15357        window: &mut Window,
15358        cx: &mut Context<Self>,
15359    ) -> Task<Result<Navigated>> {
15360        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15361    }
15362
15363    fn go_to_definition_of_kind(
15364        &mut self,
15365        kind: GotoDefinitionKind,
15366        split: bool,
15367        window: &mut Window,
15368        cx: &mut Context<Self>,
15369    ) -> Task<Result<Navigated>> {
15370        let Some(provider) = self.semantics_provider.clone() else {
15371            return Task::ready(Ok(Navigated::No));
15372        };
15373        let head = self.selections.newest::<usize>(cx).head();
15374        let buffer = self.buffer.read(cx);
15375        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15376            text_anchor
15377        } else {
15378            return Task::ready(Ok(Navigated::No));
15379        };
15380
15381        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15382            return Task::ready(Ok(Navigated::No));
15383        };
15384
15385        cx.spawn_in(window, async move |editor, cx| {
15386            let definitions = definitions.await?;
15387            let navigated = editor
15388                .update_in(cx, |editor, window, cx| {
15389                    editor.navigate_to_hover_links(
15390                        Some(kind),
15391                        definitions
15392                            .into_iter()
15393                            .filter(|location| {
15394                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15395                            })
15396                            .map(HoverLink::Text)
15397                            .collect::<Vec<_>>(),
15398                        split,
15399                        window,
15400                        cx,
15401                    )
15402                })?
15403                .await?;
15404            anyhow::Ok(navigated)
15405        })
15406    }
15407
15408    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15409        let selection = self.selections.newest_anchor();
15410        let head = selection.head();
15411        let tail = selection.tail();
15412
15413        let Some((buffer, start_position)) =
15414            self.buffer.read(cx).text_anchor_for_position(head, cx)
15415        else {
15416            return;
15417        };
15418
15419        let end_position = if head != tail {
15420            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15421                return;
15422            };
15423            Some(pos)
15424        } else {
15425            None
15426        };
15427
15428        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15429            let url = if let Some(end_pos) = end_position {
15430                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15431            } else {
15432                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15433            };
15434
15435            if let Some(url) = url {
15436                editor.update(cx, |_, cx| {
15437                    cx.open_url(&url);
15438                })
15439            } else {
15440                Ok(())
15441            }
15442        });
15443
15444        url_finder.detach();
15445    }
15446
15447    pub fn open_selected_filename(
15448        &mut self,
15449        _: &OpenSelectedFilename,
15450        window: &mut Window,
15451        cx: &mut Context<Self>,
15452    ) {
15453        let Some(workspace) = self.workspace() else {
15454            return;
15455        };
15456
15457        let position = self.selections.newest_anchor().head();
15458
15459        let Some((buffer, buffer_position)) =
15460            self.buffer.read(cx).text_anchor_for_position(position, cx)
15461        else {
15462            return;
15463        };
15464
15465        let project = self.project.clone();
15466
15467        cx.spawn_in(window, async move |_, cx| {
15468            let result = find_file(&buffer, project, buffer_position, cx).await;
15469
15470            if let Some((_, path)) = result {
15471                workspace
15472                    .update_in(cx, |workspace, window, cx| {
15473                        workspace.open_resolved_path(path, window, cx)
15474                    })?
15475                    .await?;
15476            }
15477            anyhow::Ok(())
15478        })
15479        .detach();
15480    }
15481
15482    pub(crate) fn navigate_to_hover_links(
15483        &mut self,
15484        kind: Option<GotoDefinitionKind>,
15485        mut definitions: Vec<HoverLink>,
15486        split: bool,
15487        window: &mut Window,
15488        cx: &mut Context<Editor>,
15489    ) -> Task<Result<Navigated>> {
15490        // If there is one definition, just open it directly
15491        if definitions.len() == 1 {
15492            let definition = definitions.pop().unwrap();
15493
15494            enum TargetTaskResult {
15495                Location(Option<Location>),
15496                AlreadyNavigated,
15497            }
15498
15499            let target_task = match definition {
15500                HoverLink::Text(link) => {
15501                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15502                }
15503                HoverLink::InlayHint(lsp_location, server_id) => {
15504                    let computation =
15505                        self.compute_target_location(lsp_location, server_id, window, cx);
15506                    cx.background_spawn(async move {
15507                        let location = computation.await?;
15508                        Ok(TargetTaskResult::Location(location))
15509                    })
15510                }
15511                HoverLink::Url(url) => {
15512                    cx.open_url(&url);
15513                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15514                }
15515                HoverLink::File(path) => {
15516                    if let Some(workspace) = self.workspace() {
15517                        cx.spawn_in(window, async move |_, cx| {
15518                            workspace
15519                                .update_in(cx, |workspace, window, cx| {
15520                                    workspace.open_resolved_path(path, window, cx)
15521                                })?
15522                                .await
15523                                .map(|_| TargetTaskResult::AlreadyNavigated)
15524                        })
15525                    } else {
15526                        Task::ready(Ok(TargetTaskResult::Location(None)))
15527                    }
15528                }
15529            };
15530            cx.spawn_in(window, async move |editor, cx| {
15531                let target = match target_task.await.context("target resolution task")? {
15532                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15533                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15534                    TargetTaskResult::Location(Some(target)) => target,
15535                };
15536
15537                editor.update_in(cx, |editor, window, cx| {
15538                    let Some(workspace) = editor.workspace() else {
15539                        return Navigated::No;
15540                    };
15541                    let pane = workspace.read(cx).active_pane().clone();
15542
15543                    let range = target.range.to_point(target.buffer.read(cx));
15544                    let range = editor.range_for_match(&range);
15545                    let range = collapse_multiline_range(range);
15546
15547                    if !split
15548                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15549                    {
15550                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15551                    } else {
15552                        window.defer(cx, move |window, cx| {
15553                            let target_editor: Entity<Self> =
15554                                workspace.update(cx, |workspace, cx| {
15555                                    let pane = if split {
15556                                        workspace.adjacent_pane(window, cx)
15557                                    } else {
15558                                        workspace.active_pane().clone()
15559                                    };
15560
15561                                    workspace.open_project_item(
15562                                        pane,
15563                                        target.buffer.clone(),
15564                                        true,
15565                                        true,
15566                                        window,
15567                                        cx,
15568                                    )
15569                                });
15570                            target_editor.update(cx, |target_editor, cx| {
15571                                // When selecting a definition in a different buffer, disable the nav history
15572                                // to avoid creating a history entry at the previous cursor location.
15573                                pane.update(cx, |pane, _| pane.disable_history());
15574                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15575                                pane.update(cx, |pane, _| pane.enable_history());
15576                            });
15577                        });
15578                    }
15579                    Navigated::Yes
15580                })
15581            })
15582        } else if !definitions.is_empty() {
15583            cx.spawn_in(window, async move |editor, cx| {
15584                let (title, location_tasks, workspace) = editor
15585                    .update_in(cx, |editor, window, cx| {
15586                        let tab_kind = match kind {
15587                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15588                            _ => "Definitions",
15589                        };
15590                        let title = definitions
15591                            .iter()
15592                            .find_map(|definition| match definition {
15593                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15594                                    let buffer = origin.buffer.read(cx);
15595                                    format!(
15596                                        "{} for {}",
15597                                        tab_kind,
15598                                        buffer
15599                                            .text_for_range(origin.range.clone())
15600                                            .collect::<String>()
15601                                    )
15602                                }),
15603                                HoverLink::InlayHint(_, _) => None,
15604                                HoverLink::Url(_) => None,
15605                                HoverLink::File(_) => None,
15606                            })
15607                            .unwrap_or(tab_kind.to_string());
15608                        let location_tasks = definitions
15609                            .into_iter()
15610                            .map(|definition| match definition {
15611                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15612                                HoverLink::InlayHint(lsp_location, server_id) => editor
15613                                    .compute_target_location(lsp_location, server_id, window, cx),
15614                                HoverLink::Url(_) => Task::ready(Ok(None)),
15615                                HoverLink::File(_) => Task::ready(Ok(None)),
15616                            })
15617                            .collect::<Vec<_>>();
15618                        (title, location_tasks, editor.workspace().clone())
15619                    })
15620                    .context("location tasks preparation")?;
15621
15622                let locations: Vec<Location> = future::join_all(location_tasks)
15623                    .await
15624                    .into_iter()
15625                    .filter_map(|location| location.transpose())
15626                    .collect::<Result<_>>()
15627                    .context("location tasks")?;
15628
15629                if locations.is_empty() {
15630                    return Ok(Navigated::No);
15631                }
15632
15633                let Some(workspace) = workspace else {
15634                    return Ok(Navigated::No);
15635                };
15636
15637                let opened = workspace
15638                    .update_in(cx, |workspace, window, cx| {
15639                        Self::open_locations_in_multibuffer(
15640                            workspace,
15641                            locations,
15642                            title,
15643                            split,
15644                            MultibufferSelectionMode::First,
15645                            window,
15646                            cx,
15647                        )
15648                    })
15649                    .ok();
15650
15651                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15652            })
15653        } else {
15654            Task::ready(Ok(Navigated::No))
15655        }
15656    }
15657
15658    fn compute_target_location(
15659        &self,
15660        lsp_location: lsp::Location,
15661        server_id: LanguageServerId,
15662        window: &mut Window,
15663        cx: &mut Context<Self>,
15664    ) -> Task<anyhow::Result<Option<Location>>> {
15665        let Some(project) = self.project.clone() else {
15666            return Task::ready(Ok(None));
15667        };
15668
15669        cx.spawn_in(window, async move |editor, cx| {
15670            let location_task = editor.update(cx, |_, cx| {
15671                project.update(cx, |project, cx| {
15672                    let language_server_name = project
15673                        .language_server_statuses(cx)
15674                        .find(|(id, _)| server_id == *id)
15675                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15676                    language_server_name.map(|language_server_name| {
15677                        project.open_local_buffer_via_lsp(
15678                            lsp_location.uri.clone(),
15679                            server_id,
15680                            language_server_name,
15681                            cx,
15682                        )
15683                    })
15684                })
15685            })?;
15686            let location = match location_task {
15687                Some(task) => Some({
15688                    let target_buffer_handle = task.await.context("open local buffer")?;
15689                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15690                        let target_start = target_buffer
15691                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15692                        let target_end = target_buffer
15693                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15694                        target_buffer.anchor_after(target_start)
15695                            ..target_buffer.anchor_before(target_end)
15696                    })?;
15697                    Location {
15698                        buffer: target_buffer_handle,
15699                        range,
15700                    }
15701                }),
15702                None => None,
15703            };
15704            Ok(location)
15705        })
15706    }
15707
15708    pub fn find_all_references(
15709        &mut self,
15710        _: &FindAllReferences,
15711        window: &mut Window,
15712        cx: &mut Context<Self>,
15713    ) -> Option<Task<Result<Navigated>>> {
15714        let selection = self.selections.newest::<usize>(cx);
15715        let multi_buffer = self.buffer.read(cx);
15716        let head = selection.head();
15717
15718        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15719        let head_anchor = multi_buffer_snapshot.anchor_at(
15720            head,
15721            if head < selection.tail() {
15722                Bias::Right
15723            } else {
15724                Bias::Left
15725            },
15726        );
15727
15728        match self
15729            .find_all_references_task_sources
15730            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15731        {
15732            Ok(_) => {
15733                log::info!(
15734                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15735                );
15736                return None;
15737            }
15738            Err(i) => {
15739                self.find_all_references_task_sources.insert(i, head_anchor);
15740            }
15741        }
15742
15743        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15744        let workspace = self.workspace()?;
15745        let project = workspace.read(cx).project().clone();
15746        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15747        Some(cx.spawn_in(window, async move |editor, cx| {
15748            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15749                if let Ok(i) = editor
15750                    .find_all_references_task_sources
15751                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15752                {
15753                    editor.find_all_references_task_sources.remove(i);
15754                }
15755            });
15756
15757            let locations = references.await?;
15758            if locations.is_empty() {
15759                return anyhow::Ok(Navigated::No);
15760            }
15761
15762            workspace.update_in(cx, |workspace, window, cx| {
15763                let title = locations
15764                    .first()
15765                    .as_ref()
15766                    .map(|location| {
15767                        let buffer = location.buffer.read(cx);
15768                        format!(
15769                            "References to `{}`",
15770                            buffer
15771                                .text_for_range(location.range.clone())
15772                                .collect::<String>()
15773                        )
15774                    })
15775                    .unwrap();
15776                Self::open_locations_in_multibuffer(
15777                    workspace,
15778                    locations,
15779                    title,
15780                    false,
15781                    MultibufferSelectionMode::First,
15782                    window,
15783                    cx,
15784                );
15785                Navigated::Yes
15786            })
15787        }))
15788    }
15789
15790    /// Opens a multibuffer with the given project locations in it
15791    pub fn open_locations_in_multibuffer(
15792        workspace: &mut Workspace,
15793        mut locations: Vec<Location>,
15794        title: String,
15795        split: bool,
15796        multibuffer_selection_mode: MultibufferSelectionMode,
15797        window: &mut Window,
15798        cx: &mut Context<Workspace>,
15799    ) {
15800        if locations.is_empty() {
15801            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15802            return;
15803        }
15804
15805        // If there are multiple definitions, open them in a multibuffer
15806        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15807        let mut locations = locations.into_iter().peekable();
15808        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15809        let capability = workspace.project().read(cx).capability();
15810
15811        let excerpt_buffer = cx.new(|cx| {
15812            let mut multibuffer = MultiBuffer::new(capability);
15813            while let Some(location) = locations.next() {
15814                let buffer = location.buffer.read(cx);
15815                let mut ranges_for_buffer = Vec::new();
15816                let range = location.range.to_point(buffer);
15817                ranges_for_buffer.push(range.clone());
15818
15819                while let Some(next_location) = locations.peek() {
15820                    if next_location.buffer == location.buffer {
15821                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15822                        locations.next();
15823                    } else {
15824                        break;
15825                    }
15826                }
15827
15828                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15829                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15830                    PathKey::for_buffer(&location.buffer, cx),
15831                    location.buffer.clone(),
15832                    ranges_for_buffer,
15833                    DEFAULT_MULTIBUFFER_CONTEXT,
15834                    cx,
15835                );
15836                ranges.extend(new_ranges)
15837            }
15838
15839            multibuffer.with_title(title)
15840        });
15841
15842        let editor = cx.new(|cx| {
15843            Editor::for_multibuffer(
15844                excerpt_buffer,
15845                Some(workspace.project().clone()),
15846                window,
15847                cx,
15848            )
15849        });
15850        editor.update(cx, |editor, cx| {
15851            match multibuffer_selection_mode {
15852                MultibufferSelectionMode::First => {
15853                    if let Some(first_range) = ranges.first() {
15854                        editor.change_selections(
15855                            SelectionEffects::no_scroll(),
15856                            window,
15857                            cx,
15858                            |selections| {
15859                                selections.clear_disjoint();
15860                                selections
15861                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
15862                            },
15863                        );
15864                    }
15865                    editor.highlight_background::<Self>(
15866                        &ranges,
15867                        |theme| theme.colors().editor_highlighted_line_background,
15868                        cx,
15869                    );
15870                }
15871                MultibufferSelectionMode::All => {
15872                    editor.change_selections(
15873                        SelectionEffects::no_scroll(),
15874                        window,
15875                        cx,
15876                        |selections| {
15877                            selections.clear_disjoint();
15878                            selections.select_anchor_ranges(ranges);
15879                        },
15880                    );
15881                }
15882            }
15883            editor.register_buffers_with_language_servers(cx);
15884        });
15885
15886        let item = Box::new(editor);
15887        let item_id = item.item_id();
15888
15889        if split {
15890            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15891        } else {
15892            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15893                let (preview_item_id, preview_item_idx) =
15894                    workspace.active_pane().read_with(cx, |pane, _| {
15895                        (pane.preview_item_id(), pane.preview_item_idx())
15896                    });
15897
15898                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15899
15900                if let Some(preview_item_id) = preview_item_id {
15901                    workspace.active_pane().update(cx, |pane, cx| {
15902                        pane.remove_item(preview_item_id, false, false, window, cx);
15903                    });
15904                }
15905            } else {
15906                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15907            }
15908        }
15909        workspace.active_pane().update(cx, |pane, cx| {
15910            pane.set_preview_item_id(Some(item_id), cx);
15911        });
15912    }
15913
15914    pub fn rename(
15915        &mut self,
15916        _: &Rename,
15917        window: &mut Window,
15918        cx: &mut Context<Self>,
15919    ) -> Option<Task<Result<()>>> {
15920        use language::ToOffset as _;
15921
15922        let provider = self.semantics_provider.clone()?;
15923        let selection = self.selections.newest_anchor().clone();
15924        let (cursor_buffer, cursor_buffer_position) = self
15925            .buffer
15926            .read(cx)
15927            .text_anchor_for_position(selection.head(), cx)?;
15928        let (tail_buffer, cursor_buffer_position_end) = self
15929            .buffer
15930            .read(cx)
15931            .text_anchor_for_position(selection.tail(), cx)?;
15932        if tail_buffer != cursor_buffer {
15933            return None;
15934        }
15935
15936        let snapshot = cursor_buffer.read(cx).snapshot();
15937        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15938        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15939        let prepare_rename = provider
15940            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15941            .unwrap_or_else(|| Task::ready(Ok(None)));
15942        drop(snapshot);
15943
15944        Some(cx.spawn_in(window, async move |this, cx| {
15945            let rename_range = if let Some(range) = prepare_rename.await? {
15946                Some(range)
15947            } else {
15948                this.update(cx, |this, cx| {
15949                    let buffer = this.buffer.read(cx).snapshot(cx);
15950                    let mut buffer_highlights = this
15951                        .document_highlights_for_position(selection.head(), &buffer)
15952                        .filter(|highlight| {
15953                            highlight.start.excerpt_id == selection.head().excerpt_id
15954                                && highlight.end.excerpt_id == selection.head().excerpt_id
15955                        });
15956                    buffer_highlights
15957                        .next()
15958                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15959                })?
15960            };
15961            if let Some(rename_range) = rename_range {
15962                this.update_in(cx, |this, window, cx| {
15963                    let snapshot = cursor_buffer.read(cx).snapshot();
15964                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15965                    let cursor_offset_in_rename_range =
15966                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15967                    let cursor_offset_in_rename_range_end =
15968                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15969
15970                    this.take_rename(false, window, cx);
15971                    let buffer = this.buffer.read(cx).read(cx);
15972                    let cursor_offset = selection.head().to_offset(&buffer);
15973                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15974                    let rename_end = rename_start + rename_buffer_range.len();
15975                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15976                    let mut old_highlight_id = None;
15977                    let old_name: Arc<str> = buffer
15978                        .chunks(rename_start..rename_end, true)
15979                        .map(|chunk| {
15980                            if old_highlight_id.is_none() {
15981                                old_highlight_id = chunk.syntax_highlight_id;
15982                            }
15983                            chunk.text
15984                        })
15985                        .collect::<String>()
15986                        .into();
15987
15988                    drop(buffer);
15989
15990                    // Position the selection in the rename editor so that it matches the current selection.
15991                    this.show_local_selections = false;
15992                    let rename_editor = cx.new(|cx| {
15993                        let mut editor = Editor::single_line(window, cx);
15994                        editor.buffer.update(cx, |buffer, cx| {
15995                            buffer.edit([(0..0, old_name.clone())], None, cx)
15996                        });
15997                        let rename_selection_range = match cursor_offset_in_rename_range
15998                            .cmp(&cursor_offset_in_rename_range_end)
15999                        {
16000                            Ordering::Equal => {
16001                                editor.select_all(&SelectAll, window, cx);
16002                                return editor;
16003                            }
16004                            Ordering::Less => {
16005                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16006                            }
16007                            Ordering::Greater => {
16008                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16009                            }
16010                        };
16011                        if rename_selection_range.end > old_name.len() {
16012                            editor.select_all(&SelectAll, window, cx);
16013                        } else {
16014                            editor.change_selections(Default::default(), window, cx, |s| {
16015                                s.select_ranges([rename_selection_range]);
16016                            });
16017                        }
16018                        editor
16019                    });
16020                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16021                        if e == &EditorEvent::Focused {
16022                            cx.emit(EditorEvent::FocusedIn)
16023                        }
16024                    })
16025                    .detach();
16026
16027                    let write_highlights =
16028                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16029                    let read_highlights =
16030                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16031                    let ranges = write_highlights
16032                        .iter()
16033                        .flat_map(|(_, ranges)| ranges.iter())
16034                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16035                        .cloned()
16036                        .collect();
16037
16038                    this.highlight_text::<Rename>(
16039                        ranges,
16040                        HighlightStyle {
16041                            fade_out: Some(0.6),
16042                            ..Default::default()
16043                        },
16044                        cx,
16045                    );
16046                    let rename_focus_handle = rename_editor.focus_handle(cx);
16047                    window.focus(&rename_focus_handle);
16048                    let block_id = this.insert_blocks(
16049                        [BlockProperties {
16050                            style: BlockStyle::Flex,
16051                            placement: BlockPlacement::Below(range.start),
16052                            height: Some(1),
16053                            render: Arc::new({
16054                                let rename_editor = rename_editor.clone();
16055                                move |cx: &mut BlockContext| {
16056                                    let mut text_style = cx.editor_style.text.clone();
16057                                    if let Some(highlight_style) = old_highlight_id
16058                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16059                                    {
16060                                        text_style = text_style.highlight(highlight_style);
16061                                    }
16062                                    div()
16063                                        .block_mouse_except_scroll()
16064                                        .pl(cx.anchor_x)
16065                                        .child(EditorElement::new(
16066                                            &rename_editor,
16067                                            EditorStyle {
16068                                                background: cx.theme().system().transparent,
16069                                                local_player: cx.editor_style.local_player,
16070                                                text: text_style,
16071                                                scrollbar_width: cx.editor_style.scrollbar_width,
16072                                                syntax: cx.editor_style.syntax.clone(),
16073                                                status: cx.editor_style.status.clone(),
16074                                                inlay_hints_style: HighlightStyle {
16075                                                    font_weight: Some(FontWeight::BOLD),
16076                                                    ..make_inlay_hints_style(cx.app)
16077                                                },
16078                                                inline_completion_styles: make_suggestion_styles(
16079                                                    cx.app,
16080                                                ),
16081                                                ..EditorStyle::default()
16082                                            },
16083                                        ))
16084                                        .into_any_element()
16085                                }
16086                            }),
16087                            priority: 0,
16088                            render_in_minimap: true,
16089                        }],
16090                        Some(Autoscroll::fit()),
16091                        cx,
16092                    )[0];
16093                    this.pending_rename = Some(RenameState {
16094                        range,
16095                        old_name,
16096                        editor: rename_editor,
16097                        block_id,
16098                    });
16099                })?;
16100            }
16101
16102            Ok(())
16103        }))
16104    }
16105
16106    pub fn confirm_rename(
16107        &mut self,
16108        _: &ConfirmRename,
16109        window: &mut Window,
16110        cx: &mut Context<Self>,
16111    ) -> Option<Task<Result<()>>> {
16112        let rename = self.take_rename(false, window, cx)?;
16113        let workspace = self.workspace()?.downgrade();
16114        let (buffer, start) = self
16115            .buffer
16116            .read(cx)
16117            .text_anchor_for_position(rename.range.start, cx)?;
16118        let (end_buffer, _) = self
16119            .buffer
16120            .read(cx)
16121            .text_anchor_for_position(rename.range.end, cx)?;
16122        if buffer != end_buffer {
16123            return None;
16124        }
16125
16126        let old_name = rename.old_name;
16127        let new_name = rename.editor.read(cx).text(cx);
16128
16129        let rename = self.semantics_provider.as_ref()?.perform_rename(
16130            &buffer,
16131            start,
16132            new_name.clone(),
16133            cx,
16134        )?;
16135
16136        Some(cx.spawn_in(window, async move |editor, cx| {
16137            let project_transaction = rename.await?;
16138            Self::open_project_transaction(
16139                &editor,
16140                workspace,
16141                project_transaction,
16142                format!("Rename: {}{}", old_name, new_name),
16143                cx,
16144            )
16145            .await?;
16146
16147            editor.update(cx, |editor, cx| {
16148                editor.refresh_document_highlights(cx);
16149            })?;
16150            Ok(())
16151        }))
16152    }
16153
16154    fn take_rename(
16155        &mut self,
16156        moving_cursor: bool,
16157        window: &mut Window,
16158        cx: &mut Context<Self>,
16159    ) -> Option<RenameState> {
16160        let rename = self.pending_rename.take()?;
16161        if rename.editor.focus_handle(cx).is_focused(window) {
16162            window.focus(&self.focus_handle);
16163        }
16164
16165        self.remove_blocks(
16166            [rename.block_id].into_iter().collect(),
16167            Some(Autoscroll::fit()),
16168            cx,
16169        );
16170        self.clear_highlights::<Rename>(cx);
16171        self.show_local_selections = true;
16172
16173        if moving_cursor {
16174            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16175                editor.selections.newest::<usize>(cx).head()
16176            });
16177
16178            // Update the selection to match the position of the selection inside
16179            // the rename editor.
16180            let snapshot = self.buffer.read(cx).read(cx);
16181            let rename_range = rename.range.to_offset(&snapshot);
16182            let cursor_in_editor = snapshot
16183                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16184                .min(rename_range.end);
16185            drop(snapshot);
16186
16187            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16188                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16189            });
16190        } else {
16191            self.refresh_document_highlights(cx);
16192        }
16193
16194        Some(rename)
16195    }
16196
16197    pub fn pending_rename(&self) -> Option<&RenameState> {
16198        self.pending_rename.as_ref()
16199    }
16200
16201    fn format(
16202        &mut self,
16203        _: &Format,
16204        window: &mut Window,
16205        cx: &mut Context<Self>,
16206    ) -> Option<Task<Result<()>>> {
16207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16208
16209        let project = match &self.project {
16210            Some(project) => project.clone(),
16211            None => return None,
16212        };
16213
16214        Some(self.perform_format(
16215            project,
16216            FormatTrigger::Manual,
16217            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16218            window,
16219            cx,
16220        ))
16221    }
16222
16223    fn format_selections(
16224        &mut self,
16225        _: &FormatSelections,
16226        window: &mut Window,
16227        cx: &mut Context<Self>,
16228    ) -> Option<Task<Result<()>>> {
16229        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16230
16231        let project = match &self.project {
16232            Some(project) => project.clone(),
16233            None => return None,
16234        };
16235
16236        let ranges = self
16237            .selections
16238            .all_adjusted(cx)
16239            .into_iter()
16240            .map(|selection| selection.range())
16241            .collect_vec();
16242
16243        Some(self.perform_format(
16244            project,
16245            FormatTrigger::Manual,
16246            FormatTarget::Ranges(ranges),
16247            window,
16248            cx,
16249        ))
16250    }
16251
16252    fn perform_format(
16253        &mut self,
16254        project: Entity<Project>,
16255        trigger: FormatTrigger,
16256        target: FormatTarget,
16257        window: &mut Window,
16258        cx: &mut Context<Self>,
16259    ) -> Task<Result<()>> {
16260        let buffer = self.buffer.clone();
16261        let (buffers, target) = match target {
16262            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16263            FormatTarget::Ranges(selection_ranges) => {
16264                let multi_buffer = buffer.read(cx);
16265                let snapshot = multi_buffer.read(cx);
16266                let mut buffers = HashSet::default();
16267                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16268                    BTreeMap::new();
16269                for selection_range in selection_ranges {
16270                    for (buffer, buffer_range, _) in
16271                        snapshot.range_to_buffer_ranges(selection_range)
16272                    {
16273                        let buffer_id = buffer.remote_id();
16274                        let start = buffer.anchor_before(buffer_range.start);
16275                        let end = buffer.anchor_after(buffer_range.end);
16276                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16277                        buffer_id_to_ranges
16278                            .entry(buffer_id)
16279                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16280                            .or_insert_with(|| vec![start..end]);
16281                    }
16282                }
16283                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16284            }
16285        };
16286
16287        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16288        let selections_prev = transaction_id_prev
16289            .and_then(|transaction_id_prev| {
16290                // default to selections as they were after the last edit, if we have them,
16291                // instead of how they are now.
16292                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16293                // will take you back to where you made the last edit, instead of staying where you scrolled
16294                self.selection_history
16295                    .transaction(transaction_id_prev)
16296                    .map(|t| t.0.clone())
16297            })
16298            .unwrap_or_else(|| {
16299                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16300                self.selections.disjoint_anchors()
16301            });
16302
16303        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16304        let format = project.update(cx, |project, cx| {
16305            project.format(buffers, target, true, trigger, cx)
16306        });
16307
16308        cx.spawn_in(window, async move |editor, cx| {
16309            let transaction = futures::select_biased! {
16310                transaction = format.log_err().fuse() => transaction,
16311                () = timeout => {
16312                    log::warn!("timed out waiting for formatting");
16313                    None
16314                }
16315            };
16316
16317            buffer
16318                .update(cx, |buffer, cx| {
16319                    if let Some(transaction) = transaction {
16320                        if !buffer.is_singleton() {
16321                            buffer.push_transaction(&transaction.0, cx);
16322                        }
16323                    }
16324                    cx.notify();
16325                })
16326                .ok();
16327
16328            if let Some(transaction_id_now) =
16329                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16330            {
16331                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16332                if has_new_transaction {
16333                    _ = editor.update(cx, |editor, _| {
16334                        editor
16335                            .selection_history
16336                            .insert_transaction(transaction_id_now, selections_prev);
16337                    });
16338                }
16339            }
16340
16341            Ok(())
16342        })
16343    }
16344
16345    fn organize_imports(
16346        &mut self,
16347        _: &OrganizeImports,
16348        window: &mut Window,
16349        cx: &mut Context<Self>,
16350    ) -> Option<Task<Result<()>>> {
16351        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16352        let project = match &self.project {
16353            Some(project) => project.clone(),
16354            None => return None,
16355        };
16356        Some(self.perform_code_action_kind(
16357            project,
16358            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16359            window,
16360            cx,
16361        ))
16362    }
16363
16364    fn perform_code_action_kind(
16365        &mut self,
16366        project: Entity<Project>,
16367        kind: CodeActionKind,
16368        window: &mut Window,
16369        cx: &mut Context<Self>,
16370    ) -> Task<Result<()>> {
16371        let buffer = self.buffer.clone();
16372        let buffers = buffer.read(cx).all_buffers();
16373        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16374        let apply_action = project.update(cx, |project, cx| {
16375            project.apply_code_action_kind(buffers, kind, true, cx)
16376        });
16377        cx.spawn_in(window, async move |_, cx| {
16378            let transaction = futures::select_biased! {
16379                () = timeout => {
16380                    log::warn!("timed out waiting for executing code action");
16381                    None
16382                }
16383                transaction = apply_action.log_err().fuse() => transaction,
16384            };
16385            buffer
16386                .update(cx, |buffer, cx| {
16387                    // check if we need this
16388                    if let Some(transaction) = transaction {
16389                        if !buffer.is_singleton() {
16390                            buffer.push_transaction(&transaction.0, cx);
16391                        }
16392                    }
16393                    cx.notify();
16394                })
16395                .ok();
16396            Ok(())
16397        })
16398    }
16399
16400    pub fn restart_language_server(
16401        &mut self,
16402        _: &RestartLanguageServer,
16403        _: &mut Window,
16404        cx: &mut Context<Self>,
16405    ) {
16406        if let Some(project) = self.project.clone() {
16407            self.buffer.update(cx, |multi_buffer, cx| {
16408                project.update(cx, |project, cx| {
16409                    project.restart_language_servers_for_buffers(
16410                        multi_buffer.all_buffers().into_iter().collect(),
16411                        HashSet::default(),
16412                        cx,
16413                    );
16414                });
16415            })
16416        }
16417    }
16418
16419    pub fn stop_language_server(
16420        &mut self,
16421        _: &StopLanguageServer,
16422        _: &mut Window,
16423        cx: &mut Context<Self>,
16424    ) {
16425        if let Some(project) = self.project.clone() {
16426            self.buffer.update(cx, |multi_buffer, cx| {
16427                project.update(cx, |project, cx| {
16428                    project.stop_language_servers_for_buffers(
16429                        multi_buffer.all_buffers().into_iter().collect(),
16430                        HashSet::default(),
16431                        cx,
16432                    );
16433                    cx.emit(project::Event::RefreshInlayHints);
16434                });
16435            });
16436        }
16437    }
16438
16439    fn cancel_language_server_work(
16440        workspace: &mut Workspace,
16441        _: &actions::CancelLanguageServerWork,
16442        _: &mut Window,
16443        cx: &mut Context<Workspace>,
16444    ) {
16445        let project = workspace.project();
16446        let buffers = workspace
16447            .active_item(cx)
16448            .and_then(|item| item.act_as::<Editor>(cx))
16449            .map_or(HashSet::default(), |editor| {
16450                editor.read(cx).buffer.read(cx).all_buffers()
16451            });
16452        project.update(cx, |project, cx| {
16453            project.cancel_language_server_work_for_buffers(buffers, cx);
16454        });
16455    }
16456
16457    fn show_character_palette(
16458        &mut self,
16459        _: &ShowCharacterPalette,
16460        window: &mut Window,
16461        _: &mut Context<Self>,
16462    ) {
16463        window.show_character_palette();
16464    }
16465
16466    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16467        if !self.diagnostics_enabled() {
16468            return;
16469        }
16470
16471        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16472            let buffer = self.buffer.read(cx).snapshot(cx);
16473            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16474            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16475            let is_valid = buffer
16476                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16477                .any(|entry| {
16478                    entry.diagnostic.is_primary
16479                        && !entry.range.is_empty()
16480                        && entry.range.start == primary_range_start
16481                        && entry.diagnostic.message == active_diagnostics.active_message
16482                });
16483
16484            if !is_valid {
16485                self.dismiss_diagnostics(cx);
16486            }
16487        }
16488    }
16489
16490    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16491        match &self.active_diagnostics {
16492            ActiveDiagnostic::Group(group) => Some(group),
16493            _ => None,
16494        }
16495    }
16496
16497    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16498        if !self.diagnostics_enabled() {
16499            return;
16500        }
16501        self.dismiss_diagnostics(cx);
16502        self.active_diagnostics = ActiveDiagnostic::All;
16503    }
16504
16505    fn activate_diagnostics(
16506        &mut self,
16507        buffer_id: BufferId,
16508        diagnostic: DiagnosticEntry<usize>,
16509        window: &mut Window,
16510        cx: &mut Context<Self>,
16511    ) {
16512        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16513            return;
16514        }
16515        self.dismiss_diagnostics(cx);
16516        let snapshot = self.snapshot(window, cx);
16517        let buffer = self.buffer.read(cx).snapshot(cx);
16518        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16519            return;
16520        };
16521
16522        let diagnostic_group = buffer
16523            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16524            .collect::<Vec<_>>();
16525
16526        let blocks =
16527            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16528
16529        let blocks = self.display_map.update(cx, |display_map, cx| {
16530            display_map.insert_blocks(blocks, cx).into_iter().collect()
16531        });
16532        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16533            active_range: buffer.anchor_before(diagnostic.range.start)
16534                ..buffer.anchor_after(diagnostic.range.end),
16535            active_message: diagnostic.diagnostic.message.clone(),
16536            group_id: diagnostic.diagnostic.group_id,
16537            blocks,
16538        });
16539        cx.notify();
16540    }
16541
16542    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16543        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16544            return;
16545        };
16546
16547        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16548        if let ActiveDiagnostic::Group(group) = prev {
16549            self.display_map.update(cx, |display_map, cx| {
16550                display_map.remove_blocks(group.blocks, cx);
16551            });
16552            cx.notify();
16553        }
16554    }
16555
16556    /// Disable inline diagnostics rendering for this editor.
16557    pub fn disable_inline_diagnostics(&mut self) {
16558        self.inline_diagnostics_enabled = false;
16559        self.inline_diagnostics_update = Task::ready(());
16560        self.inline_diagnostics.clear();
16561    }
16562
16563    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16564        self.diagnostics_enabled = false;
16565        self.dismiss_diagnostics(cx);
16566        self.inline_diagnostics_update = Task::ready(());
16567        self.inline_diagnostics.clear();
16568    }
16569
16570    pub fn diagnostics_enabled(&self) -> bool {
16571        self.diagnostics_enabled && self.mode.is_full()
16572    }
16573
16574    pub fn inline_diagnostics_enabled(&self) -> bool {
16575        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16576    }
16577
16578    pub fn show_inline_diagnostics(&self) -> bool {
16579        self.show_inline_diagnostics
16580    }
16581
16582    pub fn toggle_inline_diagnostics(
16583        &mut self,
16584        _: &ToggleInlineDiagnostics,
16585        window: &mut Window,
16586        cx: &mut Context<Editor>,
16587    ) {
16588        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16589        self.refresh_inline_diagnostics(false, window, cx);
16590    }
16591
16592    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16593        self.diagnostics_max_severity = severity;
16594        self.display_map.update(cx, |display_map, _| {
16595            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16596        });
16597    }
16598
16599    pub fn toggle_diagnostics(
16600        &mut self,
16601        _: &ToggleDiagnostics,
16602        window: &mut Window,
16603        cx: &mut Context<Editor>,
16604    ) {
16605        if !self.diagnostics_enabled() {
16606            return;
16607        }
16608
16609        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16610            EditorSettings::get_global(cx)
16611                .diagnostics_max_severity
16612                .filter(|severity| severity != &DiagnosticSeverity::Off)
16613                .unwrap_or(DiagnosticSeverity::Hint)
16614        } else {
16615            DiagnosticSeverity::Off
16616        };
16617        self.set_max_diagnostics_severity(new_severity, cx);
16618        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16619            self.active_diagnostics = ActiveDiagnostic::None;
16620            self.inline_diagnostics_update = Task::ready(());
16621            self.inline_diagnostics.clear();
16622        } else {
16623            self.refresh_inline_diagnostics(false, window, cx);
16624        }
16625
16626        cx.notify();
16627    }
16628
16629    pub fn toggle_minimap(
16630        &mut self,
16631        _: &ToggleMinimap,
16632        window: &mut Window,
16633        cx: &mut Context<Editor>,
16634    ) {
16635        if self.supports_minimap(cx) {
16636            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16637        }
16638    }
16639
16640    fn refresh_inline_diagnostics(
16641        &mut self,
16642        debounce: bool,
16643        window: &mut Window,
16644        cx: &mut Context<Self>,
16645    ) {
16646        let max_severity = ProjectSettings::get_global(cx)
16647            .diagnostics
16648            .inline
16649            .max_severity
16650            .unwrap_or(self.diagnostics_max_severity);
16651
16652        if !self.inline_diagnostics_enabled()
16653            || !self.show_inline_diagnostics
16654            || max_severity == DiagnosticSeverity::Off
16655        {
16656            self.inline_diagnostics_update = Task::ready(());
16657            self.inline_diagnostics.clear();
16658            return;
16659        }
16660
16661        let debounce_ms = ProjectSettings::get_global(cx)
16662            .diagnostics
16663            .inline
16664            .update_debounce_ms;
16665        let debounce = if debounce && debounce_ms > 0 {
16666            Some(Duration::from_millis(debounce_ms))
16667        } else {
16668            None
16669        };
16670        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16671            if let Some(debounce) = debounce {
16672                cx.background_executor().timer(debounce).await;
16673            }
16674            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16675                editor
16676                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16677                    .ok()
16678            }) else {
16679                return;
16680            };
16681
16682            let new_inline_diagnostics = cx
16683                .background_spawn(async move {
16684                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16685                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16686                        let message = diagnostic_entry
16687                            .diagnostic
16688                            .message
16689                            .split_once('\n')
16690                            .map(|(line, _)| line)
16691                            .map(SharedString::new)
16692                            .unwrap_or_else(|| {
16693                                SharedString::from(diagnostic_entry.diagnostic.message)
16694                            });
16695                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16696                        let (Ok(i) | Err(i)) = inline_diagnostics
16697                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16698                        inline_diagnostics.insert(
16699                            i,
16700                            (
16701                                start_anchor,
16702                                InlineDiagnostic {
16703                                    message,
16704                                    group_id: diagnostic_entry.diagnostic.group_id,
16705                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16706                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16707                                    severity: diagnostic_entry.diagnostic.severity,
16708                                },
16709                            ),
16710                        );
16711                    }
16712                    inline_diagnostics
16713                })
16714                .await;
16715
16716            editor
16717                .update(cx, |editor, cx| {
16718                    editor.inline_diagnostics = new_inline_diagnostics;
16719                    cx.notify();
16720                })
16721                .ok();
16722        });
16723    }
16724
16725    fn pull_diagnostics(
16726        &mut self,
16727        buffer_id: Option<BufferId>,
16728        window: &Window,
16729        cx: &mut Context<Self>,
16730    ) -> Option<()> {
16731        if !self.mode().is_full() {
16732            return None;
16733        }
16734        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16735            .diagnostics
16736            .lsp_pull_diagnostics;
16737        if !pull_diagnostics_settings.enabled {
16738            return None;
16739        }
16740        let project = self.project.as_ref()?.downgrade();
16741        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16742        let mut buffers = self.buffer.read(cx).all_buffers();
16743        if let Some(buffer_id) = buffer_id {
16744            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16745        }
16746
16747        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16748            cx.background_executor().timer(debounce).await;
16749
16750            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16751                buffers
16752                    .into_iter()
16753                    .filter_map(|buffer| {
16754                        project
16755                            .update(cx, |project, cx| {
16756                                project.lsp_store().update(cx, |lsp_store, cx| {
16757                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16758                                })
16759                            })
16760                            .ok()
16761                    })
16762                    .collect::<FuturesUnordered<_>>()
16763            }) else {
16764                return;
16765            };
16766
16767            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16768                match pull_task {
16769                    Ok(()) => {
16770                        if editor
16771                            .update_in(cx, |editor, window, cx| {
16772                                editor.update_diagnostics_state(window, cx);
16773                            })
16774                            .is_err()
16775                        {
16776                            return;
16777                        }
16778                    }
16779                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16780                }
16781            }
16782        });
16783
16784        Some(())
16785    }
16786
16787    pub fn set_selections_from_remote(
16788        &mut self,
16789        selections: Vec<Selection<Anchor>>,
16790        pending_selection: Option<Selection<Anchor>>,
16791        window: &mut Window,
16792        cx: &mut Context<Self>,
16793    ) {
16794        let old_cursor_position = self.selections.newest_anchor().head();
16795        self.selections.change_with(cx, |s| {
16796            s.select_anchors(selections);
16797            if let Some(pending_selection) = pending_selection {
16798                s.set_pending(pending_selection, SelectMode::Character);
16799            } else {
16800                s.clear_pending();
16801            }
16802        });
16803        self.selections_did_change(
16804            false,
16805            &old_cursor_position,
16806            SelectionEffects::default(),
16807            window,
16808            cx,
16809        );
16810    }
16811
16812    pub fn transact(
16813        &mut self,
16814        window: &mut Window,
16815        cx: &mut Context<Self>,
16816        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16817    ) -> Option<TransactionId> {
16818        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16819            this.start_transaction_at(Instant::now(), window, cx);
16820            update(this, window, cx);
16821            this.end_transaction_at(Instant::now(), cx)
16822        })
16823    }
16824
16825    pub fn start_transaction_at(
16826        &mut self,
16827        now: Instant,
16828        window: &mut Window,
16829        cx: &mut Context<Self>,
16830    ) {
16831        self.end_selection(window, cx);
16832        if let Some(tx_id) = self
16833            .buffer
16834            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16835        {
16836            self.selection_history
16837                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16838            cx.emit(EditorEvent::TransactionBegun {
16839                transaction_id: tx_id,
16840            })
16841        }
16842    }
16843
16844    pub fn end_transaction_at(
16845        &mut self,
16846        now: Instant,
16847        cx: &mut Context<Self>,
16848    ) -> Option<TransactionId> {
16849        if let Some(transaction_id) = self
16850            .buffer
16851            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16852        {
16853            if let Some((_, end_selections)) =
16854                self.selection_history.transaction_mut(transaction_id)
16855            {
16856                *end_selections = Some(self.selections.disjoint_anchors());
16857            } else {
16858                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16859            }
16860
16861            cx.emit(EditorEvent::Edited { transaction_id });
16862            Some(transaction_id)
16863        } else {
16864            None
16865        }
16866    }
16867
16868    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16869        if self.selection_mark_mode {
16870            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16871                s.move_with(|_, sel| {
16872                    sel.collapse_to(sel.head(), SelectionGoal::None);
16873                });
16874            })
16875        }
16876        self.selection_mark_mode = true;
16877        cx.notify();
16878    }
16879
16880    pub fn swap_selection_ends(
16881        &mut self,
16882        _: &actions::SwapSelectionEnds,
16883        window: &mut Window,
16884        cx: &mut Context<Self>,
16885    ) {
16886        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16887            s.move_with(|_, sel| {
16888                if sel.start != sel.end {
16889                    sel.reversed = !sel.reversed
16890                }
16891            });
16892        });
16893        self.request_autoscroll(Autoscroll::newest(), cx);
16894        cx.notify();
16895    }
16896
16897    pub fn toggle_fold(
16898        &mut self,
16899        _: &actions::ToggleFold,
16900        window: &mut Window,
16901        cx: &mut Context<Self>,
16902    ) {
16903        if self.is_singleton(cx) {
16904            let selection = self.selections.newest::<Point>(cx);
16905
16906            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16907            let range = if selection.is_empty() {
16908                let point = selection.head().to_display_point(&display_map);
16909                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16910                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16911                    .to_point(&display_map);
16912                start..end
16913            } else {
16914                selection.range()
16915            };
16916            if display_map.folds_in_range(range).next().is_some() {
16917                self.unfold_lines(&Default::default(), window, cx)
16918            } else {
16919                self.fold(&Default::default(), window, cx)
16920            }
16921        } else {
16922            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16923            let buffer_ids: HashSet<_> = self
16924                .selections
16925                .disjoint_anchor_ranges()
16926                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16927                .collect();
16928
16929            let should_unfold = buffer_ids
16930                .iter()
16931                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16932
16933            for buffer_id in buffer_ids {
16934                if should_unfold {
16935                    self.unfold_buffer(buffer_id, cx);
16936                } else {
16937                    self.fold_buffer(buffer_id, cx);
16938                }
16939            }
16940        }
16941    }
16942
16943    pub fn toggle_fold_recursive(
16944        &mut self,
16945        _: &actions::ToggleFoldRecursive,
16946        window: &mut Window,
16947        cx: &mut Context<Self>,
16948    ) {
16949        let selection = self.selections.newest::<Point>(cx);
16950
16951        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16952        let range = if selection.is_empty() {
16953            let point = selection.head().to_display_point(&display_map);
16954            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16955            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16956                .to_point(&display_map);
16957            start..end
16958        } else {
16959            selection.range()
16960        };
16961        if display_map.folds_in_range(range).next().is_some() {
16962            self.unfold_recursive(&Default::default(), window, cx)
16963        } else {
16964            self.fold_recursive(&Default::default(), window, cx)
16965        }
16966    }
16967
16968    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16969        if self.is_singleton(cx) {
16970            let mut to_fold = Vec::new();
16971            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16972            let selections = self.selections.all_adjusted(cx);
16973
16974            for selection in selections {
16975                let range = selection.range().sorted();
16976                let buffer_start_row = range.start.row;
16977
16978                if range.start.row != range.end.row {
16979                    let mut found = false;
16980                    let mut row = range.start.row;
16981                    while row <= range.end.row {
16982                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16983                        {
16984                            found = true;
16985                            row = crease.range().end.row + 1;
16986                            to_fold.push(crease);
16987                        } else {
16988                            row += 1
16989                        }
16990                    }
16991                    if found {
16992                        continue;
16993                    }
16994                }
16995
16996                for row in (0..=range.start.row).rev() {
16997                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16998                        if crease.range().end.row >= buffer_start_row {
16999                            to_fold.push(crease);
17000                            if row <= range.start.row {
17001                                break;
17002                            }
17003                        }
17004                    }
17005                }
17006            }
17007
17008            self.fold_creases(to_fold, true, window, cx);
17009        } else {
17010            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17011            let buffer_ids = self
17012                .selections
17013                .disjoint_anchor_ranges()
17014                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17015                .collect::<HashSet<_>>();
17016            for buffer_id in buffer_ids {
17017                self.fold_buffer(buffer_id, cx);
17018            }
17019        }
17020    }
17021
17022    fn fold_at_level(
17023        &mut self,
17024        fold_at: &FoldAtLevel,
17025        window: &mut Window,
17026        cx: &mut Context<Self>,
17027    ) {
17028        if !self.buffer.read(cx).is_singleton() {
17029            return;
17030        }
17031
17032        let fold_at_level = fold_at.0;
17033        let snapshot = self.buffer.read(cx).snapshot(cx);
17034        let mut to_fold = Vec::new();
17035        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17036
17037        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17038            while start_row < end_row {
17039                match self
17040                    .snapshot(window, cx)
17041                    .crease_for_buffer_row(MultiBufferRow(start_row))
17042                {
17043                    Some(crease) => {
17044                        let nested_start_row = crease.range().start.row + 1;
17045                        let nested_end_row = crease.range().end.row;
17046
17047                        if current_level < fold_at_level {
17048                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17049                        } else if current_level == fold_at_level {
17050                            to_fold.push(crease);
17051                        }
17052
17053                        start_row = nested_end_row + 1;
17054                    }
17055                    None => start_row += 1,
17056                }
17057            }
17058        }
17059
17060        self.fold_creases(to_fold, true, window, cx);
17061    }
17062
17063    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17064        if self.buffer.read(cx).is_singleton() {
17065            let mut fold_ranges = Vec::new();
17066            let snapshot = self.buffer.read(cx).snapshot(cx);
17067
17068            for row in 0..snapshot.max_row().0 {
17069                if let Some(foldable_range) = self
17070                    .snapshot(window, cx)
17071                    .crease_for_buffer_row(MultiBufferRow(row))
17072                {
17073                    fold_ranges.push(foldable_range);
17074                }
17075            }
17076
17077            self.fold_creases(fold_ranges, true, window, cx);
17078        } else {
17079            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17080                editor
17081                    .update_in(cx, |editor, _, cx| {
17082                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17083                            editor.fold_buffer(buffer_id, cx);
17084                        }
17085                    })
17086                    .ok();
17087            });
17088        }
17089    }
17090
17091    pub fn fold_function_bodies(
17092        &mut self,
17093        _: &actions::FoldFunctionBodies,
17094        window: &mut Window,
17095        cx: &mut Context<Self>,
17096    ) {
17097        let snapshot = self.buffer.read(cx).snapshot(cx);
17098
17099        let ranges = snapshot
17100            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17101            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17102            .collect::<Vec<_>>();
17103
17104        let creases = ranges
17105            .into_iter()
17106            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17107            .collect();
17108
17109        self.fold_creases(creases, true, window, cx);
17110    }
17111
17112    pub fn fold_recursive(
17113        &mut self,
17114        _: &actions::FoldRecursive,
17115        window: &mut Window,
17116        cx: &mut Context<Self>,
17117    ) {
17118        let mut to_fold = Vec::new();
17119        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17120        let selections = self.selections.all_adjusted(cx);
17121
17122        for selection in selections {
17123            let range = selection.range().sorted();
17124            let buffer_start_row = range.start.row;
17125
17126            if range.start.row != range.end.row {
17127                let mut found = false;
17128                for row in range.start.row..=range.end.row {
17129                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17130                        found = true;
17131                        to_fold.push(crease);
17132                    }
17133                }
17134                if found {
17135                    continue;
17136                }
17137            }
17138
17139            for row in (0..=range.start.row).rev() {
17140                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17141                    if crease.range().end.row >= buffer_start_row {
17142                        to_fold.push(crease);
17143                    } else {
17144                        break;
17145                    }
17146                }
17147            }
17148        }
17149
17150        self.fold_creases(to_fold, true, window, cx);
17151    }
17152
17153    pub fn fold_at(
17154        &mut self,
17155        buffer_row: MultiBufferRow,
17156        window: &mut Window,
17157        cx: &mut Context<Self>,
17158    ) {
17159        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17160
17161        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17162            let autoscroll = self
17163                .selections
17164                .all::<Point>(cx)
17165                .iter()
17166                .any(|selection| crease.range().overlaps(&selection.range()));
17167
17168            self.fold_creases(vec![crease], autoscroll, window, cx);
17169        }
17170    }
17171
17172    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17173        if self.is_singleton(cx) {
17174            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17175            let buffer = &display_map.buffer_snapshot;
17176            let selections = self.selections.all::<Point>(cx);
17177            let ranges = selections
17178                .iter()
17179                .map(|s| {
17180                    let range = s.display_range(&display_map).sorted();
17181                    let mut start = range.start.to_point(&display_map);
17182                    let mut end = range.end.to_point(&display_map);
17183                    start.column = 0;
17184                    end.column = buffer.line_len(MultiBufferRow(end.row));
17185                    start..end
17186                })
17187                .collect::<Vec<_>>();
17188
17189            self.unfold_ranges(&ranges, true, true, cx);
17190        } else {
17191            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17192            let buffer_ids = self
17193                .selections
17194                .disjoint_anchor_ranges()
17195                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17196                .collect::<HashSet<_>>();
17197            for buffer_id in buffer_ids {
17198                self.unfold_buffer(buffer_id, cx);
17199            }
17200        }
17201    }
17202
17203    pub fn unfold_recursive(
17204        &mut self,
17205        _: &UnfoldRecursive,
17206        _window: &mut Window,
17207        cx: &mut Context<Self>,
17208    ) {
17209        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17210        let selections = self.selections.all::<Point>(cx);
17211        let ranges = selections
17212            .iter()
17213            .map(|s| {
17214                let mut range = s.display_range(&display_map).sorted();
17215                *range.start.column_mut() = 0;
17216                *range.end.column_mut() = display_map.line_len(range.end.row());
17217                let start = range.start.to_point(&display_map);
17218                let end = range.end.to_point(&display_map);
17219                start..end
17220            })
17221            .collect::<Vec<_>>();
17222
17223        self.unfold_ranges(&ranges, true, true, cx);
17224    }
17225
17226    pub fn unfold_at(
17227        &mut self,
17228        buffer_row: MultiBufferRow,
17229        _window: &mut Window,
17230        cx: &mut Context<Self>,
17231    ) {
17232        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17233
17234        let intersection_range = Point::new(buffer_row.0, 0)
17235            ..Point::new(
17236                buffer_row.0,
17237                display_map.buffer_snapshot.line_len(buffer_row),
17238            );
17239
17240        let autoscroll = self
17241            .selections
17242            .all::<Point>(cx)
17243            .iter()
17244            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17245
17246        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17247    }
17248
17249    pub fn unfold_all(
17250        &mut self,
17251        _: &actions::UnfoldAll,
17252        _window: &mut Window,
17253        cx: &mut Context<Self>,
17254    ) {
17255        if self.buffer.read(cx).is_singleton() {
17256            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17257            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17258        } else {
17259            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17260                editor
17261                    .update(cx, |editor, cx| {
17262                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17263                            editor.unfold_buffer(buffer_id, cx);
17264                        }
17265                    })
17266                    .ok();
17267            });
17268        }
17269    }
17270
17271    pub fn fold_selected_ranges(
17272        &mut self,
17273        _: &FoldSelectedRanges,
17274        window: &mut Window,
17275        cx: &mut Context<Self>,
17276    ) {
17277        let selections = self.selections.all_adjusted(cx);
17278        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17279        let ranges = selections
17280            .into_iter()
17281            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17282            .collect::<Vec<_>>();
17283        self.fold_creases(ranges, true, window, cx);
17284    }
17285
17286    pub fn fold_ranges<T: ToOffset + Clone>(
17287        &mut self,
17288        ranges: Vec<Range<T>>,
17289        auto_scroll: bool,
17290        window: &mut Window,
17291        cx: &mut Context<Self>,
17292    ) {
17293        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17294        let ranges = ranges
17295            .into_iter()
17296            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17297            .collect::<Vec<_>>();
17298        self.fold_creases(ranges, auto_scroll, window, cx);
17299    }
17300
17301    pub fn fold_creases<T: ToOffset + Clone>(
17302        &mut self,
17303        creases: Vec<Crease<T>>,
17304        auto_scroll: bool,
17305        _window: &mut Window,
17306        cx: &mut Context<Self>,
17307    ) {
17308        if creases.is_empty() {
17309            return;
17310        }
17311
17312        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17313
17314        if auto_scroll {
17315            self.request_autoscroll(Autoscroll::fit(), cx);
17316        }
17317
17318        cx.notify();
17319
17320        self.scrollbar_marker_state.dirty = true;
17321        self.folds_did_change(cx);
17322    }
17323
17324    /// Removes any folds whose ranges intersect any of the given ranges.
17325    pub fn unfold_ranges<T: ToOffset + Clone>(
17326        &mut self,
17327        ranges: &[Range<T>],
17328        inclusive: bool,
17329        auto_scroll: bool,
17330        cx: &mut Context<Self>,
17331    ) {
17332        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17333            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17334        });
17335        self.folds_did_change(cx);
17336    }
17337
17338    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17339        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17340            return;
17341        }
17342        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17343        self.display_map.update(cx, |display_map, cx| {
17344            display_map.fold_buffers([buffer_id], cx)
17345        });
17346        cx.emit(EditorEvent::BufferFoldToggled {
17347            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17348            folded: true,
17349        });
17350        cx.notify();
17351    }
17352
17353    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17354        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17355            return;
17356        }
17357        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17358        self.display_map.update(cx, |display_map, cx| {
17359            display_map.unfold_buffers([buffer_id], cx);
17360        });
17361        cx.emit(EditorEvent::BufferFoldToggled {
17362            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17363            folded: false,
17364        });
17365        cx.notify();
17366    }
17367
17368    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17369        self.display_map.read(cx).is_buffer_folded(buffer)
17370    }
17371
17372    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17373        self.display_map.read(cx).folded_buffers()
17374    }
17375
17376    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17377        self.display_map.update(cx, |display_map, cx| {
17378            display_map.disable_header_for_buffer(buffer_id, cx);
17379        });
17380        cx.notify();
17381    }
17382
17383    /// Removes any folds with the given ranges.
17384    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17385        &mut self,
17386        ranges: &[Range<T>],
17387        type_id: TypeId,
17388        auto_scroll: bool,
17389        cx: &mut Context<Self>,
17390    ) {
17391        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17392            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17393        });
17394        self.folds_did_change(cx);
17395    }
17396
17397    fn remove_folds_with<T: ToOffset + Clone>(
17398        &mut self,
17399        ranges: &[Range<T>],
17400        auto_scroll: bool,
17401        cx: &mut Context<Self>,
17402        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17403    ) {
17404        if ranges.is_empty() {
17405            return;
17406        }
17407
17408        let mut buffers_affected = HashSet::default();
17409        let multi_buffer = self.buffer().read(cx);
17410        for range in ranges {
17411            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17412                buffers_affected.insert(buffer.read(cx).remote_id());
17413            };
17414        }
17415
17416        self.display_map.update(cx, update);
17417
17418        if auto_scroll {
17419            self.request_autoscroll(Autoscroll::fit(), cx);
17420        }
17421
17422        cx.notify();
17423        self.scrollbar_marker_state.dirty = true;
17424        self.active_indent_guides_state.dirty = true;
17425    }
17426
17427    pub fn update_renderer_widths(
17428        &mut self,
17429        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17430        cx: &mut Context<Self>,
17431    ) -> bool {
17432        self.display_map
17433            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17434    }
17435
17436    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17437        self.display_map.read(cx).fold_placeholder.clone()
17438    }
17439
17440    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17441        self.buffer.update(cx, |buffer, cx| {
17442            buffer.set_all_diff_hunks_expanded(cx);
17443        });
17444    }
17445
17446    pub fn expand_all_diff_hunks(
17447        &mut self,
17448        _: &ExpandAllDiffHunks,
17449        _window: &mut Window,
17450        cx: &mut Context<Self>,
17451    ) {
17452        self.buffer.update(cx, |buffer, cx| {
17453            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17454        });
17455    }
17456
17457    pub fn toggle_selected_diff_hunks(
17458        &mut self,
17459        _: &ToggleSelectedDiffHunks,
17460        _window: &mut Window,
17461        cx: &mut Context<Self>,
17462    ) {
17463        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17464        self.toggle_diff_hunks_in_ranges(ranges, cx);
17465    }
17466
17467    pub fn diff_hunks_in_ranges<'a>(
17468        &'a self,
17469        ranges: &'a [Range<Anchor>],
17470        buffer: &'a MultiBufferSnapshot,
17471    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17472        ranges.iter().flat_map(move |range| {
17473            let end_excerpt_id = range.end.excerpt_id;
17474            let range = range.to_point(buffer);
17475            let mut peek_end = range.end;
17476            if range.end.row < buffer.max_row().0 {
17477                peek_end = Point::new(range.end.row + 1, 0);
17478            }
17479            buffer
17480                .diff_hunks_in_range(range.start..peek_end)
17481                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17482        })
17483    }
17484
17485    pub fn has_stageable_diff_hunks_in_ranges(
17486        &self,
17487        ranges: &[Range<Anchor>],
17488        snapshot: &MultiBufferSnapshot,
17489    ) -> bool {
17490        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17491        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17492    }
17493
17494    pub fn toggle_staged_selected_diff_hunks(
17495        &mut self,
17496        _: &::git::ToggleStaged,
17497        _: &mut Window,
17498        cx: &mut Context<Self>,
17499    ) {
17500        let snapshot = self.buffer.read(cx).snapshot(cx);
17501        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17502        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17503        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17504    }
17505
17506    pub fn set_render_diff_hunk_controls(
17507        &mut self,
17508        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17509        cx: &mut Context<Self>,
17510    ) {
17511        self.render_diff_hunk_controls = render_diff_hunk_controls;
17512        cx.notify();
17513    }
17514
17515    pub fn stage_and_next(
17516        &mut self,
17517        _: &::git::StageAndNext,
17518        window: &mut Window,
17519        cx: &mut Context<Self>,
17520    ) {
17521        self.do_stage_or_unstage_and_next(true, window, cx);
17522    }
17523
17524    pub fn unstage_and_next(
17525        &mut self,
17526        _: &::git::UnstageAndNext,
17527        window: &mut Window,
17528        cx: &mut Context<Self>,
17529    ) {
17530        self.do_stage_or_unstage_and_next(false, window, cx);
17531    }
17532
17533    pub fn stage_or_unstage_diff_hunks(
17534        &mut self,
17535        stage: bool,
17536        ranges: Vec<Range<Anchor>>,
17537        cx: &mut Context<Self>,
17538    ) {
17539        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17540        cx.spawn(async move |this, cx| {
17541            task.await?;
17542            this.update(cx, |this, cx| {
17543                let snapshot = this.buffer.read(cx).snapshot(cx);
17544                let chunk_by = this
17545                    .diff_hunks_in_ranges(&ranges, &snapshot)
17546                    .chunk_by(|hunk| hunk.buffer_id);
17547                for (buffer_id, hunks) in &chunk_by {
17548                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17549                }
17550            })
17551        })
17552        .detach_and_log_err(cx);
17553    }
17554
17555    fn save_buffers_for_ranges_if_needed(
17556        &mut self,
17557        ranges: &[Range<Anchor>],
17558        cx: &mut Context<Editor>,
17559    ) -> Task<Result<()>> {
17560        let multibuffer = self.buffer.read(cx);
17561        let snapshot = multibuffer.read(cx);
17562        let buffer_ids: HashSet<_> = ranges
17563            .iter()
17564            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17565            .collect();
17566        drop(snapshot);
17567
17568        let mut buffers = HashSet::default();
17569        for buffer_id in buffer_ids {
17570            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17571                let buffer = buffer_entity.read(cx);
17572                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17573                {
17574                    buffers.insert(buffer_entity);
17575                }
17576            }
17577        }
17578
17579        if let Some(project) = &self.project {
17580            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17581        } else {
17582            Task::ready(Ok(()))
17583        }
17584    }
17585
17586    fn do_stage_or_unstage_and_next(
17587        &mut self,
17588        stage: bool,
17589        window: &mut Window,
17590        cx: &mut Context<Self>,
17591    ) {
17592        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17593
17594        if ranges.iter().any(|range| range.start != range.end) {
17595            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17596            return;
17597        }
17598
17599        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17600        let snapshot = self.snapshot(window, cx);
17601        let position = self.selections.newest::<Point>(cx).head();
17602        let mut row = snapshot
17603            .buffer_snapshot
17604            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17605            .find(|hunk| hunk.row_range.start.0 > position.row)
17606            .map(|hunk| hunk.row_range.start);
17607
17608        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17609        // Outside of the project diff editor, wrap around to the beginning.
17610        if !all_diff_hunks_expanded {
17611            row = row.or_else(|| {
17612                snapshot
17613                    .buffer_snapshot
17614                    .diff_hunks_in_range(Point::zero()..position)
17615                    .find(|hunk| hunk.row_range.end.0 < position.row)
17616                    .map(|hunk| hunk.row_range.start)
17617            });
17618        }
17619
17620        if let Some(row) = row {
17621            let destination = Point::new(row.0, 0);
17622            let autoscroll = Autoscroll::center();
17623
17624            self.unfold_ranges(&[destination..destination], false, false, cx);
17625            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17626                s.select_ranges([destination..destination]);
17627            });
17628        }
17629    }
17630
17631    fn do_stage_or_unstage(
17632        &self,
17633        stage: bool,
17634        buffer_id: BufferId,
17635        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17636        cx: &mut App,
17637    ) -> Option<()> {
17638        let project = self.project.as_ref()?;
17639        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17640        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17641        let buffer_snapshot = buffer.read(cx).snapshot();
17642        let file_exists = buffer_snapshot
17643            .file()
17644            .is_some_and(|file| file.disk_state().exists());
17645        diff.update(cx, |diff, cx| {
17646            diff.stage_or_unstage_hunks(
17647                stage,
17648                &hunks
17649                    .map(|hunk| buffer_diff::DiffHunk {
17650                        buffer_range: hunk.buffer_range,
17651                        diff_base_byte_range: hunk.diff_base_byte_range,
17652                        secondary_status: hunk.secondary_status,
17653                        range: Point::zero()..Point::zero(), // unused
17654                    })
17655                    .collect::<Vec<_>>(),
17656                &buffer_snapshot,
17657                file_exists,
17658                cx,
17659            )
17660        });
17661        None
17662    }
17663
17664    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17665        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17666        self.buffer
17667            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17668    }
17669
17670    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17671        self.buffer.update(cx, |buffer, cx| {
17672            let ranges = vec![Anchor::min()..Anchor::max()];
17673            if !buffer.all_diff_hunks_expanded()
17674                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17675            {
17676                buffer.collapse_diff_hunks(ranges, cx);
17677                true
17678            } else {
17679                false
17680            }
17681        })
17682    }
17683
17684    fn toggle_diff_hunks_in_ranges(
17685        &mut self,
17686        ranges: Vec<Range<Anchor>>,
17687        cx: &mut Context<Editor>,
17688    ) {
17689        self.buffer.update(cx, |buffer, cx| {
17690            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17691            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17692        })
17693    }
17694
17695    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17696        self.buffer.update(cx, |buffer, cx| {
17697            let snapshot = buffer.snapshot(cx);
17698            let excerpt_id = range.end.excerpt_id;
17699            let point_range = range.to_point(&snapshot);
17700            let expand = !buffer.single_hunk_is_expanded(range, cx);
17701            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17702        })
17703    }
17704
17705    pub(crate) fn apply_all_diff_hunks(
17706        &mut self,
17707        _: &ApplyAllDiffHunks,
17708        window: &mut Window,
17709        cx: &mut Context<Self>,
17710    ) {
17711        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17712
17713        let buffers = self.buffer.read(cx).all_buffers();
17714        for branch_buffer in buffers {
17715            branch_buffer.update(cx, |branch_buffer, cx| {
17716                branch_buffer.merge_into_base(Vec::new(), cx);
17717            });
17718        }
17719
17720        if let Some(project) = self.project.clone() {
17721            self.save(
17722                SaveOptions {
17723                    format: true,
17724                    autosave: false,
17725                },
17726                project,
17727                window,
17728                cx,
17729            )
17730            .detach_and_log_err(cx);
17731        }
17732    }
17733
17734    pub(crate) fn apply_selected_diff_hunks(
17735        &mut self,
17736        _: &ApplyDiffHunk,
17737        window: &mut Window,
17738        cx: &mut Context<Self>,
17739    ) {
17740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17741        let snapshot = self.snapshot(window, cx);
17742        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17743        let mut ranges_by_buffer = HashMap::default();
17744        self.transact(window, cx, |editor, _window, cx| {
17745            for hunk in hunks {
17746                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17747                    ranges_by_buffer
17748                        .entry(buffer.clone())
17749                        .or_insert_with(Vec::new)
17750                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17751                }
17752            }
17753
17754            for (buffer, ranges) in ranges_by_buffer {
17755                buffer.update(cx, |buffer, cx| {
17756                    buffer.merge_into_base(ranges, cx);
17757                });
17758            }
17759        });
17760
17761        if let Some(project) = self.project.clone() {
17762            self.save(
17763                SaveOptions {
17764                    format: true,
17765                    autosave: false,
17766                },
17767                project,
17768                window,
17769                cx,
17770            )
17771            .detach_and_log_err(cx);
17772        }
17773    }
17774
17775    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17776        if hovered != self.gutter_hovered {
17777            self.gutter_hovered = hovered;
17778            cx.notify();
17779        }
17780    }
17781
17782    pub fn insert_blocks(
17783        &mut self,
17784        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17785        autoscroll: Option<Autoscroll>,
17786        cx: &mut Context<Self>,
17787    ) -> Vec<CustomBlockId> {
17788        let blocks = self
17789            .display_map
17790            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17791        if let Some(autoscroll) = autoscroll {
17792            self.request_autoscroll(autoscroll, cx);
17793        }
17794        cx.notify();
17795        blocks
17796    }
17797
17798    pub fn resize_blocks(
17799        &mut self,
17800        heights: HashMap<CustomBlockId, u32>,
17801        autoscroll: Option<Autoscroll>,
17802        cx: &mut Context<Self>,
17803    ) {
17804        self.display_map
17805            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17806        if let Some(autoscroll) = autoscroll {
17807            self.request_autoscroll(autoscroll, cx);
17808        }
17809        cx.notify();
17810    }
17811
17812    pub fn replace_blocks(
17813        &mut self,
17814        renderers: HashMap<CustomBlockId, RenderBlock>,
17815        autoscroll: Option<Autoscroll>,
17816        cx: &mut Context<Self>,
17817    ) {
17818        self.display_map
17819            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17820        if let Some(autoscroll) = autoscroll {
17821            self.request_autoscroll(autoscroll, cx);
17822        }
17823        cx.notify();
17824    }
17825
17826    pub fn remove_blocks(
17827        &mut self,
17828        block_ids: HashSet<CustomBlockId>,
17829        autoscroll: Option<Autoscroll>,
17830        cx: &mut Context<Self>,
17831    ) {
17832        self.display_map.update(cx, |display_map, cx| {
17833            display_map.remove_blocks(block_ids, cx)
17834        });
17835        if let Some(autoscroll) = autoscroll {
17836            self.request_autoscroll(autoscroll, cx);
17837        }
17838        cx.notify();
17839    }
17840
17841    pub fn row_for_block(
17842        &self,
17843        block_id: CustomBlockId,
17844        cx: &mut Context<Self>,
17845    ) -> Option<DisplayRow> {
17846        self.display_map
17847            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17848    }
17849
17850    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17851        self.focused_block = Some(focused_block);
17852    }
17853
17854    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17855        self.focused_block.take()
17856    }
17857
17858    pub fn insert_creases(
17859        &mut self,
17860        creases: impl IntoIterator<Item = Crease<Anchor>>,
17861        cx: &mut Context<Self>,
17862    ) -> Vec<CreaseId> {
17863        self.display_map
17864            .update(cx, |map, cx| map.insert_creases(creases, cx))
17865    }
17866
17867    pub fn remove_creases(
17868        &mut self,
17869        ids: impl IntoIterator<Item = CreaseId>,
17870        cx: &mut Context<Self>,
17871    ) -> Vec<(CreaseId, Range<Anchor>)> {
17872        self.display_map
17873            .update(cx, |map, cx| map.remove_creases(ids, cx))
17874    }
17875
17876    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17877        self.display_map
17878            .update(cx, |map, cx| map.snapshot(cx))
17879            .longest_row()
17880    }
17881
17882    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17883        self.display_map
17884            .update(cx, |map, cx| map.snapshot(cx))
17885            .max_point()
17886    }
17887
17888    pub fn text(&self, cx: &App) -> String {
17889        self.buffer.read(cx).read(cx).text()
17890    }
17891
17892    pub fn is_empty(&self, cx: &App) -> bool {
17893        self.buffer.read(cx).read(cx).is_empty()
17894    }
17895
17896    pub fn text_option(&self, cx: &App) -> Option<String> {
17897        let text = self.text(cx);
17898        let text = text.trim();
17899
17900        if text.is_empty() {
17901            return None;
17902        }
17903
17904        Some(text.to_string())
17905    }
17906
17907    pub fn set_text(
17908        &mut self,
17909        text: impl Into<Arc<str>>,
17910        window: &mut Window,
17911        cx: &mut Context<Self>,
17912    ) {
17913        self.transact(window, cx, |this, _, cx| {
17914            this.buffer
17915                .read(cx)
17916                .as_singleton()
17917                .expect("you can only call set_text on editors for singleton buffers")
17918                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17919        });
17920    }
17921
17922    pub fn display_text(&self, cx: &mut App) -> String {
17923        self.display_map
17924            .update(cx, |map, cx| map.snapshot(cx))
17925            .text()
17926    }
17927
17928    fn create_minimap(
17929        &self,
17930        minimap_settings: MinimapSettings,
17931        window: &mut Window,
17932        cx: &mut Context<Self>,
17933    ) -> Option<Entity<Self>> {
17934        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17935            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17936    }
17937
17938    fn initialize_new_minimap(
17939        &self,
17940        minimap_settings: MinimapSettings,
17941        window: &mut Window,
17942        cx: &mut Context<Self>,
17943    ) -> Entity<Self> {
17944        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17945
17946        let mut minimap = Editor::new_internal(
17947            EditorMode::Minimap {
17948                parent: cx.weak_entity(),
17949            },
17950            self.buffer.clone(),
17951            self.project.clone(),
17952            Some(self.display_map.clone()),
17953            window,
17954            cx,
17955        );
17956        minimap.scroll_manager.clone_state(&self.scroll_manager);
17957        minimap.set_text_style_refinement(TextStyleRefinement {
17958            font_size: Some(MINIMAP_FONT_SIZE),
17959            font_weight: Some(MINIMAP_FONT_WEIGHT),
17960            ..Default::default()
17961        });
17962        minimap.update_minimap_configuration(minimap_settings, cx);
17963        cx.new(|_| minimap)
17964    }
17965
17966    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17967        let current_line_highlight = minimap_settings
17968            .current_line_highlight
17969            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17970        self.set_current_line_highlight(Some(current_line_highlight));
17971    }
17972
17973    pub fn minimap(&self) -> Option<&Entity<Self>> {
17974        self.minimap
17975            .as_ref()
17976            .filter(|_| self.minimap_visibility.visible())
17977    }
17978
17979    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17980        let mut wrap_guides = smallvec![];
17981
17982        if self.show_wrap_guides == Some(false) {
17983            return wrap_guides;
17984        }
17985
17986        let settings = self.buffer.read(cx).language_settings(cx);
17987        if settings.show_wrap_guides {
17988            match self.soft_wrap_mode(cx) {
17989                SoftWrap::Column(soft_wrap) => {
17990                    wrap_guides.push((soft_wrap as usize, true));
17991                }
17992                SoftWrap::Bounded(soft_wrap) => {
17993                    wrap_guides.push((soft_wrap as usize, true));
17994                }
17995                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17996            }
17997            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17998        }
17999
18000        wrap_guides
18001    }
18002
18003    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18004        let settings = self.buffer.read(cx).language_settings(cx);
18005        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18006        match mode {
18007            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18008                SoftWrap::None
18009            }
18010            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18011            language_settings::SoftWrap::PreferredLineLength => {
18012                SoftWrap::Column(settings.preferred_line_length)
18013            }
18014            language_settings::SoftWrap::Bounded => {
18015                SoftWrap::Bounded(settings.preferred_line_length)
18016            }
18017        }
18018    }
18019
18020    pub fn set_soft_wrap_mode(
18021        &mut self,
18022        mode: language_settings::SoftWrap,
18023
18024        cx: &mut Context<Self>,
18025    ) {
18026        self.soft_wrap_mode_override = Some(mode);
18027        cx.notify();
18028    }
18029
18030    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18031        self.hard_wrap = hard_wrap;
18032        cx.notify();
18033    }
18034
18035    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18036        self.text_style_refinement = Some(style);
18037    }
18038
18039    /// called by the Element so we know what style we were most recently rendered with.
18040    pub(crate) fn set_style(
18041        &mut self,
18042        style: EditorStyle,
18043        window: &mut Window,
18044        cx: &mut Context<Self>,
18045    ) {
18046        // We intentionally do not inform the display map about the minimap style
18047        // so that wrapping is not recalculated and stays consistent for the editor
18048        // and its linked minimap.
18049        if !self.mode.is_minimap() {
18050            let rem_size = window.rem_size();
18051            self.display_map.update(cx, |map, cx| {
18052                map.set_font(
18053                    style.text.font(),
18054                    style.text.font_size.to_pixels(rem_size),
18055                    cx,
18056                )
18057            });
18058        }
18059        self.style = Some(style);
18060    }
18061
18062    pub fn style(&self) -> Option<&EditorStyle> {
18063        self.style.as_ref()
18064    }
18065
18066    // Called by the element. This method is not designed to be called outside of the editor
18067    // element's layout code because it does not notify when rewrapping is computed synchronously.
18068    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18069        self.display_map
18070            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18071    }
18072
18073    pub fn set_soft_wrap(&mut self) {
18074        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18075    }
18076
18077    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18078        if self.soft_wrap_mode_override.is_some() {
18079            self.soft_wrap_mode_override.take();
18080        } else {
18081            let soft_wrap = match self.soft_wrap_mode(cx) {
18082                SoftWrap::GitDiff => return,
18083                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18084                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18085                    language_settings::SoftWrap::None
18086                }
18087            };
18088            self.soft_wrap_mode_override = Some(soft_wrap);
18089        }
18090        cx.notify();
18091    }
18092
18093    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18094        let Some(workspace) = self.workspace() else {
18095            return;
18096        };
18097        let fs = workspace.read(cx).app_state().fs.clone();
18098        let current_show = TabBarSettings::get_global(cx).show;
18099        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18100            setting.show = Some(!current_show);
18101        });
18102    }
18103
18104    pub fn toggle_indent_guides(
18105        &mut self,
18106        _: &ToggleIndentGuides,
18107        _: &mut Window,
18108        cx: &mut Context<Self>,
18109    ) {
18110        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18111            self.buffer
18112                .read(cx)
18113                .language_settings(cx)
18114                .indent_guides
18115                .enabled
18116        });
18117        self.show_indent_guides = Some(!currently_enabled);
18118        cx.notify();
18119    }
18120
18121    fn should_show_indent_guides(&self) -> Option<bool> {
18122        self.show_indent_guides
18123    }
18124
18125    pub fn toggle_line_numbers(
18126        &mut self,
18127        _: &ToggleLineNumbers,
18128        _: &mut Window,
18129        cx: &mut Context<Self>,
18130    ) {
18131        let mut editor_settings = EditorSettings::get_global(cx).clone();
18132        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18133        EditorSettings::override_global(editor_settings, cx);
18134    }
18135
18136    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18137        if let Some(show_line_numbers) = self.show_line_numbers {
18138            return show_line_numbers;
18139        }
18140        EditorSettings::get_global(cx).gutter.line_numbers
18141    }
18142
18143    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18144        self.use_relative_line_numbers
18145            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18146    }
18147
18148    pub fn toggle_relative_line_numbers(
18149        &mut self,
18150        _: &ToggleRelativeLineNumbers,
18151        _: &mut Window,
18152        cx: &mut Context<Self>,
18153    ) {
18154        let is_relative = self.should_use_relative_line_numbers(cx);
18155        self.set_relative_line_number(Some(!is_relative), cx)
18156    }
18157
18158    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18159        self.use_relative_line_numbers = is_relative;
18160        cx.notify();
18161    }
18162
18163    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18164        self.show_gutter = show_gutter;
18165        cx.notify();
18166    }
18167
18168    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18169        self.show_scrollbars = ScrollbarAxes {
18170            horizontal: show,
18171            vertical: show,
18172        };
18173        cx.notify();
18174    }
18175
18176    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18177        self.show_scrollbars.vertical = show;
18178        cx.notify();
18179    }
18180
18181    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18182        self.show_scrollbars.horizontal = show;
18183        cx.notify();
18184    }
18185
18186    pub fn set_minimap_visibility(
18187        &mut self,
18188        minimap_visibility: MinimapVisibility,
18189        window: &mut Window,
18190        cx: &mut Context<Self>,
18191    ) {
18192        if self.minimap_visibility != minimap_visibility {
18193            if minimap_visibility.visible() && self.minimap.is_none() {
18194                let minimap_settings = EditorSettings::get_global(cx).minimap;
18195                self.minimap =
18196                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18197            }
18198            self.minimap_visibility = minimap_visibility;
18199            cx.notify();
18200        }
18201    }
18202
18203    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18204        self.set_show_scrollbars(false, cx);
18205        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18206    }
18207
18208    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18209        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18210    }
18211
18212    /// Normally the text in full mode and auto height editors is padded on the
18213    /// left side by roughly half a character width for improved hit testing.
18214    ///
18215    /// Use this method to disable this for cases where this is not wanted (e.g.
18216    /// if you want to align the editor text with some other text above or below)
18217    /// or if you want to add this padding to single-line editors.
18218    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18219        self.offset_content = offset_content;
18220        cx.notify();
18221    }
18222
18223    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18224        self.show_line_numbers = Some(show_line_numbers);
18225        cx.notify();
18226    }
18227
18228    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18229        self.disable_expand_excerpt_buttons = true;
18230        cx.notify();
18231    }
18232
18233    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18234        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18235        cx.notify();
18236    }
18237
18238    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18239        self.show_code_actions = Some(show_code_actions);
18240        cx.notify();
18241    }
18242
18243    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18244        self.show_runnables = Some(show_runnables);
18245        cx.notify();
18246    }
18247
18248    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18249        self.show_breakpoints = Some(show_breakpoints);
18250        cx.notify();
18251    }
18252
18253    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18254        if self.display_map.read(cx).masked != masked {
18255            self.display_map.update(cx, |map, _| map.masked = masked);
18256        }
18257        cx.notify()
18258    }
18259
18260    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18261        self.show_wrap_guides = Some(show_wrap_guides);
18262        cx.notify();
18263    }
18264
18265    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18266        self.show_indent_guides = Some(show_indent_guides);
18267        cx.notify();
18268    }
18269
18270    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18271        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18272            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18273                if let Some(dir) = file.abs_path(cx).parent() {
18274                    return Some(dir.to_owned());
18275                }
18276            }
18277
18278            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18279                return Some(project_path.path.to_path_buf());
18280            }
18281        }
18282
18283        None
18284    }
18285
18286    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18287        self.active_excerpt(cx)?
18288            .1
18289            .read(cx)
18290            .file()
18291            .and_then(|f| f.as_local())
18292    }
18293
18294    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18295        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18296            let buffer = buffer.read(cx);
18297            if let Some(project_path) = buffer.project_path(cx) {
18298                let project = self.project.as_ref()?.read(cx);
18299                project.absolute_path(&project_path, cx)
18300            } else {
18301                buffer
18302                    .file()
18303                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18304            }
18305        })
18306    }
18307
18308    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18309        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18310            let project_path = buffer.read(cx).project_path(cx)?;
18311            let project = self.project.as_ref()?.read(cx);
18312            let entry = project.entry_for_path(&project_path, cx)?;
18313            let path = entry.path.to_path_buf();
18314            Some(path)
18315        })
18316    }
18317
18318    pub fn reveal_in_finder(
18319        &mut self,
18320        _: &RevealInFileManager,
18321        _window: &mut Window,
18322        cx: &mut Context<Self>,
18323    ) {
18324        if let Some(target) = self.target_file(cx) {
18325            cx.reveal_path(&target.abs_path(cx));
18326        }
18327    }
18328
18329    pub fn copy_path(
18330        &mut self,
18331        _: &zed_actions::workspace::CopyPath,
18332        _window: &mut Window,
18333        cx: &mut Context<Self>,
18334    ) {
18335        if let Some(path) = self.target_file_abs_path(cx) {
18336            if let Some(path) = path.to_str() {
18337                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18338            }
18339        }
18340    }
18341
18342    pub fn copy_relative_path(
18343        &mut self,
18344        _: &zed_actions::workspace::CopyRelativePath,
18345        _window: &mut Window,
18346        cx: &mut Context<Self>,
18347    ) {
18348        if let Some(path) = self.target_file_path(cx) {
18349            if let Some(path) = path.to_str() {
18350                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18351            }
18352        }
18353    }
18354
18355    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18356        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18357            buffer.read(cx).project_path(cx)
18358        } else {
18359            None
18360        }
18361    }
18362
18363    // Returns true if the editor handled a go-to-line request
18364    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18365        maybe!({
18366            let breakpoint_store = self.breakpoint_store.as_ref()?;
18367
18368            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18369            else {
18370                self.clear_row_highlights::<ActiveDebugLine>();
18371                return None;
18372            };
18373
18374            let position = active_stack_frame.position;
18375            let buffer_id = position.buffer_id?;
18376            let snapshot = self
18377                .project
18378                .as_ref()?
18379                .read(cx)
18380                .buffer_for_id(buffer_id, cx)?
18381                .read(cx)
18382                .snapshot();
18383
18384            let mut handled = false;
18385            for (id, ExcerptRange { context, .. }) in
18386                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18387            {
18388                if context.start.cmp(&position, &snapshot).is_ge()
18389                    || context.end.cmp(&position, &snapshot).is_lt()
18390                {
18391                    continue;
18392                }
18393                let snapshot = self.buffer.read(cx).snapshot(cx);
18394                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18395
18396                handled = true;
18397                self.clear_row_highlights::<ActiveDebugLine>();
18398
18399                self.go_to_line::<ActiveDebugLine>(
18400                    multibuffer_anchor,
18401                    Some(cx.theme().colors().editor_debugger_active_line_background),
18402                    window,
18403                    cx,
18404                );
18405
18406                cx.notify();
18407            }
18408
18409            handled.then_some(())
18410        })
18411        .is_some()
18412    }
18413
18414    pub fn copy_file_name_without_extension(
18415        &mut self,
18416        _: &CopyFileNameWithoutExtension,
18417        _: &mut Window,
18418        cx: &mut Context<Self>,
18419    ) {
18420        if let Some(file) = self.target_file(cx) {
18421            if let Some(file_stem) = file.path().file_stem() {
18422                if let Some(name) = file_stem.to_str() {
18423                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18424                }
18425            }
18426        }
18427    }
18428
18429    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18430        if let Some(file) = self.target_file(cx) {
18431            if let Some(file_name) = file.path().file_name() {
18432                if let Some(name) = file_name.to_str() {
18433                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18434                }
18435            }
18436        }
18437    }
18438
18439    pub fn toggle_git_blame(
18440        &mut self,
18441        _: &::git::Blame,
18442        window: &mut Window,
18443        cx: &mut Context<Self>,
18444    ) {
18445        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18446
18447        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18448            self.start_git_blame(true, window, cx);
18449        }
18450
18451        cx.notify();
18452    }
18453
18454    pub fn toggle_git_blame_inline(
18455        &mut self,
18456        _: &ToggleGitBlameInline,
18457        window: &mut Window,
18458        cx: &mut Context<Self>,
18459    ) {
18460        self.toggle_git_blame_inline_internal(true, window, cx);
18461        cx.notify();
18462    }
18463
18464    pub fn open_git_blame_commit(
18465        &mut self,
18466        _: &OpenGitBlameCommit,
18467        window: &mut Window,
18468        cx: &mut Context<Self>,
18469    ) {
18470        self.open_git_blame_commit_internal(window, cx);
18471    }
18472
18473    fn open_git_blame_commit_internal(
18474        &mut self,
18475        window: &mut Window,
18476        cx: &mut Context<Self>,
18477    ) -> Option<()> {
18478        let blame = self.blame.as_ref()?;
18479        let snapshot = self.snapshot(window, cx);
18480        let cursor = self.selections.newest::<Point>(cx).head();
18481        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18482        let blame_entry = blame
18483            .update(cx, |blame, cx| {
18484                blame
18485                    .blame_for_rows(
18486                        &[RowInfo {
18487                            buffer_id: Some(buffer.remote_id()),
18488                            buffer_row: Some(point.row),
18489                            ..Default::default()
18490                        }],
18491                        cx,
18492                    )
18493                    .next()
18494            })
18495            .flatten()?;
18496        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18497        let repo = blame.read(cx).repository(cx)?;
18498        let workspace = self.workspace()?.downgrade();
18499        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18500        None
18501    }
18502
18503    pub fn git_blame_inline_enabled(&self) -> bool {
18504        self.git_blame_inline_enabled
18505    }
18506
18507    pub fn toggle_selection_menu(
18508        &mut self,
18509        _: &ToggleSelectionMenu,
18510        _: &mut Window,
18511        cx: &mut Context<Self>,
18512    ) {
18513        self.show_selection_menu = self
18514            .show_selection_menu
18515            .map(|show_selections_menu| !show_selections_menu)
18516            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18517
18518        cx.notify();
18519    }
18520
18521    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18522        self.show_selection_menu
18523            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18524    }
18525
18526    fn start_git_blame(
18527        &mut self,
18528        user_triggered: bool,
18529        window: &mut Window,
18530        cx: &mut Context<Self>,
18531    ) {
18532        if let Some(project) = self.project.as_ref() {
18533            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18534                return;
18535            };
18536
18537            if buffer.read(cx).file().is_none() {
18538                return;
18539            }
18540
18541            let focused = self.focus_handle(cx).contains_focused(window, cx);
18542
18543            let project = project.clone();
18544            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18545            self.blame_subscription =
18546                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18547            self.blame = Some(blame);
18548        }
18549    }
18550
18551    fn toggle_git_blame_inline_internal(
18552        &mut self,
18553        user_triggered: bool,
18554        window: &mut Window,
18555        cx: &mut Context<Self>,
18556    ) {
18557        if self.git_blame_inline_enabled {
18558            self.git_blame_inline_enabled = false;
18559            self.show_git_blame_inline = false;
18560            self.show_git_blame_inline_delay_task.take();
18561        } else {
18562            self.git_blame_inline_enabled = true;
18563            self.start_git_blame_inline(user_triggered, window, cx);
18564        }
18565
18566        cx.notify();
18567    }
18568
18569    fn start_git_blame_inline(
18570        &mut self,
18571        user_triggered: bool,
18572        window: &mut Window,
18573        cx: &mut Context<Self>,
18574    ) {
18575        self.start_git_blame(user_triggered, window, cx);
18576
18577        if ProjectSettings::get_global(cx)
18578            .git
18579            .inline_blame_delay()
18580            .is_some()
18581        {
18582            self.start_inline_blame_timer(window, cx);
18583        } else {
18584            self.show_git_blame_inline = true
18585        }
18586    }
18587
18588    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18589        self.blame.as_ref()
18590    }
18591
18592    pub fn show_git_blame_gutter(&self) -> bool {
18593        self.show_git_blame_gutter
18594    }
18595
18596    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18597        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18598    }
18599
18600    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18601        self.show_git_blame_inline
18602            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18603            && !self.newest_selection_head_on_empty_line(cx)
18604            && self.has_blame_entries(cx)
18605    }
18606
18607    fn has_blame_entries(&self, cx: &App) -> bool {
18608        self.blame()
18609            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18610    }
18611
18612    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18613        let cursor_anchor = self.selections.newest_anchor().head();
18614
18615        let snapshot = self.buffer.read(cx).snapshot(cx);
18616        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18617
18618        snapshot.line_len(buffer_row) == 0
18619    }
18620
18621    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18622        let buffer_and_selection = maybe!({
18623            let selection = self.selections.newest::<Point>(cx);
18624            let selection_range = selection.range();
18625
18626            let multi_buffer = self.buffer().read(cx);
18627            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18628            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18629
18630            let (buffer, range, _) = if selection.reversed {
18631                buffer_ranges.first()
18632            } else {
18633                buffer_ranges.last()
18634            }?;
18635
18636            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18637                ..text::ToPoint::to_point(&range.end, &buffer).row;
18638            Some((
18639                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18640                selection,
18641            ))
18642        });
18643
18644        let Some((buffer, selection)) = buffer_and_selection else {
18645            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18646        };
18647
18648        let Some(project) = self.project.as_ref() else {
18649            return Task::ready(Err(anyhow!("editor does not have project")));
18650        };
18651
18652        project.update(cx, |project, cx| {
18653            project.get_permalink_to_line(&buffer, selection, cx)
18654        })
18655    }
18656
18657    pub fn copy_permalink_to_line(
18658        &mut self,
18659        _: &CopyPermalinkToLine,
18660        window: &mut Window,
18661        cx: &mut Context<Self>,
18662    ) {
18663        let permalink_task = self.get_permalink_to_line(cx);
18664        let workspace = self.workspace();
18665
18666        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18667            Ok(permalink) => {
18668                cx.update(|_, cx| {
18669                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18670                })
18671                .ok();
18672            }
18673            Err(err) => {
18674                let message = format!("Failed to copy permalink: {err}");
18675
18676                anyhow::Result::<()>::Err(err).log_err();
18677
18678                if let Some(workspace) = workspace {
18679                    workspace
18680                        .update_in(cx, |workspace, _, cx| {
18681                            struct CopyPermalinkToLine;
18682
18683                            workspace.show_toast(
18684                                Toast::new(
18685                                    NotificationId::unique::<CopyPermalinkToLine>(),
18686                                    message,
18687                                ),
18688                                cx,
18689                            )
18690                        })
18691                        .ok();
18692                }
18693            }
18694        })
18695        .detach();
18696    }
18697
18698    pub fn copy_file_location(
18699        &mut self,
18700        _: &CopyFileLocation,
18701        _: &mut Window,
18702        cx: &mut Context<Self>,
18703    ) {
18704        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18705        if let Some(file) = self.target_file(cx) {
18706            if let Some(path) = file.path().to_str() {
18707                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18708            }
18709        }
18710    }
18711
18712    pub fn open_permalink_to_line(
18713        &mut self,
18714        _: &OpenPermalinkToLine,
18715        window: &mut Window,
18716        cx: &mut Context<Self>,
18717    ) {
18718        let permalink_task = self.get_permalink_to_line(cx);
18719        let workspace = self.workspace();
18720
18721        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18722            Ok(permalink) => {
18723                cx.update(|_, cx| {
18724                    cx.open_url(permalink.as_ref());
18725                })
18726                .ok();
18727            }
18728            Err(err) => {
18729                let message = format!("Failed to open permalink: {err}");
18730
18731                anyhow::Result::<()>::Err(err).log_err();
18732
18733                if let Some(workspace) = workspace {
18734                    workspace
18735                        .update(cx, |workspace, cx| {
18736                            struct OpenPermalinkToLine;
18737
18738                            workspace.show_toast(
18739                                Toast::new(
18740                                    NotificationId::unique::<OpenPermalinkToLine>(),
18741                                    message,
18742                                ),
18743                                cx,
18744                            )
18745                        })
18746                        .ok();
18747                }
18748            }
18749        })
18750        .detach();
18751    }
18752
18753    pub fn insert_uuid_v4(
18754        &mut self,
18755        _: &InsertUuidV4,
18756        window: &mut Window,
18757        cx: &mut Context<Self>,
18758    ) {
18759        self.insert_uuid(UuidVersion::V4, window, cx);
18760    }
18761
18762    pub fn insert_uuid_v7(
18763        &mut self,
18764        _: &InsertUuidV7,
18765        window: &mut Window,
18766        cx: &mut Context<Self>,
18767    ) {
18768        self.insert_uuid(UuidVersion::V7, window, cx);
18769    }
18770
18771    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18773        self.transact(window, cx, |this, window, cx| {
18774            let edits = this
18775                .selections
18776                .all::<Point>(cx)
18777                .into_iter()
18778                .map(|selection| {
18779                    let uuid = match version {
18780                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18781                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18782                    };
18783
18784                    (selection.range(), uuid.to_string())
18785                });
18786            this.edit(edits, cx);
18787            this.refresh_inline_completion(true, false, window, cx);
18788        });
18789    }
18790
18791    pub fn open_selections_in_multibuffer(
18792        &mut self,
18793        _: &OpenSelectionsInMultibuffer,
18794        window: &mut Window,
18795        cx: &mut Context<Self>,
18796    ) {
18797        let multibuffer = self.buffer.read(cx);
18798
18799        let Some(buffer) = multibuffer.as_singleton() else {
18800            return;
18801        };
18802
18803        let Some(workspace) = self.workspace() else {
18804            return;
18805        };
18806
18807        let title = multibuffer.title(cx).to_string();
18808
18809        let locations = self
18810            .selections
18811            .all_anchors(cx)
18812            .into_iter()
18813            .map(|selection| Location {
18814                buffer: buffer.clone(),
18815                range: selection.start.text_anchor..selection.end.text_anchor,
18816            })
18817            .collect::<Vec<_>>();
18818
18819        cx.spawn_in(window, async move |_, cx| {
18820            workspace.update_in(cx, |workspace, window, cx| {
18821                Self::open_locations_in_multibuffer(
18822                    workspace,
18823                    locations,
18824                    format!("Selections for '{title}'"),
18825                    false,
18826                    MultibufferSelectionMode::All,
18827                    window,
18828                    cx,
18829                );
18830            })
18831        })
18832        .detach();
18833    }
18834
18835    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18836    /// last highlight added will be used.
18837    ///
18838    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18839    pub fn highlight_rows<T: 'static>(
18840        &mut self,
18841        range: Range<Anchor>,
18842        color: Hsla,
18843        options: RowHighlightOptions,
18844        cx: &mut Context<Self>,
18845    ) {
18846        let snapshot = self.buffer().read(cx).snapshot(cx);
18847        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18848        let ix = row_highlights.binary_search_by(|highlight| {
18849            Ordering::Equal
18850                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18851                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18852        });
18853
18854        if let Err(mut ix) = ix {
18855            let index = post_inc(&mut self.highlight_order);
18856
18857            // If this range intersects with the preceding highlight, then merge it with
18858            // the preceding highlight. Otherwise insert a new highlight.
18859            let mut merged = false;
18860            if ix > 0 {
18861                let prev_highlight = &mut row_highlights[ix - 1];
18862                if prev_highlight
18863                    .range
18864                    .end
18865                    .cmp(&range.start, &snapshot)
18866                    .is_ge()
18867                {
18868                    ix -= 1;
18869                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18870                        prev_highlight.range.end = range.end;
18871                    }
18872                    merged = true;
18873                    prev_highlight.index = index;
18874                    prev_highlight.color = color;
18875                    prev_highlight.options = options;
18876                }
18877            }
18878
18879            if !merged {
18880                row_highlights.insert(
18881                    ix,
18882                    RowHighlight {
18883                        range: range.clone(),
18884                        index,
18885                        color,
18886                        options,
18887                        type_id: TypeId::of::<T>(),
18888                    },
18889                );
18890            }
18891
18892            // If any of the following highlights intersect with this one, merge them.
18893            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18894                let highlight = &row_highlights[ix];
18895                if next_highlight
18896                    .range
18897                    .start
18898                    .cmp(&highlight.range.end, &snapshot)
18899                    .is_le()
18900                {
18901                    if next_highlight
18902                        .range
18903                        .end
18904                        .cmp(&highlight.range.end, &snapshot)
18905                        .is_gt()
18906                    {
18907                        row_highlights[ix].range.end = next_highlight.range.end;
18908                    }
18909                    row_highlights.remove(ix + 1);
18910                } else {
18911                    break;
18912                }
18913            }
18914        }
18915    }
18916
18917    /// Remove any highlighted row ranges of the given type that intersect the
18918    /// given ranges.
18919    pub fn remove_highlighted_rows<T: 'static>(
18920        &mut self,
18921        ranges_to_remove: Vec<Range<Anchor>>,
18922        cx: &mut Context<Self>,
18923    ) {
18924        let snapshot = self.buffer().read(cx).snapshot(cx);
18925        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18926        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18927        row_highlights.retain(|highlight| {
18928            while let Some(range_to_remove) = ranges_to_remove.peek() {
18929                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18930                    Ordering::Less | Ordering::Equal => {
18931                        ranges_to_remove.next();
18932                    }
18933                    Ordering::Greater => {
18934                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18935                            Ordering::Less | Ordering::Equal => {
18936                                return false;
18937                            }
18938                            Ordering::Greater => break,
18939                        }
18940                    }
18941                }
18942            }
18943
18944            true
18945        })
18946    }
18947
18948    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18949    pub fn clear_row_highlights<T: 'static>(&mut self) {
18950        self.highlighted_rows.remove(&TypeId::of::<T>());
18951    }
18952
18953    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18954    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18955        self.highlighted_rows
18956            .get(&TypeId::of::<T>())
18957            .map_or(&[] as &[_], |vec| vec.as_slice())
18958            .iter()
18959            .map(|highlight| (highlight.range.clone(), highlight.color))
18960    }
18961
18962    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18963    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18964    /// Allows to ignore certain kinds of highlights.
18965    pub fn highlighted_display_rows(
18966        &self,
18967        window: &mut Window,
18968        cx: &mut App,
18969    ) -> BTreeMap<DisplayRow, LineHighlight> {
18970        let snapshot = self.snapshot(window, cx);
18971        let mut used_highlight_orders = HashMap::default();
18972        self.highlighted_rows
18973            .iter()
18974            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18975            .fold(
18976                BTreeMap::<DisplayRow, LineHighlight>::new(),
18977                |mut unique_rows, highlight| {
18978                    let start = highlight.range.start.to_display_point(&snapshot);
18979                    let end = highlight.range.end.to_display_point(&snapshot);
18980                    let start_row = start.row().0;
18981                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18982                        && end.column() == 0
18983                    {
18984                        end.row().0.saturating_sub(1)
18985                    } else {
18986                        end.row().0
18987                    };
18988                    for row in start_row..=end_row {
18989                        let used_index =
18990                            used_highlight_orders.entry(row).or_insert(highlight.index);
18991                        if highlight.index >= *used_index {
18992                            *used_index = highlight.index;
18993                            unique_rows.insert(
18994                                DisplayRow(row),
18995                                LineHighlight {
18996                                    include_gutter: highlight.options.include_gutter,
18997                                    border: None,
18998                                    background: highlight.color.into(),
18999                                    type_id: Some(highlight.type_id),
19000                                },
19001                            );
19002                        }
19003                    }
19004                    unique_rows
19005                },
19006            )
19007    }
19008
19009    pub fn highlighted_display_row_for_autoscroll(
19010        &self,
19011        snapshot: &DisplaySnapshot,
19012    ) -> Option<DisplayRow> {
19013        self.highlighted_rows
19014            .values()
19015            .flat_map(|highlighted_rows| highlighted_rows.iter())
19016            .filter_map(|highlight| {
19017                if highlight.options.autoscroll {
19018                    Some(highlight.range.start.to_display_point(snapshot).row())
19019                } else {
19020                    None
19021                }
19022            })
19023            .min()
19024    }
19025
19026    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19027        self.highlight_background::<SearchWithinRange>(
19028            ranges,
19029            |colors| colors.colors().editor_document_highlight_read_background,
19030            cx,
19031        )
19032    }
19033
19034    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19035        self.breadcrumb_header = Some(new_header);
19036    }
19037
19038    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19039        self.clear_background_highlights::<SearchWithinRange>(cx);
19040    }
19041
19042    pub fn highlight_background<T: 'static>(
19043        &mut self,
19044        ranges: &[Range<Anchor>],
19045        color_fetcher: fn(&Theme) -> Hsla,
19046        cx: &mut Context<Self>,
19047    ) {
19048        self.background_highlights.insert(
19049            HighlightKey::Type(TypeId::of::<T>()),
19050            (color_fetcher, Arc::from(ranges)),
19051        );
19052        self.scrollbar_marker_state.dirty = true;
19053        cx.notify();
19054    }
19055
19056    pub fn highlight_background_key<T: 'static>(
19057        &mut self,
19058        key: usize,
19059        ranges: &[Range<Anchor>],
19060        color_fetcher: fn(&Theme) -> Hsla,
19061        cx: &mut Context<Self>,
19062    ) {
19063        self.background_highlights.insert(
19064            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19065            (color_fetcher, Arc::from(ranges)),
19066        );
19067        self.scrollbar_marker_state.dirty = true;
19068        cx.notify();
19069    }
19070
19071    pub fn clear_background_highlights<T: 'static>(
19072        &mut self,
19073        cx: &mut Context<Self>,
19074    ) -> Option<BackgroundHighlight> {
19075        let text_highlights = self
19076            .background_highlights
19077            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19078        if !text_highlights.1.is_empty() {
19079            self.scrollbar_marker_state.dirty = true;
19080            cx.notify();
19081        }
19082        Some(text_highlights)
19083    }
19084
19085    pub fn highlight_gutter<T: 'static>(
19086        &mut self,
19087        ranges: impl Into<Vec<Range<Anchor>>>,
19088        color_fetcher: fn(&App) -> Hsla,
19089        cx: &mut Context<Self>,
19090    ) {
19091        self.gutter_highlights
19092            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19093        cx.notify();
19094    }
19095
19096    pub fn clear_gutter_highlights<T: 'static>(
19097        &mut self,
19098        cx: &mut Context<Self>,
19099    ) -> Option<GutterHighlight> {
19100        cx.notify();
19101        self.gutter_highlights.remove(&TypeId::of::<T>())
19102    }
19103
19104    pub fn insert_gutter_highlight<T: 'static>(
19105        &mut self,
19106        range: Range<Anchor>,
19107        color_fetcher: fn(&App) -> Hsla,
19108        cx: &mut Context<Self>,
19109    ) {
19110        let snapshot = self.buffer().read(cx).snapshot(cx);
19111        let mut highlights = self
19112            .gutter_highlights
19113            .remove(&TypeId::of::<T>())
19114            .map(|(_, highlights)| highlights)
19115            .unwrap_or_default();
19116        let ix = highlights.binary_search_by(|highlight| {
19117            Ordering::Equal
19118                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19119                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19120        });
19121        if let Err(ix) = ix {
19122            highlights.insert(ix, range);
19123        }
19124        self.gutter_highlights
19125            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19126    }
19127
19128    pub fn remove_gutter_highlights<T: 'static>(
19129        &mut self,
19130        ranges_to_remove: Vec<Range<Anchor>>,
19131        cx: &mut Context<Self>,
19132    ) {
19133        let snapshot = self.buffer().read(cx).snapshot(cx);
19134        let Some((color_fetcher, mut gutter_highlights)) =
19135            self.gutter_highlights.remove(&TypeId::of::<T>())
19136        else {
19137            return;
19138        };
19139        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19140        gutter_highlights.retain(|highlight| {
19141            while let Some(range_to_remove) = ranges_to_remove.peek() {
19142                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19143                    Ordering::Less | Ordering::Equal => {
19144                        ranges_to_remove.next();
19145                    }
19146                    Ordering::Greater => {
19147                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19148                            Ordering::Less | Ordering::Equal => {
19149                                return false;
19150                            }
19151                            Ordering::Greater => break,
19152                        }
19153                    }
19154                }
19155            }
19156
19157            true
19158        });
19159        self.gutter_highlights
19160            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19161    }
19162
19163    #[cfg(feature = "test-support")]
19164    pub fn all_text_highlights(
19165        &self,
19166        window: &mut Window,
19167        cx: &mut Context<Self>,
19168    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19169        let snapshot = self.snapshot(window, cx);
19170        self.display_map.update(cx, |display_map, _| {
19171            display_map
19172                .all_text_highlights()
19173                .map(|highlight| {
19174                    let (style, ranges) = highlight.as_ref();
19175                    (
19176                        *style,
19177                        ranges
19178                            .iter()
19179                            .map(|range| range.clone().to_display_points(&snapshot))
19180                            .collect(),
19181                    )
19182                })
19183                .collect()
19184        })
19185    }
19186
19187    #[cfg(feature = "test-support")]
19188    pub fn all_text_background_highlights(
19189        &self,
19190        window: &mut Window,
19191        cx: &mut Context<Self>,
19192    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19193        let snapshot = self.snapshot(window, cx);
19194        let buffer = &snapshot.buffer_snapshot;
19195        let start = buffer.anchor_before(0);
19196        let end = buffer.anchor_after(buffer.len());
19197        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19198    }
19199
19200    #[cfg(feature = "test-support")]
19201    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19202        let snapshot = self.buffer().read(cx).snapshot(cx);
19203
19204        let highlights = self
19205            .background_highlights
19206            .get(&HighlightKey::Type(TypeId::of::<
19207                items::BufferSearchHighlights,
19208            >()));
19209
19210        if let Some((_color, ranges)) = highlights {
19211            ranges
19212                .iter()
19213                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19214                .collect_vec()
19215        } else {
19216            vec![]
19217        }
19218    }
19219
19220    fn document_highlights_for_position<'a>(
19221        &'a self,
19222        position: Anchor,
19223        buffer: &'a MultiBufferSnapshot,
19224    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19225        let read_highlights = self
19226            .background_highlights
19227            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19228            .map(|h| &h.1);
19229        let write_highlights = self
19230            .background_highlights
19231            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19232            .map(|h| &h.1);
19233        let left_position = position.bias_left(buffer);
19234        let right_position = position.bias_right(buffer);
19235        read_highlights
19236            .into_iter()
19237            .chain(write_highlights)
19238            .flat_map(move |ranges| {
19239                let start_ix = match ranges.binary_search_by(|probe| {
19240                    let cmp = probe.end.cmp(&left_position, buffer);
19241                    if cmp.is_ge() {
19242                        Ordering::Greater
19243                    } else {
19244                        Ordering::Less
19245                    }
19246                }) {
19247                    Ok(i) | Err(i) => i,
19248                };
19249
19250                ranges[start_ix..]
19251                    .iter()
19252                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19253            })
19254    }
19255
19256    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19257        self.background_highlights
19258            .get(&HighlightKey::Type(TypeId::of::<T>()))
19259            .map_or(false, |(_, highlights)| !highlights.is_empty())
19260    }
19261
19262    pub fn background_highlights_in_range(
19263        &self,
19264        search_range: Range<Anchor>,
19265        display_snapshot: &DisplaySnapshot,
19266        theme: &Theme,
19267    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19268        let mut results = Vec::new();
19269        for (color_fetcher, ranges) in self.background_highlights.values() {
19270            let color = color_fetcher(theme);
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            for range in &ranges[start_ix..] {
19284                if range
19285                    .start
19286                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19287                    .is_ge()
19288                {
19289                    break;
19290                }
19291
19292                let start = range.start.to_display_point(display_snapshot);
19293                let end = range.end.to_display_point(display_snapshot);
19294                results.push((start..end, color))
19295            }
19296        }
19297        results
19298    }
19299
19300    pub fn background_highlight_row_ranges<T: 'static>(
19301        &self,
19302        search_range: Range<Anchor>,
19303        display_snapshot: &DisplaySnapshot,
19304        count: usize,
19305    ) -> Vec<RangeInclusive<DisplayPoint>> {
19306        let mut results = Vec::new();
19307        let Some((_, ranges)) = self
19308            .background_highlights
19309            .get(&HighlightKey::Type(TypeId::of::<T>()))
19310        else {
19311            return vec![];
19312        };
19313
19314        let start_ix = match ranges.binary_search_by(|probe| {
19315            let cmp = probe
19316                .end
19317                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19318            if cmp.is_gt() {
19319                Ordering::Greater
19320            } else {
19321                Ordering::Less
19322            }
19323        }) {
19324            Ok(i) | Err(i) => i,
19325        };
19326        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19327            if let (Some(start_display), Some(end_display)) = (start, end) {
19328                results.push(
19329                    start_display.to_display_point(display_snapshot)
19330                        ..=end_display.to_display_point(display_snapshot),
19331                );
19332            }
19333        };
19334        let mut start_row: Option<Point> = None;
19335        let mut end_row: Option<Point> = None;
19336        if ranges.len() > count {
19337            return Vec::new();
19338        }
19339        for range in &ranges[start_ix..] {
19340            if range
19341                .start
19342                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19343                .is_ge()
19344            {
19345                break;
19346            }
19347            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19348            if let Some(current_row) = &end_row {
19349                if end.row == current_row.row {
19350                    continue;
19351                }
19352            }
19353            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19354            if start_row.is_none() {
19355                assert_eq!(end_row, None);
19356                start_row = Some(start);
19357                end_row = Some(end);
19358                continue;
19359            }
19360            if let Some(current_end) = end_row.as_mut() {
19361                if start.row > current_end.row + 1 {
19362                    push_region(start_row, end_row);
19363                    start_row = Some(start);
19364                    end_row = Some(end);
19365                } else {
19366                    // Merge two hunks.
19367                    *current_end = end;
19368                }
19369            } else {
19370                unreachable!();
19371            }
19372        }
19373        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19374        push_region(start_row, end_row);
19375        results
19376    }
19377
19378    pub fn gutter_highlights_in_range(
19379        &self,
19380        search_range: Range<Anchor>,
19381        display_snapshot: &DisplaySnapshot,
19382        cx: &App,
19383    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19384        let mut results = Vec::new();
19385        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19386            let color = color_fetcher(cx);
19387            let start_ix = match ranges.binary_search_by(|probe| {
19388                let cmp = probe
19389                    .end
19390                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19391                if cmp.is_gt() {
19392                    Ordering::Greater
19393                } else {
19394                    Ordering::Less
19395                }
19396            }) {
19397                Ok(i) | Err(i) => i,
19398            };
19399            for range in &ranges[start_ix..] {
19400                if range
19401                    .start
19402                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19403                    .is_ge()
19404                {
19405                    break;
19406                }
19407
19408                let start = range.start.to_display_point(display_snapshot);
19409                let end = range.end.to_display_point(display_snapshot);
19410                results.push((start..end, color))
19411            }
19412        }
19413        results
19414    }
19415
19416    /// Get the text ranges corresponding to the redaction query
19417    pub fn redacted_ranges(
19418        &self,
19419        search_range: Range<Anchor>,
19420        display_snapshot: &DisplaySnapshot,
19421        cx: &App,
19422    ) -> Vec<Range<DisplayPoint>> {
19423        display_snapshot
19424            .buffer_snapshot
19425            .redacted_ranges(search_range, |file| {
19426                if let Some(file) = file {
19427                    file.is_private()
19428                        && EditorSettings::get(
19429                            Some(SettingsLocation {
19430                                worktree_id: file.worktree_id(cx),
19431                                path: file.path().as_ref(),
19432                            }),
19433                            cx,
19434                        )
19435                        .redact_private_values
19436                } else {
19437                    false
19438                }
19439            })
19440            .map(|range| {
19441                range.start.to_display_point(display_snapshot)
19442                    ..range.end.to_display_point(display_snapshot)
19443            })
19444            .collect()
19445    }
19446
19447    pub fn highlight_text_key<T: 'static>(
19448        &mut self,
19449        key: usize,
19450        ranges: Vec<Range<Anchor>>,
19451        style: HighlightStyle,
19452        cx: &mut Context<Self>,
19453    ) {
19454        self.display_map.update(cx, |map, _| {
19455            map.highlight_text(
19456                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19457                ranges,
19458                style,
19459            );
19460        });
19461        cx.notify();
19462    }
19463
19464    pub fn highlight_text<T: 'static>(
19465        &mut self,
19466        ranges: Vec<Range<Anchor>>,
19467        style: HighlightStyle,
19468        cx: &mut Context<Self>,
19469    ) {
19470        self.display_map.update(cx, |map, _| {
19471            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19472        });
19473        cx.notify();
19474    }
19475
19476    pub(crate) fn highlight_inlays<T: 'static>(
19477        &mut self,
19478        highlights: Vec<InlayHighlight>,
19479        style: HighlightStyle,
19480        cx: &mut Context<Self>,
19481    ) {
19482        self.display_map.update(cx, |map, _| {
19483            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19484        });
19485        cx.notify();
19486    }
19487
19488    pub fn text_highlights<'a, T: 'static>(
19489        &'a self,
19490        cx: &'a App,
19491    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19492        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19493    }
19494
19495    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19496        let cleared = self
19497            .display_map
19498            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19499        if cleared {
19500            cx.notify();
19501        }
19502    }
19503
19504    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19505        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19506            && self.focus_handle.is_focused(window)
19507    }
19508
19509    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19510        self.show_cursor_when_unfocused = is_enabled;
19511        cx.notify();
19512    }
19513
19514    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19515        cx.notify();
19516    }
19517
19518    fn on_debug_session_event(
19519        &mut self,
19520        _session: Entity<Session>,
19521        event: &SessionEvent,
19522        cx: &mut Context<Self>,
19523    ) {
19524        match event {
19525            SessionEvent::InvalidateInlineValue => {
19526                self.refresh_inline_values(cx);
19527            }
19528            _ => {}
19529        }
19530    }
19531
19532    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19533        let Some(project) = self.project.clone() else {
19534            return;
19535        };
19536
19537        if !self.inline_value_cache.enabled {
19538            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19539            self.splice_inlays(&inlays, Vec::new(), cx);
19540            return;
19541        }
19542
19543        let current_execution_position = self
19544            .highlighted_rows
19545            .get(&TypeId::of::<ActiveDebugLine>())
19546            .and_then(|lines| lines.last().map(|line| line.range.end));
19547
19548        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19549            let inline_values = editor
19550                .update(cx, |editor, cx| {
19551                    let Some(current_execution_position) = current_execution_position else {
19552                        return Some(Task::ready(Ok(Vec::new())));
19553                    };
19554
19555                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19556                        let snapshot = buffer.snapshot(cx);
19557
19558                        let excerpt = snapshot.excerpt_containing(
19559                            current_execution_position..current_execution_position,
19560                        )?;
19561
19562                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19563                    })?;
19564
19565                    let range =
19566                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19567
19568                    project.inline_values(buffer, range, cx)
19569                })
19570                .ok()
19571                .flatten()?
19572                .await
19573                .context("refreshing debugger inlays")
19574                .log_err()?;
19575
19576            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19577
19578            for (buffer_id, inline_value) in inline_values
19579                .into_iter()
19580                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19581            {
19582                buffer_inline_values
19583                    .entry(buffer_id)
19584                    .or_default()
19585                    .push(inline_value);
19586            }
19587
19588            editor
19589                .update(cx, |editor, cx| {
19590                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19591                    let mut new_inlays = Vec::default();
19592
19593                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19594                        let buffer_id = buffer_snapshot.remote_id();
19595                        buffer_inline_values
19596                            .get(&buffer_id)
19597                            .into_iter()
19598                            .flatten()
19599                            .for_each(|hint| {
19600                                let inlay = Inlay::debugger(
19601                                    post_inc(&mut editor.next_inlay_id),
19602                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19603                                    hint.text(),
19604                                );
19605
19606                                new_inlays.push(inlay);
19607                            });
19608                    }
19609
19610                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19611                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19612
19613                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19614                })
19615                .ok()?;
19616            Some(())
19617        });
19618    }
19619
19620    fn on_buffer_event(
19621        &mut self,
19622        multibuffer: &Entity<MultiBuffer>,
19623        event: &multi_buffer::Event,
19624        window: &mut Window,
19625        cx: &mut Context<Self>,
19626    ) {
19627        match event {
19628            multi_buffer::Event::Edited {
19629                singleton_buffer_edited,
19630                edited_buffer,
19631            } => {
19632                self.scrollbar_marker_state.dirty = true;
19633                self.active_indent_guides_state.dirty = true;
19634                self.refresh_active_diagnostics(cx);
19635                self.refresh_code_actions(window, cx);
19636                self.refresh_selected_text_highlights(true, window, cx);
19637                self.refresh_single_line_folds(window, cx);
19638                refresh_matching_bracket_highlights(self, window, cx);
19639                if self.has_active_inline_completion() {
19640                    self.update_visible_inline_completion(window, cx);
19641                }
19642                if let Some(project) = self.project.as_ref() {
19643                    if let Some(edited_buffer) = edited_buffer {
19644                        project.update(cx, |project, cx| {
19645                            self.registered_buffers
19646                                .entry(edited_buffer.read(cx).remote_id())
19647                                .or_insert_with(|| {
19648                                    project
19649                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19650                                });
19651                        });
19652                    }
19653                }
19654                cx.emit(EditorEvent::BufferEdited);
19655                cx.emit(SearchEvent::MatchesInvalidated);
19656
19657                if let Some(buffer) = edited_buffer {
19658                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19659                }
19660
19661                if *singleton_buffer_edited {
19662                    if let Some(buffer) = edited_buffer {
19663                        if buffer.read(cx).file().is_none() {
19664                            cx.emit(EditorEvent::TitleChanged);
19665                        }
19666                    }
19667                    if let Some(project) = &self.project {
19668                        #[allow(clippy::mutable_key_type)]
19669                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19670                            multibuffer
19671                                .all_buffers()
19672                                .into_iter()
19673                                .filter_map(|buffer| {
19674                                    buffer.update(cx, |buffer, cx| {
19675                                        let language = buffer.language()?;
19676                                        let should_discard = project.update(cx, |project, cx| {
19677                                            project.is_local()
19678                                                && !project.has_language_servers_for(buffer, cx)
19679                                        });
19680                                        should_discard.not().then_some(language.clone())
19681                                    })
19682                                })
19683                                .collect::<HashSet<_>>()
19684                        });
19685                        if !languages_affected.is_empty() {
19686                            self.refresh_inlay_hints(
19687                                InlayHintRefreshReason::BufferEdited(languages_affected),
19688                                cx,
19689                            );
19690                        }
19691                    }
19692                }
19693
19694                let Some(project) = &self.project else { return };
19695                let (telemetry, is_via_ssh) = {
19696                    let project = project.read(cx);
19697                    let telemetry = project.client().telemetry().clone();
19698                    let is_via_ssh = project.is_via_ssh();
19699                    (telemetry, is_via_ssh)
19700                };
19701                refresh_linked_ranges(self, window, cx);
19702                telemetry.log_edit_event("editor", is_via_ssh);
19703            }
19704            multi_buffer::Event::ExcerptsAdded {
19705                buffer,
19706                predecessor,
19707                excerpts,
19708            } => {
19709                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19710                let buffer_id = buffer.read(cx).remote_id();
19711                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19712                    if let Some(project) = &self.project {
19713                        update_uncommitted_diff_for_buffer(
19714                            cx.entity(),
19715                            project,
19716                            [buffer.clone()],
19717                            self.buffer.clone(),
19718                            cx,
19719                        )
19720                        .detach();
19721                    }
19722                }
19723                self.update_lsp_data(false, Some(buffer_id), window, cx);
19724                cx.emit(EditorEvent::ExcerptsAdded {
19725                    buffer: buffer.clone(),
19726                    predecessor: *predecessor,
19727                    excerpts: excerpts.clone(),
19728                });
19729                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19730            }
19731            multi_buffer::Event::ExcerptsRemoved {
19732                ids,
19733                removed_buffer_ids,
19734            } => {
19735                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19736                let buffer = self.buffer.read(cx);
19737                self.registered_buffers
19738                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19739                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19740                cx.emit(EditorEvent::ExcerptsRemoved {
19741                    ids: ids.clone(),
19742                    removed_buffer_ids: removed_buffer_ids.clone(),
19743                });
19744            }
19745            multi_buffer::Event::ExcerptsEdited {
19746                excerpt_ids,
19747                buffer_ids,
19748            } => {
19749                self.display_map.update(cx, |map, cx| {
19750                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19751                });
19752                cx.emit(EditorEvent::ExcerptsEdited {
19753                    ids: excerpt_ids.clone(),
19754                });
19755            }
19756            multi_buffer::Event::ExcerptsExpanded { ids } => {
19757                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19758                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19759            }
19760            multi_buffer::Event::Reparsed(buffer_id) => {
19761                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19762                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19763
19764                cx.emit(EditorEvent::Reparsed(*buffer_id));
19765            }
19766            multi_buffer::Event::DiffHunksToggled => {
19767                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19768            }
19769            multi_buffer::Event::LanguageChanged(buffer_id) => {
19770                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19771                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19772                cx.emit(EditorEvent::Reparsed(*buffer_id));
19773                cx.notify();
19774            }
19775            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19776            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19777            multi_buffer::Event::FileHandleChanged
19778            | multi_buffer::Event::Reloaded
19779            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19780            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19781            multi_buffer::Event::DiagnosticsUpdated => {
19782                self.update_diagnostics_state(window, cx);
19783            }
19784            _ => {}
19785        };
19786    }
19787
19788    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19789        if !self.diagnostics_enabled() {
19790            return;
19791        }
19792        self.refresh_active_diagnostics(cx);
19793        self.refresh_inline_diagnostics(true, window, cx);
19794        self.scrollbar_marker_state.dirty = true;
19795        cx.notify();
19796    }
19797
19798    pub fn start_temporary_diff_override(&mut self) {
19799        self.load_diff_task.take();
19800        self.temporary_diff_override = true;
19801    }
19802
19803    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19804        self.temporary_diff_override = false;
19805        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19806        self.buffer.update(cx, |buffer, cx| {
19807            buffer.set_all_diff_hunks_collapsed(cx);
19808        });
19809
19810        if let Some(project) = self.project.clone() {
19811            self.load_diff_task = Some(
19812                update_uncommitted_diff_for_buffer(
19813                    cx.entity(),
19814                    &project,
19815                    self.buffer.read(cx).all_buffers(),
19816                    self.buffer.clone(),
19817                    cx,
19818                )
19819                .shared(),
19820            );
19821        }
19822    }
19823
19824    fn on_display_map_changed(
19825        &mut self,
19826        _: Entity<DisplayMap>,
19827        _: &mut Window,
19828        cx: &mut Context<Self>,
19829    ) {
19830        cx.notify();
19831    }
19832
19833    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19834        let new_severity = if self.diagnostics_enabled() {
19835            EditorSettings::get_global(cx)
19836                .diagnostics_max_severity
19837                .unwrap_or(DiagnosticSeverity::Hint)
19838        } else {
19839            DiagnosticSeverity::Off
19840        };
19841        self.set_max_diagnostics_severity(new_severity, cx);
19842        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19843        self.update_edit_prediction_settings(cx);
19844        self.refresh_inline_completion(true, false, window, cx);
19845        self.refresh_inlay_hints(
19846            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19847                self.selections.newest_anchor().head(),
19848                &self.buffer.read(cx).snapshot(cx),
19849                cx,
19850            )),
19851            cx,
19852        );
19853
19854        let old_cursor_shape = self.cursor_shape;
19855
19856        {
19857            let editor_settings = EditorSettings::get_global(cx);
19858            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19859            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19860            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19861            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19862            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19863        }
19864
19865        if old_cursor_shape != self.cursor_shape {
19866            cx.emit(EditorEvent::CursorShapeChanged);
19867        }
19868
19869        let project_settings = ProjectSettings::get_global(cx);
19870        self.serialize_dirty_buffers =
19871            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19872
19873        if self.mode.is_full() {
19874            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19875            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19876            if self.show_inline_diagnostics != show_inline_diagnostics {
19877                self.show_inline_diagnostics = show_inline_diagnostics;
19878                self.refresh_inline_diagnostics(false, window, cx);
19879            }
19880
19881            if self.git_blame_inline_enabled != inline_blame_enabled {
19882                self.toggle_git_blame_inline_internal(false, window, cx);
19883            }
19884
19885            let minimap_settings = EditorSettings::get_global(cx).minimap;
19886            if self.minimap_visibility != MinimapVisibility::Disabled {
19887                if self.minimap_visibility.settings_visibility()
19888                    != minimap_settings.minimap_enabled()
19889                {
19890                    self.set_minimap_visibility(
19891                        MinimapVisibility::for_mode(self.mode(), cx),
19892                        window,
19893                        cx,
19894                    );
19895                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19896                    minimap_entity.update(cx, |minimap_editor, cx| {
19897                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19898                    })
19899                }
19900            }
19901        }
19902
19903        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19904            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19905        }) {
19906            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19907                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19908            }
19909            self.refresh_colors(false, None, window, cx);
19910        }
19911
19912        cx.notify();
19913    }
19914
19915    pub fn set_searchable(&mut self, searchable: bool) {
19916        self.searchable = searchable;
19917    }
19918
19919    pub fn searchable(&self) -> bool {
19920        self.searchable
19921    }
19922
19923    fn open_proposed_changes_editor(
19924        &mut self,
19925        _: &OpenProposedChangesEditor,
19926        window: &mut Window,
19927        cx: &mut Context<Self>,
19928    ) {
19929        let Some(workspace) = self.workspace() else {
19930            cx.propagate();
19931            return;
19932        };
19933
19934        let selections = self.selections.all::<usize>(cx);
19935        let multi_buffer = self.buffer.read(cx);
19936        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19937        let mut new_selections_by_buffer = HashMap::default();
19938        for selection in selections {
19939            for (buffer, range, _) in
19940                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19941            {
19942                let mut range = range.to_point(buffer);
19943                range.start.column = 0;
19944                range.end.column = buffer.line_len(range.end.row);
19945                new_selections_by_buffer
19946                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19947                    .or_insert(Vec::new())
19948                    .push(range)
19949            }
19950        }
19951
19952        let proposed_changes_buffers = new_selections_by_buffer
19953            .into_iter()
19954            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19955            .collect::<Vec<_>>();
19956        let proposed_changes_editor = cx.new(|cx| {
19957            ProposedChangesEditor::new(
19958                "Proposed changes",
19959                proposed_changes_buffers,
19960                self.project.clone(),
19961                window,
19962                cx,
19963            )
19964        });
19965
19966        window.defer(cx, move |window, cx| {
19967            workspace.update(cx, |workspace, cx| {
19968                workspace.active_pane().update(cx, |pane, cx| {
19969                    pane.add_item(
19970                        Box::new(proposed_changes_editor),
19971                        true,
19972                        true,
19973                        None,
19974                        window,
19975                        cx,
19976                    );
19977                });
19978            });
19979        });
19980    }
19981
19982    pub fn open_excerpts_in_split(
19983        &mut self,
19984        _: &OpenExcerptsSplit,
19985        window: &mut Window,
19986        cx: &mut Context<Self>,
19987    ) {
19988        self.open_excerpts_common(None, true, window, cx)
19989    }
19990
19991    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19992        self.open_excerpts_common(None, false, window, cx)
19993    }
19994
19995    fn open_excerpts_common(
19996        &mut self,
19997        jump_data: Option<JumpData>,
19998        split: bool,
19999        window: &mut Window,
20000        cx: &mut Context<Self>,
20001    ) {
20002        let Some(workspace) = self.workspace() else {
20003            cx.propagate();
20004            return;
20005        };
20006
20007        if self.buffer.read(cx).is_singleton() {
20008            cx.propagate();
20009            return;
20010        }
20011
20012        let mut new_selections_by_buffer = HashMap::default();
20013        match &jump_data {
20014            Some(JumpData::MultiBufferPoint {
20015                excerpt_id,
20016                position,
20017                anchor,
20018                line_offset_from_top,
20019            }) => {
20020                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20021                if let Some(buffer) = multi_buffer_snapshot
20022                    .buffer_id_for_excerpt(*excerpt_id)
20023                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20024                {
20025                    let buffer_snapshot = buffer.read(cx).snapshot();
20026                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20027                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20028                    } else {
20029                        buffer_snapshot.clip_point(*position, Bias::Left)
20030                    };
20031                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20032                    new_selections_by_buffer.insert(
20033                        buffer,
20034                        (
20035                            vec![jump_to_offset..jump_to_offset],
20036                            Some(*line_offset_from_top),
20037                        ),
20038                    );
20039                }
20040            }
20041            Some(JumpData::MultiBufferRow {
20042                row,
20043                line_offset_from_top,
20044            }) => {
20045                let point = MultiBufferPoint::new(row.0, 0);
20046                if let Some((buffer, buffer_point, _)) =
20047                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20048                {
20049                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20050                    new_selections_by_buffer
20051                        .entry(buffer)
20052                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20053                        .0
20054                        .push(buffer_offset..buffer_offset)
20055                }
20056            }
20057            None => {
20058                let selections = self.selections.all::<usize>(cx);
20059                let multi_buffer = self.buffer.read(cx);
20060                for selection in selections {
20061                    for (snapshot, range, _, anchor) in multi_buffer
20062                        .snapshot(cx)
20063                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20064                    {
20065                        if let Some(anchor) = anchor {
20066                            // selection is in a deleted hunk
20067                            let Some(buffer_id) = anchor.buffer_id else {
20068                                continue;
20069                            };
20070                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20071                                continue;
20072                            };
20073                            let offset = text::ToOffset::to_offset(
20074                                &anchor.text_anchor,
20075                                &buffer_handle.read(cx).snapshot(),
20076                            );
20077                            let range = offset..offset;
20078                            new_selections_by_buffer
20079                                .entry(buffer_handle)
20080                                .or_insert((Vec::new(), None))
20081                                .0
20082                                .push(range)
20083                        } else {
20084                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20085                            else {
20086                                continue;
20087                            };
20088                            new_selections_by_buffer
20089                                .entry(buffer_handle)
20090                                .or_insert((Vec::new(), None))
20091                                .0
20092                                .push(range)
20093                        }
20094                    }
20095                }
20096            }
20097        }
20098
20099        new_selections_by_buffer
20100            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20101
20102        if new_selections_by_buffer.is_empty() {
20103            return;
20104        }
20105
20106        // We defer the pane interaction because we ourselves are a workspace item
20107        // and activating a new item causes the pane to call a method on us reentrantly,
20108        // which panics if we're on the stack.
20109        window.defer(cx, move |window, cx| {
20110            workspace.update(cx, |workspace, cx| {
20111                let pane = if split {
20112                    workspace.adjacent_pane(window, cx)
20113                } else {
20114                    workspace.active_pane().clone()
20115                };
20116
20117                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20118                    let editor = buffer
20119                        .read(cx)
20120                        .file()
20121                        .is_none()
20122                        .then(|| {
20123                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20124                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20125                            // Instead, we try to activate the existing editor in the pane first.
20126                            let (editor, pane_item_index) =
20127                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20128                                    let editor = item.downcast::<Editor>()?;
20129                                    let singleton_buffer =
20130                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20131                                    if singleton_buffer == buffer {
20132                                        Some((editor, i))
20133                                    } else {
20134                                        None
20135                                    }
20136                                })?;
20137                            pane.update(cx, |pane, cx| {
20138                                pane.activate_item(pane_item_index, true, true, window, cx)
20139                            });
20140                            Some(editor)
20141                        })
20142                        .flatten()
20143                        .unwrap_or_else(|| {
20144                            workspace.open_project_item::<Self>(
20145                                pane.clone(),
20146                                buffer,
20147                                true,
20148                                true,
20149                                window,
20150                                cx,
20151                            )
20152                        });
20153
20154                    editor.update(cx, |editor, cx| {
20155                        let autoscroll = match scroll_offset {
20156                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20157                            None => Autoscroll::newest(),
20158                        };
20159                        let nav_history = editor.nav_history.take();
20160                        editor.change_selections(
20161                            SelectionEffects::scroll(autoscroll),
20162                            window,
20163                            cx,
20164                            |s| {
20165                                s.select_ranges(ranges);
20166                            },
20167                        );
20168                        editor.nav_history = nav_history;
20169                    });
20170                }
20171            })
20172        });
20173    }
20174
20175    // For now, don't allow opening excerpts in buffers that aren't backed by
20176    // regular project files.
20177    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20178        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20179    }
20180
20181    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20182        let snapshot = self.buffer.read(cx).read(cx);
20183        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20184        Some(
20185            ranges
20186                .iter()
20187                .map(move |range| {
20188                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20189                })
20190                .collect(),
20191        )
20192    }
20193
20194    fn selection_replacement_ranges(
20195        &self,
20196        range: Range<OffsetUtf16>,
20197        cx: &mut App,
20198    ) -> Vec<Range<OffsetUtf16>> {
20199        let selections = self.selections.all::<OffsetUtf16>(cx);
20200        let newest_selection = selections
20201            .iter()
20202            .max_by_key(|selection| selection.id)
20203            .unwrap();
20204        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20205        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20206        let snapshot = self.buffer.read(cx).read(cx);
20207        selections
20208            .into_iter()
20209            .map(|mut selection| {
20210                selection.start.0 =
20211                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20212                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20213                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20214                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20215            })
20216            .collect()
20217    }
20218
20219    fn report_editor_event(
20220        &self,
20221        event_type: &'static str,
20222        file_extension: Option<String>,
20223        cx: &App,
20224    ) {
20225        if cfg!(any(test, feature = "test-support")) {
20226            return;
20227        }
20228
20229        let Some(project) = &self.project else { return };
20230
20231        // If None, we are in a file without an extension
20232        let file = self
20233            .buffer
20234            .read(cx)
20235            .as_singleton()
20236            .and_then(|b| b.read(cx).file());
20237        let file_extension = file_extension.or(file
20238            .as_ref()
20239            .and_then(|file| Path::new(file.file_name(cx)).extension())
20240            .and_then(|e| e.to_str())
20241            .map(|a| a.to_string()));
20242
20243        let vim_mode = vim_enabled(cx);
20244
20245        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20246        let copilot_enabled = edit_predictions_provider
20247            == language::language_settings::EditPredictionProvider::Copilot;
20248        let copilot_enabled_for_language = self
20249            .buffer
20250            .read(cx)
20251            .language_settings(cx)
20252            .show_edit_predictions;
20253
20254        let project = project.read(cx);
20255        telemetry::event!(
20256            event_type,
20257            file_extension,
20258            vim_mode,
20259            copilot_enabled,
20260            copilot_enabled_for_language,
20261            edit_predictions_provider,
20262            is_via_ssh = project.is_via_ssh(),
20263        );
20264    }
20265
20266    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20267    /// with each line being an array of {text, highlight} objects.
20268    fn copy_highlight_json(
20269        &mut self,
20270        _: &CopyHighlightJson,
20271        window: &mut Window,
20272        cx: &mut Context<Self>,
20273    ) {
20274        #[derive(Serialize)]
20275        struct Chunk<'a> {
20276            text: String,
20277            highlight: Option<&'a str>,
20278        }
20279
20280        let snapshot = self.buffer.read(cx).snapshot(cx);
20281        let range = self
20282            .selected_text_range(false, window, cx)
20283            .and_then(|selection| {
20284                if selection.range.is_empty() {
20285                    None
20286                } else {
20287                    Some(selection.range)
20288                }
20289            })
20290            .unwrap_or_else(|| 0..snapshot.len());
20291
20292        let chunks = snapshot.chunks(range, true);
20293        let mut lines = Vec::new();
20294        let mut line: VecDeque<Chunk> = VecDeque::new();
20295
20296        let Some(style) = self.style.as_ref() else {
20297            return;
20298        };
20299
20300        for chunk in chunks {
20301            let highlight = chunk
20302                .syntax_highlight_id
20303                .and_then(|id| id.name(&style.syntax));
20304            let mut chunk_lines = chunk.text.split('\n').peekable();
20305            while let Some(text) = chunk_lines.next() {
20306                let mut merged_with_last_token = false;
20307                if let Some(last_token) = line.back_mut() {
20308                    if last_token.highlight == highlight {
20309                        last_token.text.push_str(text);
20310                        merged_with_last_token = true;
20311                    }
20312                }
20313
20314                if !merged_with_last_token {
20315                    line.push_back(Chunk {
20316                        text: text.into(),
20317                        highlight,
20318                    });
20319                }
20320
20321                if chunk_lines.peek().is_some() {
20322                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20323                        line.pop_front();
20324                    }
20325                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20326                        line.pop_back();
20327                    }
20328
20329                    lines.push(mem::take(&mut line));
20330                }
20331            }
20332        }
20333
20334        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20335            return;
20336        };
20337        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20338    }
20339
20340    pub fn open_context_menu(
20341        &mut self,
20342        _: &OpenContextMenu,
20343        window: &mut Window,
20344        cx: &mut Context<Self>,
20345    ) {
20346        self.request_autoscroll(Autoscroll::newest(), cx);
20347        let position = self.selections.newest_display(cx).start;
20348        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20349    }
20350
20351    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20352        &self.inlay_hint_cache
20353    }
20354
20355    pub fn replay_insert_event(
20356        &mut self,
20357        text: &str,
20358        relative_utf16_range: Option<Range<isize>>,
20359        window: &mut Window,
20360        cx: &mut Context<Self>,
20361    ) {
20362        if !self.input_enabled {
20363            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20364            return;
20365        }
20366        if let Some(relative_utf16_range) = relative_utf16_range {
20367            let selections = self.selections.all::<OffsetUtf16>(cx);
20368            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20369                let new_ranges = selections.into_iter().map(|range| {
20370                    let start = OffsetUtf16(
20371                        range
20372                            .head()
20373                            .0
20374                            .saturating_add_signed(relative_utf16_range.start),
20375                    );
20376                    let end = OffsetUtf16(
20377                        range
20378                            .head()
20379                            .0
20380                            .saturating_add_signed(relative_utf16_range.end),
20381                    );
20382                    start..end
20383                });
20384                s.select_ranges(new_ranges);
20385            });
20386        }
20387
20388        self.handle_input(text, window, cx);
20389    }
20390
20391    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20392        let Some(provider) = self.semantics_provider.as_ref() else {
20393            return false;
20394        };
20395
20396        let mut supports = false;
20397        self.buffer().update(cx, |this, cx| {
20398            this.for_each_buffer(|buffer| {
20399                supports |= provider.supports_inlay_hints(buffer, cx);
20400            });
20401        });
20402
20403        supports
20404    }
20405
20406    pub fn is_focused(&self, window: &Window) -> bool {
20407        self.focus_handle.is_focused(window)
20408    }
20409
20410    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20411        cx.emit(EditorEvent::Focused);
20412
20413        if let Some(descendant) = self
20414            .last_focused_descendant
20415            .take()
20416            .and_then(|descendant| descendant.upgrade())
20417        {
20418            window.focus(&descendant);
20419        } else {
20420            if let Some(blame) = self.blame.as_ref() {
20421                blame.update(cx, GitBlame::focus)
20422            }
20423
20424            self.blink_manager.update(cx, BlinkManager::enable);
20425            self.show_cursor_names(window, cx);
20426            self.buffer.update(cx, |buffer, cx| {
20427                buffer.finalize_last_transaction(cx);
20428                if self.leader_id.is_none() {
20429                    buffer.set_active_selections(
20430                        &self.selections.disjoint_anchors(),
20431                        self.selections.line_mode,
20432                        self.cursor_shape,
20433                        cx,
20434                    );
20435                }
20436            });
20437        }
20438    }
20439
20440    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20441        cx.emit(EditorEvent::FocusedIn)
20442    }
20443
20444    fn handle_focus_out(
20445        &mut self,
20446        event: FocusOutEvent,
20447        _window: &mut Window,
20448        cx: &mut Context<Self>,
20449    ) {
20450        if event.blurred != self.focus_handle {
20451            self.last_focused_descendant = Some(event.blurred);
20452        }
20453        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20454    }
20455
20456    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20457        self.blink_manager.update(cx, BlinkManager::disable);
20458        self.buffer
20459            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20460
20461        if let Some(blame) = self.blame.as_ref() {
20462            blame.update(cx, GitBlame::blur)
20463        }
20464        if !self.hover_state.focused(window, cx) {
20465            hide_hover(self, cx);
20466        }
20467        if !self
20468            .context_menu
20469            .borrow()
20470            .as_ref()
20471            .is_some_and(|context_menu| context_menu.focused(window, cx))
20472        {
20473            self.hide_context_menu(window, cx);
20474        }
20475        self.discard_inline_completion(false, cx);
20476        cx.emit(EditorEvent::Blurred);
20477        cx.notify();
20478    }
20479
20480    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20481        let mut pending: String = window
20482            .pending_input_keystrokes()
20483            .into_iter()
20484            .flatten()
20485            .filter_map(|keystroke| {
20486                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20487                    keystroke.key_char.clone()
20488                } else {
20489                    None
20490                }
20491            })
20492            .collect();
20493
20494        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20495            pending = "".to_string();
20496        }
20497
20498        let existing_pending = self
20499            .text_highlights::<PendingInput>(cx)
20500            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20501        if existing_pending.is_none() && pending.is_empty() {
20502            return;
20503        }
20504        let transaction =
20505            self.transact(window, cx, |this, window, cx| {
20506                let selections = this.selections.all::<usize>(cx);
20507                let edits = selections
20508                    .iter()
20509                    .map(|selection| (selection.end..selection.end, pending.clone()));
20510                this.edit(edits, cx);
20511                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20512                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20513                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20514                    }));
20515                });
20516                if let Some(existing_ranges) = existing_pending {
20517                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20518                    this.edit(edits, cx);
20519                }
20520            });
20521
20522        let snapshot = self.snapshot(window, cx);
20523        let ranges = self
20524            .selections
20525            .all::<usize>(cx)
20526            .into_iter()
20527            .map(|selection| {
20528                snapshot.buffer_snapshot.anchor_after(selection.end)
20529                    ..snapshot
20530                        .buffer_snapshot
20531                        .anchor_before(selection.end + pending.len())
20532            })
20533            .collect();
20534
20535        if pending.is_empty() {
20536            self.clear_highlights::<PendingInput>(cx);
20537        } else {
20538            self.highlight_text::<PendingInput>(
20539                ranges,
20540                HighlightStyle {
20541                    underline: Some(UnderlineStyle {
20542                        thickness: px(1.),
20543                        color: None,
20544                        wavy: false,
20545                    }),
20546                    ..Default::default()
20547                },
20548                cx,
20549            );
20550        }
20551
20552        self.ime_transaction = self.ime_transaction.or(transaction);
20553        if let Some(transaction) = self.ime_transaction {
20554            self.buffer.update(cx, |buffer, cx| {
20555                buffer.group_until_transaction(transaction, cx);
20556            });
20557        }
20558
20559        if self.text_highlights::<PendingInput>(cx).is_none() {
20560            self.ime_transaction.take();
20561        }
20562    }
20563
20564    pub fn register_action_renderer(
20565        &mut self,
20566        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20567    ) -> Subscription {
20568        let id = self.next_editor_action_id.post_inc();
20569        self.editor_actions
20570            .borrow_mut()
20571            .insert(id, Box::new(listener));
20572
20573        let editor_actions = self.editor_actions.clone();
20574        Subscription::new(move || {
20575            editor_actions.borrow_mut().remove(&id);
20576        })
20577    }
20578
20579    pub fn register_action<A: Action>(
20580        &mut self,
20581        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20582    ) -> Subscription {
20583        let id = self.next_editor_action_id.post_inc();
20584        let listener = Arc::new(listener);
20585        self.editor_actions.borrow_mut().insert(
20586            id,
20587            Box::new(move |_, window, _| {
20588                let listener = listener.clone();
20589                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20590                    let action = action.downcast_ref().unwrap();
20591                    if phase == DispatchPhase::Bubble {
20592                        listener(action, window, cx)
20593                    }
20594                })
20595            }),
20596        );
20597
20598        let editor_actions = self.editor_actions.clone();
20599        Subscription::new(move || {
20600            editor_actions.borrow_mut().remove(&id);
20601        })
20602    }
20603
20604    pub fn file_header_size(&self) -> u32 {
20605        FILE_HEADER_HEIGHT
20606    }
20607
20608    pub fn restore(
20609        &mut self,
20610        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20611        window: &mut Window,
20612        cx: &mut Context<Self>,
20613    ) {
20614        let workspace = self.workspace();
20615        let project = self.project.as_ref();
20616        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20617            let mut tasks = Vec::new();
20618            for (buffer_id, changes) in revert_changes {
20619                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20620                    buffer.update(cx, |buffer, cx| {
20621                        buffer.edit(
20622                            changes
20623                                .into_iter()
20624                                .map(|(range, text)| (range, text.to_string())),
20625                            None,
20626                            cx,
20627                        );
20628                    });
20629
20630                    if let Some(project) =
20631                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20632                    {
20633                        project.update(cx, |project, cx| {
20634                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20635                        })
20636                    }
20637                }
20638            }
20639            tasks
20640        });
20641        cx.spawn_in(window, async move |_, cx| {
20642            for (buffer, task) in save_tasks {
20643                let result = task.await;
20644                if result.is_err() {
20645                    let Some(path) = buffer
20646                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20647                        .ok()
20648                    else {
20649                        continue;
20650                    };
20651                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20652                        let Some(task) = cx
20653                            .update_window_entity(&workspace, |workspace, window, cx| {
20654                                workspace
20655                                    .open_path_preview(path, None, false, false, false, window, cx)
20656                            })
20657                            .ok()
20658                        else {
20659                            continue;
20660                        };
20661                        task.await.log_err();
20662                    }
20663                }
20664            }
20665        })
20666        .detach();
20667        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20668            selections.refresh()
20669        });
20670    }
20671
20672    pub fn to_pixel_point(
20673        &self,
20674        source: multi_buffer::Anchor,
20675        editor_snapshot: &EditorSnapshot,
20676        window: &mut Window,
20677    ) -> Option<gpui::Point<Pixels>> {
20678        let source_point = source.to_display_point(editor_snapshot);
20679        self.display_to_pixel_point(source_point, editor_snapshot, window)
20680    }
20681
20682    pub fn display_to_pixel_point(
20683        &self,
20684        source: DisplayPoint,
20685        editor_snapshot: &EditorSnapshot,
20686        window: &mut Window,
20687    ) -> Option<gpui::Point<Pixels>> {
20688        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20689        let text_layout_details = self.text_layout_details(window);
20690        let scroll_top = text_layout_details
20691            .scroll_anchor
20692            .scroll_position(editor_snapshot)
20693            .y;
20694
20695        if source.row().as_f32() < scroll_top.floor() {
20696            return None;
20697        }
20698        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20699        let source_y = line_height * (source.row().as_f32() - scroll_top);
20700        Some(gpui::Point::new(source_x, source_y))
20701    }
20702
20703    pub fn has_visible_completions_menu(&self) -> bool {
20704        !self.edit_prediction_preview_is_active()
20705            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20706                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20707            })
20708    }
20709
20710    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20711        if self.mode.is_minimap() {
20712            return;
20713        }
20714        self.addons
20715            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20716    }
20717
20718    pub fn unregister_addon<T: Addon>(&mut self) {
20719        self.addons.remove(&std::any::TypeId::of::<T>());
20720    }
20721
20722    pub fn addon<T: Addon>(&self) -> Option<&T> {
20723        let type_id = std::any::TypeId::of::<T>();
20724        self.addons
20725            .get(&type_id)
20726            .and_then(|item| item.to_any().downcast_ref::<T>())
20727    }
20728
20729    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20730        let type_id = std::any::TypeId::of::<T>();
20731        self.addons
20732            .get_mut(&type_id)
20733            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20734    }
20735
20736    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20737        let text_layout_details = self.text_layout_details(window);
20738        let style = &text_layout_details.editor_style;
20739        let font_id = window.text_system().resolve_font(&style.text.font());
20740        let font_size = style.text.font_size.to_pixels(window.rem_size());
20741        let line_height = style.text.line_height_in_pixels(window.rem_size());
20742        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20743        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20744
20745        CharacterDimensions {
20746            em_width,
20747            em_advance,
20748            line_height,
20749        }
20750    }
20751
20752    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20753        self.load_diff_task.clone()
20754    }
20755
20756    fn read_metadata_from_db(
20757        &mut self,
20758        item_id: u64,
20759        workspace_id: WorkspaceId,
20760        window: &mut Window,
20761        cx: &mut Context<Editor>,
20762    ) {
20763        if self.is_singleton(cx)
20764            && !self.mode.is_minimap()
20765            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20766        {
20767            let buffer_snapshot = OnceCell::new();
20768
20769            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20770                if !folds.is_empty() {
20771                    let snapshot =
20772                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20773                    self.fold_ranges(
20774                        folds
20775                            .into_iter()
20776                            .map(|(start, end)| {
20777                                snapshot.clip_offset(start, Bias::Left)
20778                                    ..snapshot.clip_offset(end, Bias::Right)
20779                            })
20780                            .collect(),
20781                        false,
20782                        window,
20783                        cx,
20784                    );
20785                }
20786            }
20787
20788            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20789                if !selections.is_empty() {
20790                    let snapshot =
20791                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20792                    // skip adding the initial selection to selection history
20793                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20794                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20795                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20796                            snapshot.clip_offset(start, Bias::Left)
20797                                ..snapshot.clip_offset(end, Bias::Right)
20798                        }));
20799                    });
20800                    self.selection_history.mode = SelectionHistoryMode::Normal;
20801                }
20802            };
20803        }
20804
20805        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20806    }
20807
20808    fn update_lsp_data(
20809        &mut self,
20810        ignore_cache: bool,
20811        for_buffer: Option<BufferId>,
20812        window: &mut Window,
20813        cx: &mut Context<'_, Self>,
20814    ) {
20815        self.pull_diagnostics(for_buffer, window, cx);
20816        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20817    }
20818}
20819
20820fn vim_enabled(cx: &App) -> bool {
20821    cx.global::<SettingsStore>()
20822        .raw_user_settings()
20823        .get("vim_mode")
20824        == Some(&serde_json::Value::Bool(true))
20825}
20826
20827fn process_completion_for_edit(
20828    completion: &Completion,
20829    intent: CompletionIntent,
20830    buffer: &Entity<Buffer>,
20831    cursor_position: &text::Anchor,
20832    cx: &mut Context<Editor>,
20833) -> CompletionEdit {
20834    let buffer = buffer.read(cx);
20835    let buffer_snapshot = buffer.snapshot();
20836    let (snippet, new_text) = if completion.is_snippet() {
20837        // Workaround for typescript language server issues so that methods don't expand within
20838        // strings and functions with type expressions. The previous point is used because the query
20839        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20840        let mut snippet_source = completion.new_text.clone();
20841        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20842        previous_point.column = previous_point.column.saturating_sub(1);
20843        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20844            if scope.prefers_label_for_snippet_in_completion() {
20845                if let Some(label) = completion.label() {
20846                    if matches!(
20847                        completion.kind(),
20848                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20849                    ) {
20850                        snippet_source = label;
20851                    }
20852                }
20853            }
20854        }
20855        match Snippet::parse(&snippet_source).log_err() {
20856            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20857            None => (None, completion.new_text.clone()),
20858        }
20859    } else {
20860        (None, completion.new_text.clone())
20861    };
20862
20863    let mut range_to_replace = {
20864        let replace_range = &completion.replace_range;
20865        if let CompletionSource::Lsp {
20866            insert_range: Some(insert_range),
20867            ..
20868        } = &completion.source
20869        {
20870            debug_assert_eq!(
20871                insert_range.start, replace_range.start,
20872                "insert_range and replace_range should start at the same position"
20873            );
20874            debug_assert!(
20875                insert_range
20876                    .start
20877                    .cmp(&cursor_position, &buffer_snapshot)
20878                    .is_le(),
20879                "insert_range should start before or at cursor position"
20880            );
20881            debug_assert!(
20882                replace_range
20883                    .start
20884                    .cmp(&cursor_position, &buffer_snapshot)
20885                    .is_le(),
20886                "replace_range should start before or at cursor position"
20887            );
20888            debug_assert!(
20889                insert_range
20890                    .end
20891                    .cmp(&cursor_position, &buffer_snapshot)
20892                    .is_le(),
20893                "insert_range should end before or at cursor position"
20894            );
20895
20896            let should_replace = match intent {
20897                CompletionIntent::CompleteWithInsert => false,
20898                CompletionIntent::CompleteWithReplace => true,
20899                CompletionIntent::Complete | CompletionIntent::Compose => {
20900                    let insert_mode =
20901                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20902                            .completions
20903                            .lsp_insert_mode;
20904                    match insert_mode {
20905                        LspInsertMode::Insert => false,
20906                        LspInsertMode::Replace => true,
20907                        LspInsertMode::ReplaceSubsequence => {
20908                            let mut text_to_replace = buffer.chars_for_range(
20909                                buffer.anchor_before(replace_range.start)
20910                                    ..buffer.anchor_after(replace_range.end),
20911                            );
20912                            let mut current_needle = text_to_replace.next();
20913                            for haystack_ch in completion.label.text.chars() {
20914                                if let Some(needle_ch) = current_needle {
20915                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20916                                        current_needle = text_to_replace.next();
20917                                    }
20918                                }
20919                            }
20920                            current_needle.is_none()
20921                        }
20922                        LspInsertMode::ReplaceSuffix => {
20923                            if replace_range
20924                                .end
20925                                .cmp(&cursor_position, &buffer_snapshot)
20926                                .is_gt()
20927                            {
20928                                let range_after_cursor = *cursor_position..replace_range.end;
20929                                let text_after_cursor = buffer
20930                                    .text_for_range(
20931                                        buffer.anchor_before(range_after_cursor.start)
20932                                            ..buffer.anchor_after(range_after_cursor.end),
20933                                    )
20934                                    .collect::<String>()
20935                                    .to_ascii_lowercase();
20936                                completion
20937                                    .label
20938                                    .text
20939                                    .to_ascii_lowercase()
20940                                    .ends_with(&text_after_cursor)
20941                            } else {
20942                                true
20943                            }
20944                        }
20945                    }
20946                }
20947            };
20948
20949            if should_replace {
20950                replace_range.clone()
20951            } else {
20952                insert_range.clone()
20953            }
20954        } else {
20955            replace_range.clone()
20956        }
20957    };
20958
20959    if range_to_replace
20960        .end
20961        .cmp(&cursor_position, &buffer_snapshot)
20962        .is_lt()
20963    {
20964        range_to_replace.end = *cursor_position;
20965    }
20966
20967    CompletionEdit {
20968        new_text,
20969        replace_range: range_to_replace.to_offset(&buffer),
20970        snippet,
20971    }
20972}
20973
20974struct CompletionEdit {
20975    new_text: String,
20976    replace_range: Range<usize>,
20977    snippet: Option<Snippet>,
20978}
20979
20980fn insert_extra_newline_brackets(
20981    buffer: &MultiBufferSnapshot,
20982    range: Range<usize>,
20983    language: &language::LanguageScope,
20984) -> bool {
20985    let leading_whitespace_len = buffer
20986        .reversed_chars_at(range.start)
20987        .take_while(|c| c.is_whitespace() && *c != '\n')
20988        .map(|c| c.len_utf8())
20989        .sum::<usize>();
20990    let trailing_whitespace_len = buffer
20991        .chars_at(range.end)
20992        .take_while(|c| c.is_whitespace() && *c != '\n')
20993        .map(|c| c.len_utf8())
20994        .sum::<usize>();
20995    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20996
20997    language.brackets().any(|(pair, enabled)| {
20998        let pair_start = pair.start.trim_end();
20999        let pair_end = pair.end.trim_start();
21000
21001        enabled
21002            && pair.newline
21003            && buffer.contains_str_at(range.end, pair_end)
21004            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21005    })
21006}
21007
21008fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21009    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21010        [(buffer, range, _)] => (*buffer, range.clone()),
21011        _ => return false,
21012    };
21013    let pair = {
21014        let mut result: Option<BracketMatch> = None;
21015
21016        for pair in buffer
21017            .all_bracket_ranges(range.clone())
21018            .filter(move |pair| {
21019                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21020            })
21021        {
21022            let len = pair.close_range.end - pair.open_range.start;
21023
21024            if let Some(existing) = &result {
21025                let existing_len = existing.close_range.end - existing.open_range.start;
21026                if len > existing_len {
21027                    continue;
21028                }
21029            }
21030
21031            result = Some(pair);
21032        }
21033
21034        result
21035    };
21036    let Some(pair) = pair else {
21037        return false;
21038    };
21039    pair.newline_only
21040        && buffer
21041            .chars_for_range(pair.open_range.end..range.start)
21042            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21043            .all(|c| c.is_whitespace() && c != '\n')
21044}
21045
21046fn update_uncommitted_diff_for_buffer(
21047    editor: Entity<Editor>,
21048    project: &Entity<Project>,
21049    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21050    buffer: Entity<MultiBuffer>,
21051    cx: &mut App,
21052) -> Task<()> {
21053    let mut tasks = Vec::new();
21054    project.update(cx, |project, cx| {
21055        for buffer in buffers {
21056            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21057                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21058            }
21059        }
21060    });
21061    cx.spawn(async move |cx| {
21062        let diffs = future::join_all(tasks).await;
21063        if editor
21064            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21065            .unwrap_or(false)
21066        {
21067            return;
21068        }
21069
21070        buffer
21071            .update(cx, |buffer, cx| {
21072                for diff in diffs.into_iter().flatten() {
21073                    buffer.add_diff(diff, cx);
21074                }
21075            })
21076            .ok();
21077    })
21078}
21079
21080fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21081    let tab_size = tab_size.get() as usize;
21082    let mut width = offset;
21083
21084    for ch in text.chars() {
21085        width += if ch == '\t' {
21086            tab_size - (width % tab_size)
21087        } else {
21088            1
21089        };
21090    }
21091
21092    width - offset
21093}
21094
21095#[cfg(test)]
21096mod tests {
21097    use super::*;
21098
21099    #[test]
21100    fn test_string_size_with_expanded_tabs() {
21101        let nz = |val| NonZeroU32::new(val).unwrap();
21102        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21103        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21104        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21105        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21106        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21107        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21108        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21109        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21110    }
21111}
21112
21113/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21114struct WordBreakingTokenizer<'a> {
21115    input: &'a str,
21116}
21117
21118impl<'a> WordBreakingTokenizer<'a> {
21119    fn new(input: &'a str) -> Self {
21120        Self { input }
21121    }
21122}
21123
21124fn is_char_ideographic(ch: char) -> bool {
21125    use unicode_script::Script::*;
21126    use unicode_script::UnicodeScript;
21127    matches!(ch.script(), Han | Tangut | Yi)
21128}
21129
21130fn is_grapheme_ideographic(text: &str) -> bool {
21131    text.chars().any(is_char_ideographic)
21132}
21133
21134fn is_grapheme_whitespace(text: &str) -> bool {
21135    text.chars().any(|x| x.is_whitespace())
21136}
21137
21138fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21139    text.chars().next().map_or(false, |ch| {
21140        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21141    })
21142}
21143
21144#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21145enum WordBreakToken<'a> {
21146    Word { token: &'a str, grapheme_len: usize },
21147    InlineWhitespace { token: &'a str, grapheme_len: usize },
21148    Newline,
21149}
21150
21151impl<'a> Iterator for WordBreakingTokenizer<'a> {
21152    /// Yields a span, the count of graphemes in the token, and whether it was
21153    /// whitespace. Note that it also breaks at word boundaries.
21154    type Item = WordBreakToken<'a>;
21155
21156    fn next(&mut self) -> Option<Self::Item> {
21157        use unicode_segmentation::UnicodeSegmentation;
21158        if self.input.is_empty() {
21159            return None;
21160        }
21161
21162        let mut iter = self.input.graphemes(true).peekable();
21163        let mut offset = 0;
21164        let mut grapheme_len = 0;
21165        if let Some(first_grapheme) = iter.next() {
21166            let is_newline = first_grapheme == "\n";
21167            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21168            offset += first_grapheme.len();
21169            grapheme_len += 1;
21170            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21171                if let Some(grapheme) = iter.peek().copied() {
21172                    if should_stay_with_preceding_ideograph(grapheme) {
21173                        offset += grapheme.len();
21174                        grapheme_len += 1;
21175                    }
21176                }
21177            } else {
21178                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21179                let mut next_word_bound = words.peek().copied();
21180                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21181                    next_word_bound = words.next();
21182                }
21183                while let Some(grapheme) = iter.peek().copied() {
21184                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21185                        break;
21186                    };
21187                    if is_grapheme_whitespace(grapheme) != is_whitespace
21188                        || (grapheme == "\n") != is_newline
21189                    {
21190                        break;
21191                    };
21192                    offset += grapheme.len();
21193                    grapheme_len += 1;
21194                    iter.next();
21195                }
21196            }
21197            let token = &self.input[..offset];
21198            self.input = &self.input[offset..];
21199            if token == "\n" {
21200                Some(WordBreakToken::Newline)
21201            } else if is_whitespace {
21202                Some(WordBreakToken::InlineWhitespace {
21203                    token,
21204                    grapheme_len,
21205                })
21206            } else {
21207                Some(WordBreakToken::Word {
21208                    token,
21209                    grapheme_len,
21210                })
21211            }
21212        } else {
21213            None
21214        }
21215    }
21216}
21217
21218#[test]
21219fn test_word_breaking_tokenizer() {
21220    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21221        ("", &[]),
21222        ("  ", &[whitespace("  ", 2)]),
21223        ("Ʒ", &[word("Ʒ", 1)]),
21224        ("Ǽ", &[word("Ǽ", 1)]),
21225        ("", &[word("", 1)]),
21226        ("⋑⋑", &[word("⋑⋑", 2)]),
21227        (
21228            "原理,进而",
21229            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21230        ),
21231        (
21232            "hello world",
21233            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21234        ),
21235        (
21236            "hello, world",
21237            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21238        ),
21239        (
21240            "  hello world",
21241            &[
21242                whitespace("  ", 2),
21243                word("hello", 5),
21244                whitespace(" ", 1),
21245                word("world", 5),
21246            ],
21247        ),
21248        (
21249            "这是什么 \n 钢笔",
21250            &[
21251                word("", 1),
21252                word("", 1),
21253                word("", 1),
21254                word("", 1),
21255                whitespace(" ", 1),
21256                newline(),
21257                whitespace(" ", 1),
21258                word("", 1),
21259                word("", 1),
21260            ],
21261        ),
21262        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21263    ];
21264
21265    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21266        WordBreakToken::Word {
21267            token,
21268            grapheme_len,
21269        }
21270    }
21271
21272    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21273        WordBreakToken::InlineWhitespace {
21274            token,
21275            grapheme_len,
21276        }
21277    }
21278
21279    fn newline() -> WordBreakToken<'static> {
21280        WordBreakToken::Newline
21281    }
21282
21283    for (input, result) in tests {
21284        assert_eq!(
21285            WordBreakingTokenizer::new(input)
21286                .collect::<Vec<_>>()
21287                .as_slice(),
21288            *result,
21289        );
21290    }
21291}
21292
21293fn wrap_with_prefix(
21294    first_line_prefix: String,
21295    subsequent_lines_prefix: String,
21296    unwrapped_text: String,
21297    wrap_column: usize,
21298    tab_size: NonZeroU32,
21299    preserve_existing_whitespace: bool,
21300) -> String {
21301    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21302    let subsequent_lines_prefix_len =
21303        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21304    let mut wrapped_text = String::new();
21305    let mut current_line = first_line_prefix.clone();
21306    let mut is_first_line = true;
21307
21308    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21309    let mut current_line_len = first_line_prefix_len;
21310    let mut in_whitespace = false;
21311    for token in tokenizer {
21312        let have_preceding_whitespace = in_whitespace;
21313        match token {
21314            WordBreakToken::Word {
21315                token,
21316                grapheme_len,
21317            } => {
21318                in_whitespace = false;
21319                let current_prefix_len = if is_first_line {
21320                    first_line_prefix_len
21321                } else {
21322                    subsequent_lines_prefix_len
21323                };
21324                if current_line_len + grapheme_len > wrap_column
21325                    && current_line_len != current_prefix_len
21326                {
21327                    wrapped_text.push_str(current_line.trim_end());
21328                    wrapped_text.push('\n');
21329                    is_first_line = false;
21330                    current_line = subsequent_lines_prefix.clone();
21331                    current_line_len = subsequent_lines_prefix_len;
21332                }
21333                current_line.push_str(token);
21334                current_line_len += grapheme_len;
21335            }
21336            WordBreakToken::InlineWhitespace {
21337                mut token,
21338                mut grapheme_len,
21339            } => {
21340                in_whitespace = true;
21341                if have_preceding_whitespace && !preserve_existing_whitespace {
21342                    continue;
21343                }
21344                if !preserve_existing_whitespace {
21345                    token = " ";
21346                    grapheme_len = 1;
21347                }
21348                let current_prefix_len = if is_first_line {
21349                    first_line_prefix_len
21350                } else {
21351                    subsequent_lines_prefix_len
21352                };
21353                if current_line_len + grapheme_len > wrap_column {
21354                    wrapped_text.push_str(current_line.trim_end());
21355                    wrapped_text.push('\n');
21356                    is_first_line = false;
21357                    current_line = subsequent_lines_prefix.clone();
21358                    current_line_len = subsequent_lines_prefix_len;
21359                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21360                    current_line.push_str(token);
21361                    current_line_len += grapheme_len;
21362                }
21363            }
21364            WordBreakToken::Newline => {
21365                in_whitespace = true;
21366                let current_prefix_len = if is_first_line {
21367                    first_line_prefix_len
21368                } else {
21369                    subsequent_lines_prefix_len
21370                };
21371                if preserve_existing_whitespace {
21372                    wrapped_text.push_str(current_line.trim_end());
21373                    wrapped_text.push('\n');
21374                    is_first_line = false;
21375                    current_line = subsequent_lines_prefix.clone();
21376                    current_line_len = subsequent_lines_prefix_len;
21377                } else if have_preceding_whitespace {
21378                    continue;
21379                } else if current_line_len + 1 > wrap_column
21380                    && current_line_len != current_prefix_len
21381                {
21382                    wrapped_text.push_str(current_line.trim_end());
21383                    wrapped_text.push('\n');
21384                    is_first_line = false;
21385                    current_line = subsequent_lines_prefix.clone();
21386                    current_line_len = subsequent_lines_prefix_len;
21387                } else if current_line_len != current_prefix_len {
21388                    current_line.push(' ');
21389                    current_line_len += 1;
21390                }
21391            }
21392        }
21393    }
21394
21395    if !current_line.is_empty() {
21396        wrapped_text.push_str(&current_line);
21397    }
21398    wrapped_text
21399}
21400
21401#[test]
21402fn test_wrap_with_prefix() {
21403    assert_eq!(
21404        wrap_with_prefix(
21405            "# ".to_string(),
21406            "# ".to_string(),
21407            "abcdefg".to_string(),
21408            4,
21409            NonZeroU32::new(4).unwrap(),
21410            false,
21411        ),
21412        "# abcdefg"
21413    );
21414    assert_eq!(
21415        wrap_with_prefix(
21416            "".to_string(),
21417            "".to_string(),
21418            "\thello world".to_string(),
21419            8,
21420            NonZeroU32::new(4).unwrap(),
21421            false,
21422        ),
21423        "hello\nworld"
21424    );
21425    assert_eq!(
21426        wrap_with_prefix(
21427            "// ".to_string(),
21428            "// ".to_string(),
21429            "xx \nyy zz aa bb cc".to_string(),
21430            12,
21431            NonZeroU32::new(4).unwrap(),
21432            false,
21433        ),
21434        "// xx yy zz\n// aa bb cc"
21435    );
21436    assert_eq!(
21437        wrap_with_prefix(
21438            String::new(),
21439            String::new(),
21440            "这是什么 \n 钢笔".to_string(),
21441            3,
21442            NonZeroU32::new(4).unwrap(),
21443            false,
21444        ),
21445        "这是什\n么 钢\n"
21446    );
21447}
21448
21449pub trait CollaborationHub {
21450    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21451    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21452    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21453}
21454
21455impl CollaborationHub for Entity<Project> {
21456    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21457        self.read(cx).collaborators()
21458    }
21459
21460    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21461        self.read(cx).user_store().read(cx).participant_indices()
21462    }
21463
21464    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21465        let this = self.read(cx);
21466        let user_ids = this.collaborators().values().map(|c| c.user_id);
21467        this.user_store().read(cx).participant_names(user_ids, cx)
21468    }
21469}
21470
21471pub trait SemanticsProvider {
21472    fn hover(
21473        &self,
21474        buffer: &Entity<Buffer>,
21475        position: text::Anchor,
21476        cx: &mut App,
21477    ) -> Option<Task<Vec<project::Hover>>>;
21478
21479    fn inline_values(
21480        &self,
21481        buffer_handle: Entity<Buffer>,
21482        range: Range<text::Anchor>,
21483        cx: &mut App,
21484    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21485
21486    fn inlay_hints(
21487        &self,
21488        buffer_handle: Entity<Buffer>,
21489        range: Range<text::Anchor>,
21490        cx: &mut App,
21491    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21492
21493    fn resolve_inlay_hint(
21494        &self,
21495        hint: InlayHint,
21496        buffer_handle: Entity<Buffer>,
21497        server_id: LanguageServerId,
21498        cx: &mut App,
21499    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21500
21501    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21502
21503    fn document_highlights(
21504        &self,
21505        buffer: &Entity<Buffer>,
21506        position: text::Anchor,
21507        cx: &mut App,
21508    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21509
21510    fn definitions(
21511        &self,
21512        buffer: &Entity<Buffer>,
21513        position: text::Anchor,
21514        kind: GotoDefinitionKind,
21515        cx: &mut App,
21516    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21517
21518    fn range_for_rename(
21519        &self,
21520        buffer: &Entity<Buffer>,
21521        position: text::Anchor,
21522        cx: &mut App,
21523    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21524
21525    fn perform_rename(
21526        &self,
21527        buffer: &Entity<Buffer>,
21528        position: text::Anchor,
21529        new_name: String,
21530        cx: &mut App,
21531    ) -> Option<Task<Result<ProjectTransaction>>>;
21532}
21533
21534pub trait CompletionProvider {
21535    fn completions(
21536        &self,
21537        excerpt_id: ExcerptId,
21538        buffer: &Entity<Buffer>,
21539        buffer_position: text::Anchor,
21540        trigger: CompletionContext,
21541        window: &mut Window,
21542        cx: &mut Context<Editor>,
21543    ) -> Task<Result<Vec<CompletionResponse>>>;
21544
21545    fn resolve_completions(
21546        &self,
21547        _buffer: Entity<Buffer>,
21548        _completion_indices: Vec<usize>,
21549        _completions: Rc<RefCell<Box<[Completion]>>>,
21550        _cx: &mut Context<Editor>,
21551    ) -> Task<Result<bool>> {
21552        Task::ready(Ok(false))
21553    }
21554
21555    fn apply_additional_edits_for_completion(
21556        &self,
21557        _buffer: Entity<Buffer>,
21558        _completions: Rc<RefCell<Box<[Completion]>>>,
21559        _completion_index: usize,
21560        _push_to_history: bool,
21561        _cx: &mut Context<Editor>,
21562    ) -> Task<Result<Option<language::Transaction>>> {
21563        Task::ready(Ok(None))
21564    }
21565
21566    fn is_completion_trigger(
21567        &self,
21568        buffer: &Entity<Buffer>,
21569        position: language::Anchor,
21570        text: &str,
21571        trigger_in_words: bool,
21572        menu_is_open: bool,
21573        cx: &mut Context<Editor>,
21574    ) -> bool;
21575
21576    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21577
21578    fn sort_completions(&self) -> bool {
21579        true
21580    }
21581
21582    fn filter_completions(&self) -> bool {
21583        true
21584    }
21585}
21586
21587pub trait CodeActionProvider {
21588    fn id(&self) -> Arc<str>;
21589
21590    fn code_actions(
21591        &self,
21592        buffer: &Entity<Buffer>,
21593        range: Range<text::Anchor>,
21594        window: &mut Window,
21595        cx: &mut App,
21596    ) -> Task<Result<Vec<CodeAction>>>;
21597
21598    fn apply_code_action(
21599        &self,
21600        buffer_handle: Entity<Buffer>,
21601        action: CodeAction,
21602        excerpt_id: ExcerptId,
21603        push_to_history: bool,
21604        window: &mut Window,
21605        cx: &mut App,
21606    ) -> Task<Result<ProjectTransaction>>;
21607}
21608
21609impl CodeActionProvider for Entity<Project> {
21610    fn id(&self) -> Arc<str> {
21611        "project".into()
21612    }
21613
21614    fn code_actions(
21615        &self,
21616        buffer: &Entity<Buffer>,
21617        range: Range<text::Anchor>,
21618        _window: &mut Window,
21619        cx: &mut App,
21620    ) -> Task<Result<Vec<CodeAction>>> {
21621        self.update(cx, |project, cx| {
21622            let code_lens = project.code_lens(buffer, range.clone(), cx);
21623            let code_actions = project.code_actions(buffer, range, None, cx);
21624            cx.background_spawn(async move {
21625                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21626                Ok(code_lens
21627                    .context("code lens fetch")?
21628                    .into_iter()
21629                    .chain(code_actions.context("code action fetch")?)
21630                    .collect())
21631            })
21632        })
21633    }
21634
21635    fn apply_code_action(
21636        &self,
21637        buffer_handle: Entity<Buffer>,
21638        action: CodeAction,
21639        _excerpt_id: ExcerptId,
21640        push_to_history: bool,
21641        _window: &mut Window,
21642        cx: &mut App,
21643    ) -> Task<Result<ProjectTransaction>> {
21644        self.update(cx, |project, cx| {
21645            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21646        })
21647    }
21648}
21649
21650fn snippet_completions(
21651    project: &Project,
21652    buffer: &Entity<Buffer>,
21653    buffer_position: text::Anchor,
21654    cx: &mut App,
21655) -> Task<Result<CompletionResponse>> {
21656    let languages = buffer.read(cx).languages_at(buffer_position);
21657    let snippet_store = project.snippets().read(cx);
21658
21659    let scopes: Vec<_> = languages
21660        .iter()
21661        .filter_map(|language| {
21662            let language_name = language.lsp_id();
21663            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21664
21665            if snippets.is_empty() {
21666                None
21667            } else {
21668                Some((language.default_scope(), snippets))
21669            }
21670        })
21671        .collect();
21672
21673    if scopes.is_empty() {
21674        return Task::ready(Ok(CompletionResponse {
21675            completions: vec![],
21676            is_incomplete: false,
21677        }));
21678    }
21679
21680    let snapshot = buffer.read(cx).text_snapshot();
21681    let chars: String = snapshot
21682        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21683        .collect();
21684    let executor = cx.background_executor().clone();
21685
21686    cx.background_spawn(async move {
21687        let mut is_incomplete = false;
21688        let mut completions: Vec<Completion> = Vec::new();
21689        for (scope, snippets) in scopes.into_iter() {
21690            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21691            let mut last_word = chars
21692                .chars()
21693                .take_while(|c| classifier.is_word(*c))
21694                .collect::<String>();
21695            last_word = last_word.chars().rev().collect();
21696
21697            if last_word.is_empty() {
21698                return Ok(CompletionResponse {
21699                    completions: vec![],
21700                    is_incomplete: true,
21701                });
21702            }
21703
21704            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21705            let to_lsp = |point: &text::Anchor| {
21706                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21707                point_to_lsp(end)
21708            };
21709            let lsp_end = to_lsp(&buffer_position);
21710
21711            let candidates = snippets
21712                .iter()
21713                .enumerate()
21714                .flat_map(|(ix, snippet)| {
21715                    snippet
21716                        .prefix
21717                        .iter()
21718                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21719                })
21720                .collect::<Vec<StringMatchCandidate>>();
21721
21722            const MAX_RESULTS: usize = 100;
21723            let mut matches = fuzzy::match_strings(
21724                &candidates,
21725                &last_word,
21726                last_word.chars().any(|c| c.is_uppercase()),
21727                true,
21728                MAX_RESULTS,
21729                &Default::default(),
21730                executor.clone(),
21731            )
21732            .await;
21733
21734            if matches.len() >= MAX_RESULTS {
21735                is_incomplete = true;
21736            }
21737
21738            // Remove all candidates where the query's start does not match the start of any word in the candidate
21739            if let Some(query_start) = last_word.chars().next() {
21740                matches.retain(|string_match| {
21741                    split_words(&string_match.string).any(|word| {
21742                        // Check that the first codepoint of the word as lowercase matches the first
21743                        // codepoint of the query as lowercase
21744                        word.chars()
21745                            .flat_map(|codepoint| codepoint.to_lowercase())
21746                            .zip(query_start.to_lowercase())
21747                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21748                    })
21749                });
21750            }
21751
21752            let matched_strings = matches
21753                .into_iter()
21754                .map(|m| m.string)
21755                .collect::<HashSet<_>>();
21756
21757            completions.extend(snippets.iter().filter_map(|snippet| {
21758                let matching_prefix = snippet
21759                    .prefix
21760                    .iter()
21761                    .find(|prefix| matched_strings.contains(*prefix))?;
21762                let start = as_offset - last_word.len();
21763                let start = snapshot.anchor_before(start);
21764                let range = start..buffer_position;
21765                let lsp_start = to_lsp(&start);
21766                let lsp_range = lsp::Range {
21767                    start: lsp_start,
21768                    end: lsp_end,
21769                };
21770                Some(Completion {
21771                    replace_range: range,
21772                    new_text: snippet.body.clone(),
21773                    source: CompletionSource::Lsp {
21774                        insert_range: None,
21775                        server_id: LanguageServerId(usize::MAX),
21776                        resolved: true,
21777                        lsp_completion: Box::new(lsp::CompletionItem {
21778                            label: snippet.prefix.first().unwrap().clone(),
21779                            kind: Some(CompletionItemKind::SNIPPET),
21780                            label_details: snippet.description.as_ref().map(|description| {
21781                                lsp::CompletionItemLabelDetails {
21782                                    detail: Some(description.clone()),
21783                                    description: None,
21784                                }
21785                            }),
21786                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21787                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21788                                lsp::InsertReplaceEdit {
21789                                    new_text: snippet.body.clone(),
21790                                    insert: lsp_range,
21791                                    replace: lsp_range,
21792                                },
21793                            )),
21794                            filter_text: Some(snippet.body.clone()),
21795                            sort_text: Some(char::MAX.to_string()),
21796                            ..lsp::CompletionItem::default()
21797                        }),
21798                        lsp_defaults: None,
21799                    },
21800                    label: CodeLabel {
21801                        text: matching_prefix.clone(),
21802                        runs: Vec::new(),
21803                        filter_range: 0..matching_prefix.len(),
21804                    },
21805                    icon_path: None,
21806                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21807                        single_line: snippet.name.clone().into(),
21808                        plain_text: snippet
21809                            .description
21810                            .clone()
21811                            .map(|description| description.into()),
21812                    }),
21813                    insert_text_mode: None,
21814                    confirm: None,
21815                })
21816            }))
21817        }
21818
21819        Ok(CompletionResponse {
21820            completions,
21821            is_incomplete,
21822        })
21823    })
21824}
21825
21826impl CompletionProvider for Entity<Project> {
21827    fn completions(
21828        &self,
21829        _excerpt_id: ExcerptId,
21830        buffer: &Entity<Buffer>,
21831        buffer_position: text::Anchor,
21832        options: CompletionContext,
21833        _window: &mut Window,
21834        cx: &mut Context<Editor>,
21835    ) -> Task<Result<Vec<CompletionResponse>>> {
21836        self.update(cx, |project, cx| {
21837            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21838            let project_completions = project.completions(buffer, buffer_position, options, cx);
21839            cx.background_spawn(async move {
21840                let mut responses = project_completions.await?;
21841                let snippets = snippets.await?;
21842                if !snippets.completions.is_empty() {
21843                    responses.push(snippets);
21844                }
21845                Ok(responses)
21846            })
21847        })
21848    }
21849
21850    fn resolve_completions(
21851        &self,
21852        buffer: Entity<Buffer>,
21853        completion_indices: Vec<usize>,
21854        completions: Rc<RefCell<Box<[Completion]>>>,
21855        cx: &mut Context<Editor>,
21856    ) -> Task<Result<bool>> {
21857        self.update(cx, |project, cx| {
21858            project.lsp_store().update(cx, |lsp_store, cx| {
21859                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21860            })
21861        })
21862    }
21863
21864    fn apply_additional_edits_for_completion(
21865        &self,
21866        buffer: Entity<Buffer>,
21867        completions: Rc<RefCell<Box<[Completion]>>>,
21868        completion_index: usize,
21869        push_to_history: bool,
21870        cx: &mut Context<Editor>,
21871    ) -> Task<Result<Option<language::Transaction>>> {
21872        self.update(cx, |project, cx| {
21873            project.lsp_store().update(cx, |lsp_store, cx| {
21874                lsp_store.apply_additional_edits_for_completion(
21875                    buffer,
21876                    completions,
21877                    completion_index,
21878                    push_to_history,
21879                    cx,
21880                )
21881            })
21882        })
21883    }
21884
21885    fn is_completion_trigger(
21886        &self,
21887        buffer: &Entity<Buffer>,
21888        position: language::Anchor,
21889        text: &str,
21890        trigger_in_words: bool,
21891        menu_is_open: bool,
21892        cx: &mut Context<Editor>,
21893    ) -> bool {
21894        let mut chars = text.chars();
21895        let char = if let Some(char) = chars.next() {
21896            char
21897        } else {
21898            return false;
21899        };
21900        if chars.next().is_some() {
21901            return false;
21902        }
21903
21904        let buffer = buffer.read(cx);
21905        let snapshot = buffer.snapshot();
21906        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21907            return false;
21908        }
21909        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21910        if trigger_in_words && classifier.is_word(char) {
21911            return true;
21912        }
21913
21914        buffer.completion_triggers().contains(text)
21915    }
21916}
21917
21918impl SemanticsProvider for Entity<Project> {
21919    fn hover(
21920        &self,
21921        buffer: &Entity<Buffer>,
21922        position: text::Anchor,
21923        cx: &mut App,
21924    ) -> Option<Task<Vec<project::Hover>>> {
21925        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21926    }
21927
21928    fn document_highlights(
21929        &self,
21930        buffer: &Entity<Buffer>,
21931        position: text::Anchor,
21932        cx: &mut App,
21933    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21934        Some(self.update(cx, |project, cx| {
21935            project.document_highlights(buffer, position, cx)
21936        }))
21937    }
21938
21939    fn definitions(
21940        &self,
21941        buffer: &Entity<Buffer>,
21942        position: text::Anchor,
21943        kind: GotoDefinitionKind,
21944        cx: &mut App,
21945    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21946        Some(self.update(cx, |project, cx| match kind {
21947            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
21948            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
21949            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
21950            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
21951        }))
21952    }
21953
21954    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21955        // TODO: make this work for remote projects
21956        self.update(cx, |project, cx| {
21957            if project
21958                .active_debug_session(cx)
21959                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21960            {
21961                return true;
21962            }
21963
21964            buffer.update(cx, |buffer, cx| {
21965                project.any_language_server_supports_inlay_hints(buffer, cx)
21966            })
21967        })
21968    }
21969
21970    fn inline_values(
21971        &self,
21972        buffer_handle: Entity<Buffer>,
21973        range: Range<text::Anchor>,
21974        cx: &mut App,
21975    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21976        self.update(cx, |project, cx| {
21977            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21978
21979            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21980        })
21981    }
21982
21983    fn inlay_hints(
21984        &self,
21985        buffer_handle: Entity<Buffer>,
21986        range: Range<text::Anchor>,
21987        cx: &mut App,
21988    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21989        Some(self.update(cx, |project, cx| {
21990            project.inlay_hints(buffer_handle, range, cx)
21991        }))
21992    }
21993
21994    fn resolve_inlay_hint(
21995        &self,
21996        hint: InlayHint,
21997        buffer_handle: Entity<Buffer>,
21998        server_id: LanguageServerId,
21999        cx: &mut App,
22000    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22001        Some(self.update(cx, |project, cx| {
22002            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22003        }))
22004    }
22005
22006    fn range_for_rename(
22007        &self,
22008        buffer: &Entity<Buffer>,
22009        position: text::Anchor,
22010        cx: &mut App,
22011    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22012        Some(self.update(cx, |project, cx| {
22013            let buffer = buffer.clone();
22014            let task = project.prepare_rename(buffer.clone(), position, cx);
22015            cx.spawn(async move |_, cx| {
22016                Ok(match task.await? {
22017                    PrepareRenameResponse::Success(range) => Some(range),
22018                    PrepareRenameResponse::InvalidPosition => None,
22019                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22020                        // Fallback on using TreeSitter info to determine identifier range
22021                        buffer.read_with(cx, |buffer, _| {
22022                            let snapshot = buffer.snapshot();
22023                            let (range, kind) = snapshot.surrounding_word(position);
22024                            if kind != Some(CharKind::Word) {
22025                                return None;
22026                            }
22027                            Some(
22028                                snapshot.anchor_before(range.start)
22029                                    ..snapshot.anchor_after(range.end),
22030                            )
22031                        })?
22032                    }
22033                })
22034            })
22035        }))
22036    }
22037
22038    fn perform_rename(
22039        &self,
22040        buffer: &Entity<Buffer>,
22041        position: text::Anchor,
22042        new_name: String,
22043        cx: &mut App,
22044    ) -> Option<Task<Result<ProjectTransaction>>> {
22045        Some(self.update(cx, |project, cx| {
22046            project.perform_rename(buffer.clone(), position, new_name, cx)
22047        }))
22048    }
22049}
22050
22051fn inlay_hint_settings(
22052    location: Anchor,
22053    snapshot: &MultiBufferSnapshot,
22054    cx: &mut Context<Editor>,
22055) -> InlayHintSettings {
22056    let file = snapshot.file_at(location);
22057    let language = snapshot.language_at(location).map(|l| l.name());
22058    language_settings(language, file, cx).inlay_hints
22059}
22060
22061fn consume_contiguous_rows(
22062    contiguous_row_selections: &mut Vec<Selection<Point>>,
22063    selection: &Selection<Point>,
22064    display_map: &DisplaySnapshot,
22065    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22066) -> (MultiBufferRow, MultiBufferRow) {
22067    contiguous_row_selections.push(selection.clone());
22068    let start_row = MultiBufferRow(selection.start.row);
22069    let mut end_row = ending_row(selection, display_map);
22070
22071    while let Some(next_selection) = selections.peek() {
22072        if next_selection.start.row <= end_row.0 {
22073            end_row = ending_row(next_selection, display_map);
22074            contiguous_row_selections.push(selections.next().unwrap().clone());
22075        } else {
22076            break;
22077        }
22078    }
22079    (start_row, end_row)
22080}
22081
22082fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22083    if next_selection.end.column > 0 || next_selection.is_empty() {
22084        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22085    } else {
22086        MultiBufferRow(next_selection.end.row)
22087    }
22088}
22089
22090impl EditorSnapshot {
22091    pub fn remote_selections_in_range<'a>(
22092        &'a self,
22093        range: &'a Range<Anchor>,
22094        collaboration_hub: &dyn CollaborationHub,
22095        cx: &'a App,
22096    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22097        let participant_names = collaboration_hub.user_names(cx);
22098        let participant_indices = collaboration_hub.user_participant_indices(cx);
22099        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22100        let collaborators_by_replica_id = collaborators_by_peer_id
22101            .values()
22102            .map(|collaborator| (collaborator.replica_id, collaborator))
22103            .collect::<HashMap<_, _>>();
22104        self.buffer_snapshot
22105            .selections_in_range(range, false)
22106            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22107                if replica_id == AGENT_REPLICA_ID {
22108                    Some(RemoteSelection {
22109                        replica_id,
22110                        selection,
22111                        cursor_shape,
22112                        line_mode,
22113                        collaborator_id: CollaboratorId::Agent,
22114                        user_name: Some("Agent".into()),
22115                        color: cx.theme().players().agent(),
22116                    })
22117                } else {
22118                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22119                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22120                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22121                    Some(RemoteSelection {
22122                        replica_id,
22123                        selection,
22124                        cursor_shape,
22125                        line_mode,
22126                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22127                        user_name,
22128                        color: if let Some(index) = participant_index {
22129                            cx.theme().players().color_for_participant(index.0)
22130                        } else {
22131                            cx.theme().players().absent()
22132                        },
22133                    })
22134                }
22135            })
22136    }
22137
22138    pub fn hunks_for_ranges(
22139        &self,
22140        ranges: impl IntoIterator<Item = Range<Point>>,
22141    ) -> Vec<MultiBufferDiffHunk> {
22142        let mut hunks = Vec::new();
22143        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22144            HashMap::default();
22145        for query_range in ranges {
22146            let query_rows =
22147                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22148            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22149                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22150            ) {
22151                // Include deleted hunks that are adjacent to the query range, because
22152                // otherwise they would be missed.
22153                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22154                if hunk.status().is_deleted() {
22155                    intersects_range |= hunk.row_range.start == query_rows.end;
22156                    intersects_range |= hunk.row_range.end == query_rows.start;
22157                }
22158                if intersects_range {
22159                    if !processed_buffer_rows
22160                        .entry(hunk.buffer_id)
22161                        .or_default()
22162                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22163                    {
22164                        continue;
22165                    }
22166                    hunks.push(hunk);
22167                }
22168            }
22169        }
22170
22171        hunks
22172    }
22173
22174    fn display_diff_hunks_for_rows<'a>(
22175        &'a self,
22176        display_rows: Range<DisplayRow>,
22177        folded_buffers: &'a HashSet<BufferId>,
22178    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22179        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22180        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22181
22182        self.buffer_snapshot
22183            .diff_hunks_in_range(buffer_start..buffer_end)
22184            .filter_map(|hunk| {
22185                if folded_buffers.contains(&hunk.buffer_id) {
22186                    return None;
22187                }
22188
22189                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22190                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22191
22192                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22193                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22194
22195                let display_hunk = if hunk_display_start.column() != 0 {
22196                    DisplayDiffHunk::Folded {
22197                        display_row: hunk_display_start.row(),
22198                    }
22199                } else {
22200                    let mut end_row = hunk_display_end.row();
22201                    if hunk_display_end.column() > 0 {
22202                        end_row.0 += 1;
22203                    }
22204                    let is_created_file = hunk.is_created_file();
22205                    DisplayDiffHunk::Unfolded {
22206                        status: hunk.status(),
22207                        diff_base_byte_range: hunk.diff_base_byte_range,
22208                        display_row_range: hunk_display_start.row()..end_row,
22209                        multi_buffer_range: Anchor::range_in_buffer(
22210                            hunk.excerpt_id,
22211                            hunk.buffer_id,
22212                            hunk.buffer_range,
22213                        ),
22214                        is_created_file,
22215                    }
22216                };
22217
22218                Some(display_hunk)
22219            })
22220    }
22221
22222    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22223        self.display_snapshot.buffer_snapshot.language_at(position)
22224    }
22225
22226    pub fn is_focused(&self) -> bool {
22227        self.is_focused
22228    }
22229
22230    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22231        self.placeholder_text.as_ref()
22232    }
22233
22234    pub fn scroll_position(&self) -> gpui::Point<f32> {
22235        self.scroll_anchor.scroll_position(&self.display_snapshot)
22236    }
22237
22238    fn gutter_dimensions(
22239        &self,
22240        font_id: FontId,
22241        font_size: Pixels,
22242        max_line_number_width: Pixels,
22243        cx: &App,
22244    ) -> Option<GutterDimensions> {
22245        if !self.show_gutter {
22246            return None;
22247        }
22248
22249        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22250        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22251
22252        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22253            matches!(
22254                ProjectSettings::get_global(cx).git.git_gutter,
22255                Some(GitGutterSetting::TrackedFiles)
22256            )
22257        });
22258        let gutter_settings = EditorSettings::get_global(cx).gutter;
22259        let show_line_numbers = self
22260            .show_line_numbers
22261            .unwrap_or(gutter_settings.line_numbers);
22262        let line_gutter_width = if show_line_numbers {
22263            // Avoid flicker-like gutter resizes when the line number gains another digit by
22264            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22265            let min_width_for_number_on_gutter =
22266                ch_advance * gutter_settings.min_line_number_digits as f32;
22267            max_line_number_width.max(min_width_for_number_on_gutter)
22268        } else {
22269            0.0.into()
22270        };
22271
22272        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22273        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22274
22275        let git_blame_entries_width =
22276            self.git_blame_gutter_max_author_length
22277                .map(|max_author_length| {
22278                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22279                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22280
22281                    /// The number of characters to dedicate to gaps and margins.
22282                    const SPACING_WIDTH: usize = 4;
22283
22284                    let max_char_count = max_author_length.min(renderer.max_author_length())
22285                        + ::git::SHORT_SHA_LENGTH
22286                        + MAX_RELATIVE_TIMESTAMP.len()
22287                        + SPACING_WIDTH;
22288
22289                    ch_advance * max_char_count
22290                });
22291
22292        let is_singleton = self.buffer_snapshot.is_singleton();
22293
22294        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22295        left_padding += if !is_singleton {
22296            ch_width * 4.0
22297        } else if show_runnables || show_breakpoints {
22298            ch_width * 3.0
22299        } else if show_git_gutter && show_line_numbers {
22300            ch_width * 2.0
22301        } else if show_git_gutter || show_line_numbers {
22302            ch_width
22303        } else {
22304            px(0.)
22305        };
22306
22307        let shows_folds = is_singleton && gutter_settings.folds;
22308
22309        let right_padding = if shows_folds && show_line_numbers {
22310            ch_width * 4.0
22311        } else if shows_folds || (!is_singleton && show_line_numbers) {
22312            ch_width * 3.0
22313        } else if show_line_numbers {
22314            ch_width
22315        } else {
22316            px(0.)
22317        };
22318
22319        Some(GutterDimensions {
22320            left_padding,
22321            right_padding,
22322            width: line_gutter_width + left_padding + right_padding,
22323            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22324            git_blame_entries_width,
22325        })
22326    }
22327
22328    pub fn render_crease_toggle(
22329        &self,
22330        buffer_row: MultiBufferRow,
22331        row_contains_cursor: bool,
22332        editor: Entity<Editor>,
22333        window: &mut Window,
22334        cx: &mut App,
22335    ) -> Option<AnyElement> {
22336        let folded = self.is_line_folded(buffer_row);
22337        let mut is_foldable = false;
22338
22339        if let Some(crease) = self
22340            .crease_snapshot
22341            .query_row(buffer_row, &self.buffer_snapshot)
22342        {
22343            is_foldable = true;
22344            match crease {
22345                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22346                    if let Some(render_toggle) = render_toggle {
22347                        let toggle_callback =
22348                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22349                                if folded {
22350                                    editor.update(cx, |editor, cx| {
22351                                        editor.fold_at(buffer_row, window, cx)
22352                                    });
22353                                } else {
22354                                    editor.update(cx, |editor, cx| {
22355                                        editor.unfold_at(buffer_row, window, cx)
22356                                    });
22357                                }
22358                            });
22359                        return Some((render_toggle)(
22360                            buffer_row,
22361                            folded,
22362                            toggle_callback,
22363                            window,
22364                            cx,
22365                        ));
22366                    }
22367                }
22368            }
22369        }
22370
22371        is_foldable |= self.starts_indent(buffer_row);
22372
22373        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22374            Some(
22375                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22376                    .toggle_state(folded)
22377                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22378                        if folded {
22379                            this.unfold_at(buffer_row, window, cx);
22380                        } else {
22381                            this.fold_at(buffer_row, window, cx);
22382                        }
22383                    }))
22384                    .into_any_element(),
22385            )
22386        } else {
22387            None
22388        }
22389    }
22390
22391    pub fn render_crease_trailer(
22392        &self,
22393        buffer_row: MultiBufferRow,
22394        window: &mut Window,
22395        cx: &mut App,
22396    ) -> Option<AnyElement> {
22397        let folded = self.is_line_folded(buffer_row);
22398        if let Crease::Inline { render_trailer, .. } = self
22399            .crease_snapshot
22400            .query_row(buffer_row, &self.buffer_snapshot)?
22401        {
22402            let render_trailer = render_trailer.as_ref()?;
22403            Some(render_trailer(buffer_row, folded, window, cx))
22404        } else {
22405            None
22406        }
22407    }
22408}
22409
22410impl Deref for EditorSnapshot {
22411    type Target = DisplaySnapshot;
22412
22413    fn deref(&self) -> &Self::Target {
22414        &self.display_snapshot
22415    }
22416}
22417
22418#[derive(Clone, Debug, PartialEq, Eq)]
22419pub enum EditorEvent {
22420    InputIgnored {
22421        text: Arc<str>,
22422    },
22423    InputHandled {
22424        utf16_range_to_replace: Option<Range<isize>>,
22425        text: Arc<str>,
22426    },
22427    ExcerptsAdded {
22428        buffer: Entity<Buffer>,
22429        predecessor: ExcerptId,
22430        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22431    },
22432    ExcerptsRemoved {
22433        ids: Vec<ExcerptId>,
22434        removed_buffer_ids: Vec<BufferId>,
22435    },
22436    BufferFoldToggled {
22437        ids: Vec<ExcerptId>,
22438        folded: bool,
22439    },
22440    ExcerptsEdited {
22441        ids: Vec<ExcerptId>,
22442    },
22443    ExcerptsExpanded {
22444        ids: Vec<ExcerptId>,
22445    },
22446    BufferEdited,
22447    Edited {
22448        transaction_id: clock::Lamport,
22449    },
22450    Reparsed(BufferId),
22451    Focused,
22452    FocusedIn,
22453    Blurred,
22454    DirtyChanged,
22455    Saved,
22456    TitleChanged,
22457    DiffBaseChanged,
22458    SelectionsChanged {
22459        local: bool,
22460    },
22461    ScrollPositionChanged {
22462        local: bool,
22463        autoscroll: bool,
22464    },
22465    Closed,
22466    TransactionUndone {
22467        transaction_id: clock::Lamport,
22468    },
22469    TransactionBegun {
22470        transaction_id: clock::Lamport,
22471    },
22472    Reloaded,
22473    CursorShapeChanged,
22474    PushedToNavHistory {
22475        anchor: Anchor,
22476        is_deactivate: bool,
22477    },
22478}
22479
22480impl EventEmitter<EditorEvent> for Editor {}
22481
22482impl Focusable for Editor {
22483    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22484        self.focus_handle.clone()
22485    }
22486}
22487
22488impl Render for Editor {
22489    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22490        let settings = ThemeSettings::get_global(cx);
22491
22492        let mut text_style = match self.mode {
22493            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22494                color: cx.theme().colors().editor_foreground,
22495                font_family: settings.ui_font.family.clone(),
22496                font_features: settings.ui_font.features.clone(),
22497                font_fallbacks: settings.ui_font.fallbacks.clone(),
22498                font_size: rems(0.875).into(),
22499                font_weight: settings.ui_font.weight,
22500                line_height: relative(settings.buffer_line_height.value()),
22501                ..Default::default()
22502            },
22503            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22504                color: cx.theme().colors().editor_foreground,
22505                font_family: settings.buffer_font.family.clone(),
22506                font_features: settings.buffer_font.features.clone(),
22507                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22508                font_size: settings.buffer_font_size(cx).into(),
22509                font_weight: settings.buffer_font.weight,
22510                line_height: relative(settings.buffer_line_height.value()),
22511                ..Default::default()
22512            },
22513        };
22514        if let Some(text_style_refinement) = &self.text_style_refinement {
22515            text_style.refine(text_style_refinement)
22516        }
22517
22518        let background = match self.mode {
22519            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22520            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22521            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22522            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22523        };
22524
22525        EditorElement::new(
22526            &cx.entity(),
22527            EditorStyle {
22528                background,
22529                border: cx.theme().colors().border,
22530                local_player: cx.theme().players().local(),
22531                text: text_style,
22532                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22533                syntax: cx.theme().syntax().clone(),
22534                status: cx.theme().status().clone(),
22535                inlay_hints_style: make_inlay_hints_style(cx),
22536                inline_completion_styles: make_suggestion_styles(cx),
22537                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22538                show_underlines: self.diagnostics_enabled(),
22539            },
22540        )
22541    }
22542}
22543
22544impl EntityInputHandler for Editor {
22545    fn text_for_range(
22546        &mut self,
22547        range_utf16: Range<usize>,
22548        adjusted_range: &mut Option<Range<usize>>,
22549        _: &mut Window,
22550        cx: &mut Context<Self>,
22551    ) -> Option<String> {
22552        let snapshot = self.buffer.read(cx).read(cx);
22553        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22554        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22555        if (start.0..end.0) != range_utf16 {
22556            adjusted_range.replace(start.0..end.0);
22557        }
22558        Some(snapshot.text_for_range(start..end).collect())
22559    }
22560
22561    fn selected_text_range(
22562        &mut self,
22563        ignore_disabled_input: bool,
22564        _: &mut Window,
22565        cx: &mut Context<Self>,
22566    ) -> Option<UTF16Selection> {
22567        // Prevent the IME menu from appearing when holding down an alphabetic key
22568        // while input is disabled.
22569        if !ignore_disabled_input && !self.input_enabled {
22570            return None;
22571        }
22572
22573        let selection = self.selections.newest::<OffsetUtf16>(cx);
22574        let range = selection.range();
22575
22576        Some(UTF16Selection {
22577            range: range.start.0..range.end.0,
22578            reversed: selection.reversed,
22579        })
22580    }
22581
22582    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22583        let snapshot = self.buffer.read(cx).read(cx);
22584        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22585        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22586    }
22587
22588    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22589        self.clear_highlights::<InputComposition>(cx);
22590        self.ime_transaction.take();
22591    }
22592
22593    fn replace_text_in_range(
22594        &mut self,
22595        range_utf16: Option<Range<usize>>,
22596        text: &str,
22597        window: &mut Window,
22598        cx: &mut Context<Self>,
22599    ) {
22600        if !self.input_enabled {
22601            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22602            return;
22603        }
22604
22605        self.transact(window, cx, |this, window, cx| {
22606            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22607                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22608                Some(this.selection_replacement_ranges(range_utf16, cx))
22609            } else {
22610                this.marked_text_ranges(cx)
22611            };
22612
22613            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22614                let newest_selection_id = this.selections.newest_anchor().id;
22615                this.selections
22616                    .all::<OffsetUtf16>(cx)
22617                    .iter()
22618                    .zip(ranges_to_replace.iter())
22619                    .find_map(|(selection, range)| {
22620                        if selection.id == newest_selection_id {
22621                            Some(
22622                                (range.start.0 as isize - selection.head().0 as isize)
22623                                    ..(range.end.0 as isize - selection.head().0 as isize),
22624                            )
22625                        } else {
22626                            None
22627                        }
22628                    })
22629            });
22630
22631            cx.emit(EditorEvent::InputHandled {
22632                utf16_range_to_replace: range_to_replace,
22633                text: text.into(),
22634            });
22635
22636            if let Some(new_selected_ranges) = new_selected_ranges {
22637                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22638                    selections.select_ranges(new_selected_ranges)
22639                });
22640                this.backspace(&Default::default(), window, cx);
22641            }
22642
22643            this.handle_input(text, window, cx);
22644        });
22645
22646        if let Some(transaction) = self.ime_transaction {
22647            self.buffer.update(cx, |buffer, cx| {
22648                buffer.group_until_transaction(transaction, cx);
22649            });
22650        }
22651
22652        self.unmark_text(window, cx);
22653    }
22654
22655    fn replace_and_mark_text_in_range(
22656        &mut self,
22657        range_utf16: Option<Range<usize>>,
22658        text: &str,
22659        new_selected_range_utf16: Option<Range<usize>>,
22660        window: &mut Window,
22661        cx: &mut Context<Self>,
22662    ) {
22663        if !self.input_enabled {
22664            return;
22665        }
22666
22667        let transaction = self.transact(window, cx, |this, window, cx| {
22668            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22669                let snapshot = this.buffer.read(cx).read(cx);
22670                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22671                    for marked_range in &mut marked_ranges {
22672                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22673                        marked_range.start.0 += relative_range_utf16.start;
22674                        marked_range.start =
22675                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22676                        marked_range.end =
22677                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22678                    }
22679                }
22680                Some(marked_ranges)
22681            } else if let Some(range_utf16) = range_utf16 {
22682                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22683                Some(this.selection_replacement_ranges(range_utf16, cx))
22684            } else {
22685                None
22686            };
22687
22688            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22689                let newest_selection_id = this.selections.newest_anchor().id;
22690                this.selections
22691                    .all::<OffsetUtf16>(cx)
22692                    .iter()
22693                    .zip(ranges_to_replace.iter())
22694                    .find_map(|(selection, range)| {
22695                        if selection.id == newest_selection_id {
22696                            Some(
22697                                (range.start.0 as isize - selection.head().0 as isize)
22698                                    ..(range.end.0 as isize - selection.head().0 as isize),
22699                            )
22700                        } else {
22701                            None
22702                        }
22703                    })
22704            });
22705
22706            cx.emit(EditorEvent::InputHandled {
22707                utf16_range_to_replace: range_to_replace,
22708                text: text.into(),
22709            });
22710
22711            if let Some(ranges) = ranges_to_replace {
22712                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22713                    s.select_ranges(ranges)
22714                });
22715            }
22716
22717            let marked_ranges = {
22718                let snapshot = this.buffer.read(cx).read(cx);
22719                this.selections
22720                    .disjoint_anchors()
22721                    .iter()
22722                    .map(|selection| {
22723                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22724                    })
22725                    .collect::<Vec<_>>()
22726            };
22727
22728            if text.is_empty() {
22729                this.unmark_text(window, cx);
22730            } else {
22731                this.highlight_text::<InputComposition>(
22732                    marked_ranges.clone(),
22733                    HighlightStyle {
22734                        underline: Some(UnderlineStyle {
22735                            thickness: px(1.),
22736                            color: None,
22737                            wavy: false,
22738                        }),
22739                        ..Default::default()
22740                    },
22741                    cx,
22742                );
22743            }
22744
22745            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22746            let use_autoclose = this.use_autoclose;
22747            let use_auto_surround = this.use_auto_surround;
22748            this.set_use_autoclose(false);
22749            this.set_use_auto_surround(false);
22750            this.handle_input(text, window, cx);
22751            this.set_use_autoclose(use_autoclose);
22752            this.set_use_auto_surround(use_auto_surround);
22753
22754            if let Some(new_selected_range) = new_selected_range_utf16 {
22755                let snapshot = this.buffer.read(cx).read(cx);
22756                let new_selected_ranges = marked_ranges
22757                    .into_iter()
22758                    .map(|marked_range| {
22759                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22760                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22761                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22762                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22763                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22764                    })
22765                    .collect::<Vec<_>>();
22766
22767                drop(snapshot);
22768                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22769                    selections.select_ranges(new_selected_ranges)
22770                });
22771            }
22772        });
22773
22774        self.ime_transaction = self.ime_transaction.or(transaction);
22775        if let Some(transaction) = self.ime_transaction {
22776            self.buffer.update(cx, |buffer, cx| {
22777                buffer.group_until_transaction(transaction, cx);
22778            });
22779        }
22780
22781        if self.text_highlights::<InputComposition>(cx).is_none() {
22782            self.ime_transaction.take();
22783        }
22784    }
22785
22786    fn bounds_for_range(
22787        &mut self,
22788        range_utf16: Range<usize>,
22789        element_bounds: gpui::Bounds<Pixels>,
22790        window: &mut Window,
22791        cx: &mut Context<Self>,
22792    ) -> Option<gpui::Bounds<Pixels>> {
22793        let text_layout_details = self.text_layout_details(window);
22794        let CharacterDimensions {
22795            em_width,
22796            em_advance,
22797            line_height,
22798        } = self.character_dimensions(window);
22799
22800        let snapshot = self.snapshot(window, cx);
22801        let scroll_position = snapshot.scroll_position();
22802        let scroll_left = scroll_position.x * em_advance;
22803
22804        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22805        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22806            + self.gutter_dimensions.full_width();
22807        let y = line_height * (start.row().as_f32() - scroll_position.y);
22808
22809        Some(Bounds {
22810            origin: element_bounds.origin + point(x, y),
22811            size: size(em_width, line_height),
22812        })
22813    }
22814
22815    fn character_index_for_point(
22816        &mut self,
22817        point: gpui::Point<Pixels>,
22818        _window: &mut Window,
22819        _cx: &mut Context<Self>,
22820    ) -> Option<usize> {
22821        let position_map = self.last_position_map.as_ref()?;
22822        if !position_map.text_hitbox.contains(&point) {
22823            return None;
22824        }
22825        let display_point = position_map.point_for_position(point).previous_valid;
22826        let anchor = position_map
22827            .snapshot
22828            .display_point_to_anchor(display_point, Bias::Left);
22829        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22830        Some(utf16_offset.0)
22831    }
22832}
22833
22834trait SelectionExt {
22835    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22836    fn spanned_rows(
22837        &self,
22838        include_end_if_at_line_start: bool,
22839        map: &DisplaySnapshot,
22840    ) -> Range<MultiBufferRow>;
22841}
22842
22843impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22844    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22845        let start = self
22846            .start
22847            .to_point(&map.buffer_snapshot)
22848            .to_display_point(map);
22849        let end = self
22850            .end
22851            .to_point(&map.buffer_snapshot)
22852            .to_display_point(map);
22853        if self.reversed {
22854            end..start
22855        } else {
22856            start..end
22857        }
22858    }
22859
22860    fn spanned_rows(
22861        &self,
22862        include_end_if_at_line_start: bool,
22863        map: &DisplaySnapshot,
22864    ) -> Range<MultiBufferRow> {
22865        let start = self.start.to_point(&map.buffer_snapshot);
22866        let mut end = self.end.to_point(&map.buffer_snapshot);
22867        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22868            end.row -= 1;
22869        }
22870
22871        let buffer_start = map.prev_line_boundary(start).0;
22872        let buffer_end = map.next_line_boundary(end).0;
22873        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22874    }
22875}
22876
22877impl<T: InvalidationRegion> InvalidationStack<T> {
22878    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22879    where
22880        S: Clone + ToOffset,
22881    {
22882        while let Some(region) = self.last() {
22883            let all_selections_inside_invalidation_ranges =
22884                if selections.len() == region.ranges().len() {
22885                    selections
22886                        .iter()
22887                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22888                        .all(|(selection, invalidation_range)| {
22889                            let head = selection.head().to_offset(buffer);
22890                            invalidation_range.start <= head && invalidation_range.end >= head
22891                        })
22892                } else {
22893                    false
22894                };
22895
22896            if all_selections_inside_invalidation_ranges {
22897                break;
22898            } else {
22899                self.pop();
22900            }
22901        }
22902    }
22903}
22904
22905impl<T> Default for InvalidationStack<T> {
22906    fn default() -> Self {
22907        Self(Default::default())
22908    }
22909}
22910
22911impl<T> Deref for InvalidationStack<T> {
22912    type Target = Vec<T>;
22913
22914    fn deref(&self) -> &Self::Target {
22915        &self.0
22916    }
22917}
22918
22919impl<T> DerefMut for InvalidationStack<T> {
22920    fn deref_mut(&mut self) -> &mut Self::Target {
22921        &mut self.0
22922    }
22923}
22924
22925impl InvalidationRegion for SnippetState {
22926    fn ranges(&self) -> &[Range<Anchor>] {
22927        &self.ranges[self.active_index]
22928    }
22929}
22930
22931fn inline_completion_edit_text(
22932    current_snapshot: &BufferSnapshot,
22933    edits: &[(Range<Anchor>, String)],
22934    edit_preview: &EditPreview,
22935    include_deletions: bool,
22936    cx: &App,
22937) -> HighlightedText {
22938    let edits = edits
22939        .iter()
22940        .map(|(anchor, text)| {
22941            (
22942                anchor.start.text_anchor..anchor.end.text_anchor,
22943                text.clone(),
22944            )
22945        })
22946        .collect::<Vec<_>>();
22947
22948    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22949}
22950
22951pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22952    match severity {
22953        lsp::DiagnosticSeverity::ERROR => colors.error,
22954        lsp::DiagnosticSeverity::WARNING => colors.warning,
22955        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22956        lsp::DiagnosticSeverity::HINT => colors.info,
22957        _ => colors.ignored,
22958    }
22959}
22960
22961pub fn styled_runs_for_code_label<'a>(
22962    label: &'a CodeLabel,
22963    syntax_theme: &'a theme::SyntaxTheme,
22964) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22965    let fade_out = HighlightStyle {
22966        fade_out: Some(0.35),
22967        ..Default::default()
22968    };
22969
22970    let mut prev_end = label.filter_range.end;
22971    label
22972        .runs
22973        .iter()
22974        .enumerate()
22975        .flat_map(move |(ix, (range, highlight_id))| {
22976            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22977                style
22978            } else {
22979                return Default::default();
22980            };
22981            let mut muted_style = style;
22982            muted_style.highlight(fade_out);
22983
22984            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22985            if range.start >= label.filter_range.end {
22986                if range.start > prev_end {
22987                    runs.push((prev_end..range.start, fade_out));
22988                }
22989                runs.push((range.clone(), muted_style));
22990            } else if range.end <= label.filter_range.end {
22991                runs.push((range.clone(), style));
22992            } else {
22993                runs.push((range.start..label.filter_range.end, style));
22994                runs.push((label.filter_range.end..range.end, muted_style));
22995            }
22996            prev_end = cmp::max(prev_end, range.end);
22997
22998            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22999                runs.push((prev_end..label.text.len(), fade_out));
23000            }
23001
23002            runs
23003        })
23004}
23005
23006pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23007    let mut prev_index = 0;
23008    let mut prev_codepoint: Option<char> = None;
23009    text.char_indices()
23010        .chain([(text.len(), '\0')])
23011        .filter_map(move |(index, codepoint)| {
23012            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23013            let is_boundary = index == text.len()
23014                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23015                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23016            if is_boundary {
23017                let chunk = &text[prev_index..index];
23018                prev_index = index;
23019                Some(chunk)
23020            } else {
23021                None
23022            }
23023        })
23024}
23025
23026pub trait RangeToAnchorExt: Sized {
23027    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23028
23029    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23030        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23031        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23032    }
23033}
23034
23035impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23036    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23037        let start_offset = self.start.to_offset(snapshot);
23038        let end_offset = self.end.to_offset(snapshot);
23039        if start_offset == end_offset {
23040            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23041        } else {
23042            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23043        }
23044    }
23045}
23046
23047pub trait RowExt {
23048    fn as_f32(&self) -> f32;
23049
23050    fn next_row(&self) -> Self;
23051
23052    fn previous_row(&self) -> Self;
23053
23054    fn minus(&self, other: Self) -> u32;
23055}
23056
23057impl RowExt for DisplayRow {
23058    fn as_f32(&self) -> f32 {
23059        self.0 as f32
23060    }
23061
23062    fn next_row(&self) -> Self {
23063        Self(self.0 + 1)
23064    }
23065
23066    fn previous_row(&self) -> Self {
23067        Self(self.0.saturating_sub(1))
23068    }
23069
23070    fn minus(&self, other: Self) -> u32 {
23071        self.0 - other.0
23072    }
23073}
23074
23075impl RowExt for MultiBufferRow {
23076    fn as_f32(&self) -> f32 {
23077        self.0 as f32
23078    }
23079
23080    fn next_row(&self) -> Self {
23081        Self(self.0 + 1)
23082    }
23083
23084    fn previous_row(&self) -> Self {
23085        Self(self.0.saturating_sub(1))
23086    }
23087
23088    fn minus(&self, other: Self) -> u32 {
23089        self.0 - other.0
23090    }
23091}
23092
23093trait RowRangeExt {
23094    type Row;
23095
23096    fn len(&self) -> usize;
23097
23098    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23099}
23100
23101impl RowRangeExt for Range<MultiBufferRow> {
23102    type Row = MultiBufferRow;
23103
23104    fn len(&self) -> usize {
23105        (self.end.0 - self.start.0) as usize
23106    }
23107
23108    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23109        (self.start.0..self.end.0).map(MultiBufferRow)
23110    }
23111}
23112
23113impl RowRangeExt for Range<DisplayRow> {
23114    type Row = DisplayRow;
23115
23116    fn len(&self) -> usize {
23117        (self.end.0 - self.start.0) as usize
23118    }
23119
23120    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23121        (self.start.0..self.end.0).map(DisplayRow)
23122    }
23123}
23124
23125/// If select range has more than one line, we
23126/// just point the cursor to range.start.
23127fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23128    if range.start.row == range.end.row {
23129        range
23130    } else {
23131        range.start..range.start
23132    }
23133}
23134pub struct KillRing(ClipboardItem);
23135impl Global for KillRing {}
23136
23137const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23138
23139enum BreakpointPromptEditAction {
23140    Log,
23141    Condition,
23142    HitCondition,
23143}
23144
23145struct BreakpointPromptEditor {
23146    pub(crate) prompt: Entity<Editor>,
23147    editor: WeakEntity<Editor>,
23148    breakpoint_anchor: Anchor,
23149    breakpoint: Breakpoint,
23150    edit_action: BreakpointPromptEditAction,
23151    block_ids: HashSet<CustomBlockId>,
23152    editor_margins: Arc<Mutex<EditorMargins>>,
23153    _subscriptions: Vec<Subscription>,
23154}
23155
23156impl BreakpointPromptEditor {
23157    const MAX_LINES: u8 = 4;
23158
23159    fn new(
23160        editor: WeakEntity<Editor>,
23161        breakpoint_anchor: Anchor,
23162        breakpoint: Breakpoint,
23163        edit_action: BreakpointPromptEditAction,
23164        window: &mut Window,
23165        cx: &mut Context<Self>,
23166    ) -> Self {
23167        let base_text = match edit_action {
23168            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23169            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23170            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23171        }
23172        .map(|msg| msg.to_string())
23173        .unwrap_or_default();
23174
23175        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23176        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23177
23178        let prompt = cx.new(|cx| {
23179            let mut prompt = Editor::new(
23180                EditorMode::AutoHeight {
23181                    min_lines: 1,
23182                    max_lines: Some(Self::MAX_LINES as usize),
23183                },
23184                buffer,
23185                None,
23186                window,
23187                cx,
23188            );
23189            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23190            prompt.set_show_cursor_when_unfocused(false, cx);
23191            prompt.set_placeholder_text(
23192                match edit_action {
23193                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23194                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23195                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23196                },
23197                cx,
23198            );
23199
23200            prompt
23201        });
23202
23203        Self {
23204            prompt,
23205            editor,
23206            breakpoint_anchor,
23207            breakpoint,
23208            edit_action,
23209            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23210            block_ids: Default::default(),
23211            _subscriptions: vec![],
23212        }
23213    }
23214
23215    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23216        self.block_ids.extend(block_ids)
23217    }
23218
23219    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23220        if let Some(editor) = self.editor.upgrade() {
23221            let message = self
23222                .prompt
23223                .read(cx)
23224                .buffer
23225                .read(cx)
23226                .as_singleton()
23227                .expect("A multi buffer in breakpoint prompt isn't possible")
23228                .read(cx)
23229                .as_rope()
23230                .to_string();
23231
23232            editor.update(cx, |editor, cx| {
23233                editor.edit_breakpoint_at_anchor(
23234                    self.breakpoint_anchor,
23235                    self.breakpoint.clone(),
23236                    match self.edit_action {
23237                        BreakpointPromptEditAction::Log => {
23238                            BreakpointEditAction::EditLogMessage(message.into())
23239                        }
23240                        BreakpointPromptEditAction::Condition => {
23241                            BreakpointEditAction::EditCondition(message.into())
23242                        }
23243                        BreakpointPromptEditAction::HitCondition => {
23244                            BreakpointEditAction::EditHitCondition(message.into())
23245                        }
23246                    },
23247                    cx,
23248                );
23249
23250                editor.remove_blocks(self.block_ids.clone(), None, cx);
23251                cx.focus_self(window);
23252            });
23253        }
23254    }
23255
23256    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23257        self.editor
23258            .update(cx, |editor, cx| {
23259                editor.remove_blocks(self.block_ids.clone(), None, cx);
23260                window.focus(&editor.focus_handle);
23261            })
23262            .log_err();
23263    }
23264
23265    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23266        let settings = ThemeSettings::get_global(cx);
23267        let text_style = TextStyle {
23268            color: if self.prompt.read(cx).read_only(cx) {
23269                cx.theme().colors().text_disabled
23270            } else {
23271                cx.theme().colors().text
23272            },
23273            font_family: settings.buffer_font.family.clone(),
23274            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23275            font_size: settings.buffer_font_size(cx).into(),
23276            font_weight: settings.buffer_font.weight,
23277            line_height: relative(settings.buffer_line_height.value()),
23278            ..Default::default()
23279        };
23280        EditorElement::new(
23281            &self.prompt,
23282            EditorStyle {
23283                background: cx.theme().colors().editor_background,
23284                local_player: cx.theme().players().local(),
23285                text: text_style,
23286                ..Default::default()
23287            },
23288        )
23289    }
23290}
23291
23292impl Render for BreakpointPromptEditor {
23293    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23294        let editor_margins = *self.editor_margins.lock();
23295        let gutter_dimensions = editor_margins.gutter;
23296        h_flex()
23297            .key_context("Editor")
23298            .bg(cx.theme().colors().editor_background)
23299            .border_y_1()
23300            .border_color(cx.theme().status().info_border)
23301            .size_full()
23302            .py(window.line_height() / 2.5)
23303            .on_action(cx.listener(Self::confirm))
23304            .on_action(cx.listener(Self::cancel))
23305            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23306            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23307    }
23308}
23309
23310impl Focusable for BreakpointPromptEditor {
23311    fn focus_handle(&self, cx: &App) -> FocusHandle {
23312        self.prompt.focus_handle(cx)
23313    }
23314}
23315
23316fn all_edits_insertions_or_deletions(
23317    edits: &Vec<(Range<Anchor>, String)>,
23318    snapshot: &MultiBufferSnapshot,
23319) -> bool {
23320    let mut all_insertions = true;
23321    let mut all_deletions = true;
23322
23323    for (range, new_text) in edits.iter() {
23324        let range_is_empty = range.to_offset(&snapshot).is_empty();
23325        let text_is_empty = new_text.is_empty();
23326
23327        if range_is_empty != text_is_empty {
23328            if range_is_empty {
23329                all_deletions = false;
23330            } else {
23331                all_insertions = false;
23332            }
23333        } else {
23334            return false;
23335        }
23336
23337        if !all_insertions && !all_deletions {
23338            return false;
23339        }
23340    }
23341    all_insertions || all_deletions
23342}
23343
23344struct MissingEditPredictionKeybindingTooltip;
23345
23346impl Render for MissingEditPredictionKeybindingTooltip {
23347    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23348        ui::tooltip_container(window, cx, |container, _, cx| {
23349            container
23350                .flex_shrink_0()
23351                .max_w_80()
23352                .min_h(rems_from_px(124.))
23353                .justify_between()
23354                .child(
23355                    v_flex()
23356                        .flex_1()
23357                        .text_ui_sm(cx)
23358                        .child(Label::new("Conflict with Accept Keybinding"))
23359                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23360                )
23361                .child(
23362                    h_flex()
23363                        .pb_1()
23364                        .gap_1()
23365                        .items_end()
23366                        .w_full()
23367                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23368                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23369                        }))
23370                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23371                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23372                        })),
23373                )
23374        })
23375    }
23376}
23377
23378#[derive(Debug, Clone, Copy, PartialEq)]
23379pub struct LineHighlight {
23380    pub background: Background,
23381    pub border: Option<gpui::Hsla>,
23382    pub include_gutter: bool,
23383    pub type_id: Option<TypeId>,
23384}
23385
23386struct LineManipulationResult {
23387    pub new_text: String,
23388    pub line_count_before: usize,
23389    pub line_count_after: usize,
23390}
23391
23392fn render_diff_hunk_controls(
23393    row: u32,
23394    status: &DiffHunkStatus,
23395    hunk_range: Range<Anchor>,
23396    is_created_file: bool,
23397    line_height: Pixels,
23398    editor: &Entity<Editor>,
23399    _window: &mut Window,
23400    cx: &mut App,
23401) -> AnyElement {
23402    h_flex()
23403        .h(line_height)
23404        .mr_1()
23405        .gap_1()
23406        .px_0p5()
23407        .pb_1()
23408        .border_x_1()
23409        .border_b_1()
23410        .border_color(cx.theme().colors().border_variant)
23411        .rounded_b_lg()
23412        .bg(cx.theme().colors().editor_background)
23413        .gap_1()
23414        .block_mouse_except_scroll()
23415        .shadow_md()
23416        .child(if status.has_secondary_hunk() {
23417            Button::new(("stage", row as u64), "Stage")
23418                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23419                .tooltip({
23420                    let focus_handle = editor.focus_handle(cx);
23421                    move |window, cx| {
23422                        Tooltip::for_action_in(
23423                            "Stage Hunk",
23424                            &::git::ToggleStaged,
23425                            &focus_handle,
23426                            window,
23427                            cx,
23428                        )
23429                    }
23430                })
23431                .on_click({
23432                    let editor = editor.clone();
23433                    move |_event, _window, cx| {
23434                        editor.update(cx, |editor, cx| {
23435                            editor.stage_or_unstage_diff_hunks(
23436                                true,
23437                                vec![hunk_range.start..hunk_range.start],
23438                                cx,
23439                            );
23440                        });
23441                    }
23442                })
23443        } else {
23444            Button::new(("unstage", row as u64), "Unstage")
23445                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23446                .tooltip({
23447                    let focus_handle = editor.focus_handle(cx);
23448                    move |window, cx| {
23449                        Tooltip::for_action_in(
23450                            "Unstage Hunk",
23451                            &::git::ToggleStaged,
23452                            &focus_handle,
23453                            window,
23454                            cx,
23455                        )
23456                    }
23457                })
23458                .on_click({
23459                    let editor = editor.clone();
23460                    move |_event, _window, cx| {
23461                        editor.update(cx, |editor, cx| {
23462                            editor.stage_or_unstage_diff_hunks(
23463                                false,
23464                                vec![hunk_range.start..hunk_range.start],
23465                                cx,
23466                            );
23467                        });
23468                    }
23469                })
23470        })
23471        .child(
23472            Button::new(("restore", row as u64), "Restore")
23473                .tooltip({
23474                    let focus_handle = editor.focus_handle(cx);
23475                    move |window, cx| {
23476                        Tooltip::for_action_in(
23477                            "Restore Hunk",
23478                            &::git::Restore,
23479                            &focus_handle,
23480                            window,
23481                            cx,
23482                        )
23483                    }
23484                })
23485                .on_click({
23486                    let editor = editor.clone();
23487                    move |_event, window, cx| {
23488                        editor.update(cx, |editor, cx| {
23489                            let snapshot = editor.snapshot(window, cx);
23490                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23491                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23492                        });
23493                    }
23494                })
23495                .disabled(is_created_file),
23496        )
23497        .when(
23498            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23499            |el| {
23500                el.child(
23501                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23502                        .shape(IconButtonShape::Square)
23503                        .icon_size(IconSize::Small)
23504                        // .disabled(!has_multiple_hunks)
23505                        .tooltip({
23506                            let focus_handle = editor.focus_handle(cx);
23507                            move |window, cx| {
23508                                Tooltip::for_action_in(
23509                                    "Next Hunk",
23510                                    &GoToHunk,
23511                                    &focus_handle,
23512                                    window,
23513                                    cx,
23514                                )
23515                            }
23516                        })
23517                        .on_click({
23518                            let editor = editor.clone();
23519                            move |_event, window, cx| {
23520                                editor.update(cx, |editor, cx| {
23521                                    let snapshot = editor.snapshot(window, cx);
23522                                    let position =
23523                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23524                                    editor.go_to_hunk_before_or_after_position(
23525                                        &snapshot,
23526                                        position,
23527                                        Direction::Next,
23528                                        window,
23529                                        cx,
23530                                    );
23531                                    editor.expand_selected_diff_hunks(cx);
23532                                });
23533                            }
23534                        }),
23535                )
23536                .child(
23537                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23538                        .shape(IconButtonShape::Square)
23539                        .icon_size(IconSize::Small)
23540                        // .disabled(!has_multiple_hunks)
23541                        .tooltip({
23542                            let focus_handle = editor.focus_handle(cx);
23543                            move |window, cx| {
23544                                Tooltip::for_action_in(
23545                                    "Previous Hunk",
23546                                    &GoToPreviousHunk,
23547                                    &focus_handle,
23548                                    window,
23549                                    cx,
23550                                )
23551                            }
23552                        })
23553                        .on_click({
23554                            let editor = editor.clone();
23555                            move |_event, window, cx| {
23556                                editor.update(cx, |editor, cx| {
23557                                    let snapshot = editor.snapshot(window, cx);
23558                                    let point =
23559                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23560                                    editor.go_to_hunk_before_or_after_position(
23561                                        &snapshot,
23562                                        point,
23563                                        Direction::Prev,
23564                                        window,
23565                                        cx,
23566                                    );
23567                                    editor.expand_selected_diff_hunks(cx);
23568                                });
23569                            }
23570                        }),
23571                )
23572            },
23573        )
23574        .into_any_element()
23575}