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
  868struct ChangeLocation {
  869    current: Option<Vec<Anchor>>,
  870    original: Vec<Anchor>,
  871}
  872impl ChangeLocation {
  873    fn locations(&self) -> &[Anchor] {
  874        self.current.as_ref().unwrap_or(&self.original)
  875    }
  876}
  877
  878/// A set of caret positions, registered when the editor was edited.
  879pub struct ChangeList {
  880    changes: Vec<ChangeLocation>,
  881    /// Currently "selected" change.
  882    position: Option<usize>,
  883}
  884
  885impl ChangeList {
  886    pub fn new() -> Self {
  887        Self {
  888            changes: Vec::new(),
  889            position: None,
  890        }
  891    }
  892
  893    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  894    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  895    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  896        if self.changes.is_empty() {
  897            return None;
  898        }
  899
  900        let prev = self.position.unwrap_or(self.changes.len());
  901        let next = if direction == Direction::Prev {
  902            prev.saturating_sub(count)
  903        } else {
  904            (prev + count).min(self.changes.len() - 1)
  905        };
  906        self.position = Some(next);
  907        self.changes.get(next).map(|change| change.locations())
  908    }
  909
  910    /// Adds a new change to the list, resetting the change list position.
  911    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  912        self.position.take();
  913        if let Some(last) = self.changes.last_mut()
  914            && group
  915        {
  916            last.current = Some(new_positions)
  917        } else {
  918            self.changes.push(ChangeLocation {
  919                original: new_positions,
  920                current: None,
  921            });
  922        }
  923    }
  924
  925    pub fn last(&self) -> Option<&[Anchor]> {
  926        self.changes.last().map(|change| change.locations())
  927    }
  928
  929    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  930        self.changes.last().map(|change| change.original.as_slice())
  931    }
  932
  933    pub fn invert_last_group(&mut self) {
  934        if let Some(last) = self.changes.last_mut() {
  935            if let Some(current) = last.current.as_mut() {
  936                mem::swap(&mut last.original, current);
  937            }
  938        }
  939    }
  940}
  941
  942#[derive(Clone)]
  943struct InlineBlamePopoverState {
  944    scroll_handle: ScrollHandle,
  945    commit_message: Option<ParsedCommitMessage>,
  946    markdown: Entity<Markdown>,
  947}
  948
  949struct InlineBlamePopover {
  950    position: gpui::Point<Pixels>,
  951    hide_task: Option<Task<()>>,
  952    popover_bounds: Option<Bounds<Pixels>>,
  953    popover_state: InlineBlamePopoverState,
  954}
  955
  956enum SelectionDragState {
  957    /// State when no drag related activity is detected.
  958    None,
  959    /// State when the mouse is down on a selection that is about to be dragged.
  960    ReadyToDrag {
  961        selection: Selection<Anchor>,
  962        click_position: gpui::Point<Pixels>,
  963        mouse_down_time: Instant,
  964    },
  965    /// State when the mouse is dragging the selection in the editor.
  966    Dragging {
  967        selection: Selection<Anchor>,
  968        drop_cursor: Selection<Anchor>,
  969        hide_drop_cursor: bool,
  970    },
  971}
  972
  973enum ColumnarSelectionState {
  974    FromMouse {
  975        selection_tail: Anchor,
  976        display_point: Option<DisplayPoint>,
  977    },
  978    FromSelection {
  979        selection_tail: Anchor,
  980    },
  981}
  982
  983/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  984/// a breakpoint on them.
  985#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  986struct PhantomBreakpointIndicator {
  987    display_row: DisplayRow,
  988    /// There's a small debounce between hovering over the line and showing the indicator.
  989    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  990    is_active: bool,
  991    collides_with_existing_breakpoint: bool,
  992}
  993
  994/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  995///
  996/// See the [module level documentation](self) for more information.
  997pub struct Editor {
  998    focus_handle: FocusHandle,
  999    last_focused_descendant: Option<WeakFocusHandle>,
 1000    /// The text buffer being edited
 1001    buffer: Entity<MultiBuffer>,
 1002    /// Map of how text in the buffer should be displayed.
 1003    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1004    pub display_map: Entity<DisplayMap>,
 1005    pub selections: SelectionsCollection,
 1006    pub scroll_manager: ScrollManager,
 1007    /// When inline assist editors are linked, they all render cursors because
 1008    /// typing enters text into each of them, even the ones that aren't focused.
 1009    pub(crate) show_cursor_when_unfocused: bool,
 1010    columnar_selection_state: Option<ColumnarSelectionState>,
 1011    add_selections_state: Option<AddSelectionsState>,
 1012    select_next_state: Option<SelectNextState>,
 1013    select_prev_state: Option<SelectNextState>,
 1014    selection_history: SelectionHistory,
 1015    defer_selection_effects: bool,
 1016    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1017    autoclose_regions: Vec<AutocloseRegion>,
 1018    snippet_stack: InvalidationStack<SnippetState>,
 1019    select_syntax_node_history: SelectSyntaxNodeHistory,
 1020    ime_transaction: Option<TransactionId>,
 1021    pub diagnostics_max_severity: DiagnosticSeverity,
 1022    active_diagnostics: ActiveDiagnostic,
 1023    show_inline_diagnostics: bool,
 1024    inline_diagnostics_update: Task<()>,
 1025    inline_diagnostics_enabled: bool,
 1026    diagnostics_enabled: bool,
 1027    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1028    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1029    hard_wrap: Option<usize>,
 1030
 1031    // TODO: make this a access method
 1032    pub project: Option<Entity<Project>>,
 1033    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1034    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1035    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1036    blink_manager: Entity<BlinkManager>,
 1037    show_cursor_names: bool,
 1038    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1039    pub show_local_selections: bool,
 1040    mode: EditorMode,
 1041    show_breadcrumbs: bool,
 1042    show_gutter: bool,
 1043    show_scrollbars: ScrollbarAxes,
 1044    minimap_visibility: MinimapVisibility,
 1045    offset_content: bool,
 1046    disable_expand_excerpt_buttons: bool,
 1047    show_line_numbers: Option<bool>,
 1048    use_relative_line_numbers: Option<bool>,
 1049    show_git_diff_gutter: Option<bool>,
 1050    show_code_actions: Option<bool>,
 1051    show_runnables: Option<bool>,
 1052    show_breakpoints: Option<bool>,
 1053    show_wrap_guides: Option<bool>,
 1054    show_indent_guides: Option<bool>,
 1055    placeholder_text: Option<Arc<str>>,
 1056    highlight_order: usize,
 1057    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1058    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1059    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1060    scrollbar_marker_state: ScrollbarMarkerState,
 1061    active_indent_guides_state: ActiveIndentGuidesState,
 1062    nav_history: Option<ItemNavHistory>,
 1063    context_menu: RefCell<Option<CodeContextMenu>>,
 1064    context_menu_options: Option<ContextMenuOptions>,
 1065    mouse_context_menu: Option<MouseContextMenu>,
 1066    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1067    inline_blame_popover: Option<InlineBlamePopover>,
 1068    inline_blame_popover_show_task: Option<Task<()>>,
 1069    signature_help_state: SignatureHelpState,
 1070    auto_signature_help: Option<bool>,
 1071    find_all_references_task_sources: Vec<Anchor>,
 1072    next_completion_id: CompletionId,
 1073    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1074    code_actions_task: Option<Task<Result<()>>>,
 1075    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1076    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    document_highlights_task: Option<Task<()>>,
 1078    linked_editing_range_task: Option<Task<Option<()>>>,
 1079    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1080    pending_rename: Option<RenameState>,
 1081    searchable: bool,
 1082    cursor_shape: CursorShape,
 1083    current_line_highlight: Option<CurrentLineHighlight>,
 1084    collapse_matches: bool,
 1085    autoindent_mode: Option<AutoindentMode>,
 1086    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1087    input_enabled: bool,
 1088    use_modal_editing: bool,
 1089    read_only: bool,
 1090    leader_id: Option<CollaboratorId>,
 1091    remote_id: Option<ViewId>,
 1092    pub hover_state: HoverState,
 1093    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1094    gutter_hovered: bool,
 1095    hovered_link_state: Option<HoveredLinkState>,
 1096    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1097    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1098    active_inline_completion: Option<InlineCompletionState>,
 1099    /// Used to prevent flickering as the user types while the menu is open
 1100    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1101    edit_prediction_settings: EditPredictionSettings,
 1102    inline_completions_hidden_for_vim_mode: bool,
 1103    show_inline_completions_override: Option<bool>,
 1104    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1105    edit_prediction_preview: EditPredictionPreview,
 1106    edit_prediction_indent_conflict: bool,
 1107    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1108    inlay_hint_cache: InlayHintCache,
 1109    next_inlay_id: usize,
 1110    _subscriptions: Vec<Subscription>,
 1111    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1112    gutter_dimensions: GutterDimensions,
 1113    style: Option<EditorStyle>,
 1114    text_style_refinement: Option<TextStyleRefinement>,
 1115    next_editor_action_id: EditorActionId,
 1116    editor_actions: Rc<
 1117        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1118    >,
 1119    use_autoclose: bool,
 1120    use_auto_surround: bool,
 1121    auto_replace_emoji_shortcode: bool,
 1122    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1123    show_git_blame_gutter: bool,
 1124    show_git_blame_inline: bool,
 1125    show_git_blame_inline_delay_task: Option<Task<()>>,
 1126    git_blame_inline_enabled: bool,
 1127    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1128    serialize_dirty_buffers: bool,
 1129    show_selection_menu: Option<bool>,
 1130    blame: Option<Entity<GitBlame>>,
 1131    blame_subscription: Option<Subscription>,
 1132    custom_context_menu: Option<
 1133        Box<
 1134            dyn 'static
 1135                + Fn(
 1136                    &mut Self,
 1137                    DisplayPoint,
 1138                    &mut Window,
 1139                    &mut Context<Self>,
 1140                ) -> Option<Entity<ui::ContextMenu>>,
 1141        >,
 1142    >,
 1143    last_bounds: Option<Bounds<Pixels>>,
 1144    last_position_map: Option<Rc<PositionMap>>,
 1145    expect_bounds_change: Option<Bounds<Pixels>>,
 1146    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1147    tasks_update_task: Option<Task<()>>,
 1148    breakpoint_store: Option<Entity<BreakpointStore>>,
 1149    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1150    hovered_diff_hunk_row: Option<DisplayRow>,
 1151    pull_diagnostics_task: Task<()>,
 1152    in_project_search: bool,
 1153    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1154    breadcrumb_header: Option<String>,
 1155    focused_block: Option<FocusedBlock>,
 1156    next_scroll_position: NextScrollCursorCenterTopBottom,
 1157    addons: HashMap<TypeId, Box<dyn Addon>>,
 1158    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1159    load_diff_task: Option<Shared<Task<()>>>,
 1160    /// Whether we are temporarily displaying a diff other than git's
 1161    temporary_diff_override: bool,
 1162    selection_mark_mode: bool,
 1163    toggle_fold_multiple_buffers: Task<()>,
 1164    _scroll_cursor_center_top_bottom_task: Task<()>,
 1165    serialize_selections: Task<()>,
 1166    serialize_folds: Task<()>,
 1167    mouse_cursor_hidden: bool,
 1168    minimap: Option<Entity<Self>>,
 1169    hide_mouse_mode: HideMouseMode,
 1170    pub change_list: ChangeList,
 1171    inline_value_cache: InlineValueCache,
 1172    selection_drag_state: SelectionDragState,
 1173    next_color_inlay_id: usize,
 1174    colors: Option<LspColorData>,
 1175    folding_newlines: Task<()>,
 1176}
 1177
 1178#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1179enum NextScrollCursorCenterTopBottom {
 1180    #[default]
 1181    Center,
 1182    Top,
 1183    Bottom,
 1184}
 1185
 1186impl NextScrollCursorCenterTopBottom {
 1187    fn next(&self) -> Self {
 1188        match self {
 1189            Self::Center => Self::Top,
 1190            Self::Top => Self::Bottom,
 1191            Self::Bottom => Self::Center,
 1192        }
 1193    }
 1194}
 1195
 1196#[derive(Clone)]
 1197pub struct EditorSnapshot {
 1198    pub mode: EditorMode,
 1199    show_gutter: bool,
 1200    show_line_numbers: Option<bool>,
 1201    show_git_diff_gutter: Option<bool>,
 1202    show_code_actions: Option<bool>,
 1203    show_runnables: Option<bool>,
 1204    show_breakpoints: Option<bool>,
 1205    git_blame_gutter_max_author_length: Option<usize>,
 1206    pub display_snapshot: DisplaySnapshot,
 1207    pub placeholder_text: Option<Arc<str>>,
 1208    is_focused: bool,
 1209    scroll_anchor: ScrollAnchor,
 1210    ongoing_scroll: OngoingScroll,
 1211    current_line_highlight: CurrentLineHighlight,
 1212    gutter_hovered: bool,
 1213}
 1214
 1215#[derive(Default, Debug, Clone, Copy)]
 1216pub struct GutterDimensions {
 1217    pub left_padding: Pixels,
 1218    pub right_padding: Pixels,
 1219    pub width: Pixels,
 1220    pub margin: Pixels,
 1221    pub git_blame_entries_width: Option<Pixels>,
 1222}
 1223
 1224impl GutterDimensions {
 1225    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1226        Self {
 1227            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1228            ..Default::default()
 1229        }
 1230    }
 1231
 1232    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1233        -cx.text_system().descent(font_id, font_size)
 1234    }
 1235    /// The full width of the space taken up by the gutter.
 1236    pub fn full_width(&self) -> Pixels {
 1237        self.margin + self.width
 1238    }
 1239
 1240    /// The width of the space reserved for the fold indicators,
 1241    /// use alongside 'justify_end' and `gutter_width` to
 1242    /// right align content with the line numbers
 1243    pub fn fold_area_width(&self) -> Pixels {
 1244        self.margin + self.right_padding
 1245    }
 1246}
 1247
 1248struct CharacterDimensions {
 1249    em_width: Pixels,
 1250    em_advance: Pixels,
 1251    line_height: Pixels,
 1252}
 1253
 1254#[derive(Debug)]
 1255pub struct RemoteSelection {
 1256    pub replica_id: ReplicaId,
 1257    pub selection: Selection<Anchor>,
 1258    pub cursor_shape: CursorShape,
 1259    pub collaborator_id: CollaboratorId,
 1260    pub line_mode: bool,
 1261    pub user_name: Option<SharedString>,
 1262    pub color: PlayerColor,
 1263}
 1264
 1265#[derive(Clone, Debug)]
 1266struct SelectionHistoryEntry {
 1267    selections: Arc<[Selection<Anchor>]>,
 1268    select_next_state: Option<SelectNextState>,
 1269    select_prev_state: Option<SelectNextState>,
 1270    add_selections_state: Option<AddSelectionsState>,
 1271}
 1272
 1273#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1274enum SelectionHistoryMode {
 1275    Normal,
 1276    Undoing,
 1277    Redoing,
 1278    Skipping,
 1279}
 1280
 1281#[derive(Clone, PartialEq, Eq, Hash)]
 1282struct HoveredCursor {
 1283    replica_id: u16,
 1284    selection_id: usize,
 1285}
 1286
 1287impl Default for SelectionHistoryMode {
 1288    fn default() -> Self {
 1289        Self::Normal
 1290    }
 1291}
 1292
 1293#[derive(Debug)]
 1294/// SelectionEffects controls the side-effects of updating the selection.
 1295///
 1296/// The default behaviour does "what you mostly want":
 1297/// - it pushes to the nav history if the cursor moved by >10 lines
 1298/// - it re-triggers completion requests
 1299/// - it scrolls to fit
 1300///
 1301/// You might want to modify these behaviours. For example when doing a "jump"
 1302/// like go to definition, we always want to add to nav history; but when scrolling
 1303/// in vim mode we never do.
 1304///
 1305/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1306/// move.
 1307pub struct SelectionEffects {
 1308    nav_history: Option<bool>,
 1309    completions: bool,
 1310    scroll: Option<Autoscroll>,
 1311}
 1312
 1313impl Default for SelectionEffects {
 1314    fn default() -> Self {
 1315        Self {
 1316            nav_history: None,
 1317            completions: true,
 1318            scroll: Some(Autoscroll::fit()),
 1319        }
 1320    }
 1321}
 1322impl SelectionEffects {
 1323    pub fn scroll(scroll: Autoscroll) -> Self {
 1324        Self {
 1325            scroll: Some(scroll),
 1326            ..Default::default()
 1327        }
 1328    }
 1329
 1330    pub fn no_scroll() -> Self {
 1331        Self {
 1332            scroll: None,
 1333            ..Default::default()
 1334        }
 1335    }
 1336
 1337    pub fn completions(self, completions: bool) -> Self {
 1338        Self {
 1339            completions,
 1340            ..self
 1341        }
 1342    }
 1343
 1344    pub fn nav_history(self, nav_history: bool) -> Self {
 1345        Self {
 1346            nav_history: Some(nav_history),
 1347            ..self
 1348        }
 1349    }
 1350}
 1351
 1352struct DeferredSelectionEffectsState {
 1353    changed: bool,
 1354    effects: SelectionEffects,
 1355    old_cursor_position: Anchor,
 1356    history_entry: SelectionHistoryEntry,
 1357}
 1358
 1359#[derive(Default)]
 1360struct SelectionHistory {
 1361    #[allow(clippy::type_complexity)]
 1362    selections_by_transaction:
 1363        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1364    mode: SelectionHistoryMode,
 1365    undo_stack: VecDeque<SelectionHistoryEntry>,
 1366    redo_stack: VecDeque<SelectionHistoryEntry>,
 1367}
 1368
 1369impl SelectionHistory {
 1370    #[track_caller]
 1371    fn insert_transaction(
 1372        &mut self,
 1373        transaction_id: TransactionId,
 1374        selections: Arc<[Selection<Anchor>]>,
 1375    ) {
 1376        if selections.is_empty() {
 1377            log::error!(
 1378                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1379                std::panic::Location::caller()
 1380            );
 1381            return;
 1382        }
 1383        self.selections_by_transaction
 1384            .insert(transaction_id, (selections, None));
 1385    }
 1386
 1387    #[allow(clippy::type_complexity)]
 1388    fn transaction(
 1389        &self,
 1390        transaction_id: TransactionId,
 1391    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1392        self.selections_by_transaction.get(&transaction_id)
 1393    }
 1394
 1395    #[allow(clippy::type_complexity)]
 1396    fn transaction_mut(
 1397        &mut self,
 1398        transaction_id: TransactionId,
 1399    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1400        self.selections_by_transaction.get_mut(&transaction_id)
 1401    }
 1402
 1403    fn push(&mut self, entry: SelectionHistoryEntry) {
 1404        if !entry.selections.is_empty() {
 1405            match self.mode {
 1406                SelectionHistoryMode::Normal => {
 1407                    self.push_undo(entry);
 1408                    self.redo_stack.clear();
 1409                }
 1410                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1411                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1412                SelectionHistoryMode::Skipping => {}
 1413            }
 1414        }
 1415    }
 1416
 1417    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1418        if self
 1419            .undo_stack
 1420            .back()
 1421            .map_or(true, |e| e.selections != entry.selections)
 1422        {
 1423            self.undo_stack.push_back(entry);
 1424            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1425                self.undo_stack.pop_front();
 1426            }
 1427        }
 1428    }
 1429
 1430    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1431        if self
 1432            .redo_stack
 1433            .back()
 1434            .map_or(true, |e| e.selections != entry.selections)
 1435        {
 1436            self.redo_stack.push_back(entry);
 1437            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1438                self.redo_stack.pop_front();
 1439            }
 1440        }
 1441    }
 1442}
 1443
 1444#[derive(Clone, Copy)]
 1445pub struct RowHighlightOptions {
 1446    pub autoscroll: bool,
 1447    pub include_gutter: bool,
 1448}
 1449
 1450impl Default for RowHighlightOptions {
 1451    fn default() -> Self {
 1452        Self {
 1453            autoscroll: Default::default(),
 1454            include_gutter: true,
 1455        }
 1456    }
 1457}
 1458
 1459struct RowHighlight {
 1460    index: usize,
 1461    range: Range<Anchor>,
 1462    color: Hsla,
 1463    options: RowHighlightOptions,
 1464    type_id: TypeId,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsState {
 1469    groups: Vec<AddSelectionsGroup>,
 1470}
 1471
 1472#[derive(Clone, Debug)]
 1473struct AddSelectionsGroup {
 1474    above: bool,
 1475    stack: Vec<usize>,
 1476}
 1477
 1478#[derive(Clone)]
 1479struct SelectNextState {
 1480    query: AhoCorasick,
 1481    wordwise: bool,
 1482    done: bool,
 1483}
 1484
 1485impl std::fmt::Debug for SelectNextState {
 1486    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1487        f.debug_struct(std::any::type_name::<Self>())
 1488            .field("wordwise", &self.wordwise)
 1489            .field("done", &self.done)
 1490            .finish()
 1491    }
 1492}
 1493
 1494#[derive(Debug)]
 1495struct AutocloseRegion {
 1496    selection_id: usize,
 1497    range: Range<Anchor>,
 1498    pair: BracketPair,
 1499}
 1500
 1501#[derive(Debug)]
 1502struct SnippetState {
 1503    ranges: Vec<Vec<Range<Anchor>>>,
 1504    active_index: usize,
 1505    choices: Vec<Option<Vec<String>>>,
 1506}
 1507
 1508#[doc(hidden)]
 1509pub struct RenameState {
 1510    pub range: Range<Anchor>,
 1511    pub old_name: Arc<str>,
 1512    pub editor: Entity<Editor>,
 1513    block_id: CustomBlockId,
 1514}
 1515
 1516struct InvalidationStack<T>(Vec<T>);
 1517
 1518struct RegisteredInlineCompletionProvider {
 1519    provider: Arc<dyn InlineCompletionProviderHandle>,
 1520    _subscription: Subscription,
 1521}
 1522
 1523#[derive(Debug, PartialEq, Eq)]
 1524pub struct ActiveDiagnosticGroup {
 1525    pub active_range: Range<Anchor>,
 1526    pub active_message: String,
 1527    pub group_id: usize,
 1528    pub blocks: HashSet<CustomBlockId>,
 1529}
 1530
 1531#[derive(Debug, PartialEq, Eq)]
 1532
 1533pub(crate) enum ActiveDiagnostic {
 1534    None,
 1535    All,
 1536    Group(ActiveDiagnosticGroup),
 1537}
 1538
 1539#[derive(Serialize, Deserialize, Clone, Debug)]
 1540pub struct ClipboardSelection {
 1541    /// The number of bytes in this selection.
 1542    pub len: usize,
 1543    /// Whether this was a full-line selection.
 1544    pub is_entire_line: bool,
 1545    /// The indentation of the first line when this content was originally copied.
 1546    pub first_line_indent: u32,
 1547}
 1548
 1549// selections, scroll behavior, was newest selection reversed
 1550type SelectSyntaxNodeHistoryState = (
 1551    Box<[Selection<usize>]>,
 1552    SelectSyntaxNodeScrollBehavior,
 1553    bool,
 1554);
 1555
 1556#[derive(Default)]
 1557struct SelectSyntaxNodeHistory {
 1558    stack: Vec<SelectSyntaxNodeHistoryState>,
 1559    // disable temporarily to allow changing selections without losing the stack
 1560    pub disable_clearing: bool,
 1561}
 1562
 1563impl SelectSyntaxNodeHistory {
 1564    pub fn try_clear(&mut self) {
 1565        if !self.disable_clearing {
 1566            self.stack.clear();
 1567        }
 1568    }
 1569
 1570    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1571        self.stack.push(selection);
 1572    }
 1573
 1574    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1575        self.stack.pop()
 1576    }
 1577}
 1578
 1579enum SelectSyntaxNodeScrollBehavior {
 1580    CursorTop,
 1581    FitSelection,
 1582    CursorBottom,
 1583}
 1584
 1585#[derive(Debug)]
 1586pub(crate) struct NavigationData {
 1587    cursor_anchor: Anchor,
 1588    cursor_position: Point,
 1589    scroll_anchor: ScrollAnchor,
 1590    scroll_top_row: u32,
 1591}
 1592
 1593#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1594pub enum GotoDefinitionKind {
 1595    Symbol,
 1596    Declaration,
 1597    Type,
 1598    Implementation,
 1599}
 1600
 1601#[derive(Debug, Clone)]
 1602enum InlayHintRefreshReason {
 1603    ModifiersChanged(bool),
 1604    Toggle(bool),
 1605    SettingsChange(InlayHintSettings),
 1606    NewLinesShown,
 1607    BufferEdited(HashSet<Arc<Language>>),
 1608    RefreshRequested,
 1609    ExcerptsRemoved(Vec<ExcerptId>),
 1610}
 1611
 1612impl InlayHintRefreshReason {
 1613    fn description(&self) -> &'static str {
 1614        match self {
 1615            Self::ModifiersChanged(_) => "modifiers changed",
 1616            Self::Toggle(_) => "toggle",
 1617            Self::SettingsChange(_) => "settings change",
 1618            Self::NewLinesShown => "new lines shown",
 1619            Self::BufferEdited(_) => "buffer edited",
 1620            Self::RefreshRequested => "refresh requested",
 1621            Self::ExcerptsRemoved(_) => "excerpts removed",
 1622        }
 1623    }
 1624}
 1625
 1626pub enum FormatTarget {
 1627    Buffers(HashSet<Entity<Buffer>>),
 1628    Ranges(Vec<Range<MultiBufferPoint>>),
 1629}
 1630
 1631pub(crate) struct FocusedBlock {
 1632    id: BlockId,
 1633    focus_handle: WeakFocusHandle,
 1634}
 1635
 1636#[derive(Clone)]
 1637enum JumpData {
 1638    MultiBufferRow {
 1639        row: MultiBufferRow,
 1640        line_offset_from_top: u32,
 1641    },
 1642    MultiBufferPoint {
 1643        excerpt_id: ExcerptId,
 1644        position: Point,
 1645        anchor: text::Anchor,
 1646        line_offset_from_top: u32,
 1647    },
 1648}
 1649
 1650pub enum MultibufferSelectionMode {
 1651    First,
 1652    All,
 1653}
 1654
 1655#[derive(Clone, Copy, Debug, Default)]
 1656pub struct RewrapOptions {
 1657    pub override_language_settings: bool,
 1658    pub preserve_existing_whitespace: bool,
 1659}
 1660
 1661impl Editor {
 1662    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1663        let buffer = cx.new(|cx| Buffer::local("", cx));
 1664        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1665        Self::new(
 1666            EditorMode::SingleLine { auto_width: false },
 1667            buffer,
 1668            None,
 1669            window,
 1670            cx,
 1671        )
 1672    }
 1673
 1674    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(EditorMode::full(), buffer, None, window, cx)
 1678    }
 1679
 1680    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1681        let buffer = cx.new(|cx| Buffer::local("", cx));
 1682        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1683        Self::new(
 1684            EditorMode::SingleLine { auto_width: true },
 1685            buffer,
 1686            None,
 1687            window,
 1688            cx,
 1689        )
 1690    }
 1691
 1692    pub fn auto_height(
 1693        min_lines: usize,
 1694        max_lines: usize,
 1695        window: &mut Window,
 1696        cx: &mut Context<Self>,
 1697    ) -> Self {
 1698        let buffer = cx.new(|cx| Buffer::local("", cx));
 1699        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1700        Self::new(
 1701            EditorMode::AutoHeight {
 1702                min_lines,
 1703                max_lines: Some(max_lines),
 1704            },
 1705            buffer,
 1706            None,
 1707            window,
 1708            cx,
 1709        )
 1710    }
 1711
 1712    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1713    /// The editor grows as tall as needed to fit its content.
 1714    pub fn auto_height_unbounded(
 1715        min_lines: usize,
 1716        window: &mut Window,
 1717        cx: &mut Context<Self>,
 1718    ) -> Self {
 1719        let buffer = cx.new(|cx| Buffer::local("", cx));
 1720        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1721        Self::new(
 1722            EditorMode::AutoHeight {
 1723                min_lines,
 1724                max_lines: None,
 1725            },
 1726            buffer,
 1727            None,
 1728            window,
 1729            cx,
 1730        )
 1731    }
 1732
 1733    pub fn for_buffer(
 1734        buffer: Entity<Buffer>,
 1735        project: Option<Entity<Project>>,
 1736        window: &mut Window,
 1737        cx: &mut Context<Self>,
 1738    ) -> Self {
 1739        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1740        Self::new(EditorMode::full(), buffer, project, window, cx)
 1741    }
 1742
 1743    pub fn for_multibuffer(
 1744        buffer: Entity<MultiBuffer>,
 1745        project: Option<Entity<Project>>,
 1746        window: &mut Window,
 1747        cx: &mut Context<Self>,
 1748    ) -> Self {
 1749        Self::new(EditorMode::full(), buffer, project, window, cx)
 1750    }
 1751
 1752    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1753        let mut clone = Self::new(
 1754            self.mode.clone(),
 1755            self.buffer.clone(),
 1756            self.project.clone(),
 1757            window,
 1758            cx,
 1759        );
 1760        self.display_map.update(cx, |display_map, cx| {
 1761            let snapshot = display_map.snapshot(cx);
 1762            clone.display_map.update(cx, |display_map, cx| {
 1763                display_map.set_state(&snapshot, cx);
 1764            });
 1765        });
 1766        clone.folds_did_change(cx);
 1767        clone.selections.clone_state(&self.selections);
 1768        clone.scroll_manager.clone_state(&self.scroll_manager);
 1769        clone.searchable = self.searchable;
 1770        clone.read_only = self.read_only;
 1771        clone
 1772    }
 1773
 1774    pub fn new(
 1775        mode: EditorMode,
 1776        buffer: Entity<MultiBuffer>,
 1777        project: Option<Entity<Project>>,
 1778        window: &mut Window,
 1779        cx: &mut Context<Self>,
 1780    ) -> Self {
 1781        Editor::new_internal(mode, buffer, project, None, window, cx)
 1782    }
 1783
 1784    fn new_internal(
 1785        mode: EditorMode,
 1786        buffer: Entity<MultiBuffer>,
 1787        project: Option<Entity<Project>>,
 1788        display_map: Option<Entity<DisplayMap>>,
 1789        window: &mut Window,
 1790        cx: &mut Context<Self>,
 1791    ) -> Self {
 1792        debug_assert!(
 1793            display_map.is_none() || mode.is_minimap(),
 1794            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1795        );
 1796
 1797        let full_mode = mode.is_full();
 1798        let diagnostics_max_severity = if full_mode {
 1799            EditorSettings::get_global(cx)
 1800                .diagnostics_max_severity
 1801                .unwrap_or(DiagnosticSeverity::Hint)
 1802        } else {
 1803            DiagnosticSeverity::Off
 1804        };
 1805        let style = window.text_style();
 1806        let font_size = style.font_size.to_pixels(window.rem_size());
 1807        let editor = cx.entity().downgrade();
 1808        let fold_placeholder = FoldPlaceholder {
 1809            constrain_width: true,
 1810            render: Arc::new(move |fold_id, fold_range, cx| {
 1811                let editor = editor.clone();
 1812                div()
 1813                    .id(fold_id)
 1814                    .bg(cx.theme().colors().ghost_element_background)
 1815                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1816                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1817                    .rounded_xs()
 1818                    .size_full()
 1819                    .cursor_pointer()
 1820                    .child("")
 1821                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1822                    .on_click(move |_, _window, cx| {
 1823                        editor
 1824                            .update(cx, |editor, cx| {
 1825                                editor.unfold_ranges(
 1826                                    &[fold_range.start..fold_range.end],
 1827                                    true,
 1828                                    false,
 1829                                    cx,
 1830                                );
 1831                                cx.stop_propagation();
 1832                            })
 1833                            .ok();
 1834                    })
 1835                    .into_any()
 1836            }),
 1837            merge_adjacent: true,
 1838            ..FoldPlaceholder::default()
 1839        };
 1840        let display_map = display_map.unwrap_or_else(|| {
 1841            cx.new(|cx| {
 1842                DisplayMap::new(
 1843                    buffer.clone(),
 1844                    style.font(),
 1845                    font_size,
 1846                    None,
 1847                    FILE_HEADER_HEIGHT,
 1848                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1849                    fold_placeholder,
 1850                    diagnostics_max_severity,
 1851                    cx,
 1852                )
 1853            })
 1854        });
 1855
 1856        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1857
 1858        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1859
 1860        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1861            .then(|| language_settings::SoftWrap::None);
 1862
 1863        let mut project_subscriptions = Vec::new();
 1864        if mode.is_full() {
 1865            if let Some(project) = project.as_ref() {
 1866                project_subscriptions.push(cx.subscribe_in(
 1867                    project,
 1868                    window,
 1869                    |editor, _, event, window, cx| match event {
 1870                        project::Event::RefreshCodeLens => {
 1871                            // we always query lens with actions, without storing them, always refreshing them
 1872                        }
 1873                        project::Event::RefreshInlayHints => {
 1874                            editor
 1875                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1876                        }
 1877                        project::Event::LanguageServerAdded(..)
 1878                        | project::Event::LanguageServerRemoved(..) => {
 1879                            if editor.tasks_update_task.is_none() {
 1880                                editor.tasks_update_task =
 1881                                    Some(editor.refresh_runnables(window, cx));
 1882                            }
 1883                            editor.update_lsp_data(true, None, window, cx);
 1884                        }
 1885                        project::Event::SnippetEdit(id, snippet_edits) => {
 1886                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1887                                let focus_handle = editor.focus_handle(cx);
 1888                                if focus_handle.is_focused(window) {
 1889                                    let snapshot = buffer.read(cx).snapshot();
 1890                                    for (range, snippet) in snippet_edits {
 1891                                        let editor_range =
 1892                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1893                                        editor
 1894                                            .insert_snippet(
 1895                                                &[editor_range],
 1896                                                snippet.clone(),
 1897                                                window,
 1898                                                cx,
 1899                                            )
 1900                                            .ok();
 1901                                    }
 1902                                }
 1903                            }
 1904                        }
 1905                        _ => {}
 1906                    },
 1907                ));
 1908                if let Some(task_inventory) = project
 1909                    .read(cx)
 1910                    .task_store()
 1911                    .read(cx)
 1912                    .task_inventory()
 1913                    .cloned()
 1914                {
 1915                    project_subscriptions.push(cx.observe_in(
 1916                        &task_inventory,
 1917                        window,
 1918                        |editor, _, window, cx| {
 1919                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1920                        },
 1921                    ));
 1922                };
 1923
 1924                project_subscriptions.push(cx.subscribe_in(
 1925                    &project.read(cx).breakpoint_store(),
 1926                    window,
 1927                    |editor, _, event, window, cx| match event {
 1928                        BreakpointStoreEvent::ClearDebugLines => {
 1929                            editor.clear_row_highlights::<ActiveDebugLine>();
 1930                            editor.refresh_inline_values(cx);
 1931                        }
 1932                        BreakpointStoreEvent::SetDebugLine => {
 1933                            if editor.go_to_active_debug_line(window, cx) {
 1934                                cx.stop_propagation();
 1935                            }
 1936
 1937                            editor.refresh_inline_values(cx);
 1938                        }
 1939                        _ => {}
 1940                    },
 1941                ));
 1942                let git_store = project.read(cx).git_store().clone();
 1943                let project = project.clone();
 1944                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1945                    match event {
 1946                        GitStoreEvent::RepositoryUpdated(
 1947                            _,
 1948                            RepositoryEvent::Updated {
 1949                                new_instance: true, ..
 1950                            },
 1951                            _,
 1952                        ) => {
 1953                            this.load_diff_task = Some(
 1954                                update_uncommitted_diff_for_buffer(
 1955                                    cx.entity(),
 1956                                    &project,
 1957                                    this.buffer.read(cx).all_buffers(),
 1958                                    this.buffer.clone(),
 1959                                    cx,
 1960                                )
 1961                                .shared(),
 1962                            );
 1963                        }
 1964                        _ => {}
 1965                    }
 1966                }));
 1967            }
 1968        }
 1969
 1970        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1971
 1972        let inlay_hint_settings =
 1973            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1974        let focus_handle = cx.focus_handle();
 1975        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1976            .detach();
 1977        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1978            .detach();
 1979        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1980            .detach();
 1981        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1982            .detach();
 1983        cx.observe_pending_input(window, Self::observe_pending_input)
 1984            .detach();
 1985
 1986        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1987            Some(false)
 1988        } else {
 1989            None
 1990        };
 1991
 1992        let breakpoint_store = match (&mode, project.as_ref()) {
 1993            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1994            _ => None,
 1995        };
 1996
 1997        let mut code_action_providers = Vec::new();
 1998        let mut load_uncommitted_diff = None;
 1999        if let Some(project) = project.clone() {
 2000            load_uncommitted_diff = Some(
 2001                update_uncommitted_diff_for_buffer(
 2002                    cx.entity(),
 2003                    &project,
 2004                    buffer.read(cx).all_buffers(),
 2005                    buffer.clone(),
 2006                    cx,
 2007                )
 2008                .shared(),
 2009            );
 2010            code_action_providers.push(Rc::new(project) as Rc<_>);
 2011        }
 2012
 2013        let mut editor = Self {
 2014            focus_handle,
 2015            show_cursor_when_unfocused: false,
 2016            last_focused_descendant: None,
 2017            buffer: buffer.clone(),
 2018            display_map: display_map.clone(),
 2019            selections,
 2020            scroll_manager: ScrollManager::new(cx),
 2021            columnar_selection_state: None,
 2022            add_selections_state: None,
 2023            select_next_state: None,
 2024            select_prev_state: None,
 2025            selection_history: SelectionHistory::default(),
 2026            defer_selection_effects: false,
 2027            deferred_selection_effects_state: None,
 2028            autoclose_regions: Vec::new(),
 2029            snippet_stack: InvalidationStack::default(),
 2030            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2031            ime_transaction: None,
 2032            active_diagnostics: ActiveDiagnostic::None,
 2033            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2034            inline_diagnostics_update: Task::ready(()),
 2035            inline_diagnostics: Vec::new(),
 2036            soft_wrap_mode_override,
 2037            diagnostics_max_severity,
 2038            hard_wrap: None,
 2039            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2040            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2041            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2042            project,
 2043            blink_manager: blink_manager.clone(),
 2044            show_local_selections: true,
 2045            show_scrollbars: ScrollbarAxes {
 2046                horizontal: full_mode,
 2047                vertical: full_mode,
 2048            },
 2049            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2050            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2051            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2052            show_gutter: mode.is_full(),
 2053            show_line_numbers: None,
 2054            use_relative_line_numbers: None,
 2055            disable_expand_excerpt_buttons: false,
 2056            show_git_diff_gutter: None,
 2057            show_code_actions: None,
 2058            show_runnables: None,
 2059            show_breakpoints: None,
 2060            show_wrap_guides: None,
 2061            show_indent_guides,
 2062            placeholder_text: None,
 2063            highlight_order: 0,
 2064            highlighted_rows: HashMap::default(),
 2065            background_highlights: TreeMap::default(),
 2066            gutter_highlights: TreeMap::default(),
 2067            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2068            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2069            nav_history: None,
 2070            context_menu: RefCell::new(None),
 2071            context_menu_options: None,
 2072            mouse_context_menu: None,
 2073            completion_tasks: Vec::new(),
 2074            inline_blame_popover: None,
 2075            inline_blame_popover_show_task: None,
 2076            signature_help_state: SignatureHelpState::default(),
 2077            auto_signature_help: None,
 2078            find_all_references_task_sources: Vec::new(),
 2079            next_completion_id: 0,
 2080            next_inlay_id: 0,
 2081            code_action_providers,
 2082            available_code_actions: None,
 2083            code_actions_task: None,
 2084            quick_selection_highlight_task: None,
 2085            debounced_selection_highlight_task: None,
 2086            document_highlights_task: None,
 2087            linked_editing_range_task: None,
 2088            pending_rename: None,
 2089            searchable: true,
 2090            cursor_shape: EditorSettings::get_global(cx)
 2091                .cursor_shape
 2092                .unwrap_or_default(),
 2093            current_line_highlight: None,
 2094            autoindent_mode: Some(AutoindentMode::EachLine),
 2095            collapse_matches: false,
 2096            workspace: None,
 2097            input_enabled: true,
 2098            use_modal_editing: mode.is_full(),
 2099            read_only: mode.is_minimap(),
 2100            use_autoclose: true,
 2101            use_auto_surround: true,
 2102            auto_replace_emoji_shortcode: false,
 2103            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2104            leader_id: None,
 2105            remote_id: None,
 2106            hover_state: HoverState::default(),
 2107            pending_mouse_down: None,
 2108            hovered_link_state: None,
 2109            edit_prediction_provider: None,
 2110            active_inline_completion: None,
 2111            stale_inline_completion_in_menu: None,
 2112            edit_prediction_preview: EditPredictionPreview::Inactive {
 2113                released_too_fast: false,
 2114            },
 2115            inline_diagnostics_enabled: mode.is_full(),
 2116            diagnostics_enabled: mode.is_full(),
 2117            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2118            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2119
 2120            gutter_hovered: false,
 2121            pixel_position_of_newest_cursor: None,
 2122            last_bounds: None,
 2123            last_position_map: None,
 2124            expect_bounds_change: None,
 2125            gutter_dimensions: GutterDimensions::default(),
 2126            style: None,
 2127            show_cursor_names: false,
 2128            hovered_cursors: HashMap::default(),
 2129            next_editor_action_id: EditorActionId::default(),
 2130            editor_actions: Rc::default(),
 2131            inline_completions_hidden_for_vim_mode: false,
 2132            show_inline_completions_override: None,
 2133            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2134            edit_prediction_settings: EditPredictionSettings::Disabled,
 2135            edit_prediction_indent_conflict: false,
 2136            edit_prediction_requires_modifier_in_indent_conflict: true,
 2137            custom_context_menu: None,
 2138            show_git_blame_gutter: false,
 2139            show_git_blame_inline: false,
 2140            show_selection_menu: None,
 2141            show_git_blame_inline_delay_task: None,
 2142            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2143            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2144            serialize_dirty_buffers: !mode.is_minimap()
 2145                && ProjectSettings::get_global(cx)
 2146                    .session
 2147                    .restore_unsaved_buffers,
 2148            blame: None,
 2149            blame_subscription: None,
 2150            tasks: BTreeMap::default(),
 2151
 2152            breakpoint_store,
 2153            gutter_breakpoint_indicator: (None, None),
 2154            hovered_diff_hunk_row: None,
 2155            _subscriptions: vec![
 2156                cx.observe(&buffer, Self::on_buffer_changed),
 2157                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2158                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2159                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2160                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2161                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2162                cx.observe_window_activation(window, |editor, window, cx| {
 2163                    let active = window.is_window_active();
 2164                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2165                        if active {
 2166                            blink_manager.enable(cx);
 2167                        } else {
 2168                            blink_manager.disable(cx);
 2169                        }
 2170                    });
 2171                    if active {
 2172                        editor.show_mouse_cursor(cx);
 2173                    }
 2174                }),
 2175            ],
 2176            tasks_update_task: None,
 2177            pull_diagnostics_task: Task::ready(()),
 2178            colors: None,
 2179            next_color_inlay_id: 0,
 2180            linked_edit_ranges: Default::default(),
 2181            in_project_search: false,
 2182            previous_search_ranges: None,
 2183            breadcrumb_header: None,
 2184            focused_block: None,
 2185            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2186            addons: HashMap::default(),
 2187            registered_buffers: HashMap::default(),
 2188            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2189            selection_mark_mode: false,
 2190            toggle_fold_multiple_buffers: Task::ready(()),
 2191            serialize_selections: Task::ready(()),
 2192            serialize_folds: Task::ready(()),
 2193            text_style_refinement: None,
 2194            load_diff_task: load_uncommitted_diff,
 2195            temporary_diff_override: false,
 2196            mouse_cursor_hidden: false,
 2197            minimap: None,
 2198            hide_mouse_mode: EditorSettings::get_global(cx)
 2199                .hide_mouse
 2200                .unwrap_or_default(),
 2201            change_list: ChangeList::new(),
 2202            mode,
 2203            selection_drag_state: SelectionDragState::None,
 2204            folding_newlines: Task::ready(()),
 2205        };
 2206        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2207            editor
 2208                ._subscriptions
 2209                .push(cx.observe(breakpoints, |_, _, cx| {
 2210                    cx.notify();
 2211                }));
 2212        }
 2213        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2214        editor._subscriptions.extend(project_subscriptions);
 2215
 2216        editor._subscriptions.push(cx.subscribe_in(
 2217            &cx.entity(),
 2218            window,
 2219            |editor, _, e: &EditorEvent, window, cx| match e {
 2220                EditorEvent::ScrollPositionChanged { local, .. } => {
 2221                    if *local {
 2222                        let new_anchor = editor.scroll_manager.anchor();
 2223                        let snapshot = editor.snapshot(window, cx);
 2224                        editor.update_restoration_data(cx, move |data| {
 2225                            data.scroll_position = (
 2226                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2227                                new_anchor.offset,
 2228                            );
 2229                        });
 2230                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2231                        editor.inline_blame_popover.take();
 2232                    }
 2233                }
 2234                EditorEvent::Edited { .. } => {
 2235                    if !vim_enabled(cx) {
 2236                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2237                        let pop_state = editor
 2238                            .change_list
 2239                            .last()
 2240                            .map(|previous| {
 2241                                previous.len() == selections.len()
 2242                                    && previous.iter().enumerate().all(|(ix, p)| {
 2243                                        p.to_display_point(&map).row()
 2244                                            == selections[ix].head().row()
 2245                                    })
 2246                            })
 2247                            .unwrap_or(false);
 2248                        let new_positions = selections
 2249                            .into_iter()
 2250                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2251                            .collect();
 2252                        editor
 2253                            .change_list
 2254                            .push_to_change_list(pop_state, new_positions);
 2255                    }
 2256                }
 2257                _ => (),
 2258            },
 2259        ));
 2260
 2261        if let Some(dap_store) = editor
 2262            .project
 2263            .as_ref()
 2264            .map(|project| project.read(cx).dap_store())
 2265        {
 2266            let weak_editor = cx.weak_entity();
 2267
 2268            editor
 2269                ._subscriptions
 2270                .push(
 2271                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2272                        let session_entity = cx.entity();
 2273                        weak_editor
 2274                            .update(cx, |editor, cx| {
 2275                                editor._subscriptions.push(
 2276                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2277                                );
 2278                            })
 2279                            .ok();
 2280                    }),
 2281                );
 2282
 2283            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2284                editor
 2285                    ._subscriptions
 2286                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2287            }
 2288        }
 2289
 2290        // skip adding the initial selection to selection history
 2291        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2292        editor.end_selection(window, cx);
 2293        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2294
 2295        editor.scroll_manager.show_scrollbars(window, cx);
 2296        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2297
 2298        if full_mode {
 2299            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2300            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2301
 2302            if editor.git_blame_inline_enabled {
 2303                editor.start_git_blame_inline(false, window, cx);
 2304            }
 2305
 2306            editor.go_to_active_debug_line(window, cx);
 2307
 2308            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2309                if let Some(project) = editor.project.as_ref() {
 2310                    let handle = project.update(cx, |project, cx| {
 2311                        project.register_buffer_with_language_servers(&buffer, cx)
 2312                    });
 2313                    editor
 2314                        .registered_buffers
 2315                        .insert(buffer.read(cx).remote_id(), handle);
 2316                }
 2317            }
 2318
 2319            editor.minimap =
 2320                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2321            editor.colors = Some(LspColorData::new(cx));
 2322            editor.update_lsp_data(false, None, window, cx);
 2323        }
 2324
 2325        if editor.mode.is_full() {
 2326            editor.report_editor_event("Editor Opened", None, cx);
 2327        }
 2328
 2329        editor
 2330    }
 2331
 2332    pub fn deploy_mouse_context_menu(
 2333        &mut self,
 2334        position: gpui::Point<Pixels>,
 2335        context_menu: Entity<ContextMenu>,
 2336        window: &mut Window,
 2337        cx: &mut Context<Self>,
 2338    ) {
 2339        self.mouse_context_menu = Some(MouseContextMenu::new(
 2340            self,
 2341            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2342            context_menu,
 2343            window,
 2344            cx,
 2345        ));
 2346    }
 2347
 2348    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2349        self.mouse_context_menu
 2350            .as_ref()
 2351            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2352    }
 2353
 2354    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2355        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2356    }
 2357
 2358    fn key_context_internal(
 2359        &self,
 2360        has_active_edit_prediction: bool,
 2361        window: &Window,
 2362        cx: &App,
 2363    ) -> KeyContext {
 2364        let mut key_context = KeyContext::new_with_defaults();
 2365        key_context.add("Editor");
 2366        let mode = match self.mode {
 2367            EditorMode::SingleLine { .. } => "single_line",
 2368            EditorMode::AutoHeight { .. } => "auto_height",
 2369            EditorMode::Minimap { .. } => "minimap",
 2370            EditorMode::Full { .. } => "full",
 2371        };
 2372
 2373        if EditorSettings::jupyter_enabled(cx) {
 2374            key_context.add("jupyter");
 2375        }
 2376
 2377        key_context.set("mode", mode);
 2378        if self.pending_rename.is_some() {
 2379            key_context.add("renaming");
 2380        }
 2381
 2382        match self.context_menu.borrow().as_ref() {
 2383            Some(CodeContextMenu::Completions(_)) => {
 2384                key_context.add("menu");
 2385                key_context.add("showing_completions");
 2386            }
 2387            Some(CodeContextMenu::CodeActions(_)) => {
 2388                key_context.add("menu");
 2389                key_context.add("showing_code_actions")
 2390            }
 2391            None => {}
 2392        }
 2393
 2394        if self.signature_help_state.has_multiple_signatures() {
 2395            key_context.add("showing_signature_help");
 2396        }
 2397
 2398        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2399        if !self.focus_handle(cx).contains_focused(window, cx)
 2400            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2401        {
 2402            for addon in self.addons.values() {
 2403                addon.extend_key_context(&mut key_context, cx)
 2404            }
 2405        }
 2406
 2407        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2408            if let Some(extension) = singleton_buffer
 2409                .read(cx)
 2410                .file()
 2411                .and_then(|file| file.path().extension()?.to_str())
 2412            {
 2413                key_context.set("extension", extension.to_string());
 2414            }
 2415        } else {
 2416            key_context.add("multibuffer");
 2417        }
 2418
 2419        if has_active_edit_prediction {
 2420            if self.edit_prediction_in_conflict() {
 2421                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2422            } else {
 2423                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2424                key_context.add("copilot_suggestion");
 2425            }
 2426        }
 2427
 2428        if self.selection_mark_mode {
 2429            key_context.add("selection_mode");
 2430        }
 2431
 2432        key_context
 2433    }
 2434
 2435    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2436        if self.mouse_cursor_hidden {
 2437            self.mouse_cursor_hidden = false;
 2438            cx.notify();
 2439        }
 2440    }
 2441
 2442    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2443        let hide_mouse_cursor = match origin {
 2444            HideMouseCursorOrigin::TypingAction => {
 2445                matches!(
 2446                    self.hide_mouse_mode,
 2447                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2448                )
 2449            }
 2450            HideMouseCursorOrigin::MovementAction => {
 2451                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2452            }
 2453        };
 2454        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2455            self.mouse_cursor_hidden = hide_mouse_cursor;
 2456            cx.notify();
 2457        }
 2458    }
 2459
 2460    pub fn edit_prediction_in_conflict(&self) -> bool {
 2461        if !self.show_edit_predictions_in_menu() {
 2462            return false;
 2463        }
 2464
 2465        let showing_completions = self
 2466            .context_menu
 2467            .borrow()
 2468            .as_ref()
 2469            .map_or(false, |context| {
 2470                matches!(context, CodeContextMenu::Completions(_))
 2471            });
 2472
 2473        showing_completions
 2474            || self.edit_prediction_requires_modifier()
 2475            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2476            // bindings to insert tab characters.
 2477            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2478    }
 2479
 2480    pub fn accept_edit_prediction_keybind(
 2481        &self,
 2482        accept_partial: bool,
 2483        window: &Window,
 2484        cx: &App,
 2485    ) -> AcceptEditPredictionBinding {
 2486        let key_context = self.key_context_internal(true, window, cx);
 2487        let in_conflict = self.edit_prediction_in_conflict();
 2488
 2489        let bindings = if accept_partial {
 2490            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2491        } else {
 2492            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2493        };
 2494
 2495        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2496        // just the first one.
 2497        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2498            !in_conflict
 2499                || binding
 2500                    .keystrokes()
 2501                    .first()
 2502                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2503        }))
 2504    }
 2505
 2506    pub fn new_file(
 2507        workspace: &mut Workspace,
 2508        _: &workspace::NewFile,
 2509        window: &mut Window,
 2510        cx: &mut Context<Workspace>,
 2511    ) {
 2512        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2513            "Failed to create buffer",
 2514            window,
 2515            cx,
 2516            |e, _, _| match e.error_code() {
 2517                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2518                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2519                e.error_tag("required").unwrap_or("the latest version")
 2520            )),
 2521                _ => None,
 2522            },
 2523        );
 2524    }
 2525
 2526    pub fn new_in_workspace(
 2527        workspace: &mut Workspace,
 2528        window: &mut Window,
 2529        cx: &mut Context<Workspace>,
 2530    ) -> Task<Result<Entity<Editor>>> {
 2531        let project = workspace.project().clone();
 2532        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2533
 2534        cx.spawn_in(window, async move |workspace, cx| {
 2535            let buffer = create.await?;
 2536            workspace.update_in(cx, |workspace, window, cx| {
 2537                let editor =
 2538                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2539                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2540                editor
 2541            })
 2542        })
 2543    }
 2544
 2545    fn new_file_vertical(
 2546        workspace: &mut Workspace,
 2547        _: &workspace::NewFileSplitVertical,
 2548        window: &mut Window,
 2549        cx: &mut Context<Workspace>,
 2550    ) {
 2551        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2552    }
 2553
 2554    fn new_file_horizontal(
 2555        workspace: &mut Workspace,
 2556        _: &workspace::NewFileSplitHorizontal,
 2557        window: &mut Window,
 2558        cx: &mut Context<Workspace>,
 2559    ) {
 2560        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2561    }
 2562
 2563    fn new_file_in_direction(
 2564        workspace: &mut Workspace,
 2565        direction: SplitDirection,
 2566        window: &mut Window,
 2567        cx: &mut Context<Workspace>,
 2568    ) {
 2569        let project = workspace.project().clone();
 2570        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2571
 2572        cx.spawn_in(window, async move |workspace, cx| {
 2573            let buffer = create.await?;
 2574            workspace.update_in(cx, move |workspace, window, cx| {
 2575                workspace.split_item(
 2576                    direction,
 2577                    Box::new(
 2578                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2579                    ),
 2580                    window,
 2581                    cx,
 2582                )
 2583            })?;
 2584            anyhow::Ok(())
 2585        })
 2586        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2587            match e.error_code() {
 2588                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2589                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2590                e.error_tag("required").unwrap_or("the latest version")
 2591            )),
 2592                _ => None,
 2593            }
 2594        });
 2595    }
 2596
 2597    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2598        self.leader_id
 2599    }
 2600
 2601    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2602        &self.buffer
 2603    }
 2604
 2605    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2606        self.workspace.as_ref()?.0.upgrade()
 2607    }
 2608
 2609    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2610        self.buffer().read(cx).title(cx)
 2611    }
 2612
 2613    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2614        let git_blame_gutter_max_author_length = self
 2615            .render_git_blame_gutter(cx)
 2616            .then(|| {
 2617                if let Some(blame) = self.blame.as_ref() {
 2618                    let max_author_length =
 2619                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2620                    Some(max_author_length)
 2621                } else {
 2622                    None
 2623                }
 2624            })
 2625            .flatten();
 2626
 2627        EditorSnapshot {
 2628            mode: self.mode.clone(),
 2629            show_gutter: self.show_gutter,
 2630            show_line_numbers: self.show_line_numbers,
 2631            show_git_diff_gutter: self.show_git_diff_gutter,
 2632            show_code_actions: self.show_code_actions,
 2633            show_runnables: self.show_runnables,
 2634            show_breakpoints: self.show_breakpoints,
 2635            git_blame_gutter_max_author_length,
 2636            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2637            scroll_anchor: self.scroll_manager.anchor(),
 2638            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2639            placeholder_text: self.placeholder_text.clone(),
 2640            is_focused: self.focus_handle.is_focused(window),
 2641            current_line_highlight: self
 2642                .current_line_highlight
 2643                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2644            gutter_hovered: self.gutter_hovered,
 2645        }
 2646    }
 2647
 2648    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2649        self.buffer.read(cx).language_at(point, cx)
 2650    }
 2651
 2652    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2653        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2654    }
 2655
 2656    pub fn active_excerpt(
 2657        &self,
 2658        cx: &App,
 2659    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2660        self.buffer
 2661            .read(cx)
 2662            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2663    }
 2664
 2665    pub fn mode(&self) -> &EditorMode {
 2666        &self.mode
 2667    }
 2668
 2669    pub fn set_mode(&mut self, mode: EditorMode) {
 2670        self.mode = mode;
 2671    }
 2672
 2673    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2674        self.collaboration_hub.as_deref()
 2675    }
 2676
 2677    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2678        self.collaboration_hub = Some(hub);
 2679    }
 2680
 2681    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2682        self.in_project_search = in_project_search;
 2683    }
 2684
 2685    pub fn set_custom_context_menu(
 2686        &mut self,
 2687        f: impl 'static
 2688        + Fn(
 2689            &mut Self,
 2690            DisplayPoint,
 2691            &mut Window,
 2692            &mut Context<Self>,
 2693        ) -> Option<Entity<ui::ContextMenu>>,
 2694    ) {
 2695        self.custom_context_menu = Some(Box::new(f))
 2696    }
 2697
 2698    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2699        self.completion_provider = provider;
 2700    }
 2701
 2702    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2703        self.semantics_provider.clone()
 2704    }
 2705
 2706    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2707        self.semantics_provider = provider;
 2708    }
 2709
 2710    pub fn set_edit_prediction_provider<T>(
 2711        &mut self,
 2712        provider: Option<Entity<T>>,
 2713        window: &mut Window,
 2714        cx: &mut Context<Self>,
 2715    ) where
 2716        T: EditPredictionProvider,
 2717    {
 2718        self.edit_prediction_provider =
 2719            provider.map(|provider| RegisteredInlineCompletionProvider {
 2720                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2721                    if this.focus_handle.is_focused(window) {
 2722                        this.update_visible_inline_completion(window, cx);
 2723                    }
 2724                }),
 2725                provider: Arc::new(provider),
 2726            });
 2727        self.update_edit_prediction_settings(cx);
 2728        self.refresh_inline_completion(false, false, window, cx);
 2729    }
 2730
 2731    pub fn placeholder_text(&self) -> Option<&str> {
 2732        self.placeholder_text.as_deref()
 2733    }
 2734
 2735    pub fn set_placeholder_text(
 2736        &mut self,
 2737        placeholder_text: impl Into<Arc<str>>,
 2738        cx: &mut Context<Self>,
 2739    ) {
 2740        let placeholder_text = Some(placeholder_text.into());
 2741        if self.placeholder_text != placeholder_text {
 2742            self.placeholder_text = placeholder_text;
 2743            cx.notify();
 2744        }
 2745    }
 2746
 2747    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2748        self.cursor_shape = cursor_shape;
 2749
 2750        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2751        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2752
 2753        cx.notify();
 2754    }
 2755
 2756    pub fn set_current_line_highlight(
 2757        &mut self,
 2758        current_line_highlight: Option<CurrentLineHighlight>,
 2759    ) {
 2760        self.current_line_highlight = current_line_highlight;
 2761    }
 2762
 2763    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2764        self.collapse_matches = collapse_matches;
 2765    }
 2766
 2767    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2768        let buffers = self.buffer.read(cx).all_buffers();
 2769        let Some(project) = self.project.as_ref() else {
 2770            return;
 2771        };
 2772        project.update(cx, |project, cx| {
 2773            for buffer in buffers {
 2774                self.registered_buffers
 2775                    .entry(buffer.read(cx).remote_id())
 2776                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2777            }
 2778        })
 2779    }
 2780
 2781    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2782        if self.collapse_matches {
 2783            return range.start..range.start;
 2784        }
 2785        range.clone()
 2786    }
 2787
 2788    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2789        if self.display_map.read(cx).clip_at_line_ends != clip {
 2790            self.display_map
 2791                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2792        }
 2793    }
 2794
 2795    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2796        self.input_enabled = input_enabled;
 2797    }
 2798
 2799    pub fn set_inline_completions_hidden_for_vim_mode(
 2800        &mut self,
 2801        hidden: bool,
 2802        window: &mut Window,
 2803        cx: &mut Context<Self>,
 2804    ) {
 2805        if hidden != self.inline_completions_hidden_for_vim_mode {
 2806            self.inline_completions_hidden_for_vim_mode = hidden;
 2807            if hidden {
 2808                self.update_visible_inline_completion(window, cx);
 2809            } else {
 2810                self.refresh_inline_completion(true, false, window, cx);
 2811            }
 2812        }
 2813    }
 2814
 2815    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2816        self.menu_inline_completions_policy = value;
 2817    }
 2818
 2819    pub fn set_autoindent(&mut self, autoindent: bool) {
 2820        if autoindent {
 2821            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2822        } else {
 2823            self.autoindent_mode = None;
 2824        }
 2825    }
 2826
 2827    pub fn read_only(&self, cx: &App) -> bool {
 2828        self.read_only || self.buffer.read(cx).read_only()
 2829    }
 2830
 2831    pub fn set_read_only(&mut self, read_only: bool) {
 2832        self.read_only = read_only;
 2833    }
 2834
 2835    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2836        self.use_autoclose = autoclose;
 2837    }
 2838
 2839    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2840        self.use_auto_surround = auto_surround;
 2841    }
 2842
 2843    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2844        self.auto_replace_emoji_shortcode = auto_replace;
 2845    }
 2846
 2847    pub fn toggle_edit_predictions(
 2848        &mut self,
 2849        _: &ToggleEditPrediction,
 2850        window: &mut Window,
 2851        cx: &mut Context<Self>,
 2852    ) {
 2853        if self.show_inline_completions_override.is_some() {
 2854            self.set_show_edit_predictions(None, window, cx);
 2855        } else {
 2856            let show_edit_predictions = !self.edit_predictions_enabled();
 2857            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2858        }
 2859    }
 2860
 2861    pub fn set_show_edit_predictions(
 2862        &mut self,
 2863        show_edit_predictions: Option<bool>,
 2864        window: &mut Window,
 2865        cx: &mut Context<Self>,
 2866    ) {
 2867        self.show_inline_completions_override = show_edit_predictions;
 2868        self.update_edit_prediction_settings(cx);
 2869
 2870        if let Some(false) = show_edit_predictions {
 2871            self.discard_inline_completion(false, cx);
 2872        } else {
 2873            self.refresh_inline_completion(false, true, window, cx);
 2874        }
 2875    }
 2876
 2877    fn inline_completions_disabled_in_scope(
 2878        &self,
 2879        buffer: &Entity<Buffer>,
 2880        buffer_position: language::Anchor,
 2881        cx: &App,
 2882    ) -> bool {
 2883        let snapshot = buffer.read(cx).snapshot();
 2884        let settings = snapshot.settings_at(buffer_position, cx);
 2885
 2886        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2887            return false;
 2888        };
 2889
 2890        scope.override_name().map_or(false, |scope_name| {
 2891            settings
 2892                .edit_predictions_disabled_in
 2893                .iter()
 2894                .any(|s| s == scope_name)
 2895        })
 2896    }
 2897
 2898    pub fn set_use_modal_editing(&mut self, to: bool) {
 2899        self.use_modal_editing = to;
 2900    }
 2901
 2902    pub fn use_modal_editing(&self) -> bool {
 2903        self.use_modal_editing
 2904    }
 2905
 2906    fn selections_did_change(
 2907        &mut self,
 2908        local: bool,
 2909        old_cursor_position: &Anchor,
 2910        effects: SelectionEffects,
 2911        window: &mut Window,
 2912        cx: &mut Context<Self>,
 2913    ) {
 2914        window.invalidate_character_coordinates();
 2915
 2916        // Copy selections to primary selection buffer
 2917        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2918        if local {
 2919            let selections = self.selections.all::<usize>(cx);
 2920            let buffer_handle = self.buffer.read(cx).read(cx);
 2921
 2922            let mut text = String::new();
 2923            for (index, selection) in selections.iter().enumerate() {
 2924                let text_for_selection = buffer_handle
 2925                    .text_for_range(selection.start..selection.end)
 2926                    .collect::<String>();
 2927
 2928                text.push_str(&text_for_selection);
 2929                if index != selections.len() - 1 {
 2930                    text.push('\n');
 2931                }
 2932            }
 2933
 2934            if !text.is_empty() {
 2935                cx.write_to_primary(ClipboardItem::new_string(text));
 2936            }
 2937        }
 2938
 2939        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2940            self.buffer.update(cx, |buffer, cx| {
 2941                buffer.set_active_selections(
 2942                    &self.selections.disjoint_anchors(),
 2943                    self.selections.line_mode,
 2944                    self.cursor_shape,
 2945                    cx,
 2946                )
 2947            });
 2948        }
 2949        let display_map = self
 2950            .display_map
 2951            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2952        let buffer = &display_map.buffer_snapshot;
 2953        if self.selections.count() == 1 {
 2954            self.add_selections_state = None;
 2955        }
 2956        self.select_next_state = None;
 2957        self.select_prev_state = None;
 2958        self.select_syntax_node_history.try_clear();
 2959        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2960        self.snippet_stack
 2961            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2962        self.take_rename(false, window, cx);
 2963
 2964        let newest_selection = self.selections.newest_anchor();
 2965        let new_cursor_position = newest_selection.head();
 2966        let selection_start = newest_selection.start;
 2967
 2968        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2969            self.push_to_nav_history(
 2970                *old_cursor_position,
 2971                Some(new_cursor_position.to_point(buffer)),
 2972                false,
 2973                effects.nav_history == Some(true),
 2974                cx,
 2975            );
 2976        }
 2977
 2978        if local {
 2979            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2980                if !self.registered_buffers.contains_key(&buffer_id) {
 2981                    if let Some(project) = self.project.as_ref() {
 2982                        project.update(cx, |project, cx| {
 2983                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2984                                return;
 2985                            };
 2986                            self.registered_buffers.insert(
 2987                                buffer_id,
 2988                                project.register_buffer_with_language_servers(&buffer, cx),
 2989                            );
 2990                        })
 2991                    }
 2992                }
 2993            }
 2994
 2995            let mut context_menu = self.context_menu.borrow_mut();
 2996            let completion_menu = match context_menu.as_ref() {
 2997                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2998                Some(CodeContextMenu::CodeActions(_)) => {
 2999                    *context_menu = None;
 3000                    None
 3001                }
 3002                None => None,
 3003            };
 3004            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3005            drop(context_menu);
 3006
 3007            if effects.completions {
 3008                if let Some(completion_position) = completion_position {
 3009                    let start_offset = selection_start.to_offset(buffer);
 3010                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3011                    let continue_showing = if position_matches {
 3012                        if self.snippet_stack.is_empty() {
 3013                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3014                        } else {
 3015                            // Snippet choices can be shown even when the cursor is in whitespace.
 3016                            // Dismissing the menu with actions like backspace is handled by
 3017                            // invalidation regions.
 3018                            true
 3019                        }
 3020                    } else {
 3021                        false
 3022                    };
 3023
 3024                    if continue_showing {
 3025                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3026                    } else {
 3027                        self.hide_context_menu(window, cx);
 3028                    }
 3029                }
 3030            }
 3031
 3032            hide_hover(self, cx);
 3033
 3034            if old_cursor_position.to_display_point(&display_map).row()
 3035                != new_cursor_position.to_display_point(&display_map).row()
 3036            {
 3037                self.available_code_actions.take();
 3038            }
 3039            self.refresh_code_actions(window, cx);
 3040            self.refresh_document_highlights(cx);
 3041            self.refresh_selected_text_highlights(false, window, cx);
 3042            refresh_matching_bracket_highlights(self, window, cx);
 3043            self.update_visible_inline_completion(window, cx);
 3044            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3045            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3046            self.inline_blame_popover.take();
 3047            if self.git_blame_inline_enabled {
 3048                self.start_inline_blame_timer(window, cx);
 3049            }
 3050        }
 3051
 3052        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3053        cx.emit(EditorEvent::SelectionsChanged { local });
 3054
 3055        let selections = &self.selections.disjoint;
 3056        if selections.len() == 1 {
 3057            cx.emit(SearchEvent::ActiveMatchChanged)
 3058        }
 3059        if local {
 3060            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3061                let inmemory_selections = selections
 3062                    .iter()
 3063                    .map(|s| {
 3064                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3065                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3066                    })
 3067                    .collect();
 3068                self.update_restoration_data(cx, |data| {
 3069                    data.selections = inmemory_selections;
 3070                });
 3071
 3072                if WorkspaceSettings::get(None, cx).restore_on_startup
 3073                    != RestoreOnStartupBehavior::None
 3074                {
 3075                    if let Some(workspace_id) =
 3076                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3077                    {
 3078                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3079                        let selections = selections.clone();
 3080                        let background_executor = cx.background_executor().clone();
 3081                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3082                        self.serialize_selections = cx.background_spawn(async move {
 3083                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3084                            let db_selections = selections
 3085                                .iter()
 3086                                .map(|selection| {
 3087                                    (
 3088                                        selection.start.to_offset(&snapshot),
 3089                                        selection.end.to_offset(&snapshot),
 3090                                    )
 3091                                })
 3092                                .collect();
 3093
 3094                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3095                                .await
 3096                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3097                                .log_err();
 3098                        });
 3099                    }
 3100                }
 3101            }
 3102        }
 3103
 3104        cx.notify();
 3105    }
 3106
 3107    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3108        use text::ToOffset as _;
 3109        use text::ToPoint as _;
 3110
 3111        if self.mode.is_minimap()
 3112            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3113        {
 3114            return;
 3115        }
 3116
 3117        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3118            return;
 3119        };
 3120
 3121        let snapshot = singleton.read(cx).snapshot();
 3122        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3123            let display_snapshot = display_map.snapshot(cx);
 3124
 3125            display_snapshot
 3126                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3127                .map(|fold| {
 3128                    fold.range.start.text_anchor.to_point(&snapshot)
 3129                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3130                })
 3131                .collect()
 3132        });
 3133        self.update_restoration_data(cx, |data| {
 3134            data.folds = inmemory_folds;
 3135        });
 3136
 3137        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3138            return;
 3139        };
 3140        let background_executor = cx.background_executor().clone();
 3141        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3142        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3143            display_map
 3144                .snapshot(cx)
 3145                .folds_in_range(0..snapshot.len())
 3146                .map(|fold| {
 3147                    (
 3148                        fold.range.start.text_anchor.to_offset(&snapshot),
 3149                        fold.range.end.text_anchor.to_offset(&snapshot),
 3150                    )
 3151                })
 3152                .collect()
 3153        });
 3154        self.serialize_folds = cx.background_spawn(async move {
 3155            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3156            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3157                .await
 3158                .with_context(|| {
 3159                    format!(
 3160                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3161                    )
 3162                })
 3163                .log_err();
 3164        });
 3165    }
 3166
 3167    pub fn sync_selections(
 3168        &mut self,
 3169        other: Entity<Editor>,
 3170        cx: &mut Context<Self>,
 3171    ) -> gpui::Subscription {
 3172        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3173        self.selections.change_with(cx, |selections| {
 3174            selections.select_anchors(other_selections);
 3175        });
 3176
 3177        let other_subscription =
 3178            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3179                EditorEvent::SelectionsChanged { local: true } => {
 3180                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3181                    if other_selections.is_empty() {
 3182                        return;
 3183                    }
 3184                    this.selections.change_with(cx, |selections| {
 3185                        selections.select_anchors(other_selections);
 3186                    });
 3187                }
 3188                _ => {}
 3189            });
 3190
 3191        let this_subscription =
 3192            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3193                EditorEvent::SelectionsChanged { local: true } => {
 3194                    let these_selections = this.selections.disjoint.to_vec();
 3195                    if these_selections.is_empty() {
 3196                        return;
 3197                    }
 3198                    other.update(cx, |other_editor, cx| {
 3199                        other_editor.selections.change_with(cx, |selections| {
 3200                            selections.select_anchors(these_selections);
 3201                        })
 3202                    });
 3203                }
 3204                _ => {}
 3205            });
 3206
 3207        Subscription::join(other_subscription, this_subscription)
 3208    }
 3209
 3210    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3211    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3212    /// effects of selection change occur at the end of the transaction.
 3213    pub fn change_selections<R>(
 3214        &mut self,
 3215        effects: SelectionEffects,
 3216        window: &mut Window,
 3217        cx: &mut Context<Self>,
 3218        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3219    ) -> R {
 3220        if let Some(state) = &mut self.deferred_selection_effects_state {
 3221            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3222            state.effects.completions = effects.completions;
 3223            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3224            let (changed, result) = self.selections.change_with(cx, change);
 3225            state.changed |= changed;
 3226            return result;
 3227        }
 3228        let mut state = DeferredSelectionEffectsState {
 3229            changed: false,
 3230            effects,
 3231            old_cursor_position: self.selections.newest_anchor().head(),
 3232            history_entry: SelectionHistoryEntry {
 3233                selections: self.selections.disjoint_anchors(),
 3234                select_next_state: self.select_next_state.clone(),
 3235                select_prev_state: self.select_prev_state.clone(),
 3236                add_selections_state: self.add_selections_state.clone(),
 3237            },
 3238        };
 3239        let (changed, result) = self.selections.change_with(cx, change);
 3240        state.changed = state.changed || changed;
 3241        if self.defer_selection_effects {
 3242            self.deferred_selection_effects_state = Some(state);
 3243        } else {
 3244            self.apply_selection_effects(state, window, cx);
 3245        }
 3246        result
 3247    }
 3248
 3249    /// Defers the effects of selection change, so that the effects of multiple calls to
 3250    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3251    /// to selection history and the state of popovers based on selection position aren't
 3252    /// erroneously updated.
 3253    pub fn with_selection_effects_deferred<R>(
 3254        &mut self,
 3255        window: &mut Window,
 3256        cx: &mut Context<Self>,
 3257        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3258    ) -> R {
 3259        let already_deferred = self.defer_selection_effects;
 3260        self.defer_selection_effects = true;
 3261        let result = update(self, window, cx);
 3262        if !already_deferred {
 3263            self.defer_selection_effects = false;
 3264            if let Some(state) = self.deferred_selection_effects_state.take() {
 3265                self.apply_selection_effects(state, window, cx);
 3266            }
 3267        }
 3268        result
 3269    }
 3270
 3271    fn apply_selection_effects(
 3272        &mut self,
 3273        state: DeferredSelectionEffectsState,
 3274        window: &mut Window,
 3275        cx: &mut Context<Self>,
 3276    ) {
 3277        if state.changed {
 3278            self.selection_history.push(state.history_entry);
 3279
 3280            if let Some(autoscroll) = state.effects.scroll {
 3281                self.request_autoscroll(autoscroll, cx);
 3282            }
 3283
 3284            let old_cursor_position = &state.old_cursor_position;
 3285
 3286            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3287
 3288            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3289                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3290            }
 3291        }
 3292    }
 3293
 3294    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3295    where
 3296        I: IntoIterator<Item = (Range<S>, T)>,
 3297        S: ToOffset,
 3298        T: Into<Arc<str>>,
 3299    {
 3300        if self.read_only(cx) {
 3301            return;
 3302        }
 3303
 3304        self.buffer
 3305            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3306    }
 3307
 3308    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3309    where
 3310        I: IntoIterator<Item = (Range<S>, T)>,
 3311        S: ToOffset,
 3312        T: Into<Arc<str>>,
 3313    {
 3314        if self.read_only(cx) {
 3315            return;
 3316        }
 3317
 3318        self.buffer.update(cx, |buffer, cx| {
 3319            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3320        });
 3321    }
 3322
 3323    pub fn edit_with_block_indent<I, S, T>(
 3324        &mut self,
 3325        edits: I,
 3326        original_indent_columns: Vec<Option<u32>>,
 3327        cx: &mut Context<Self>,
 3328    ) where
 3329        I: IntoIterator<Item = (Range<S>, T)>,
 3330        S: ToOffset,
 3331        T: Into<Arc<str>>,
 3332    {
 3333        if self.read_only(cx) {
 3334            return;
 3335        }
 3336
 3337        self.buffer.update(cx, |buffer, cx| {
 3338            buffer.edit(
 3339                edits,
 3340                Some(AutoindentMode::Block {
 3341                    original_indent_columns,
 3342                }),
 3343                cx,
 3344            )
 3345        });
 3346    }
 3347
 3348    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3349        self.hide_context_menu(window, cx);
 3350
 3351        match phase {
 3352            SelectPhase::Begin {
 3353                position,
 3354                add,
 3355                click_count,
 3356            } => self.begin_selection(position, add, click_count, window, cx),
 3357            SelectPhase::BeginColumnar {
 3358                position,
 3359                goal_column,
 3360                reset,
 3361                mode,
 3362            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3363            SelectPhase::Extend {
 3364                position,
 3365                click_count,
 3366            } => self.extend_selection(position, click_count, window, cx),
 3367            SelectPhase::Update {
 3368                position,
 3369                goal_column,
 3370                scroll_delta,
 3371            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3372            SelectPhase::End => self.end_selection(window, cx),
 3373        }
 3374    }
 3375
 3376    fn extend_selection(
 3377        &mut self,
 3378        position: DisplayPoint,
 3379        click_count: usize,
 3380        window: &mut Window,
 3381        cx: &mut Context<Self>,
 3382    ) {
 3383        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3384        let tail = self.selections.newest::<usize>(cx).tail();
 3385        self.begin_selection(position, false, click_count, window, cx);
 3386
 3387        let position = position.to_offset(&display_map, Bias::Left);
 3388        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3389
 3390        let mut pending_selection = self
 3391            .selections
 3392            .pending_anchor()
 3393            .expect("extend_selection not called with pending selection");
 3394        if position >= tail {
 3395            pending_selection.start = tail_anchor;
 3396        } else {
 3397            pending_selection.end = tail_anchor;
 3398            pending_selection.reversed = true;
 3399        }
 3400
 3401        let mut pending_mode = self.selections.pending_mode().unwrap();
 3402        match &mut pending_mode {
 3403            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3404            _ => {}
 3405        }
 3406
 3407        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3408            SelectionEffects::scroll(Autoscroll::fit())
 3409        } else {
 3410            SelectionEffects::no_scroll()
 3411        };
 3412
 3413        self.change_selections(effects, window, cx, |s| {
 3414            s.set_pending(pending_selection, pending_mode)
 3415        });
 3416    }
 3417
 3418    fn begin_selection(
 3419        &mut self,
 3420        position: DisplayPoint,
 3421        add: bool,
 3422        click_count: usize,
 3423        window: &mut Window,
 3424        cx: &mut Context<Self>,
 3425    ) {
 3426        if !self.focus_handle.is_focused(window) {
 3427            self.last_focused_descendant = None;
 3428            window.focus(&self.focus_handle);
 3429        }
 3430
 3431        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3432        let buffer = &display_map.buffer_snapshot;
 3433        let position = display_map.clip_point(position, Bias::Left);
 3434
 3435        let start;
 3436        let end;
 3437        let mode;
 3438        let mut auto_scroll;
 3439        match click_count {
 3440            1 => {
 3441                start = buffer.anchor_before(position.to_point(&display_map));
 3442                end = start;
 3443                mode = SelectMode::Character;
 3444                auto_scroll = true;
 3445            }
 3446            2 => {
 3447                let position = display_map
 3448                    .clip_point(position, Bias::Left)
 3449                    .to_offset(&display_map, Bias::Left);
 3450                let (range, _) = buffer.surrounding_word(position, false);
 3451                start = buffer.anchor_before(range.start);
 3452                end = buffer.anchor_before(range.end);
 3453                mode = SelectMode::Word(start..end);
 3454                auto_scroll = true;
 3455            }
 3456            3 => {
 3457                let position = display_map
 3458                    .clip_point(position, Bias::Left)
 3459                    .to_point(&display_map);
 3460                let line_start = display_map.prev_line_boundary(position).0;
 3461                let next_line_start = buffer.clip_point(
 3462                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3463                    Bias::Left,
 3464                );
 3465                start = buffer.anchor_before(line_start);
 3466                end = buffer.anchor_before(next_line_start);
 3467                mode = SelectMode::Line(start..end);
 3468                auto_scroll = true;
 3469            }
 3470            _ => {
 3471                start = buffer.anchor_before(0);
 3472                end = buffer.anchor_before(buffer.len());
 3473                mode = SelectMode::All;
 3474                auto_scroll = false;
 3475            }
 3476        }
 3477        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3478
 3479        let point_to_delete: Option<usize> = {
 3480            let selected_points: Vec<Selection<Point>> =
 3481                self.selections.disjoint_in_range(start..end, cx);
 3482
 3483            if !add || click_count > 1 {
 3484                None
 3485            } else if !selected_points.is_empty() {
 3486                Some(selected_points[0].id)
 3487            } else {
 3488                let clicked_point_already_selected =
 3489                    self.selections.disjoint.iter().find(|selection| {
 3490                        selection.start.to_point(buffer) == start.to_point(buffer)
 3491                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3492                    });
 3493
 3494                clicked_point_already_selected.map(|selection| selection.id)
 3495            }
 3496        };
 3497
 3498        let selections_count = self.selections.count();
 3499        let effects = if auto_scroll {
 3500            SelectionEffects::default()
 3501        } else {
 3502            SelectionEffects::no_scroll()
 3503        };
 3504
 3505        self.change_selections(effects, window, cx, |s| {
 3506            if let Some(point_to_delete) = point_to_delete {
 3507                s.delete(point_to_delete);
 3508
 3509                if selections_count == 1 {
 3510                    s.set_pending_anchor_range(start..end, mode);
 3511                }
 3512            } else {
 3513                if !add {
 3514                    s.clear_disjoint();
 3515                }
 3516
 3517                s.set_pending_anchor_range(start..end, mode);
 3518            }
 3519        });
 3520    }
 3521
 3522    fn begin_columnar_selection(
 3523        &mut self,
 3524        position: DisplayPoint,
 3525        goal_column: u32,
 3526        reset: bool,
 3527        mode: ColumnarMode,
 3528        window: &mut Window,
 3529        cx: &mut Context<Self>,
 3530    ) {
 3531        if !self.focus_handle.is_focused(window) {
 3532            self.last_focused_descendant = None;
 3533            window.focus(&self.focus_handle);
 3534        }
 3535
 3536        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3537
 3538        if reset {
 3539            let pointer_position = display_map
 3540                .buffer_snapshot
 3541                .anchor_before(position.to_point(&display_map));
 3542
 3543            self.change_selections(
 3544                SelectionEffects::scroll(Autoscroll::newest()),
 3545                window,
 3546                cx,
 3547                |s| {
 3548                    s.clear_disjoint();
 3549                    s.set_pending_anchor_range(
 3550                        pointer_position..pointer_position,
 3551                        SelectMode::Character,
 3552                    );
 3553                },
 3554            );
 3555        };
 3556
 3557        let tail = self.selections.newest::<Point>(cx).tail();
 3558        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3559        self.columnar_selection_state = match mode {
 3560            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3561                selection_tail: selection_anchor,
 3562                display_point: if reset {
 3563                    if position.column() != goal_column {
 3564                        Some(DisplayPoint::new(position.row(), goal_column))
 3565                    } else {
 3566                        None
 3567                    }
 3568                } else {
 3569                    None
 3570                },
 3571            }),
 3572            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3573                selection_tail: selection_anchor,
 3574            }),
 3575        };
 3576
 3577        if !reset {
 3578            self.select_columns(position, goal_column, &display_map, window, cx);
 3579        }
 3580    }
 3581
 3582    fn update_selection(
 3583        &mut self,
 3584        position: DisplayPoint,
 3585        goal_column: u32,
 3586        scroll_delta: gpui::Point<f32>,
 3587        window: &mut Window,
 3588        cx: &mut Context<Self>,
 3589    ) {
 3590        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3591
 3592        if self.columnar_selection_state.is_some() {
 3593            self.select_columns(position, goal_column, &display_map, window, cx);
 3594        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3595            let buffer = &display_map.buffer_snapshot;
 3596            let head;
 3597            let tail;
 3598            let mode = self.selections.pending_mode().unwrap();
 3599            match &mode {
 3600                SelectMode::Character => {
 3601                    head = position.to_point(&display_map);
 3602                    tail = pending.tail().to_point(buffer);
 3603                }
 3604                SelectMode::Word(original_range) => {
 3605                    let offset = display_map
 3606                        .clip_point(position, Bias::Left)
 3607                        .to_offset(&display_map, Bias::Left);
 3608                    let original_range = original_range.to_offset(buffer);
 3609
 3610                    let head_offset = if buffer.is_inside_word(offset, false)
 3611                        || original_range.contains(&offset)
 3612                    {
 3613                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3614                        if word_range.start < original_range.start {
 3615                            word_range.start
 3616                        } else {
 3617                            word_range.end
 3618                        }
 3619                    } else {
 3620                        offset
 3621                    };
 3622
 3623                    head = head_offset.to_point(buffer);
 3624                    if head_offset <= original_range.start {
 3625                        tail = original_range.end.to_point(buffer);
 3626                    } else {
 3627                        tail = original_range.start.to_point(buffer);
 3628                    }
 3629                }
 3630                SelectMode::Line(original_range) => {
 3631                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3632
 3633                    let position = display_map
 3634                        .clip_point(position, Bias::Left)
 3635                        .to_point(&display_map);
 3636                    let line_start = display_map.prev_line_boundary(position).0;
 3637                    let next_line_start = buffer.clip_point(
 3638                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3639                        Bias::Left,
 3640                    );
 3641
 3642                    if line_start < original_range.start {
 3643                        head = line_start
 3644                    } else {
 3645                        head = next_line_start
 3646                    }
 3647
 3648                    if head <= original_range.start {
 3649                        tail = original_range.end;
 3650                    } else {
 3651                        tail = original_range.start;
 3652                    }
 3653                }
 3654                SelectMode::All => {
 3655                    return;
 3656                }
 3657            };
 3658
 3659            if head < tail {
 3660                pending.start = buffer.anchor_before(head);
 3661                pending.end = buffer.anchor_before(tail);
 3662                pending.reversed = true;
 3663            } else {
 3664                pending.start = buffer.anchor_before(tail);
 3665                pending.end = buffer.anchor_before(head);
 3666                pending.reversed = false;
 3667            }
 3668
 3669            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3670                s.set_pending(pending, mode);
 3671            });
 3672        } else {
 3673            log::error!("update_selection dispatched with no pending selection");
 3674            return;
 3675        }
 3676
 3677        self.apply_scroll_delta(scroll_delta, window, cx);
 3678        cx.notify();
 3679    }
 3680
 3681    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3682        self.columnar_selection_state.take();
 3683        if self.selections.pending_anchor().is_some() {
 3684            let selections = self.selections.all::<usize>(cx);
 3685            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3686                s.select(selections);
 3687                s.clear_pending();
 3688            });
 3689        }
 3690    }
 3691
 3692    fn select_columns(
 3693        &mut self,
 3694        head: DisplayPoint,
 3695        goal_column: u32,
 3696        display_map: &DisplaySnapshot,
 3697        window: &mut Window,
 3698        cx: &mut Context<Self>,
 3699    ) {
 3700        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3701            return;
 3702        };
 3703
 3704        let tail = match columnar_state {
 3705            ColumnarSelectionState::FromMouse {
 3706                selection_tail,
 3707                display_point,
 3708            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3709            ColumnarSelectionState::FromSelection { selection_tail } => {
 3710                selection_tail.to_display_point(&display_map)
 3711            }
 3712        };
 3713
 3714        let start_row = cmp::min(tail.row(), head.row());
 3715        let end_row = cmp::max(tail.row(), head.row());
 3716        let start_column = cmp::min(tail.column(), goal_column);
 3717        let end_column = cmp::max(tail.column(), goal_column);
 3718        let reversed = start_column < tail.column();
 3719
 3720        let selection_ranges = (start_row.0..=end_row.0)
 3721            .map(DisplayRow)
 3722            .filter_map(|row| {
 3723                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3724                    || start_column <= display_map.line_len(row))
 3725                    && !display_map.is_block_line(row)
 3726                {
 3727                    let start = display_map
 3728                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3729                        .to_point(display_map);
 3730                    let end = display_map
 3731                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3732                        .to_point(display_map);
 3733                    if reversed {
 3734                        Some(end..start)
 3735                    } else {
 3736                        Some(start..end)
 3737                    }
 3738                } else {
 3739                    None
 3740                }
 3741            })
 3742            .collect::<Vec<_>>();
 3743
 3744        let ranges = match columnar_state {
 3745            ColumnarSelectionState::FromMouse { .. } => {
 3746                let mut non_empty_ranges = selection_ranges
 3747                    .iter()
 3748                    .filter(|selection_range| selection_range.start != selection_range.end)
 3749                    .peekable();
 3750                if non_empty_ranges.peek().is_some() {
 3751                    non_empty_ranges.cloned().collect()
 3752                } else {
 3753                    selection_ranges
 3754                }
 3755            }
 3756            _ => selection_ranges,
 3757        };
 3758
 3759        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3760            s.select_ranges(ranges);
 3761        });
 3762        cx.notify();
 3763    }
 3764
 3765    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3766        self.selections
 3767            .all_adjusted(cx)
 3768            .iter()
 3769            .any(|selection| !selection.is_empty())
 3770    }
 3771
 3772    pub fn has_pending_nonempty_selection(&self) -> bool {
 3773        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3774            Some(Selection { start, end, .. }) => start != end,
 3775            None => false,
 3776        };
 3777
 3778        pending_nonempty_selection
 3779            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3780    }
 3781
 3782    pub fn has_pending_selection(&self) -> bool {
 3783        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3784    }
 3785
 3786    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3787        self.selection_mark_mode = false;
 3788        self.selection_drag_state = SelectionDragState::None;
 3789
 3790        if self.clear_expanded_diff_hunks(cx) {
 3791            cx.notify();
 3792            return;
 3793        }
 3794        if self.dismiss_menus_and_popups(true, window, cx) {
 3795            return;
 3796        }
 3797
 3798        if self.mode.is_full()
 3799            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3800        {
 3801            return;
 3802        }
 3803
 3804        cx.propagate();
 3805    }
 3806
 3807    pub fn dismiss_menus_and_popups(
 3808        &mut self,
 3809        is_user_requested: bool,
 3810        window: &mut Window,
 3811        cx: &mut Context<Self>,
 3812    ) -> bool {
 3813        if self.take_rename(false, window, cx).is_some() {
 3814            return true;
 3815        }
 3816
 3817        if hide_hover(self, cx) {
 3818            return true;
 3819        }
 3820
 3821        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3822            return true;
 3823        }
 3824
 3825        if self.hide_context_menu(window, cx).is_some() {
 3826            return true;
 3827        }
 3828
 3829        if self.mouse_context_menu.take().is_some() {
 3830            return true;
 3831        }
 3832
 3833        if is_user_requested && self.discard_inline_completion(true, cx) {
 3834            return true;
 3835        }
 3836
 3837        if self.snippet_stack.pop().is_some() {
 3838            return true;
 3839        }
 3840
 3841        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3842            self.dismiss_diagnostics(cx);
 3843            return true;
 3844        }
 3845
 3846        false
 3847    }
 3848
 3849    fn linked_editing_ranges_for(
 3850        &self,
 3851        selection: Range<text::Anchor>,
 3852        cx: &App,
 3853    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3854        if self.linked_edit_ranges.is_empty() {
 3855            return None;
 3856        }
 3857        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3858            selection.end.buffer_id.and_then(|end_buffer_id| {
 3859                if selection.start.buffer_id != Some(end_buffer_id) {
 3860                    return None;
 3861                }
 3862                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3863                let snapshot = buffer.read(cx).snapshot();
 3864                self.linked_edit_ranges
 3865                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3866                    .map(|ranges| (ranges, snapshot, buffer))
 3867            })?;
 3868        use text::ToOffset as TO;
 3869        // find offset from the start of current range to current cursor position
 3870        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3871
 3872        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3873        let start_difference = start_offset - start_byte_offset;
 3874        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3875        let end_difference = end_offset - start_byte_offset;
 3876        // Current range has associated linked ranges.
 3877        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3878        for range in linked_ranges.iter() {
 3879            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3880            let end_offset = start_offset + end_difference;
 3881            let start_offset = start_offset + start_difference;
 3882            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3883                continue;
 3884            }
 3885            if self.selections.disjoint_anchor_ranges().any(|s| {
 3886                if s.start.buffer_id != selection.start.buffer_id
 3887                    || s.end.buffer_id != selection.end.buffer_id
 3888                {
 3889                    return false;
 3890                }
 3891                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3892                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3893            }) {
 3894                continue;
 3895            }
 3896            let start = buffer_snapshot.anchor_after(start_offset);
 3897            let end = buffer_snapshot.anchor_after(end_offset);
 3898            linked_edits
 3899                .entry(buffer.clone())
 3900                .or_default()
 3901                .push(start..end);
 3902        }
 3903        Some(linked_edits)
 3904    }
 3905
 3906    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3907        let text: Arc<str> = text.into();
 3908
 3909        if self.read_only(cx) {
 3910            return;
 3911        }
 3912
 3913        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3914
 3915        let selections = self.selections.all_adjusted(cx);
 3916        let mut bracket_inserted = false;
 3917        let mut edits = Vec::new();
 3918        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3919        let mut new_selections = Vec::with_capacity(selections.len());
 3920        let mut new_autoclose_regions = Vec::new();
 3921        let snapshot = self.buffer.read(cx).read(cx);
 3922        let mut clear_linked_edit_ranges = false;
 3923
 3924        for (selection, autoclose_region) in
 3925            self.selections_with_autoclose_regions(selections, &snapshot)
 3926        {
 3927            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3928                // Determine if the inserted text matches the opening or closing
 3929                // bracket of any of this language's bracket pairs.
 3930                let mut bracket_pair = None;
 3931                let mut is_bracket_pair_start = false;
 3932                let mut is_bracket_pair_end = false;
 3933                if !text.is_empty() {
 3934                    let mut bracket_pair_matching_end = None;
 3935                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3936                    //  and they are removing the character that triggered IME popup.
 3937                    for (pair, enabled) in scope.brackets() {
 3938                        if !pair.close && !pair.surround {
 3939                            continue;
 3940                        }
 3941
 3942                        if enabled && pair.start.ends_with(text.as_ref()) {
 3943                            let prefix_len = pair.start.len() - text.len();
 3944                            let preceding_text_matches_prefix = prefix_len == 0
 3945                                || (selection.start.column >= (prefix_len as u32)
 3946                                    && snapshot.contains_str_at(
 3947                                        Point::new(
 3948                                            selection.start.row,
 3949                                            selection.start.column - (prefix_len as u32),
 3950                                        ),
 3951                                        &pair.start[..prefix_len],
 3952                                    ));
 3953                            if preceding_text_matches_prefix {
 3954                                bracket_pair = Some(pair.clone());
 3955                                is_bracket_pair_start = true;
 3956                                break;
 3957                            }
 3958                        }
 3959                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3960                        {
 3961                            // take first bracket pair matching end, but don't break in case a later bracket
 3962                            // pair matches start
 3963                            bracket_pair_matching_end = Some(pair.clone());
 3964                        }
 3965                    }
 3966                    if let Some(end) = bracket_pair_matching_end
 3967                        && bracket_pair.is_none()
 3968                    {
 3969                        bracket_pair = Some(end);
 3970                        is_bracket_pair_end = true;
 3971                    }
 3972                }
 3973
 3974                if let Some(bracket_pair) = bracket_pair {
 3975                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3976                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3977                    let auto_surround =
 3978                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3979                    if selection.is_empty() {
 3980                        if is_bracket_pair_start {
 3981                            // If the inserted text is a suffix of an opening bracket and the
 3982                            // selection is preceded by the rest of the opening bracket, then
 3983                            // insert the closing bracket.
 3984                            let following_text_allows_autoclose = snapshot
 3985                                .chars_at(selection.start)
 3986                                .next()
 3987                                .map_or(true, |c| scope.should_autoclose_before(c));
 3988
 3989                            let preceding_text_allows_autoclose = selection.start.column == 0
 3990                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3991                                    true,
 3992                                    |c| {
 3993                                        bracket_pair.start != bracket_pair.end
 3994                                            || !snapshot
 3995                                                .char_classifier_at(selection.start)
 3996                                                .is_word(c)
 3997                                    },
 3998                                );
 3999
 4000                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4001                                && bracket_pair.start.len() == 1
 4002                            {
 4003                                let target = bracket_pair.start.chars().next().unwrap();
 4004                                let current_line_count = snapshot
 4005                                    .reversed_chars_at(selection.start)
 4006                                    .take_while(|&c| c != '\n')
 4007                                    .filter(|&c| c == target)
 4008                                    .count();
 4009                                current_line_count % 2 == 1
 4010                            } else {
 4011                                false
 4012                            };
 4013
 4014                            if autoclose
 4015                                && bracket_pair.close
 4016                                && following_text_allows_autoclose
 4017                                && preceding_text_allows_autoclose
 4018                                && !is_closing_quote
 4019                            {
 4020                                let anchor = snapshot.anchor_before(selection.end);
 4021                                new_selections.push((selection.map(|_| anchor), text.len()));
 4022                                new_autoclose_regions.push((
 4023                                    anchor,
 4024                                    text.len(),
 4025                                    selection.id,
 4026                                    bracket_pair.clone(),
 4027                                ));
 4028                                edits.push((
 4029                                    selection.range(),
 4030                                    format!("{}{}", text, bracket_pair.end).into(),
 4031                                ));
 4032                                bracket_inserted = true;
 4033                                continue;
 4034                            }
 4035                        }
 4036
 4037                        if let Some(region) = autoclose_region {
 4038                            // If the selection is followed by an auto-inserted closing bracket,
 4039                            // then don't insert that closing bracket again; just move the selection
 4040                            // past the closing bracket.
 4041                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4042                                && text.as_ref() == region.pair.end.as_str();
 4043                            if should_skip {
 4044                                let anchor = snapshot.anchor_after(selection.end);
 4045                                new_selections
 4046                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4047                                continue;
 4048                            }
 4049                        }
 4050
 4051                        let always_treat_brackets_as_autoclosed = snapshot
 4052                            .language_settings_at(selection.start, cx)
 4053                            .always_treat_brackets_as_autoclosed;
 4054                        if always_treat_brackets_as_autoclosed
 4055                            && is_bracket_pair_end
 4056                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4057                        {
 4058                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4059                            // and the inserted text is a closing bracket and the selection is followed
 4060                            // by the closing bracket then move the selection past the closing bracket.
 4061                            let anchor = snapshot.anchor_after(selection.end);
 4062                            new_selections.push((selection.map(|_| anchor), text.len()));
 4063                            continue;
 4064                        }
 4065                    }
 4066                    // If an opening bracket is 1 character long and is typed while
 4067                    // text is selected, then surround that text with the bracket pair.
 4068                    else if auto_surround
 4069                        && bracket_pair.surround
 4070                        && is_bracket_pair_start
 4071                        && bracket_pair.start.chars().count() == 1
 4072                    {
 4073                        edits.push((selection.start..selection.start, text.clone()));
 4074                        edits.push((
 4075                            selection.end..selection.end,
 4076                            bracket_pair.end.as_str().into(),
 4077                        ));
 4078                        bracket_inserted = true;
 4079                        new_selections.push((
 4080                            Selection {
 4081                                id: selection.id,
 4082                                start: snapshot.anchor_after(selection.start),
 4083                                end: snapshot.anchor_before(selection.end),
 4084                                reversed: selection.reversed,
 4085                                goal: selection.goal,
 4086                            },
 4087                            0,
 4088                        ));
 4089                        continue;
 4090                    }
 4091                }
 4092            }
 4093
 4094            if self.auto_replace_emoji_shortcode
 4095                && selection.is_empty()
 4096                && text.as_ref().ends_with(':')
 4097            {
 4098                if let Some(possible_emoji_short_code) =
 4099                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4100                {
 4101                    if !possible_emoji_short_code.is_empty() {
 4102                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4103                            let emoji_shortcode_start = Point::new(
 4104                                selection.start.row,
 4105                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4106                            );
 4107
 4108                            // Remove shortcode from buffer
 4109                            edits.push((
 4110                                emoji_shortcode_start..selection.start,
 4111                                "".to_string().into(),
 4112                            ));
 4113                            new_selections.push((
 4114                                Selection {
 4115                                    id: selection.id,
 4116                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4117                                    end: snapshot.anchor_before(selection.start),
 4118                                    reversed: selection.reversed,
 4119                                    goal: selection.goal,
 4120                                },
 4121                                0,
 4122                            ));
 4123
 4124                            // Insert emoji
 4125                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4126                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4127                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4128
 4129                            continue;
 4130                        }
 4131                    }
 4132                }
 4133            }
 4134
 4135            // If not handling any auto-close operation, then just replace the selected
 4136            // text with the given input and move the selection to the end of the
 4137            // newly inserted text.
 4138            let anchor = snapshot.anchor_after(selection.end);
 4139            if !self.linked_edit_ranges.is_empty() {
 4140                let start_anchor = snapshot.anchor_before(selection.start);
 4141
 4142                let is_word_char = text.chars().next().map_or(true, |char| {
 4143                    let classifier = snapshot
 4144                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4145                        .ignore_punctuation(true);
 4146                    classifier.is_word(char)
 4147                });
 4148
 4149                if is_word_char {
 4150                    if let Some(ranges) = self
 4151                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4152                    {
 4153                        for (buffer, edits) in ranges {
 4154                            linked_edits
 4155                                .entry(buffer.clone())
 4156                                .or_default()
 4157                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4158                        }
 4159                    }
 4160                } else {
 4161                    clear_linked_edit_ranges = true;
 4162                }
 4163            }
 4164
 4165            new_selections.push((selection.map(|_| anchor), 0));
 4166            edits.push((selection.start..selection.end, text.clone()));
 4167        }
 4168
 4169        drop(snapshot);
 4170
 4171        self.transact(window, cx, |this, window, cx| {
 4172            if clear_linked_edit_ranges {
 4173                this.linked_edit_ranges.clear();
 4174            }
 4175            let initial_buffer_versions =
 4176                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4177
 4178            this.buffer.update(cx, |buffer, cx| {
 4179                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4180            });
 4181            for (buffer, edits) in linked_edits {
 4182                buffer.update(cx, |buffer, cx| {
 4183                    let snapshot = buffer.snapshot();
 4184                    let edits = edits
 4185                        .into_iter()
 4186                        .map(|(range, text)| {
 4187                            use text::ToPoint as TP;
 4188                            let end_point = TP::to_point(&range.end, &snapshot);
 4189                            let start_point = TP::to_point(&range.start, &snapshot);
 4190                            (start_point..end_point, text)
 4191                        })
 4192                        .sorted_by_key(|(range, _)| range.start);
 4193                    buffer.edit(edits, None, cx);
 4194                })
 4195            }
 4196            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4197            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4198            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4199            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4200                .zip(new_selection_deltas)
 4201                .map(|(selection, delta)| Selection {
 4202                    id: selection.id,
 4203                    start: selection.start + delta,
 4204                    end: selection.end + delta,
 4205                    reversed: selection.reversed,
 4206                    goal: SelectionGoal::None,
 4207                })
 4208                .collect::<Vec<_>>();
 4209
 4210            let mut i = 0;
 4211            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4212                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4213                let start = map.buffer_snapshot.anchor_before(position);
 4214                let end = map.buffer_snapshot.anchor_after(position);
 4215                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4216                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4217                        Ordering::Less => i += 1,
 4218                        Ordering::Greater => break,
 4219                        Ordering::Equal => {
 4220                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4221                                Ordering::Less => i += 1,
 4222                                Ordering::Equal => break,
 4223                                Ordering::Greater => break,
 4224                            }
 4225                        }
 4226                    }
 4227                }
 4228                this.autoclose_regions.insert(
 4229                    i,
 4230                    AutocloseRegion {
 4231                        selection_id,
 4232                        range: start..end,
 4233                        pair,
 4234                    },
 4235                );
 4236            }
 4237
 4238            let had_active_inline_completion = this.has_active_inline_completion();
 4239            this.change_selections(
 4240                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4241                window,
 4242                cx,
 4243                |s| s.select(new_selections),
 4244            );
 4245
 4246            if !bracket_inserted {
 4247                if let Some(on_type_format_task) =
 4248                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4249                {
 4250                    on_type_format_task.detach_and_log_err(cx);
 4251                }
 4252            }
 4253
 4254            let editor_settings = EditorSettings::get_global(cx);
 4255            if bracket_inserted
 4256                && (editor_settings.auto_signature_help
 4257                    || editor_settings.show_signature_help_after_edits)
 4258            {
 4259                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4260            }
 4261
 4262            let trigger_in_words =
 4263                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4264            if this.hard_wrap.is_some() {
 4265                let latest: Range<Point> = this.selections.newest(cx).range();
 4266                if latest.is_empty()
 4267                    && this
 4268                        .buffer()
 4269                        .read(cx)
 4270                        .snapshot(cx)
 4271                        .line_len(MultiBufferRow(latest.start.row))
 4272                        == latest.start.column
 4273                {
 4274                    this.rewrap_impl(
 4275                        RewrapOptions {
 4276                            override_language_settings: true,
 4277                            preserve_existing_whitespace: true,
 4278                        },
 4279                        cx,
 4280                    )
 4281                }
 4282            }
 4283            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4284            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4285            this.refresh_inline_completion(true, false, window, cx);
 4286            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4287        });
 4288    }
 4289
 4290    fn find_possible_emoji_shortcode_at_position(
 4291        snapshot: &MultiBufferSnapshot,
 4292        position: Point,
 4293    ) -> Option<String> {
 4294        let mut chars = Vec::new();
 4295        let mut found_colon = false;
 4296        for char in snapshot.reversed_chars_at(position).take(100) {
 4297            // Found a possible emoji shortcode in the middle of the buffer
 4298            if found_colon {
 4299                if char.is_whitespace() {
 4300                    chars.reverse();
 4301                    return Some(chars.iter().collect());
 4302                }
 4303                // If the previous character is not a whitespace, we are in the middle of a word
 4304                // and we only want to complete the shortcode if the word is made up of other emojis
 4305                let mut containing_word = String::new();
 4306                for ch in snapshot
 4307                    .reversed_chars_at(position)
 4308                    .skip(chars.len() + 1)
 4309                    .take(100)
 4310                {
 4311                    if ch.is_whitespace() {
 4312                        break;
 4313                    }
 4314                    containing_word.push(ch);
 4315                }
 4316                let containing_word = containing_word.chars().rev().collect::<String>();
 4317                if util::word_consists_of_emojis(containing_word.as_str()) {
 4318                    chars.reverse();
 4319                    return Some(chars.iter().collect());
 4320                }
 4321            }
 4322
 4323            if char.is_whitespace() || !char.is_ascii() {
 4324                return None;
 4325            }
 4326            if char == ':' {
 4327                found_colon = true;
 4328            } else {
 4329                chars.push(char);
 4330            }
 4331        }
 4332        // Found a possible emoji shortcode at the beginning of the buffer
 4333        chars.reverse();
 4334        Some(chars.iter().collect())
 4335    }
 4336
 4337    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4338        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4339        self.transact(window, cx, |this, window, cx| {
 4340            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4341                let selections = this.selections.all::<usize>(cx);
 4342                let multi_buffer = this.buffer.read(cx);
 4343                let buffer = multi_buffer.snapshot(cx);
 4344                selections
 4345                    .iter()
 4346                    .map(|selection| {
 4347                        let start_point = selection.start.to_point(&buffer);
 4348                        let mut existing_indent =
 4349                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4350                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4351                        let start = selection.start;
 4352                        let end = selection.end;
 4353                        let selection_is_empty = start == end;
 4354                        let language_scope = buffer.language_scope_at(start);
 4355                        let (
 4356                            comment_delimiter,
 4357                            doc_delimiter,
 4358                            insert_extra_newline,
 4359                            indent_on_newline,
 4360                            indent_on_extra_newline,
 4361                        ) = if let Some(language) = &language_scope {
 4362                            let mut insert_extra_newline =
 4363                                insert_extra_newline_brackets(&buffer, start..end, language)
 4364                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4365
 4366                            // Comment extension on newline is allowed only for cursor selections
 4367                            let comment_delimiter = maybe!({
 4368                                if !selection_is_empty {
 4369                                    return None;
 4370                                }
 4371
 4372                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4373                                    return None;
 4374                                }
 4375
 4376                                let delimiters = language.line_comment_prefixes();
 4377                                let max_len_of_delimiter =
 4378                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4379                                let (snapshot, range) =
 4380                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4381
 4382                                let num_of_whitespaces = snapshot
 4383                                    .chars_for_range(range.clone())
 4384                                    .take_while(|c| c.is_whitespace())
 4385                                    .count();
 4386                                let comment_candidate = snapshot
 4387                                    .chars_for_range(range.clone())
 4388                                    .skip(num_of_whitespaces)
 4389                                    .take(max_len_of_delimiter)
 4390                                    .collect::<String>();
 4391                                let (delimiter, trimmed_len) = delimiters
 4392                                    .iter()
 4393                                    .filter_map(|delimiter| {
 4394                                        let prefix = delimiter.trim_end();
 4395                                        if comment_candidate.starts_with(prefix) {
 4396                                            Some((delimiter, prefix.len()))
 4397                                        } else {
 4398                                            None
 4399                                        }
 4400                                    })
 4401                                    .max_by_key(|(_, len)| *len)?;
 4402
 4403                                if let Some((block_start, _)) = language.block_comment_delimiters()
 4404                                {
 4405                                    let block_start_trimmed = block_start.trim_end();
 4406                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4407                                        let line_content = snapshot
 4408                                            .chars_for_range(range)
 4409                                            .skip(num_of_whitespaces)
 4410                                            .take(block_start_trimmed.len())
 4411                                            .collect::<String>();
 4412
 4413                                        if line_content.starts_with(block_start_trimmed) {
 4414                                            return None;
 4415                                        }
 4416                                    }
 4417                                }
 4418
 4419                                let cursor_is_placed_after_comment_marker =
 4420                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4421                                if cursor_is_placed_after_comment_marker {
 4422                                    Some(delimiter.clone())
 4423                                } else {
 4424                                    None
 4425                                }
 4426                            });
 4427
 4428                            let mut indent_on_newline = IndentSize::spaces(0);
 4429                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4430
 4431                            let doc_delimiter = maybe!({
 4432                                if !selection_is_empty {
 4433                                    return None;
 4434                                }
 4435
 4436                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4437                                    return None;
 4438                                }
 4439
 4440                                let DocumentationConfig {
 4441                                    start: start_tag,
 4442                                    end: end_tag,
 4443                                    prefix: delimiter,
 4444                                    tab_size: len,
 4445                                } = language.documentation()?;
 4446
 4447                                let is_within_block_comment = buffer
 4448                                    .language_scope_at(start_point)
 4449                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4450                                if !is_within_block_comment {
 4451                                    return None;
 4452                                }
 4453
 4454                                let (snapshot, range) =
 4455                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4456
 4457                                let num_of_whitespaces = snapshot
 4458                                    .chars_for_range(range.clone())
 4459                                    .take_while(|c| c.is_whitespace())
 4460                                    .count();
 4461
 4462                                // 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.
 4463                                let column = start_point.column;
 4464                                let cursor_is_after_start_tag = {
 4465                                    let start_tag_len = start_tag.len();
 4466                                    let start_tag_line = snapshot
 4467                                        .chars_for_range(range.clone())
 4468                                        .skip(num_of_whitespaces)
 4469                                        .take(start_tag_len)
 4470                                        .collect::<String>();
 4471                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4472                                        num_of_whitespaces + start_tag_len <= column as usize
 4473                                    } else {
 4474                                        false
 4475                                    }
 4476                                };
 4477
 4478                                let cursor_is_after_delimiter = {
 4479                                    let delimiter_trim = delimiter.trim_end();
 4480                                    let delimiter_line = snapshot
 4481                                        .chars_for_range(range.clone())
 4482                                        .skip(num_of_whitespaces)
 4483                                        .take(delimiter_trim.len())
 4484                                        .collect::<String>();
 4485                                    if delimiter_line.starts_with(delimiter_trim) {
 4486                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4487                                    } else {
 4488                                        false
 4489                                    }
 4490                                };
 4491
 4492                                let cursor_is_before_end_tag_if_exists = {
 4493                                    let mut char_position = 0u32;
 4494                                    let mut end_tag_offset = None;
 4495
 4496                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4497                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4498                                            let chars_before_match =
 4499                                                chunk[..byte_pos].chars().count() as u32;
 4500                                            end_tag_offset =
 4501                                                Some(char_position + chars_before_match);
 4502                                            break 'outer;
 4503                                        }
 4504                                        char_position += chunk.chars().count() as u32;
 4505                                    }
 4506
 4507                                    if let Some(end_tag_offset) = end_tag_offset {
 4508                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4509                                        if cursor_is_after_start_tag {
 4510                                            if cursor_is_before_end_tag {
 4511                                                insert_extra_newline = true;
 4512                                            }
 4513                                            let cursor_is_at_start_of_end_tag =
 4514                                                column == end_tag_offset;
 4515                                            if cursor_is_at_start_of_end_tag {
 4516                                                indent_on_extra_newline.len = (*len).into();
 4517                                            }
 4518                                        }
 4519                                        cursor_is_before_end_tag
 4520                                    } else {
 4521                                        true
 4522                                    }
 4523                                };
 4524
 4525                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4526                                    && cursor_is_before_end_tag_if_exists
 4527                                {
 4528                                    if cursor_is_after_start_tag {
 4529                                        indent_on_newline.len = (*len).into();
 4530                                    }
 4531                                    Some(delimiter.clone())
 4532                                } else {
 4533                                    None
 4534                                }
 4535                            });
 4536
 4537                            (
 4538                                comment_delimiter,
 4539                                doc_delimiter,
 4540                                insert_extra_newline,
 4541                                indent_on_newline,
 4542                                indent_on_extra_newline,
 4543                            )
 4544                        } else {
 4545                            (
 4546                                None,
 4547                                None,
 4548                                false,
 4549                                IndentSize::default(),
 4550                                IndentSize::default(),
 4551                            )
 4552                        };
 4553
 4554                        let prevent_auto_indent = doc_delimiter.is_some();
 4555                        let delimiter = comment_delimiter.or(doc_delimiter);
 4556
 4557                        let capacity_for_delimiter =
 4558                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4559                        let mut new_text = String::with_capacity(
 4560                            1 + capacity_for_delimiter
 4561                                + existing_indent.len as usize
 4562                                + indent_on_newline.len as usize
 4563                                + indent_on_extra_newline.len as usize,
 4564                        );
 4565                        new_text.push('\n');
 4566                        new_text.extend(existing_indent.chars());
 4567                        new_text.extend(indent_on_newline.chars());
 4568
 4569                        if let Some(delimiter) = &delimiter {
 4570                            new_text.push_str(delimiter);
 4571                        }
 4572
 4573                        if insert_extra_newline {
 4574                            new_text.push('\n');
 4575                            new_text.extend(existing_indent.chars());
 4576                            new_text.extend(indent_on_extra_newline.chars());
 4577                        }
 4578
 4579                        let anchor = buffer.anchor_after(end);
 4580                        let new_selection = selection.map(|_| anchor);
 4581                        (
 4582                            ((start..end, new_text), prevent_auto_indent),
 4583                            (insert_extra_newline, new_selection),
 4584                        )
 4585                    })
 4586                    .unzip()
 4587            };
 4588
 4589            let mut auto_indent_edits = Vec::new();
 4590            let mut edits = Vec::new();
 4591            for (edit, prevent_auto_indent) in edits_with_flags {
 4592                if prevent_auto_indent {
 4593                    edits.push(edit);
 4594                } else {
 4595                    auto_indent_edits.push(edit);
 4596                }
 4597            }
 4598            if !edits.is_empty() {
 4599                this.edit(edits, cx);
 4600            }
 4601            if !auto_indent_edits.is_empty() {
 4602                this.edit_with_autoindent(auto_indent_edits, cx);
 4603            }
 4604
 4605            let buffer = this.buffer.read(cx).snapshot(cx);
 4606            let new_selections = selection_info
 4607                .into_iter()
 4608                .map(|(extra_newline_inserted, new_selection)| {
 4609                    let mut cursor = new_selection.end.to_point(&buffer);
 4610                    if extra_newline_inserted {
 4611                        cursor.row -= 1;
 4612                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4613                    }
 4614                    new_selection.map(|_| cursor)
 4615                })
 4616                .collect();
 4617
 4618            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4619            this.refresh_inline_completion(true, false, window, cx);
 4620        });
 4621    }
 4622
 4623    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4624        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4625
 4626        let buffer = self.buffer.read(cx);
 4627        let snapshot = buffer.snapshot(cx);
 4628
 4629        let mut edits = Vec::new();
 4630        let mut rows = Vec::new();
 4631
 4632        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4633            let cursor = selection.head();
 4634            let row = cursor.row;
 4635
 4636            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4637
 4638            let newline = "\n".to_string();
 4639            edits.push((start_of_line..start_of_line, newline));
 4640
 4641            rows.push(row + rows_inserted as u32);
 4642        }
 4643
 4644        self.transact(window, cx, |editor, window, cx| {
 4645            editor.edit(edits, cx);
 4646
 4647            editor.change_selections(Default::default(), window, cx, |s| {
 4648                let mut index = 0;
 4649                s.move_cursors_with(|map, _, _| {
 4650                    let row = rows[index];
 4651                    index += 1;
 4652
 4653                    let point = Point::new(row, 0);
 4654                    let boundary = map.next_line_boundary(point).1;
 4655                    let clipped = map.clip_point(boundary, Bias::Left);
 4656
 4657                    (clipped, SelectionGoal::None)
 4658                });
 4659            });
 4660
 4661            let mut indent_edits = Vec::new();
 4662            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4663            for row in rows {
 4664                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4665                for (row, indent) in indents {
 4666                    if indent.len == 0 {
 4667                        continue;
 4668                    }
 4669
 4670                    let text = match indent.kind {
 4671                        IndentKind::Space => " ".repeat(indent.len as usize),
 4672                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4673                    };
 4674                    let point = Point::new(row.0, 0);
 4675                    indent_edits.push((point..point, text));
 4676                }
 4677            }
 4678            editor.edit(indent_edits, cx);
 4679        });
 4680    }
 4681
 4682    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4683        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4684
 4685        let buffer = self.buffer.read(cx);
 4686        let snapshot = buffer.snapshot(cx);
 4687
 4688        let mut edits = Vec::new();
 4689        let mut rows = Vec::new();
 4690        let mut rows_inserted = 0;
 4691
 4692        for selection in self.selections.all_adjusted(cx) {
 4693            let cursor = selection.head();
 4694            let row = cursor.row;
 4695
 4696            let point = Point::new(row + 1, 0);
 4697            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4698
 4699            let newline = "\n".to_string();
 4700            edits.push((start_of_line..start_of_line, newline));
 4701
 4702            rows_inserted += 1;
 4703            rows.push(row + rows_inserted);
 4704        }
 4705
 4706        self.transact(window, cx, |editor, window, cx| {
 4707            editor.edit(edits, cx);
 4708
 4709            editor.change_selections(Default::default(), window, cx, |s| {
 4710                let mut index = 0;
 4711                s.move_cursors_with(|map, _, _| {
 4712                    let row = rows[index];
 4713                    index += 1;
 4714
 4715                    let point = Point::new(row, 0);
 4716                    let boundary = map.next_line_boundary(point).1;
 4717                    let clipped = map.clip_point(boundary, Bias::Left);
 4718
 4719                    (clipped, SelectionGoal::None)
 4720                });
 4721            });
 4722
 4723            let mut indent_edits = Vec::new();
 4724            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4725            for row in rows {
 4726                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4727                for (row, indent) in indents {
 4728                    if indent.len == 0 {
 4729                        continue;
 4730                    }
 4731
 4732                    let text = match indent.kind {
 4733                        IndentKind::Space => " ".repeat(indent.len as usize),
 4734                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4735                    };
 4736                    let point = Point::new(row.0, 0);
 4737                    indent_edits.push((point..point, text));
 4738                }
 4739            }
 4740            editor.edit(indent_edits, cx);
 4741        });
 4742    }
 4743
 4744    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4745        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4746            original_indent_columns: Vec::new(),
 4747        });
 4748        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4749    }
 4750
 4751    fn insert_with_autoindent_mode(
 4752        &mut self,
 4753        text: &str,
 4754        autoindent_mode: Option<AutoindentMode>,
 4755        window: &mut Window,
 4756        cx: &mut Context<Self>,
 4757    ) {
 4758        if self.read_only(cx) {
 4759            return;
 4760        }
 4761
 4762        let text: Arc<str> = text.into();
 4763        self.transact(window, cx, |this, window, cx| {
 4764            let old_selections = this.selections.all_adjusted(cx);
 4765            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4766                let anchors = {
 4767                    let snapshot = buffer.read(cx);
 4768                    old_selections
 4769                        .iter()
 4770                        .map(|s| {
 4771                            let anchor = snapshot.anchor_after(s.head());
 4772                            s.map(|_| anchor)
 4773                        })
 4774                        .collect::<Vec<_>>()
 4775                };
 4776                buffer.edit(
 4777                    old_selections
 4778                        .iter()
 4779                        .map(|s| (s.start..s.end, text.clone())),
 4780                    autoindent_mode,
 4781                    cx,
 4782                );
 4783                anchors
 4784            });
 4785
 4786            this.change_selections(Default::default(), window, cx, |s| {
 4787                s.select_anchors(selection_anchors);
 4788            });
 4789
 4790            cx.notify();
 4791        });
 4792    }
 4793
 4794    fn trigger_completion_on_input(
 4795        &mut self,
 4796        text: &str,
 4797        trigger_in_words: bool,
 4798        window: &mut Window,
 4799        cx: &mut Context<Self>,
 4800    ) {
 4801        let completions_source = self
 4802            .context_menu
 4803            .borrow()
 4804            .as_ref()
 4805            .and_then(|menu| match menu {
 4806                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4807                CodeContextMenu::CodeActions(_) => None,
 4808            });
 4809
 4810        match completions_source {
 4811            Some(CompletionsMenuSource::Words) => {
 4812                self.show_word_completions(&ShowWordCompletions, window, cx)
 4813            }
 4814            Some(CompletionsMenuSource::Normal)
 4815            | Some(CompletionsMenuSource::SnippetChoices)
 4816            | None
 4817                if self.is_completion_trigger(
 4818                    text,
 4819                    trigger_in_words,
 4820                    completions_source.is_some(),
 4821                    cx,
 4822                ) =>
 4823            {
 4824                self.show_completions(
 4825                    &ShowCompletions {
 4826                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4827                    },
 4828                    window,
 4829                    cx,
 4830                )
 4831            }
 4832            _ => {
 4833                self.hide_context_menu(window, cx);
 4834            }
 4835        }
 4836    }
 4837
 4838    fn is_completion_trigger(
 4839        &self,
 4840        text: &str,
 4841        trigger_in_words: bool,
 4842        menu_is_open: bool,
 4843        cx: &mut Context<Self>,
 4844    ) -> bool {
 4845        let position = self.selections.newest_anchor().head();
 4846        let multibuffer = self.buffer.read(cx);
 4847        let Some(buffer) = position
 4848            .buffer_id
 4849            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4850        else {
 4851            return false;
 4852        };
 4853
 4854        if let Some(completion_provider) = &self.completion_provider {
 4855            completion_provider.is_completion_trigger(
 4856                &buffer,
 4857                position.text_anchor,
 4858                text,
 4859                trigger_in_words,
 4860                menu_is_open,
 4861                cx,
 4862            )
 4863        } else {
 4864            false
 4865        }
 4866    }
 4867
 4868    /// If any empty selections is touching the start of its innermost containing autoclose
 4869    /// region, expand it to select the brackets.
 4870    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4871        let selections = self.selections.all::<usize>(cx);
 4872        let buffer = self.buffer.read(cx).read(cx);
 4873        let new_selections = self
 4874            .selections_with_autoclose_regions(selections, &buffer)
 4875            .map(|(mut selection, region)| {
 4876                if !selection.is_empty() {
 4877                    return selection;
 4878                }
 4879
 4880                if let Some(region) = region {
 4881                    let mut range = region.range.to_offset(&buffer);
 4882                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4883                        range.start -= region.pair.start.len();
 4884                        if buffer.contains_str_at(range.start, &region.pair.start)
 4885                            && buffer.contains_str_at(range.end, &region.pair.end)
 4886                        {
 4887                            range.end += region.pair.end.len();
 4888                            selection.start = range.start;
 4889                            selection.end = range.end;
 4890
 4891                            return selection;
 4892                        }
 4893                    }
 4894                }
 4895
 4896                let always_treat_brackets_as_autoclosed = buffer
 4897                    .language_settings_at(selection.start, cx)
 4898                    .always_treat_brackets_as_autoclosed;
 4899
 4900                if !always_treat_brackets_as_autoclosed {
 4901                    return selection;
 4902                }
 4903
 4904                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4905                    for (pair, enabled) in scope.brackets() {
 4906                        if !enabled || !pair.close {
 4907                            continue;
 4908                        }
 4909
 4910                        if buffer.contains_str_at(selection.start, &pair.end) {
 4911                            let pair_start_len = pair.start.len();
 4912                            if buffer.contains_str_at(
 4913                                selection.start.saturating_sub(pair_start_len),
 4914                                &pair.start,
 4915                            ) {
 4916                                selection.start -= pair_start_len;
 4917                                selection.end += pair.end.len();
 4918
 4919                                return selection;
 4920                            }
 4921                        }
 4922                    }
 4923                }
 4924
 4925                selection
 4926            })
 4927            .collect();
 4928
 4929        drop(buffer);
 4930        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4931            selections.select(new_selections)
 4932        });
 4933    }
 4934
 4935    /// Iterate the given selections, and for each one, find the smallest surrounding
 4936    /// autoclose region. This uses the ordering of the selections and the autoclose
 4937    /// regions to avoid repeated comparisons.
 4938    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4939        &'a self,
 4940        selections: impl IntoIterator<Item = Selection<D>>,
 4941        buffer: &'a MultiBufferSnapshot,
 4942    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4943        let mut i = 0;
 4944        let mut regions = self.autoclose_regions.as_slice();
 4945        selections.into_iter().map(move |selection| {
 4946            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4947
 4948            let mut enclosing = None;
 4949            while let Some(pair_state) = regions.get(i) {
 4950                if pair_state.range.end.to_offset(buffer) < range.start {
 4951                    regions = &regions[i + 1..];
 4952                    i = 0;
 4953                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4954                    break;
 4955                } else {
 4956                    if pair_state.selection_id == selection.id {
 4957                        enclosing = Some(pair_state);
 4958                    }
 4959                    i += 1;
 4960                }
 4961            }
 4962
 4963            (selection, enclosing)
 4964        })
 4965    }
 4966
 4967    /// Remove any autoclose regions that no longer contain their selection.
 4968    fn invalidate_autoclose_regions(
 4969        &mut self,
 4970        mut selections: &[Selection<Anchor>],
 4971        buffer: &MultiBufferSnapshot,
 4972    ) {
 4973        self.autoclose_regions.retain(|state| {
 4974            let mut i = 0;
 4975            while let Some(selection) = selections.get(i) {
 4976                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4977                    selections = &selections[1..];
 4978                    continue;
 4979                }
 4980                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4981                    break;
 4982                }
 4983                if selection.id == state.selection_id {
 4984                    return true;
 4985                } else {
 4986                    i += 1;
 4987                }
 4988            }
 4989            false
 4990        });
 4991    }
 4992
 4993    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4994        let offset = position.to_offset(buffer);
 4995        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4996        if offset > word_range.start && kind == Some(CharKind::Word) {
 4997            Some(
 4998                buffer
 4999                    .text_for_range(word_range.start..offset)
 5000                    .collect::<String>(),
 5001            )
 5002        } else {
 5003            None
 5004        }
 5005    }
 5006
 5007    pub fn toggle_inline_values(
 5008        &mut self,
 5009        _: &ToggleInlineValues,
 5010        _: &mut Window,
 5011        cx: &mut Context<Self>,
 5012    ) {
 5013        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5014
 5015        self.refresh_inline_values(cx);
 5016    }
 5017
 5018    pub fn toggle_inlay_hints(
 5019        &mut self,
 5020        _: &ToggleInlayHints,
 5021        _: &mut Window,
 5022        cx: &mut Context<Self>,
 5023    ) {
 5024        self.refresh_inlay_hints(
 5025            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5026            cx,
 5027        );
 5028    }
 5029
 5030    pub fn inlay_hints_enabled(&self) -> bool {
 5031        self.inlay_hint_cache.enabled
 5032    }
 5033
 5034    pub fn inline_values_enabled(&self) -> bool {
 5035        self.inline_value_cache.enabled
 5036    }
 5037
 5038    #[cfg(any(test, feature = "test-support"))]
 5039    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5040        self.display_map
 5041            .read(cx)
 5042            .current_inlays()
 5043            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5044            .cloned()
 5045            .collect()
 5046    }
 5047
 5048    #[cfg(any(test, feature = "test-support"))]
 5049    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5050        self.display_map
 5051            .read(cx)
 5052            .current_inlays()
 5053            .cloned()
 5054            .collect()
 5055    }
 5056
 5057    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5058        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5059            return;
 5060        }
 5061
 5062        let reason_description = reason.description();
 5063        let ignore_debounce = matches!(
 5064            reason,
 5065            InlayHintRefreshReason::SettingsChange(_)
 5066                | InlayHintRefreshReason::Toggle(_)
 5067                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5068                | InlayHintRefreshReason::ModifiersChanged(_)
 5069        );
 5070        let (invalidate_cache, required_languages) = match reason {
 5071            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5072                match self.inlay_hint_cache.modifiers_override(enabled) {
 5073                    Some(enabled) => {
 5074                        if enabled {
 5075                            (InvalidationStrategy::RefreshRequested, None)
 5076                        } else {
 5077                            self.splice_inlays(
 5078                                &self
 5079                                    .visible_inlay_hints(cx)
 5080                                    .iter()
 5081                                    .map(|inlay| inlay.id)
 5082                                    .collect::<Vec<InlayId>>(),
 5083                                Vec::new(),
 5084                                cx,
 5085                            );
 5086                            return;
 5087                        }
 5088                    }
 5089                    None => return,
 5090                }
 5091            }
 5092            InlayHintRefreshReason::Toggle(enabled) => {
 5093                if self.inlay_hint_cache.toggle(enabled) {
 5094                    if enabled {
 5095                        (InvalidationStrategy::RefreshRequested, None)
 5096                    } else {
 5097                        self.splice_inlays(
 5098                            &self
 5099                                .visible_inlay_hints(cx)
 5100                                .iter()
 5101                                .map(|inlay| inlay.id)
 5102                                .collect::<Vec<InlayId>>(),
 5103                            Vec::new(),
 5104                            cx,
 5105                        );
 5106                        return;
 5107                    }
 5108                } else {
 5109                    return;
 5110                }
 5111            }
 5112            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5113                match self.inlay_hint_cache.update_settings(
 5114                    &self.buffer,
 5115                    new_settings,
 5116                    self.visible_inlay_hints(cx),
 5117                    cx,
 5118                ) {
 5119                    ControlFlow::Break(Some(InlaySplice {
 5120                        to_remove,
 5121                        to_insert,
 5122                    })) => {
 5123                        self.splice_inlays(&to_remove, to_insert, cx);
 5124                        return;
 5125                    }
 5126                    ControlFlow::Break(None) => return,
 5127                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5128                }
 5129            }
 5130            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5131                if let Some(InlaySplice {
 5132                    to_remove,
 5133                    to_insert,
 5134                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5135                {
 5136                    self.splice_inlays(&to_remove, to_insert, cx);
 5137                }
 5138                self.display_map.update(cx, |display_map, _| {
 5139                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5140                });
 5141                return;
 5142            }
 5143            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5144            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5145                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5146            }
 5147            InlayHintRefreshReason::RefreshRequested => {
 5148                (InvalidationStrategy::RefreshRequested, None)
 5149            }
 5150        };
 5151
 5152        if let Some(InlaySplice {
 5153            to_remove,
 5154            to_insert,
 5155        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5156            reason_description,
 5157            self.visible_excerpts(required_languages.as_ref(), cx),
 5158            invalidate_cache,
 5159            ignore_debounce,
 5160            cx,
 5161        ) {
 5162            self.splice_inlays(&to_remove, to_insert, cx);
 5163        }
 5164    }
 5165
 5166    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5167        self.display_map
 5168            .read(cx)
 5169            .current_inlays()
 5170            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5171            .cloned()
 5172            .collect()
 5173    }
 5174
 5175    pub fn visible_excerpts(
 5176        &self,
 5177        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5178        cx: &mut Context<Editor>,
 5179    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5180        let Some(project) = self.project.as_ref() else {
 5181            return HashMap::default();
 5182        };
 5183        let project = project.read(cx);
 5184        let multi_buffer = self.buffer().read(cx);
 5185        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5186        let multi_buffer_visible_start = self
 5187            .scroll_manager
 5188            .anchor()
 5189            .anchor
 5190            .to_point(&multi_buffer_snapshot);
 5191        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5192            multi_buffer_visible_start
 5193                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5194            Bias::Left,
 5195        );
 5196        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5197        multi_buffer_snapshot
 5198            .range_to_buffer_ranges(multi_buffer_visible_range)
 5199            .into_iter()
 5200            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5201            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5202                let buffer_file = project::File::from_dyn(buffer.file())?;
 5203                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5204                let worktree_entry = buffer_worktree
 5205                    .read(cx)
 5206                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5207                if worktree_entry.is_ignored {
 5208                    return None;
 5209                }
 5210
 5211                let language = buffer.language()?;
 5212                if let Some(restrict_to_languages) = restrict_to_languages {
 5213                    if !restrict_to_languages.contains(language) {
 5214                        return None;
 5215                    }
 5216                }
 5217                Some((
 5218                    excerpt_id,
 5219                    (
 5220                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5221                        buffer.version().clone(),
 5222                        excerpt_visible_range,
 5223                    ),
 5224                ))
 5225            })
 5226            .collect()
 5227    }
 5228
 5229    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5230        TextLayoutDetails {
 5231            text_system: window.text_system().clone(),
 5232            editor_style: self.style.clone().unwrap(),
 5233            rem_size: window.rem_size(),
 5234            scroll_anchor: self.scroll_manager.anchor(),
 5235            visible_rows: self.visible_line_count(),
 5236            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5237        }
 5238    }
 5239
 5240    pub fn splice_inlays(
 5241        &self,
 5242        to_remove: &[InlayId],
 5243        to_insert: Vec<Inlay>,
 5244        cx: &mut Context<Self>,
 5245    ) {
 5246        self.display_map.update(cx, |display_map, cx| {
 5247            display_map.splice_inlays(to_remove, to_insert, cx)
 5248        });
 5249        cx.notify();
 5250    }
 5251
 5252    fn trigger_on_type_formatting(
 5253        &self,
 5254        input: String,
 5255        window: &mut Window,
 5256        cx: &mut Context<Self>,
 5257    ) -> Option<Task<Result<()>>> {
 5258        if input.len() != 1 {
 5259            return None;
 5260        }
 5261
 5262        let project = self.project.as_ref()?;
 5263        let position = self.selections.newest_anchor().head();
 5264        let (buffer, buffer_position) = self
 5265            .buffer
 5266            .read(cx)
 5267            .text_anchor_for_position(position, cx)?;
 5268
 5269        let settings = language_settings::language_settings(
 5270            buffer
 5271                .read(cx)
 5272                .language_at(buffer_position)
 5273                .map(|l| l.name()),
 5274            buffer.read(cx).file(),
 5275            cx,
 5276        );
 5277        if !settings.use_on_type_format {
 5278            return None;
 5279        }
 5280
 5281        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5282        // hence we do LSP request & edit on host side only — add formats to host's history.
 5283        let push_to_lsp_host_history = true;
 5284        // If this is not the host, append its history with new edits.
 5285        let push_to_client_history = project.read(cx).is_via_collab();
 5286
 5287        let on_type_formatting = project.update(cx, |project, cx| {
 5288            project.on_type_format(
 5289                buffer.clone(),
 5290                buffer_position,
 5291                input,
 5292                push_to_lsp_host_history,
 5293                cx,
 5294            )
 5295        });
 5296        Some(cx.spawn_in(window, async move |editor, cx| {
 5297            if let Some(transaction) = on_type_formatting.await? {
 5298                if push_to_client_history {
 5299                    buffer
 5300                        .update(cx, |buffer, _| {
 5301                            buffer.push_transaction(transaction, Instant::now());
 5302                            buffer.finalize_last_transaction();
 5303                        })
 5304                        .ok();
 5305                }
 5306                editor.update(cx, |editor, cx| {
 5307                    editor.refresh_document_highlights(cx);
 5308                })?;
 5309            }
 5310            Ok(())
 5311        }))
 5312    }
 5313
 5314    pub fn show_word_completions(
 5315        &mut self,
 5316        _: &ShowWordCompletions,
 5317        window: &mut Window,
 5318        cx: &mut Context<Self>,
 5319    ) {
 5320        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5321    }
 5322
 5323    pub fn show_completions(
 5324        &mut self,
 5325        options: &ShowCompletions,
 5326        window: &mut Window,
 5327        cx: &mut Context<Self>,
 5328    ) {
 5329        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5330    }
 5331
 5332    fn open_or_update_completions_menu(
 5333        &mut self,
 5334        requested_source: Option<CompletionsMenuSource>,
 5335        trigger: Option<&str>,
 5336        window: &mut Window,
 5337        cx: &mut Context<Self>,
 5338    ) {
 5339        if self.pending_rename.is_some() {
 5340            return;
 5341        }
 5342
 5343        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5344
 5345        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5346        // inserted and selected. To handle that case, the start of the selection is used so that
 5347        // the menu starts with all choices.
 5348        let position = self
 5349            .selections
 5350            .newest_anchor()
 5351            .start
 5352            .bias_right(&multibuffer_snapshot);
 5353        if position.diff_base_anchor.is_some() {
 5354            return;
 5355        }
 5356        let (buffer, buffer_position) =
 5357            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5358                output
 5359            } else {
 5360                return;
 5361            };
 5362        let buffer_snapshot = buffer.read(cx).snapshot();
 5363
 5364        let query: Option<Arc<String>> =
 5365            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5366
 5367        drop(multibuffer_snapshot);
 5368
 5369        let provider = match requested_source {
 5370            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5371            Some(CompletionsMenuSource::Words) => None,
 5372            Some(CompletionsMenuSource::SnippetChoices) => {
 5373                log::error!("bug: SnippetChoices requested_source is not handled");
 5374                None
 5375            }
 5376        };
 5377
 5378        let sort_completions = provider
 5379            .as_ref()
 5380            .map_or(false, |provider| provider.sort_completions());
 5381
 5382        let filter_completions = provider
 5383            .as_ref()
 5384            .map_or(true, |provider| provider.filter_completions());
 5385
 5386        let trigger_kind = match trigger {
 5387            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5388                CompletionTriggerKind::TRIGGER_CHARACTER
 5389            }
 5390            _ => CompletionTriggerKind::INVOKED,
 5391        };
 5392        let completion_context = CompletionContext {
 5393            trigger_character: trigger.and_then(|trigger| {
 5394                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5395                    Some(String::from(trigger))
 5396                } else {
 5397                    None
 5398                }
 5399            }),
 5400            trigger_kind,
 5401        };
 5402
 5403        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5404        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5405        // involve trigger chars, so this is skipped in that case.
 5406        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5407        {
 5408            let menu_is_open = matches!(
 5409                self.context_menu.borrow().as_ref(),
 5410                Some(CodeContextMenu::Completions(_))
 5411            );
 5412            if menu_is_open {
 5413                self.hide_context_menu(window, cx);
 5414            }
 5415        }
 5416
 5417        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5418            if filter_completions {
 5419                menu.filter(query.clone(), provider.clone(), window, cx);
 5420            }
 5421            // When `is_incomplete` is false, no need to re-query completions when the current query
 5422            // is a suffix of the initial query.
 5423            if !menu.is_incomplete {
 5424                // If the new query is a suffix of the old query (typing more characters) and
 5425                // the previous result was complete, the existing completions can be filtered.
 5426                //
 5427                // Note that this is always true for snippet completions.
 5428                let query_matches = match (&menu.initial_query, &query) {
 5429                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5430                    (None, _) => true,
 5431                    _ => false,
 5432                };
 5433                if query_matches {
 5434                    let position_matches = if menu.initial_position == position {
 5435                        true
 5436                    } else {
 5437                        let snapshot = self.buffer.read(cx).read(cx);
 5438                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5439                    };
 5440                    if position_matches {
 5441                        return;
 5442                    }
 5443                }
 5444            }
 5445        };
 5446
 5447        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5448            buffer_snapshot.surrounding_word(buffer_position)
 5449        {
 5450            let word_to_exclude = buffer_snapshot
 5451                .text_for_range(word_range.clone())
 5452                .collect::<String>();
 5453            (
 5454                buffer_snapshot.anchor_before(word_range.start)
 5455                    ..buffer_snapshot.anchor_after(buffer_position),
 5456                Some(word_to_exclude),
 5457            )
 5458        } else {
 5459            (buffer_position..buffer_position, None)
 5460        };
 5461
 5462        let language = buffer_snapshot
 5463            .language_at(buffer_position)
 5464            .map(|language| language.name());
 5465
 5466        let completion_settings =
 5467            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5468
 5469        let show_completion_documentation = buffer_snapshot
 5470            .settings_at(buffer_position, cx)
 5471            .show_completion_documentation;
 5472
 5473        // The document can be large, so stay in reasonable bounds when searching for words,
 5474        // otherwise completion pop-up might be slow to appear.
 5475        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5476        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5477        let min_word_search = buffer_snapshot.clip_point(
 5478            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5479            Bias::Left,
 5480        );
 5481        let max_word_search = buffer_snapshot.clip_point(
 5482            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5483            Bias::Right,
 5484        );
 5485        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5486            ..buffer_snapshot.point_to_offset(max_word_search);
 5487
 5488        let skip_digits = query
 5489            .as_ref()
 5490            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5491
 5492        let (mut words, provider_responses) = match &provider {
 5493            Some(provider) => {
 5494                let provider_responses = provider.completions(
 5495                    position.excerpt_id,
 5496                    &buffer,
 5497                    buffer_position,
 5498                    completion_context,
 5499                    window,
 5500                    cx,
 5501                );
 5502
 5503                let words = match completion_settings.words {
 5504                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5505                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5506                        .background_spawn(async move {
 5507                            buffer_snapshot.words_in_range(WordsQuery {
 5508                                fuzzy_contents: None,
 5509                                range: word_search_range,
 5510                                skip_digits,
 5511                            })
 5512                        }),
 5513                };
 5514
 5515                (words, provider_responses)
 5516            }
 5517            None => (
 5518                cx.background_spawn(async move {
 5519                    buffer_snapshot.words_in_range(WordsQuery {
 5520                        fuzzy_contents: None,
 5521                        range: word_search_range,
 5522                        skip_digits,
 5523                    })
 5524                }),
 5525                Task::ready(Ok(Vec::new())),
 5526            ),
 5527        };
 5528
 5529        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5530
 5531        let id = post_inc(&mut self.next_completion_id);
 5532        let task = cx.spawn_in(window, async move |editor, cx| {
 5533            let Ok(()) = editor.update(cx, |this, _| {
 5534                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5535            }) else {
 5536                return;
 5537            };
 5538
 5539            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5540            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5541            let mut completions = Vec::new();
 5542            let mut is_incomplete = false;
 5543            if let Some(provider_responses) = provider_responses.await.log_err() {
 5544                if !provider_responses.is_empty() {
 5545                    for response in provider_responses {
 5546                        completions.extend(response.completions);
 5547                        is_incomplete = is_incomplete || response.is_incomplete;
 5548                    }
 5549                    if completion_settings.words == WordsCompletionMode::Fallback {
 5550                        words = Task::ready(BTreeMap::default());
 5551                    }
 5552                }
 5553            }
 5554
 5555            let mut words = words.await;
 5556            if let Some(word_to_exclude) = &word_to_exclude {
 5557                words.remove(word_to_exclude);
 5558            }
 5559            for lsp_completion in &completions {
 5560                words.remove(&lsp_completion.new_text);
 5561            }
 5562            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5563                replace_range: word_replace_range.clone(),
 5564                new_text: word.clone(),
 5565                label: CodeLabel::plain(word, None),
 5566                icon_path: None,
 5567                documentation: None,
 5568                source: CompletionSource::BufferWord {
 5569                    word_range,
 5570                    resolved: false,
 5571                },
 5572                insert_text_mode: Some(InsertTextMode::AS_IS),
 5573                confirm: None,
 5574            }));
 5575
 5576            let menu = if completions.is_empty() {
 5577                None
 5578            } else {
 5579                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5580                    let languages = editor
 5581                        .workspace
 5582                        .as_ref()
 5583                        .and_then(|(workspace, _)| workspace.upgrade())
 5584                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5585                    let menu = CompletionsMenu::new(
 5586                        id,
 5587                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5588                        sort_completions,
 5589                        show_completion_documentation,
 5590                        position,
 5591                        query.clone(),
 5592                        is_incomplete,
 5593                        buffer.clone(),
 5594                        completions.into(),
 5595                        snippet_sort_order,
 5596                        languages,
 5597                        language,
 5598                        cx,
 5599                    );
 5600
 5601                    let query = if filter_completions { query } else { None };
 5602                    let matches_task = if let Some(query) = query {
 5603                        menu.do_async_filtering(query, cx)
 5604                    } else {
 5605                        Task::ready(menu.unfiltered_matches())
 5606                    };
 5607                    (menu, matches_task)
 5608                }) else {
 5609                    return;
 5610                };
 5611
 5612                let matches = matches_task.await;
 5613
 5614                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5615                    // Newer menu already set, so exit.
 5616                    match editor.context_menu.borrow().as_ref() {
 5617                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5618                            if prev_menu.id > id {
 5619                                return;
 5620                            }
 5621                        }
 5622                        _ => {}
 5623                    };
 5624
 5625                    // Only valid to take prev_menu because it the new menu is immediately set
 5626                    // below, or the menu is hidden.
 5627                    match editor.context_menu.borrow_mut().take() {
 5628                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5629                            let position_matches =
 5630                                if prev_menu.initial_position == menu.initial_position {
 5631                                    true
 5632                                } else {
 5633                                    let snapshot = editor.buffer.read(cx).read(cx);
 5634                                    prev_menu.initial_position.to_offset(&snapshot)
 5635                                        == menu.initial_position.to_offset(&snapshot)
 5636                                };
 5637                            if position_matches {
 5638                                // Preserve markdown cache before `set_filter_results` because it will
 5639                                // try to populate the documentation cache.
 5640                                menu.preserve_markdown_cache(prev_menu);
 5641                            }
 5642                        }
 5643                        _ => {}
 5644                    };
 5645
 5646                    menu.set_filter_results(matches, provider, window, cx);
 5647                }) else {
 5648                    return;
 5649                };
 5650
 5651                menu.visible().then_some(menu)
 5652            };
 5653
 5654            editor
 5655                .update_in(cx, |editor, window, cx| {
 5656                    if editor.focus_handle.is_focused(window) {
 5657                        if let Some(menu) = menu {
 5658                            *editor.context_menu.borrow_mut() =
 5659                                Some(CodeContextMenu::Completions(menu));
 5660
 5661                            crate::hover_popover::hide_hover(editor, cx);
 5662                            if editor.show_edit_predictions_in_menu() {
 5663                                editor.update_visible_inline_completion(window, cx);
 5664                            } else {
 5665                                editor.discard_inline_completion(false, cx);
 5666                            }
 5667
 5668                            cx.notify();
 5669                            return;
 5670                        }
 5671                    }
 5672
 5673                    if editor.completion_tasks.len() <= 1 {
 5674                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5675                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5676                        // If it was already hidden and we don't show inline completions in the menu, we should
 5677                        // also show the inline-completion when available.
 5678                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5679                            editor.update_visible_inline_completion(window, cx);
 5680                        }
 5681                    }
 5682                })
 5683                .ok();
 5684        });
 5685
 5686        self.completion_tasks.push((id, task));
 5687    }
 5688
 5689    #[cfg(feature = "test-support")]
 5690    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5691        let menu = self.context_menu.borrow();
 5692        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5693            let completions = menu.completions.borrow();
 5694            Some(completions.to_vec())
 5695        } else {
 5696            None
 5697        }
 5698    }
 5699
 5700    pub fn with_completions_menu_matching_id<R>(
 5701        &self,
 5702        id: CompletionId,
 5703        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5704    ) -> R {
 5705        let mut context_menu = self.context_menu.borrow_mut();
 5706        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5707            return f(None);
 5708        };
 5709        if completions_menu.id != id {
 5710            return f(None);
 5711        }
 5712        f(Some(completions_menu))
 5713    }
 5714
 5715    pub fn confirm_completion(
 5716        &mut self,
 5717        action: &ConfirmCompletion,
 5718        window: &mut Window,
 5719        cx: &mut Context<Self>,
 5720    ) -> Option<Task<Result<()>>> {
 5721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5722        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5723    }
 5724
 5725    pub fn confirm_completion_insert(
 5726        &mut self,
 5727        _: &ConfirmCompletionInsert,
 5728        window: &mut Window,
 5729        cx: &mut Context<Self>,
 5730    ) -> Option<Task<Result<()>>> {
 5731        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5732        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5733    }
 5734
 5735    pub fn confirm_completion_replace(
 5736        &mut self,
 5737        _: &ConfirmCompletionReplace,
 5738        window: &mut Window,
 5739        cx: &mut Context<Self>,
 5740    ) -> Option<Task<Result<()>>> {
 5741        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5742        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5743    }
 5744
 5745    pub fn compose_completion(
 5746        &mut self,
 5747        action: &ComposeCompletion,
 5748        window: &mut Window,
 5749        cx: &mut Context<Self>,
 5750    ) -> Option<Task<Result<()>>> {
 5751        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5752        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5753    }
 5754
 5755    fn do_completion(
 5756        &mut self,
 5757        item_ix: Option<usize>,
 5758        intent: CompletionIntent,
 5759        window: &mut Window,
 5760        cx: &mut Context<Editor>,
 5761    ) -> Option<Task<Result<()>>> {
 5762        use language::ToOffset as _;
 5763
 5764        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5765        else {
 5766            return None;
 5767        };
 5768
 5769        let candidate_id = {
 5770            let entries = completions_menu.entries.borrow();
 5771            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5772            if self.show_edit_predictions_in_menu() {
 5773                self.discard_inline_completion(true, cx);
 5774            }
 5775            mat.candidate_id
 5776        };
 5777
 5778        let completion = completions_menu
 5779            .completions
 5780            .borrow()
 5781            .get(candidate_id)?
 5782            .clone();
 5783        cx.stop_propagation();
 5784
 5785        let buffer_handle = completions_menu.buffer.clone();
 5786
 5787        let CompletionEdit {
 5788            new_text,
 5789            snippet,
 5790            replace_range,
 5791        } = process_completion_for_edit(
 5792            &completion,
 5793            intent,
 5794            &buffer_handle,
 5795            &completions_menu.initial_position.text_anchor,
 5796            cx,
 5797        );
 5798
 5799        let buffer = buffer_handle.read(cx);
 5800        let snapshot = self.buffer.read(cx).snapshot(cx);
 5801        let newest_anchor = self.selections.newest_anchor();
 5802        let replace_range_multibuffer = {
 5803            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5804            let multibuffer_anchor = snapshot
 5805                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5806                .unwrap()
 5807                ..snapshot
 5808                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5809                    .unwrap();
 5810            multibuffer_anchor.start.to_offset(&snapshot)
 5811                ..multibuffer_anchor.end.to_offset(&snapshot)
 5812        };
 5813        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5814            return None;
 5815        }
 5816
 5817        let old_text = buffer
 5818            .text_for_range(replace_range.clone())
 5819            .collect::<String>();
 5820        let lookbehind = newest_anchor
 5821            .start
 5822            .text_anchor
 5823            .to_offset(buffer)
 5824            .saturating_sub(replace_range.start);
 5825        let lookahead = replace_range
 5826            .end
 5827            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5828        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5829        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5830
 5831        let selections = self.selections.all::<usize>(cx);
 5832        let mut ranges = Vec::new();
 5833        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5834
 5835        for selection in &selections {
 5836            let range = if selection.id == newest_anchor.id {
 5837                replace_range_multibuffer.clone()
 5838            } else {
 5839                let mut range = selection.range();
 5840
 5841                // if prefix is present, don't duplicate it
 5842                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5843                    range.start = range.start.saturating_sub(lookbehind);
 5844
 5845                    // if suffix is also present, mimic the newest cursor and replace it
 5846                    if selection.id != newest_anchor.id
 5847                        && snapshot.contains_str_at(range.end, suffix)
 5848                    {
 5849                        range.end += lookahead;
 5850                    }
 5851                }
 5852                range
 5853            };
 5854
 5855            ranges.push(range.clone());
 5856
 5857            if !self.linked_edit_ranges.is_empty() {
 5858                let start_anchor = snapshot.anchor_before(range.start);
 5859                let end_anchor = snapshot.anchor_after(range.end);
 5860                if let Some(ranges) = self
 5861                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5862                {
 5863                    for (buffer, edits) in ranges {
 5864                        linked_edits
 5865                            .entry(buffer.clone())
 5866                            .or_default()
 5867                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5868                    }
 5869                }
 5870            }
 5871        }
 5872
 5873        let common_prefix_len = old_text
 5874            .chars()
 5875            .zip(new_text.chars())
 5876            .take_while(|(a, b)| a == b)
 5877            .map(|(a, _)| a.len_utf8())
 5878            .sum::<usize>();
 5879
 5880        cx.emit(EditorEvent::InputHandled {
 5881            utf16_range_to_replace: None,
 5882            text: new_text[common_prefix_len..].into(),
 5883        });
 5884
 5885        self.transact(window, cx, |this, window, cx| {
 5886            if let Some(mut snippet) = snippet {
 5887                snippet.text = new_text.to_string();
 5888                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5889            } else {
 5890                this.buffer.update(cx, |buffer, cx| {
 5891                    let auto_indent = match completion.insert_text_mode {
 5892                        Some(InsertTextMode::AS_IS) => None,
 5893                        _ => this.autoindent_mode.clone(),
 5894                    };
 5895                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5896                    buffer.edit(edits, auto_indent, cx);
 5897                });
 5898            }
 5899            for (buffer, edits) in linked_edits {
 5900                buffer.update(cx, |buffer, cx| {
 5901                    let snapshot = buffer.snapshot();
 5902                    let edits = edits
 5903                        .into_iter()
 5904                        .map(|(range, text)| {
 5905                            use text::ToPoint as TP;
 5906                            let end_point = TP::to_point(&range.end, &snapshot);
 5907                            let start_point = TP::to_point(&range.start, &snapshot);
 5908                            (start_point..end_point, text)
 5909                        })
 5910                        .sorted_by_key(|(range, _)| range.start);
 5911                    buffer.edit(edits, None, cx);
 5912                })
 5913            }
 5914
 5915            this.refresh_inline_completion(true, false, window, cx);
 5916        });
 5917
 5918        let show_new_completions_on_confirm = completion
 5919            .confirm
 5920            .as_ref()
 5921            .map_or(false, |confirm| confirm(intent, window, cx));
 5922        if show_new_completions_on_confirm {
 5923            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5924        }
 5925
 5926        let provider = self.completion_provider.as_ref()?;
 5927        drop(completion);
 5928        let apply_edits = provider.apply_additional_edits_for_completion(
 5929            buffer_handle,
 5930            completions_menu.completions.clone(),
 5931            candidate_id,
 5932            true,
 5933            cx,
 5934        );
 5935
 5936        let editor_settings = EditorSettings::get_global(cx);
 5937        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5938            // After the code completion is finished, users often want to know what signatures are needed.
 5939            // so we should automatically call signature_help
 5940            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5941        }
 5942
 5943        Some(cx.foreground_executor().spawn(async move {
 5944            apply_edits.await?;
 5945            Ok(())
 5946        }))
 5947    }
 5948
 5949    pub fn toggle_code_actions(
 5950        &mut self,
 5951        action: &ToggleCodeActions,
 5952        window: &mut Window,
 5953        cx: &mut Context<Self>,
 5954    ) {
 5955        let quick_launch = action.quick_launch;
 5956        let mut context_menu = self.context_menu.borrow_mut();
 5957        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5958            if code_actions.deployed_from == action.deployed_from {
 5959                // Toggle if we're selecting the same one
 5960                *context_menu = None;
 5961                cx.notify();
 5962                return;
 5963            } else {
 5964                // Otherwise, clear it and start a new one
 5965                *context_menu = None;
 5966                cx.notify();
 5967            }
 5968        }
 5969        drop(context_menu);
 5970        let snapshot = self.snapshot(window, cx);
 5971        let deployed_from = action.deployed_from.clone();
 5972        let action = action.clone();
 5973        self.completion_tasks.clear();
 5974        self.discard_inline_completion(false, cx);
 5975
 5976        let multibuffer_point = match &action.deployed_from {
 5977            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5978                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5979            }
 5980            _ => self.selections.newest::<Point>(cx).head(),
 5981        };
 5982        let Some((buffer, buffer_row)) = snapshot
 5983            .buffer_snapshot
 5984            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5985            .and_then(|(buffer_snapshot, range)| {
 5986                self.buffer()
 5987                    .read(cx)
 5988                    .buffer(buffer_snapshot.remote_id())
 5989                    .map(|buffer| (buffer, range.start.row))
 5990            })
 5991        else {
 5992            return;
 5993        };
 5994        let buffer_id = buffer.read(cx).remote_id();
 5995        let tasks = self
 5996            .tasks
 5997            .get(&(buffer_id, buffer_row))
 5998            .map(|t| Arc::new(t.to_owned()));
 5999
 6000        if !self.focus_handle.is_focused(window) {
 6001            return;
 6002        }
 6003        let project = self.project.clone();
 6004
 6005        let code_actions_task = match deployed_from {
 6006            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6007            _ => self.code_actions(buffer_row, window, cx),
 6008        };
 6009
 6010        let runnable_task = match deployed_from {
 6011            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6012            _ => {
 6013                let mut task_context_task = Task::ready(None);
 6014                if let Some(tasks) = &tasks {
 6015                    if let Some(project) = project {
 6016                        task_context_task =
 6017                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6018                    }
 6019                }
 6020
 6021                cx.spawn_in(window, {
 6022                    let buffer = buffer.clone();
 6023                    async move |editor, cx| {
 6024                        let task_context = task_context_task.await;
 6025
 6026                        let resolved_tasks =
 6027                            tasks
 6028                                .zip(task_context.clone())
 6029                                .map(|(tasks, task_context)| ResolvedTasks {
 6030                                    templates: tasks.resolve(&task_context).collect(),
 6031                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6032                                        multibuffer_point.row,
 6033                                        tasks.column,
 6034                                    )),
 6035                                });
 6036                        let debug_scenarios = editor
 6037                            .update(cx, |editor, cx| {
 6038                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6039                            })?
 6040                            .await;
 6041                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6042                    }
 6043                })
 6044            }
 6045        };
 6046
 6047        cx.spawn_in(window, async move |editor, cx| {
 6048            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6049            let code_actions = code_actions_task.await;
 6050            let spawn_straight_away = quick_launch
 6051                && resolved_tasks
 6052                    .as_ref()
 6053                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6054                && code_actions
 6055                    .as_ref()
 6056                    .map_or(true, |actions| actions.is_empty())
 6057                && debug_scenarios.is_empty();
 6058
 6059            editor.update_in(cx, |editor, window, cx| {
 6060                crate::hover_popover::hide_hover(editor, cx);
 6061                let actions = CodeActionContents::new(
 6062                    resolved_tasks,
 6063                    code_actions,
 6064                    debug_scenarios,
 6065                    task_context.unwrap_or_default(),
 6066                );
 6067
 6068                // Don't show the menu if there are no actions available
 6069                if actions.is_empty() {
 6070                    cx.notify();
 6071                    return Task::ready(Ok(()));
 6072                }
 6073
 6074                *editor.context_menu.borrow_mut() =
 6075                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6076                        buffer,
 6077                        actions,
 6078                        selected_item: Default::default(),
 6079                        scroll_handle: UniformListScrollHandle::default(),
 6080                        deployed_from,
 6081                    }));
 6082                cx.notify();
 6083                if spawn_straight_away {
 6084                    if let Some(task) = editor.confirm_code_action(
 6085                        &ConfirmCodeAction { item_ix: Some(0) },
 6086                        window,
 6087                        cx,
 6088                    ) {
 6089                        return task;
 6090                    }
 6091                }
 6092
 6093                Task::ready(Ok(()))
 6094            })
 6095        })
 6096        .detach_and_log_err(cx);
 6097    }
 6098
 6099    fn debug_scenarios(
 6100        &mut self,
 6101        resolved_tasks: &Option<ResolvedTasks>,
 6102        buffer: &Entity<Buffer>,
 6103        cx: &mut App,
 6104    ) -> Task<Vec<task::DebugScenario>> {
 6105        maybe!({
 6106            let project = self.project.as_ref()?;
 6107            let dap_store = project.read(cx).dap_store();
 6108            let mut scenarios = vec![];
 6109            let resolved_tasks = resolved_tasks.as_ref()?;
 6110            let buffer = buffer.read(cx);
 6111            let language = buffer.language()?;
 6112            let file = buffer.file();
 6113            let debug_adapter = language_settings(language.name().into(), file, cx)
 6114                .debuggers
 6115                .first()
 6116                .map(SharedString::from)
 6117                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6118
 6119            dap_store.update(cx, |dap_store, cx| {
 6120                for (_, task) in &resolved_tasks.templates {
 6121                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6122                        task.original_task().clone(),
 6123                        debug_adapter.clone().into(),
 6124                        task.display_label().to_owned().into(),
 6125                        cx,
 6126                    );
 6127                    scenarios.push(maybe_scenario);
 6128                }
 6129            });
 6130            Some(cx.background_spawn(async move {
 6131                let scenarios = futures::future::join_all(scenarios)
 6132                    .await
 6133                    .into_iter()
 6134                    .flatten()
 6135                    .collect::<Vec<_>>();
 6136                scenarios
 6137            }))
 6138        })
 6139        .unwrap_or_else(|| Task::ready(vec![]))
 6140    }
 6141
 6142    fn code_actions(
 6143        &mut self,
 6144        buffer_row: u32,
 6145        window: &mut Window,
 6146        cx: &mut Context<Self>,
 6147    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6148        let mut task = self.code_actions_task.take();
 6149        cx.spawn_in(window, async move |editor, cx| {
 6150            while let Some(prev_task) = task {
 6151                prev_task.await.log_err();
 6152                task = editor
 6153                    .update(cx, |this, _| this.code_actions_task.take())
 6154                    .ok()?;
 6155            }
 6156
 6157            editor
 6158                .update(cx, |editor, cx| {
 6159                    editor
 6160                        .available_code_actions
 6161                        .clone()
 6162                        .and_then(|(location, code_actions)| {
 6163                            let snapshot = location.buffer.read(cx).snapshot();
 6164                            let point_range = location.range.to_point(&snapshot);
 6165                            let point_range = point_range.start.row..=point_range.end.row;
 6166                            if point_range.contains(&buffer_row) {
 6167                                Some(code_actions)
 6168                            } else {
 6169                                None
 6170                            }
 6171                        })
 6172                })
 6173                .ok()
 6174                .flatten()
 6175        })
 6176    }
 6177
 6178    pub fn confirm_code_action(
 6179        &mut self,
 6180        action: &ConfirmCodeAction,
 6181        window: &mut Window,
 6182        cx: &mut Context<Self>,
 6183    ) -> Option<Task<Result<()>>> {
 6184        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6185
 6186        let actions_menu =
 6187            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6188                menu
 6189            } else {
 6190                return None;
 6191            };
 6192
 6193        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6194        let action = actions_menu.actions.get(action_ix)?;
 6195        let title = action.label();
 6196        let buffer = actions_menu.buffer;
 6197        let workspace = self.workspace()?;
 6198
 6199        match action {
 6200            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6201                workspace.update(cx, |workspace, cx| {
 6202                    workspace.schedule_resolved_task(
 6203                        task_source_kind,
 6204                        resolved_task,
 6205                        false,
 6206                        window,
 6207                        cx,
 6208                    );
 6209
 6210                    Some(Task::ready(Ok(())))
 6211                })
 6212            }
 6213            CodeActionsItem::CodeAction {
 6214                excerpt_id,
 6215                action,
 6216                provider,
 6217            } => {
 6218                let apply_code_action =
 6219                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6220                let workspace = workspace.downgrade();
 6221                Some(cx.spawn_in(window, async move |editor, cx| {
 6222                    let project_transaction = apply_code_action.await?;
 6223                    Self::open_project_transaction(
 6224                        &editor,
 6225                        workspace,
 6226                        project_transaction,
 6227                        title,
 6228                        cx,
 6229                    )
 6230                    .await
 6231                }))
 6232            }
 6233            CodeActionsItem::DebugScenario(scenario) => {
 6234                let context = actions_menu.actions.context.clone();
 6235
 6236                workspace.update(cx, |workspace, cx| {
 6237                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6238                    workspace.start_debug_session(
 6239                        scenario,
 6240                        context,
 6241                        Some(buffer),
 6242                        None,
 6243                        window,
 6244                        cx,
 6245                    );
 6246                });
 6247                Some(Task::ready(Ok(())))
 6248            }
 6249        }
 6250    }
 6251
 6252    pub async fn open_project_transaction(
 6253        this: &WeakEntity<Editor>,
 6254        workspace: WeakEntity<Workspace>,
 6255        transaction: ProjectTransaction,
 6256        title: String,
 6257        cx: &mut AsyncWindowContext,
 6258    ) -> Result<()> {
 6259        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6260        cx.update(|_, cx| {
 6261            entries.sort_unstable_by_key(|(buffer, _)| {
 6262                buffer.read(cx).file().map(|f| f.path().clone())
 6263            });
 6264        })?;
 6265
 6266        // If the project transaction's edits are all contained within this editor, then
 6267        // avoid opening a new editor to display them.
 6268
 6269        if let Some((buffer, transaction)) = entries.first() {
 6270            if entries.len() == 1 {
 6271                let excerpt = this.update(cx, |editor, cx| {
 6272                    editor
 6273                        .buffer()
 6274                        .read(cx)
 6275                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6276                })?;
 6277                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6278                    if excerpted_buffer == *buffer {
 6279                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6280                            let excerpt_range = excerpt_range.to_offset(buffer);
 6281                            buffer
 6282                                .edited_ranges_for_transaction::<usize>(transaction)
 6283                                .all(|range| {
 6284                                    excerpt_range.start <= range.start
 6285                                        && excerpt_range.end >= range.end
 6286                                })
 6287                        })?;
 6288
 6289                        if all_edits_within_excerpt {
 6290                            return Ok(());
 6291                        }
 6292                    }
 6293                }
 6294            }
 6295        } else {
 6296            return Ok(());
 6297        }
 6298
 6299        let mut ranges_to_highlight = Vec::new();
 6300        let excerpt_buffer = cx.new(|cx| {
 6301            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6302            for (buffer_handle, transaction) in &entries {
 6303                let edited_ranges = buffer_handle
 6304                    .read(cx)
 6305                    .edited_ranges_for_transaction::<Point>(transaction)
 6306                    .collect::<Vec<_>>();
 6307                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6308                    PathKey::for_buffer(buffer_handle, cx),
 6309                    buffer_handle.clone(),
 6310                    edited_ranges,
 6311                    DEFAULT_MULTIBUFFER_CONTEXT,
 6312                    cx,
 6313                );
 6314
 6315                ranges_to_highlight.extend(ranges);
 6316            }
 6317            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6318            multibuffer
 6319        })?;
 6320
 6321        workspace.update_in(cx, |workspace, window, cx| {
 6322            let project = workspace.project().clone();
 6323            let editor =
 6324                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6325            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6326            editor.update(cx, |editor, cx| {
 6327                editor.highlight_background::<Self>(
 6328                    &ranges_to_highlight,
 6329                    |theme| theme.colors().editor_highlighted_line_background,
 6330                    cx,
 6331                );
 6332            });
 6333        })?;
 6334
 6335        Ok(())
 6336    }
 6337
 6338    pub fn clear_code_action_providers(&mut self) {
 6339        self.code_action_providers.clear();
 6340        self.available_code_actions.take();
 6341    }
 6342
 6343    pub fn add_code_action_provider(
 6344        &mut self,
 6345        provider: Rc<dyn CodeActionProvider>,
 6346        window: &mut Window,
 6347        cx: &mut Context<Self>,
 6348    ) {
 6349        if self
 6350            .code_action_providers
 6351            .iter()
 6352            .any(|existing_provider| existing_provider.id() == provider.id())
 6353        {
 6354            return;
 6355        }
 6356
 6357        self.code_action_providers.push(provider);
 6358        self.refresh_code_actions(window, cx);
 6359    }
 6360
 6361    pub fn remove_code_action_provider(
 6362        &mut self,
 6363        id: Arc<str>,
 6364        window: &mut Window,
 6365        cx: &mut Context<Self>,
 6366    ) {
 6367        self.code_action_providers
 6368            .retain(|provider| provider.id() != id);
 6369        self.refresh_code_actions(window, cx);
 6370    }
 6371
 6372    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6373        !self.code_action_providers.is_empty()
 6374            && EditorSettings::get_global(cx).toolbar.code_actions
 6375    }
 6376
 6377    pub fn has_available_code_actions(&self) -> bool {
 6378        self.available_code_actions
 6379            .as_ref()
 6380            .is_some_and(|(_, actions)| !actions.is_empty())
 6381    }
 6382
 6383    fn render_inline_code_actions(
 6384        &self,
 6385        icon_size: ui::IconSize,
 6386        display_row: DisplayRow,
 6387        is_active: bool,
 6388        cx: &mut Context<Self>,
 6389    ) -> AnyElement {
 6390        let show_tooltip = !self.context_menu_visible();
 6391        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6392            .icon_size(icon_size)
 6393            .shape(ui::IconButtonShape::Square)
 6394            .style(ButtonStyle::Transparent)
 6395            .icon_color(ui::Color::Hidden)
 6396            .toggle_state(is_active)
 6397            .when(show_tooltip, |this| {
 6398                this.tooltip({
 6399                    let focus_handle = self.focus_handle.clone();
 6400                    move |window, cx| {
 6401                        Tooltip::for_action_in(
 6402                            "Toggle Code Actions",
 6403                            &ToggleCodeActions {
 6404                                deployed_from: None,
 6405                                quick_launch: false,
 6406                            },
 6407                            &focus_handle,
 6408                            window,
 6409                            cx,
 6410                        )
 6411                    }
 6412                })
 6413            })
 6414            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6415                window.focus(&editor.focus_handle(cx));
 6416                editor.toggle_code_actions(
 6417                    &crate::actions::ToggleCodeActions {
 6418                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6419                            display_row,
 6420                        )),
 6421                        quick_launch: false,
 6422                    },
 6423                    window,
 6424                    cx,
 6425                );
 6426            }))
 6427            .into_any_element()
 6428    }
 6429
 6430    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6431        &self.context_menu
 6432    }
 6433
 6434    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6435        let newest_selection = self.selections.newest_anchor().clone();
 6436        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6437        let buffer = self.buffer.read(cx);
 6438        if newest_selection.head().diff_base_anchor.is_some() {
 6439            return None;
 6440        }
 6441        let (start_buffer, start) =
 6442            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6443        let (end_buffer, end) =
 6444            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6445        if start_buffer != end_buffer {
 6446            return None;
 6447        }
 6448
 6449        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6450            cx.background_executor()
 6451                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6452                .await;
 6453
 6454            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6455                let providers = this.code_action_providers.clone();
 6456                let tasks = this
 6457                    .code_action_providers
 6458                    .iter()
 6459                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6460                    .collect::<Vec<_>>();
 6461                (providers, tasks)
 6462            })?;
 6463
 6464            let mut actions = Vec::new();
 6465            for (provider, provider_actions) in
 6466                providers.into_iter().zip(future::join_all(tasks).await)
 6467            {
 6468                if let Some(provider_actions) = provider_actions.log_err() {
 6469                    actions.extend(provider_actions.into_iter().map(|action| {
 6470                        AvailableCodeAction {
 6471                            excerpt_id: newest_selection.start.excerpt_id,
 6472                            action,
 6473                            provider: provider.clone(),
 6474                        }
 6475                    }));
 6476                }
 6477            }
 6478
 6479            this.update(cx, |this, cx| {
 6480                this.available_code_actions = if actions.is_empty() {
 6481                    None
 6482                } else {
 6483                    Some((
 6484                        Location {
 6485                            buffer: start_buffer,
 6486                            range: start..end,
 6487                        },
 6488                        actions.into(),
 6489                    ))
 6490                };
 6491                cx.notify();
 6492            })
 6493        }));
 6494        None
 6495    }
 6496
 6497    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6498        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6499            self.show_git_blame_inline = false;
 6500
 6501            self.show_git_blame_inline_delay_task =
 6502                Some(cx.spawn_in(window, async move |this, cx| {
 6503                    cx.background_executor().timer(delay).await;
 6504
 6505                    this.update(cx, |this, cx| {
 6506                        this.show_git_blame_inline = true;
 6507                        cx.notify();
 6508                    })
 6509                    .log_err();
 6510                }));
 6511        }
 6512    }
 6513
 6514    fn show_blame_popover(
 6515        &mut self,
 6516        blame_entry: &BlameEntry,
 6517        position: gpui::Point<Pixels>,
 6518        cx: &mut Context<Self>,
 6519    ) {
 6520        if let Some(state) = &mut self.inline_blame_popover {
 6521            state.hide_task.take();
 6522        } else {
 6523            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6524            let blame_entry = blame_entry.clone();
 6525            let show_task = cx.spawn(async move |editor, cx| {
 6526                cx.background_executor()
 6527                    .timer(std::time::Duration::from_millis(delay))
 6528                    .await;
 6529                editor
 6530                    .update(cx, |editor, cx| {
 6531                        editor.inline_blame_popover_show_task.take();
 6532                        let Some(blame) = editor.blame.as_ref() else {
 6533                            return;
 6534                        };
 6535                        let blame = blame.read(cx);
 6536                        let details = blame.details_for_entry(&blame_entry);
 6537                        let markdown = cx.new(|cx| {
 6538                            Markdown::new(
 6539                                details
 6540                                    .as_ref()
 6541                                    .map(|message| message.message.clone())
 6542                                    .unwrap_or_default(),
 6543                                None,
 6544                                None,
 6545                                cx,
 6546                            )
 6547                        });
 6548                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6549                            position,
 6550                            hide_task: None,
 6551                            popover_bounds: None,
 6552                            popover_state: InlineBlamePopoverState {
 6553                                scroll_handle: ScrollHandle::new(),
 6554                                commit_message: details,
 6555                                markdown,
 6556                            },
 6557                        });
 6558                        cx.notify();
 6559                    })
 6560                    .ok();
 6561            });
 6562            self.inline_blame_popover_show_task = Some(show_task);
 6563        }
 6564    }
 6565
 6566    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6567        self.inline_blame_popover_show_task.take();
 6568        if let Some(state) = &mut self.inline_blame_popover {
 6569            let hide_task = cx.spawn(async move |editor, cx| {
 6570                cx.background_executor()
 6571                    .timer(std::time::Duration::from_millis(100))
 6572                    .await;
 6573                editor
 6574                    .update(cx, |editor, cx| {
 6575                        editor.inline_blame_popover.take();
 6576                        cx.notify();
 6577                    })
 6578                    .ok();
 6579            });
 6580            state.hide_task = Some(hide_task);
 6581        }
 6582    }
 6583
 6584    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6585        if self.pending_rename.is_some() {
 6586            return None;
 6587        }
 6588
 6589        let provider = self.semantics_provider.clone()?;
 6590        let buffer = self.buffer.read(cx);
 6591        let newest_selection = self.selections.newest_anchor().clone();
 6592        let cursor_position = newest_selection.head();
 6593        let (cursor_buffer, cursor_buffer_position) =
 6594            buffer.text_anchor_for_position(cursor_position, cx)?;
 6595        let (tail_buffer, tail_buffer_position) =
 6596            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6597        if cursor_buffer != tail_buffer {
 6598            return None;
 6599        }
 6600
 6601        let snapshot = cursor_buffer.read(cx).snapshot();
 6602        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6603        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6604        if start_word_range != end_word_range {
 6605            self.document_highlights_task.take();
 6606            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6607            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6608            return None;
 6609        }
 6610
 6611        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6612        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6613            cx.background_executor()
 6614                .timer(Duration::from_millis(debounce))
 6615                .await;
 6616
 6617            let highlights = if let Some(highlights) = cx
 6618                .update(|cx| {
 6619                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6620                })
 6621                .ok()
 6622                .flatten()
 6623            {
 6624                highlights.await.log_err()
 6625            } else {
 6626                None
 6627            };
 6628
 6629            if let Some(highlights) = highlights {
 6630                this.update(cx, |this, cx| {
 6631                    if this.pending_rename.is_some() {
 6632                        return;
 6633                    }
 6634
 6635                    let buffer_id = cursor_position.buffer_id;
 6636                    let buffer = this.buffer.read(cx);
 6637                    if !buffer
 6638                        .text_anchor_for_position(cursor_position, cx)
 6639                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6640                    {
 6641                        return;
 6642                    }
 6643
 6644                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6645                    let mut write_ranges = Vec::new();
 6646                    let mut read_ranges = Vec::new();
 6647                    for highlight in highlights {
 6648                        for (excerpt_id, excerpt_range) in
 6649                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6650                        {
 6651                            let start = highlight
 6652                                .range
 6653                                .start
 6654                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6655                            let end = highlight
 6656                                .range
 6657                                .end
 6658                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6659                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6660                                continue;
 6661                            }
 6662
 6663                            let range = Anchor {
 6664                                buffer_id,
 6665                                excerpt_id,
 6666                                text_anchor: start,
 6667                                diff_base_anchor: None,
 6668                            }..Anchor {
 6669                                buffer_id,
 6670                                excerpt_id,
 6671                                text_anchor: end,
 6672                                diff_base_anchor: None,
 6673                            };
 6674                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6675                                write_ranges.push(range);
 6676                            } else {
 6677                                read_ranges.push(range);
 6678                            }
 6679                        }
 6680                    }
 6681
 6682                    this.highlight_background::<DocumentHighlightRead>(
 6683                        &read_ranges,
 6684                        |theme| theme.colors().editor_document_highlight_read_background,
 6685                        cx,
 6686                    );
 6687                    this.highlight_background::<DocumentHighlightWrite>(
 6688                        &write_ranges,
 6689                        |theme| theme.colors().editor_document_highlight_write_background,
 6690                        cx,
 6691                    );
 6692                    cx.notify();
 6693                })
 6694                .log_err();
 6695            }
 6696        }));
 6697        None
 6698    }
 6699
 6700    fn prepare_highlight_query_from_selection(
 6701        &mut self,
 6702        cx: &mut Context<Editor>,
 6703    ) -> Option<(String, Range<Anchor>)> {
 6704        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6705            return None;
 6706        }
 6707        if !EditorSettings::get_global(cx).selection_highlight {
 6708            return None;
 6709        }
 6710        if self.selections.count() != 1 || self.selections.line_mode {
 6711            return None;
 6712        }
 6713        let selection = self.selections.newest::<Point>(cx);
 6714        if selection.is_empty() || selection.start.row != selection.end.row {
 6715            return None;
 6716        }
 6717        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6718        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6719        let query = multi_buffer_snapshot
 6720            .text_for_range(selection_anchor_range.clone())
 6721            .collect::<String>();
 6722        if query.trim().is_empty() {
 6723            return None;
 6724        }
 6725        Some((query, selection_anchor_range))
 6726    }
 6727
 6728    fn update_selection_occurrence_highlights(
 6729        &mut self,
 6730        query_text: String,
 6731        query_range: Range<Anchor>,
 6732        multi_buffer_range_to_query: Range<Point>,
 6733        use_debounce: bool,
 6734        window: &mut Window,
 6735        cx: &mut Context<Editor>,
 6736    ) -> Task<()> {
 6737        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6738        cx.spawn_in(window, async move |editor, cx| {
 6739            if use_debounce {
 6740                cx.background_executor()
 6741                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6742                    .await;
 6743            }
 6744            let match_task = cx.background_spawn(async move {
 6745                let buffer_ranges = multi_buffer_snapshot
 6746                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6747                    .into_iter()
 6748                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6749                let mut match_ranges = Vec::new();
 6750                let Ok(regex) = project::search::SearchQuery::text(
 6751                    query_text.clone(),
 6752                    false,
 6753                    false,
 6754                    false,
 6755                    Default::default(),
 6756                    Default::default(),
 6757                    false,
 6758                    None,
 6759                ) else {
 6760                    return Vec::default();
 6761                };
 6762                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6763                    match_ranges.extend(
 6764                        regex
 6765                            .search(&buffer_snapshot, Some(search_range.clone()))
 6766                            .await
 6767                            .into_iter()
 6768                            .filter_map(|match_range| {
 6769                                let match_start = buffer_snapshot
 6770                                    .anchor_after(search_range.start + match_range.start);
 6771                                let match_end = buffer_snapshot
 6772                                    .anchor_before(search_range.start + match_range.end);
 6773                                let match_anchor_range = Anchor::range_in_buffer(
 6774                                    excerpt_id,
 6775                                    buffer_snapshot.remote_id(),
 6776                                    match_start..match_end,
 6777                                );
 6778                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6779                            }),
 6780                    );
 6781                }
 6782                match_ranges
 6783            });
 6784            let match_ranges = match_task.await;
 6785            editor
 6786                .update_in(cx, |editor, _, cx| {
 6787                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6788                    if !match_ranges.is_empty() {
 6789                        editor.highlight_background::<SelectedTextHighlight>(
 6790                            &match_ranges,
 6791                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6792                            cx,
 6793                        )
 6794                    }
 6795                })
 6796                .log_err();
 6797        })
 6798    }
 6799
 6800    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6801        struct NewlineFold;
 6802        let type_id = std::any::TypeId::of::<NewlineFold>();
 6803        if !self.mode.is_single_line() {
 6804            return;
 6805        }
 6806        let snapshot = self.snapshot(window, cx);
 6807        if snapshot.buffer_snapshot.max_point().row == 0 {
 6808            return;
 6809        }
 6810        let task = cx.background_spawn(async move {
 6811            let new_newlines = snapshot
 6812                .buffer_chars_at(0)
 6813                .filter_map(|(c, i)| {
 6814                    if c == '\n' {
 6815                        Some(
 6816                            snapshot.buffer_snapshot.anchor_after(i)
 6817                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6818                        )
 6819                    } else {
 6820                        None
 6821                    }
 6822                })
 6823                .collect::<Vec<_>>();
 6824            let existing_newlines = snapshot
 6825                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6826                .filter_map(|fold| {
 6827                    if fold.placeholder.type_tag == Some(type_id) {
 6828                        Some(fold.range.start..fold.range.end)
 6829                    } else {
 6830                        None
 6831                    }
 6832                })
 6833                .collect::<Vec<_>>();
 6834
 6835            (new_newlines, existing_newlines)
 6836        });
 6837        self.folding_newlines = cx.spawn(async move |this, cx| {
 6838            let (new_newlines, existing_newlines) = task.await;
 6839            if new_newlines == existing_newlines {
 6840                return;
 6841            }
 6842            let placeholder = FoldPlaceholder {
 6843                render: Arc::new(move |_, _, cx| {
 6844                    div()
 6845                        .bg(cx.theme().status().hint_background)
 6846                        .border_b_1()
 6847                        .size_full()
 6848                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6849                        .border_color(cx.theme().status().hint)
 6850                        .child("\\n")
 6851                        .into_any()
 6852                }),
 6853                constrain_width: false,
 6854                merge_adjacent: false,
 6855                type_tag: Some(type_id),
 6856            };
 6857            let creases = new_newlines
 6858                .into_iter()
 6859                .map(|range| Crease::simple(range, placeholder.clone()))
 6860                .collect();
 6861            this.update(cx, |this, cx| {
 6862                this.display_map.update(cx, |display_map, cx| {
 6863                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6864                    display_map.fold(creases, cx);
 6865                });
 6866            })
 6867            .ok();
 6868        });
 6869    }
 6870
 6871    fn refresh_selected_text_highlights(
 6872        &mut self,
 6873        on_buffer_edit: bool,
 6874        window: &mut Window,
 6875        cx: &mut Context<Editor>,
 6876    ) {
 6877        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6878        else {
 6879            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6880            self.quick_selection_highlight_task.take();
 6881            self.debounced_selection_highlight_task.take();
 6882            return;
 6883        };
 6884        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6885        if on_buffer_edit
 6886            || self
 6887                .quick_selection_highlight_task
 6888                .as_ref()
 6889                .map_or(true, |(prev_anchor_range, _)| {
 6890                    prev_anchor_range != &query_range
 6891                })
 6892        {
 6893            let multi_buffer_visible_start = self
 6894                .scroll_manager
 6895                .anchor()
 6896                .anchor
 6897                .to_point(&multi_buffer_snapshot);
 6898            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6899                multi_buffer_visible_start
 6900                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6901                Bias::Left,
 6902            );
 6903            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6904            self.quick_selection_highlight_task = Some((
 6905                query_range.clone(),
 6906                self.update_selection_occurrence_highlights(
 6907                    query_text.clone(),
 6908                    query_range.clone(),
 6909                    multi_buffer_visible_range,
 6910                    false,
 6911                    window,
 6912                    cx,
 6913                ),
 6914            ));
 6915        }
 6916        if on_buffer_edit
 6917            || self
 6918                .debounced_selection_highlight_task
 6919                .as_ref()
 6920                .map_or(true, |(prev_anchor_range, _)| {
 6921                    prev_anchor_range != &query_range
 6922                })
 6923        {
 6924            let multi_buffer_start = multi_buffer_snapshot
 6925                .anchor_before(0)
 6926                .to_point(&multi_buffer_snapshot);
 6927            let multi_buffer_end = multi_buffer_snapshot
 6928                .anchor_after(multi_buffer_snapshot.len())
 6929                .to_point(&multi_buffer_snapshot);
 6930            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6931            self.debounced_selection_highlight_task = Some((
 6932                query_range.clone(),
 6933                self.update_selection_occurrence_highlights(
 6934                    query_text,
 6935                    query_range,
 6936                    multi_buffer_full_range,
 6937                    true,
 6938                    window,
 6939                    cx,
 6940                ),
 6941            ));
 6942        }
 6943    }
 6944
 6945    pub fn refresh_inline_completion(
 6946        &mut self,
 6947        debounce: bool,
 6948        user_requested: bool,
 6949        window: &mut Window,
 6950        cx: &mut Context<Self>,
 6951    ) -> Option<()> {
 6952        let provider = self.edit_prediction_provider()?;
 6953        let cursor = self.selections.newest_anchor().head();
 6954        let (buffer, cursor_buffer_position) =
 6955            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6956
 6957        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6958            self.discard_inline_completion(false, cx);
 6959            return None;
 6960        }
 6961
 6962        if !user_requested
 6963            && (!self.should_show_edit_predictions()
 6964                || !self.is_focused(window)
 6965                || buffer.read(cx).is_empty())
 6966        {
 6967            self.discard_inline_completion(false, cx);
 6968            return None;
 6969        }
 6970
 6971        self.update_visible_inline_completion(window, cx);
 6972        provider.refresh(
 6973            self.project.clone(),
 6974            buffer,
 6975            cursor_buffer_position,
 6976            debounce,
 6977            cx,
 6978        );
 6979        Some(())
 6980    }
 6981
 6982    fn show_edit_predictions_in_menu(&self) -> bool {
 6983        match self.edit_prediction_settings {
 6984            EditPredictionSettings::Disabled => false,
 6985            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6986        }
 6987    }
 6988
 6989    pub fn edit_predictions_enabled(&self) -> bool {
 6990        match self.edit_prediction_settings {
 6991            EditPredictionSettings::Disabled => false,
 6992            EditPredictionSettings::Enabled { .. } => true,
 6993        }
 6994    }
 6995
 6996    fn edit_prediction_requires_modifier(&self) -> bool {
 6997        match self.edit_prediction_settings {
 6998            EditPredictionSettings::Disabled => false,
 6999            EditPredictionSettings::Enabled {
 7000                preview_requires_modifier,
 7001                ..
 7002            } => preview_requires_modifier,
 7003        }
 7004    }
 7005
 7006    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7007        if self.edit_prediction_provider.is_none() {
 7008            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7009        } else {
 7010            let selection = self.selections.newest_anchor();
 7011            let cursor = selection.head();
 7012
 7013            if let Some((buffer, cursor_buffer_position)) =
 7014                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7015            {
 7016                self.edit_prediction_settings =
 7017                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7018            }
 7019        }
 7020    }
 7021
 7022    fn edit_prediction_settings_at_position(
 7023        &self,
 7024        buffer: &Entity<Buffer>,
 7025        buffer_position: language::Anchor,
 7026        cx: &App,
 7027    ) -> EditPredictionSettings {
 7028        if !self.mode.is_full()
 7029            || !self.show_inline_completions_override.unwrap_or(true)
 7030            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7031        {
 7032            return EditPredictionSettings::Disabled;
 7033        }
 7034
 7035        let buffer = buffer.read(cx);
 7036
 7037        let file = buffer.file();
 7038
 7039        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7040            return EditPredictionSettings::Disabled;
 7041        };
 7042
 7043        let by_provider = matches!(
 7044            self.menu_inline_completions_policy,
 7045            MenuInlineCompletionsPolicy::ByProvider
 7046        );
 7047
 7048        let show_in_menu = by_provider
 7049            && self
 7050                .edit_prediction_provider
 7051                .as_ref()
 7052                .map_or(false, |provider| {
 7053                    provider.provider.show_completions_in_menu()
 7054                });
 7055
 7056        let preview_requires_modifier =
 7057            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7058
 7059        EditPredictionSettings::Enabled {
 7060            show_in_menu,
 7061            preview_requires_modifier,
 7062        }
 7063    }
 7064
 7065    fn should_show_edit_predictions(&self) -> bool {
 7066        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7067    }
 7068
 7069    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7070        matches!(
 7071            self.edit_prediction_preview,
 7072            EditPredictionPreview::Active { .. }
 7073        )
 7074    }
 7075
 7076    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7077        let cursor = self.selections.newest_anchor().head();
 7078        if let Some((buffer, cursor_position)) =
 7079            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7080        {
 7081            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7082        } else {
 7083            false
 7084        }
 7085    }
 7086
 7087    pub fn supports_minimap(&self, cx: &App) -> bool {
 7088        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7089    }
 7090
 7091    fn edit_predictions_enabled_in_buffer(
 7092        &self,
 7093        buffer: &Entity<Buffer>,
 7094        buffer_position: language::Anchor,
 7095        cx: &App,
 7096    ) -> bool {
 7097        maybe!({
 7098            if self.read_only(cx) {
 7099                return Some(false);
 7100            }
 7101            let provider = self.edit_prediction_provider()?;
 7102            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7103                return Some(false);
 7104            }
 7105            let buffer = buffer.read(cx);
 7106            let Some(file) = buffer.file() else {
 7107                return Some(true);
 7108            };
 7109            let settings = all_language_settings(Some(file), cx);
 7110            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7111        })
 7112        .unwrap_or(false)
 7113    }
 7114
 7115    fn cycle_inline_completion(
 7116        &mut self,
 7117        direction: Direction,
 7118        window: &mut Window,
 7119        cx: &mut Context<Self>,
 7120    ) -> Option<()> {
 7121        let provider = self.edit_prediction_provider()?;
 7122        let cursor = self.selections.newest_anchor().head();
 7123        let (buffer, cursor_buffer_position) =
 7124            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7125        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7126            return None;
 7127        }
 7128
 7129        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7130        self.update_visible_inline_completion(window, cx);
 7131
 7132        Some(())
 7133    }
 7134
 7135    pub fn show_inline_completion(
 7136        &mut self,
 7137        _: &ShowEditPrediction,
 7138        window: &mut Window,
 7139        cx: &mut Context<Self>,
 7140    ) {
 7141        if !self.has_active_inline_completion() {
 7142            self.refresh_inline_completion(false, true, window, cx);
 7143            return;
 7144        }
 7145
 7146        self.update_visible_inline_completion(window, cx);
 7147    }
 7148
 7149    pub fn display_cursor_names(
 7150        &mut self,
 7151        _: &DisplayCursorNames,
 7152        window: &mut Window,
 7153        cx: &mut Context<Self>,
 7154    ) {
 7155        self.show_cursor_names(window, cx);
 7156    }
 7157
 7158    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7159        self.show_cursor_names = true;
 7160        cx.notify();
 7161        cx.spawn_in(window, async move |this, cx| {
 7162            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7163            this.update(cx, |this, cx| {
 7164                this.show_cursor_names = false;
 7165                cx.notify()
 7166            })
 7167            .ok()
 7168        })
 7169        .detach();
 7170    }
 7171
 7172    pub fn next_edit_prediction(
 7173        &mut self,
 7174        _: &NextEditPrediction,
 7175        window: &mut Window,
 7176        cx: &mut Context<Self>,
 7177    ) {
 7178        if self.has_active_inline_completion() {
 7179            self.cycle_inline_completion(Direction::Next, window, cx);
 7180        } else {
 7181            let is_copilot_disabled = self
 7182                .refresh_inline_completion(false, true, window, cx)
 7183                .is_none();
 7184            if is_copilot_disabled {
 7185                cx.propagate();
 7186            }
 7187        }
 7188    }
 7189
 7190    pub fn previous_edit_prediction(
 7191        &mut self,
 7192        _: &PreviousEditPrediction,
 7193        window: &mut Window,
 7194        cx: &mut Context<Self>,
 7195    ) {
 7196        if self.has_active_inline_completion() {
 7197            self.cycle_inline_completion(Direction::Prev, window, cx);
 7198        } else {
 7199            let is_copilot_disabled = self
 7200                .refresh_inline_completion(false, true, window, cx)
 7201                .is_none();
 7202            if is_copilot_disabled {
 7203                cx.propagate();
 7204            }
 7205        }
 7206    }
 7207
 7208    pub fn accept_edit_prediction(
 7209        &mut self,
 7210        _: &AcceptEditPrediction,
 7211        window: &mut Window,
 7212        cx: &mut Context<Self>,
 7213    ) {
 7214        if self.show_edit_predictions_in_menu() {
 7215            self.hide_context_menu(window, cx);
 7216        }
 7217
 7218        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7219            return;
 7220        };
 7221
 7222        self.report_inline_completion_event(
 7223            active_inline_completion.completion_id.clone(),
 7224            true,
 7225            cx,
 7226        );
 7227
 7228        match &active_inline_completion.completion {
 7229            InlineCompletion::Move { target, .. } => {
 7230                let target = *target;
 7231
 7232                if let Some(position_map) = &self.last_position_map {
 7233                    if position_map
 7234                        .visible_row_range
 7235                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7236                        || !self.edit_prediction_requires_modifier()
 7237                    {
 7238                        self.unfold_ranges(&[target..target], true, false, cx);
 7239                        // Note that this is also done in vim's handler of the Tab action.
 7240                        self.change_selections(
 7241                            SelectionEffects::scroll(Autoscroll::newest()),
 7242                            window,
 7243                            cx,
 7244                            |selections| {
 7245                                selections.select_anchor_ranges([target..target]);
 7246                            },
 7247                        );
 7248                        self.clear_row_highlights::<EditPredictionPreview>();
 7249
 7250                        self.edit_prediction_preview
 7251                            .set_previous_scroll_position(None);
 7252                    } else {
 7253                        self.edit_prediction_preview
 7254                            .set_previous_scroll_position(Some(
 7255                                position_map.snapshot.scroll_anchor,
 7256                            ));
 7257
 7258                        self.highlight_rows::<EditPredictionPreview>(
 7259                            target..target,
 7260                            cx.theme().colors().editor_highlighted_line_background,
 7261                            RowHighlightOptions {
 7262                                autoscroll: true,
 7263                                ..Default::default()
 7264                            },
 7265                            cx,
 7266                        );
 7267                        self.request_autoscroll(Autoscroll::fit(), cx);
 7268                    }
 7269                }
 7270            }
 7271            InlineCompletion::Edit { edits, .. } => {
 7272                if let Some(provider) = self.edit_prediction_provider() {
 7273                    provider.accept(cx);
 7274                }
 7275
 7276                // Store the transaction ID and selections before applying the edit
 7277                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7278
 7279                let snapshot = self.buffer.read(cx).snapshot(cx);
 7280                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7281
 7282                self.buffer.update(cx, |buffer, cx| {
 7283                    buffer.edit(edits.iter().cloned(), None, cx)
 7284                });
 7285
 7286                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7287                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7288                });
 7289
 7290                let selections = self.selections.disjoint_anchors();
 7291                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7292                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7293                    if has_new_transaction {
 7294                        self.selection_history
 7295                            .insert_transaction(transaction_id_now, selections);
 7296                    }
 7297                }
 7298
 7299                self.update_visible_inline_completion(window, cx);
 7300                if self.active_inline_completion.is_none() {
 7301                    self.refresh_inline_completion(true, true, window, cx);
 7302                }
 7303
 7304                cx.notify();
 7305            }
 7306        }
 7307
 7308        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7309    }
 7310
 7311    pub fn accept_partial_inline_completion(
 7312        &mut self,
 7313        _: &AcceptPartialEditPrediction,
 7314        window: &mut Window,
 7315        cx: &mut Context<Self>,
 7316    ) {
 7317        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7318            return;
 7319        };
 7320        if self.selections.count() != 1 {
 7321            return;
 7322        }
 7323
 7324        self.report_inline_completion_event(
 7325            active_inline_completion.completion_id.clone(),
 7326            true,
 7327            cx,
 7328        );
 7329
 7330        match &active_inline_completion.completion {
 7331            InlineCompletion::Move { target, .. } => {
 7332                let target = *target;
 7333                self.change_selections(
 7334                    SelectionEffects::scroll(Autoscroll::newest()),
 7335                    window,
 7336                    cx,
 7337                    |selections| {
 7338                        selections.select_anchor_ranges([target..target]);
 7339                    },
 7340                );
 7341            }
 7342            InlineCompletion::Edit { edits, .. } => {
 7343                // Find an insertion that starts at the cursor position.
 7344                let snapshot = self.buffer.read(cx).snapshot(cx);
 7345                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7346                let insertion = edits.iter().find_map(|(range, text)| {
 7347                    let range = range.to_offset(&snapshot);
 7348                    if range.is_empty() && range.start == cursor_offset {
 7349                        Some(text)
 7350                    } else {
 7351                        None
 7352                    }
 7353                });
 7354
 7355                if let Some(text) = insertion {
 7356                    let mut partial_completion = text
 7357                        .chars()
 7358                        .by_ref()
 7359                        .take_while(|c| c.is_alphabetic())
 7360                        .collect::<String>();
 7361                    if partial_completion.is_empty() {
 7362                        partial_completion = text
 7363                            .chars()
 7364                            .by_ref()
 7365                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7366                            .collect::<String>();
 7367                    }
 7368
 7369                    cx.emit(EditorEvent::InputHandled {
 7370                        utf16_range_to_replace: None,
 7371                        text: partial_completion.clone().into(),
 7372                    });
 7373
 7374                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7375
 7376                    self.refresh_inline_completion(true, true, window, cx);
 7377                    cx.notify();
 7378                } else {
 7379                    self.accept_edit_prediction(&Default::default(), window, cx);
 7380                }
 7381            }
 7382        }
 7383    }
 7384
 7385    fn discard_inline_completion(
 7386        &mut self,
 7387        should_report_inline_completion_event: bool,
 7388        cx: &mut Context<Self>,
 7389    ) -> bool {
 7390        if should_report_inline_completion_event {
 7391            let completion_id = self
 7392                .active_inline_completion
 7393                .as_ref()
 7394                .and_then(|active_completion| active_completion.completion_id.clone());
 7395
 7396            self.report_inline_completion_event(completion_id, false, cx);
 7397        }
 7398
 7399        if let Some(provider) = self.edit_prediction_provider() {
 7400            provider.discard(cx);
 7401        }
 7402
 7403        self.take_active_inline_completion(cx)
 7404    }
 7405
 7406    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7407        let Some(provider) = self.edit_prediction_provider() else {
 7408            return;
 7409        };
 7410
 7411        let Some((_, buffer, _)) = self
 7412            .buffer
 7413            .read(cx)
 7414            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7415        else {
 7416            return;
 7417        };
 7418
 7419        let extension = buffer
 7420            .read(cx)
 7421            .file()
 7422            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7423
 7424        let event_type = match accepted {
 7425            true => "Edit Prediction Accepted",
 7426            false => "Edit Prediction Discarded",
 7427        };
 7428        telemetry::event!(
 7429            event_type,
 7430            provider = provider.name(),
 7431            prediction_id = id,
 7432            suggestion_accepted = accepted,
 7433            file_extension = extension,
 7434        );
 7435    }
 7436
 7437    pub fn has_active_inline_completion(&self) -> bool {
 7438        self.active_inline_completion.is_some()
 7439    }
 7440
 7441    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7442        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7443            return false;
 7444        };
 7445
 7446        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7447        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7448        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7449        true
 7450    }
 7451
 7452    /// Returns true when we're displaying the edit prediction popover below the cursor
 7453    /// like we are not previewing and the LSP autocomplete menu is visible
 7454    /// or we are in `when_holding_modifier` mode.
 7455    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7456        if self.edit_prediction_preview_is_active()
 7457            || !self.show_edit_predictions_in_menu()
 7458            || !self.edit_predictions_enabled()
 7459        {
 7460            return false;
 7461        }
 7462
 7463        if self.has_visible_completions_menu() {
 7464            return true;
 7465        }
 7466
 7467        has_completion && self.edit_prediction_requires_modifier()
 7468    }
 7469
 7470    fn handle_modifiers_changed(
 7471        &mut self,
 7472        modifiers: Modifiers,
 7473        position_map: &PositionMap,
 7474        window: &mut Window,
 7475        cx: &mut Context<Self>,
 7476    ) {
 7477        if self.show_edit_predictions_in_menu() {
 7478            self.update_edit_prediction_preview(&modifiers, window, cx);
 7479        }
 7480
 7481        self.update_selection_mode(&modifiers, position_map, window, cx);
 7482
 7483        let mouse_position = window.mouse_position();
 7484        if !position_map.text_hitbox.is_hovered(window) {
 7485            return;
 7486        }
 7487
 7488        self.update_hovered_link(
 7489            position_map.point_for_position(mouse_position),
 7490            &position_map.snapshot,
 7491            modifiers,
 7492            window,
 7493            cx,
 7494        )
 7495    }
 7496
 7497    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7498        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7499        if invert {
 7500            match multi_cursor_setting {
 7501                MultiCursorModifier::Alt => modifiers.alt,
 7502                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7503            }
 7504        } else {
 7505            match multi_cursor_setting {
 7506                MultiCursorModifier::Alt => modifiers.secondary(),
 7507                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7508            }
 7509        }
 7510    }
 7511
 7512    fn columnar_selection_mode(
 7513        modifiers: &Modifiers,
 7514        cx: &mut Context<Self>,
 7515    ) -> Option<ColumnarMode> {
 7516        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7517            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7518                Some(ColumnarMode::FromMouse)
 7519            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7520                Some(ColumnarMode::FromSelection)
 7521            } else {
 7522                None
 7523            }
 7524        } else {
 7525            None
 7526        }
 7527    }
 7528
 7529    fn update_selection_mode(
 7530        &mut self,
 7531        modifiers: &Modifiers,
 7532        position_map: &PositionMap,
 7533        window: &mut Window,
 7534        cx: &mut Context<Self>,
 7535    ) {
 7536        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7537            return;
 7538        };
 7539        if self.selections.pending.is_none() {
 7540            return;
 7541        }
 7542
 7543        let mouse_position = window.mouse_position();
 7544        let point_for_position = position_map.point_for_position(mouse_position);
 7545        let position = point_for_position.previous_valid;
 7546
 7547        self.select(
 7548            SelectPhase::BeginColumnar {
 7549                position,
 7550                reset: false,
 7551                mode,
 7552                goal_column: point_for_position.exact_unclipped.column(),
 7553            },
 7554            window,
 7555            cx,
 7556        );
 7557    }
 7558
 7559    fn update_edit_prediction_preview(
 7560        &mut self,
 7561        modifiers: &Modifiers,
 7562        window: &mut Window,
 7563        cx: &mut Context<Self>,
 7564    ) {
 7565        let mut modifiers_held = false;
 7566        if let Some(accept_keystroke) = self
 7567            .accept_edit_prediction_keybind(false, window, cx)
 7568            .keystroke()
 7569        {
 7570            modifiers_held = modifiers_held
 7571                || (&accept_keystroke.modifiers == modifiers
 7572                    && accept_keystroke.modifiers.modified());
 7573        };
 7574        if let Some(accept_partial_keystroke) = self
 7575            .accept_edit_prediction_keybind(true, window, cx)
 7576            .keystroke()
 7577        {
 7578            modifiers_held = modifiers_held
 7579                || (&accept_partial_keystroke.modifiers == modifiers
 7580                    && accept_partial_keystroke.modifiers.modified());
 7581        }
 7582
 7583        if modifiers_held {
 7584            if matches!(
 7585                self.edit_prediction_preview,
 7586                EditPredictionPreview::Inactive { .. }
 7587            ) {
 7588                self.edit_prediction_preview = EditPredictionPreview::Active {
 7589                    previous_scroll_position: None,
 7590                    since: Instant::now(),
 7591                };
 7592
 7593                self.update_visible_inline_completion(window, cx);
 7594                cx.notify();
 7595            }
 7596        } else if let EditPredictionPreview::Active {
 7597            previous_scroll_position,
 7598            since,
 7599        } = self.edit_prediction_preview
 7600        {
 7601            if let (Some(previous_scroll_position), Some(position_map)) =
 7602                (previous_scroll_position, self.last_position_map.as_ref())
 7603            {
 7604                self.set_scroll_position(
 7605                    previous_scroll_position
 7606                        .scroll_position(&position_map.snapshot.display_snapshot),
 7607                    window,
 7608                    cx,
 7609                );
 7610            }
 7611
 7612            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7613                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7614            };
 7615            self.clear_row_highlights::<EditPredictionPreview>();
 7616            self.update_visible_inline_completion(window, cx);
 7617            cx.notify();
 7618        }
 7619    }
 7620
 7621    fn update_visible_inline_completion(
 7622        &mut self,
 7623        _window: &mut Window,
 7624        cx: &mut Context<Self>,
 7625    ) -> Option<()> {
 7626        let selection = self.selections.newest_anchor();
 7627        let cursor = selection.head();
 7628        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7629        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7630        let excerpt_id = cursor.excerpt_id;
 7631
 7632        let show_in_menu = self.show_edit_predictions_in_menu();
 7633        let completions_menu_has_precedence = !show_in_menu
 7634            && (self.context_menu.borrow().is_some()
 7635                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7636
 7637        if completions_menu_has_precedence
 7638            || !offset_selection.is_empty()
 7639            || self
 7640                .active_inline_completion
 7641                .as_ref()
 7642                .map_or(false, |completion| {
 7643                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7644                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7645                    !invalidation_range.contains(&offset_selection.head())
 7646                })
 7647        {
 7648            self.discard_inline_completion(false, cx);
 7649            return None;
 7650        }
 7651
 7652        self.take_active_inline_completion(cx);
 7653        let Some(provider) = self.edit_prediction_provider() else {
 7654            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7655            return None;
 7656        };
 7657
 7658        let (buffer, cursor_buffer_position) =
 7659            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7660
 7661        self.edit_prediction_settings =
 7662            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7663
 7664        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7665
 7666        if self.edit_prediction_indent_conflict {
 7667            let cursor_point = cursor.to_point(&multibuffer);
 7668
 7669            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7670
 7671            if let Some((_, indent)) = indents.iter().next() {
 7672                if indent.len == cursor_point.column {
 7673                    self.edit_prediction_indent_conflict = false;
 7674                }
 7675            }
 7676        }
 7677
 7678        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7679        let edits = inline_completion
 7680            .edits
 7681            .into_iter()
 7682            .flat_map(|(range, new_text)| {
 7683                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7684                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7685                Some((start..end, new_text))
 7686            })
 7687            .collect::<Vec<_>>();
 7688        if edits.is_empty() {
 7689            return None;
 7690        }
 7691
 7692        let first_edit_start = edits.first().unwrap().0.start;
 7693        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7694        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7695
 7696        let last_edit_end = edits.last().unwrap().0.end;
 7697        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7698        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7699
 7700        let cursor_row = cursor.to_point(&multibuffer).row;
 7701
 7702        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7703
 7704        let mut inlay_ids = Vec::new();
 7705        let invalidation_row_range;
 7706        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7707            Some(cursor_row..edit_end_row)
 7708        } else if cursor_row > edit_end_row {
 7709            Some(edit_start_row..cursor_row)
 7710        } else {
 7711            None
 7712        };
 7713        let is_move =
 7714            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7715        let completion = if is_move {
 7716            invalidation_row_range =
 7717                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7718            let target = first_edit_start;
 7719            InlineCompletion::Move { target, snapshot }
 7720        } else {
 7721            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7722                && !self.inline_completions_hidden_for_vim_mode;
 7723
 7724            if show_completions_in_buffer {
 7725                if edits
 7726                    .iter()
 7727                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7728                {
 7729                    let mut inlays = Vec::new();
 7730                    for (range, new_text) in &edits {
 7731                        let inlay = Inlay::inline_completion(
 7732                            post_inc(&mut self.next_inlay_id),
 7733                            range.start,
 7734                            new_text.as_str(),
 7735                        );
 7736                        inlay_ids.push(inlay.id);
 7737                        inlays.push(inlay);
 7738                    }
 7739
 7740                    self.splice_inlays(&[], inlays, cx);
 7741                } else {
 7742                    let background_color = cx.theme().status().deleted_background;
 7743                    self.highlight_text::<InlineCompletionHighlight>(
 7744                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7745                        HighlightStyle {
 7746                            background_color: Some(background_color),
 7747                            ..Default::default()
 7748                        },
 7749                        cx,
 7750                    );
 7751                }
 7752            }
 7753
 7754            invalidation_row_range = edit_start_row..edit_end_row;
 7755
 7756            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7757                if provider.show_tab_accept_marker() {
 7758                    EditDisplayMode::TabAccept
 7759                } else {
 7760                    EditDisplayMode::Inline
 7761                }
 7762            } else {
 7763                EditDisplayMode::DiffPopover
 7764            };
 7765
 7766            InlineCompletion::Edit {
 7767                edits,
 7768                edit_preview: inline_completion.edit_preview,
 7769                display_mode,
 7770                snapshot,
 7771            }
 7772        };
 7773
 7774        let invalidation_range = multibuffer
 7775            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7776            ..multibuffer.anchor_after(Point::new(
 7777                invalidation_row_range.end,
 7778                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7779            ));
 7780
 7781        self.stale_inline_completion_in_menu = None;
 7782        self.active_inline_completion = Some(InlineCompletionState {
 7783            inlay_ids,
 7784            completion,
 7785            completion_id: inline_completion.id,
 7786            invalidation_range,
 7787        });
 7788
 7789        cx.notify();
 7790
 7791        Some(())
 7792    }
 7793
 7794    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7795        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7796    }
 7797
 7798    fn clear_tasks(&mut self) {
 7799        self.tasks.clear()
 7800    }
 7801
 7802    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7803        if self.tasks.insert(key, value).is_some() {
 7804            // This case should hopefully be rare, but just in case...
 7805            log::error!(
 7806                "multiple different run targets found on a single line, only the last target will be rendered"
 7807            )
 7808        }
 7809    }
 7810
 7811    /// Get all display points of breakpoints that will be rendered within editor
 7812    ///
 7813    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7814    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7815    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7816    fn active_breakpoints(
 7817        &self,
 7818        range: Range<DisplayRow>,
 7819        window: &mut Window,
 7820        cx: &mut Context<Self>,
 7821    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7822        let mut breakpoint_display_points = HashMap::default();
 7823
 7824        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7825            return breakpoint_display_points;
 7826        };
 7827
 7828        let snapshot = self.snapshot(window, cx);
 7829
 7830        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7831        let Some(project) = self.project.as_ref() else {
 7832            return breakpoint_display_points;
 7833        };
 7834
 7835        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7836            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7837
 7838        for (buffer_snapshot, range, excerpt_id) in
 7839            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7840        {
 7841            let Some(buffer) = project
 7842                .read(cx)
 7843                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7844            else {
 7845                continue;
 7846            };
 7847            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7848                &buffer,
 7849                Some(
 7850                    buffer_snapshot.anchor_before(range.start)
 7851                        ..buffer_snapshot.anchor_after(range.end),
 7852                ),
 7853                buffer_snapshot,
 7854                cx,
 7855            );
 7856            for (breakpoint, state) in breakpoints {
 7857                let multi_buffer_anchor =
 7858                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7859                let position = multi_buffer_anchor
 7860                    .to_point(&multi_buffer_snapshot)
 7861                    .to_display_point(&snapshot);
 7862
 7863                breakpoint_display_points.insert(
 7864                    position.row(),
 7865                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7866                );
 7867            }
 7868        }
 7869
 7870        breakpoint_display_points
 7871    }
 7872
 7873    fn breakpoint_context_menu(
 7874        &self,
 7875        anchor: Anchor,
 7876        window: &mut Window,
 7877        cx: &mut Context<Self>,
 7878    ) -> Entity<ui::ContextMenu> {
 7879        let weak_editor = cx.weak_entity();
 7880        let focus_handle = self.focus_handle(cx);
 7881
 7882        let row = self
 7883            .buffer
 7884            .read(cx)
 7885            .snapshot(cx)
 7886            .summary_for_anchor::<Point>(&anchor)
 7887            .row;
 7888
 7889        let breakpoint = self
 7890            .breakpoint_at_row(row, window, cx)
 7891            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7892
 7893        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7894            "Edit Log Breakpoint"
 7895        } else {
 7896            "Set Log Breakpoint"
 7897        };
 7898
 7899        let condition_breakpoint_msg = if breakpoint
 7900            .as_ref()
 7901            .is_some_and(|bp| bp.1.condition.is_some())
 7902        {
 7903            "Edit Condition Breakpoint"
 7904        } else {
 7905            "Set Condition Breakpoint"
 7906        };
 7907
 7908        let hit_condition_breakpoint_msg = if breakpoint
 7909            .as_ref()
 7910            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7911        {
 7912            "Edit Hit Condition Breakpoint"
 7913        } else {
 7914            "Set Hit Condition Breakpoint"
 7915        };
 7916
 7917        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7918            "Unset Breakpoint"
 7919        } else {
 7920            "Set Breakpoint"
 7921        };
 7922
 7923        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7924
 7925        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7926            BreakpointState::Enabled => Some("Disable"),
 7927            BreakpointState::Disabled => Some("Enable"),
 7928        });
 7929
 7930        let (anchor, breakpoint) =
 7931            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7932
 7933        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7934            menu.on_blur_subscription(Subscription::new(|| {}))
 7935                .context(focus_handle)
 7936                .when(run_to_cursor, |this| {
 7937                    let weak_editor = weak_editor.clone();
 7938                    this.entry("Run to cursor", None, move |window, cx| {
 7939                        weak_editor
 7940                            .update(cx, |editor, cx| {
 7941                                editor.change_selections(
 7942                                    SelectionEffects::no_scroll(),
 7943                                    window,
 7944                                    cx,
 7945                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7946                                );
 7947                            })
 7948                            .ok();
 7949
 7950                        window.dispatch_action(Box::new(RunToCursor), cx);
 7951                    })
 7952                    .separator()
 7953                })
 7954                .when_some(toggle_state_msg, |this, msg| {
 7955                    this.entry(msg, None, {
 7956                        let weak_editor = weak_editor.clone();
 7957                        let breakpoint = breakpoint.clone();
 7958                        move |_window, cx| {
 7959                            weak_editor
 7960                                .update(cx, |this, cx| {
 7961                                    this.edit_breakpoint_at_anchor(
 7962                                        anchor,
 7963                                        breakpoint.as_ref().clone(),
 7964                                        BreakpointEditAction::InvertState,
 7965                                        cx,
 7966                                    );
 7967                                })
 7968                                .log_err();
 7969                        }
 7970                    })
 7971                })
 7972                .entry(set_breakpoint_msg, None, {
 7973                    let weak_editor = weak_editor.clone();
 7974                    let breakpoint = breakpoint.clone();
 7975                    move |_window, cx| {
 7976                        weak_editor
 7977                            .update(cx, |this, cx| {
 7978                                this.edit_breakpoint_at_anchor(
 7979                                    anchor,
 7980                                    breakpoint.as_ref().clone(),
 7981                                    BreakpointEditAction::Toggle,
 7982                                    cx,
 7983                                );
 7984                            })
 7985                            .log_err();
 7986                    }
 7987                })
 7988                .entry(log_breakpoint_msg, None, {
 7989                    let breakpoint = breakpoint.clone();
 7990                    let weak_editor = weak_editor.clone();
 7991                    move |window, cx| {
 7992                        weak_editor
 7993                            .update(cx, |this, cx| {
 7994                                this.add_edit_breakpoint_block(
 7995                                    anchor,
 7996                                    breakpoint.as_ref(),
 7997                                    BreakpointPromptEditAction::Log,
 7998                                    window,
 7999                                    cx,
 8000                                );
 8001                            })
 8002                            .log_err();
 8003                    }
 8004                })
 8005                .entry(condition_breakpoint_msg, None, {
 8006                    let breakpoint = breakpoint.clone();
 8007                    let weak_editor = weak_editor.clone();
 8008                    move |window, cx| {
 8009                        weak_editor
 8010                            .update(cx, |this, cx| {
 8011                                this.add_edit_breakpoint_block(
 8012                                    anchor,
 8013                                    breakpoint.as_ref(),
 8014                                    BreakpointPromptEditAction::Condition,
 8015                                    window,
 8016                                    cx,
 8017                                );
 8018                            })
 8019                            .log_err();
 8020                    }
 8021                })
 8022                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8023                    weak_editor
 8024                        .update(cx, |this, cx| {
 8025                            this.add_edit_breakpoint_block(
 8026                                anchor,
 8027                                breakpoint.as_ref(),
 8028                                BreakpointPromptEditAction::HitCondition,
 8029                                window,
 8030                                cx,
 8031                            );
 8032                        })
 8033                        .log_err();
 8034                })
 8035        })
 8036    }
 8037
 8038    fn render_breakpoint(
 8039        &self,
 8040        position: Anchor,
 8041        row: DisplayRow,
 8042        breakpoint: &Breakpoint,
 8043        state: Option<BreakpointSessionState>,
 8044        cx: &mut Context<Self>,
 8045    ) -> IconButton {
 8046        let is_rejected = state.is_some_and(|s| !s.verified);
 8047        // Is it a breakpoint that shows up when hovering over gutter?
 8048        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8049            (false, false),
 8050            |PhantomBreakpointIndicator {
 8051                 is_active,
 8052                 display_row,
 8053                 collides_with_existing_breakpoint,
 8054             }| {
 8055                (
 8056                    is_active && display_row == row,
 8057                    collides_with_existing_breakpoint,
 8058                )
 8059            },
 8060        );
 8061
 8062        let (color, icon) = {
 8063            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8064                (false, false) => ui::IconName::DebugBreakpoint,
 8065                (true, false) => ui::IconName::DebugLogBreakpoint,
 8066                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8067                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8068            };
 8069
 8070            let color = if is_phantom {
 8071                Color::Hint
 8072            } else if is_rejected {
 8073                Color::Disabled
 8074            } else {
 8075                Color::Debugger
 8076            };
 8077
 8078            (color, icon)
 8079        };
 8080
 8081        let breakpoint = Arc::from(breakpoint.clone());
 8082
 8083        let alt_as_text = gpui::Keystroke {
 8084            modifiers: Modifiers::secondary_key(),
 8085            ..Default::default()
 8086        };
 8087        let primary_action_text = if breakpoint.is_disabled() {
 8088            "Enable breakpoint"
 8089        } else if is_phantom && !collides_with_existing {
 8090            "Set breakpoint"
 8091        } else {
 8092            "Unset breakpoint"
 8093        };
 8094        let focus_handle = self.focus_handle.clone();
 8095
 8096        let meta = if is_rejected {
 8097            SharedString::from("No executable code is associated with this line.")
 8098        } else if collides_with_existing && !breakpoint.is_disabled() {
 8099            SharedString::from(format!(
 8100                "{alt_as_text}-click to disable,\nright-click for more options."
 8101            ))
 8102        } else {
 8103            SharedString::from("Right-click for more options.")
 8104        };
 8105        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8106            .icon_size(IconSize::XSmall)
 8107            .size(ui::ButtonSize::None)
 8108            .when(is_rejected, |this| {
 8109                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8110            })
 8111            .icon_color(color)
 8112            .style(ButtonStyle::Transparent)
 8113            .on_click(cx.listener({
 8114                let breakpoint = breakpoint.clone();
 8115
 8116                move |editor, event: &ClickEvent, window, cx| {
 8117                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8118                        BreakpointEditAction::InvertState
 8119                    } else {
 8120                        BreakpointEditAction::Toggle
 8121                    };
 8122
 8123                    window.focus(&editor.focus_handle(cx));
 8124                    editor.edit_breakpoint_at_anchor(
 8125                        position,
 8126                        breakpoint.as_ref().clone(),
 8127                        edit_action,
 8128                        cx,
 8129                    );
 8130                }
 8131            }))
 8132            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8133                editor.set_breakpoint_context_menu(
 8134                    row,
 8135                    Some(position),
 8136                    event.down.position,
 8137                    window,
 8138                    cx,
 8139                );
 8140            }))
 8141            .tooltip(move |window, cx| {
 8142                Tooltip::with_meta_in(
 8143                    primary_action_text,
 8144                    Some(&ToggleBreakpoint),
 8145                    meta.clone(),
 8146                    &focus_handle,
 8147                    window,
 8148                    cx,
 8149                )
 8150            })
 8151    }
 8152
 8153    fn build_tasks_context(
 8154        project: &Entity<Project>,
 8155        buffer: &Entity<Buffer>,
 8156        buffer_row: u32,
 8157        tasks: &Arc<RunnableTasks>,
 8158        cx: &mut Context<Self>,
 8159    ) -> Task<Option<task::TaskContext>> {
 8160        let position = Point::new(buffer_row, tasks.column);
 8161        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8162        let location = Location {
 8163            buffer: buffer.clone(),
 8164            range: range_start..range_start,
 8165        };
 8166        // Fill in the environmental variables from the tree-sitter captures
 8167        let mut captured_task_variables = TaskVariables::default();
 8168        for (capture_name, value) in tasks.extra_variables.clone() {
 8169            captured_task_variables.insert(
 8170                task::VariableName::Custom(capture_name.into()),
 8171                value.clone(),
 8172            );
 8173        }
 8174        project.update(cx, |project, cx| {
 8175            project.task_store().update(cx, |task_store, cx| {
 8176                task_store.task_context_for_location(captured_task_variables, location, cx)
 8177            })
 8178        })
 8179    }
 8180
 8181    pub fn spawn_nearest_task(
 8182        &mut self,
 8183        action: &SpawnNearestTask,
 8184        window: &mut Window,
 8185        cx: &mut Context<Self>,
 8186    ) {
 8187        let Some((workspace, _)) = self.workspace.clone() else {
 8188            return;
 8189        };
 8190        let Some(project) = self.project.clone() else {
 8191            return;
 8192        };
 8193
 8194        // Try to find a closest, enclosing node using tree-sitter that has a
 8195        // task
 8196        let Some((buffer, buffer_row, tasks)) = self
 8197            .find_enclosing_node_task(cx)
 8198            // Or find the task that's closest in row-distance.
 8199            .or_else(|| self.find_closest_task(cx))
 8200        else {
 8201            return;
 8202        };
 8203
 8204        let reveal_strategy = action.reveal;
 8205        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8206        cx.spawn_in(window, async move |_, cx| {
 8207            let context = task_context.await?;
 8208            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8209
 8210            let resolved = &mut resolved_task.resolved;
 8211            resolved.reveal = reveal_strategy;
 8212
 8213            workspace
 8214                .update_in(cx, |workspace, window, cx| {
 8215                    workspace.schedule_resolved_task(
 8216                        task_source_kind,
 8217                        resolved_task,
 8218                        false,
 8219                        window,
 8220                        cx,
 8221                    );
 8222                })
 8223                .ok()
 8224        })
 8225        .detach();
 8226    }
 8227
 8228    fn find_closest_task(
 8229        &mut self,
 8230        cx: &mut Context<Self>,
 8231    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8232        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8233
 8234        let ((buffer_id, row), tasks) = self
 8235            .tasks
 8236            .iter()
 8237            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8238
 8239        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8240        let tasks = Arc::new(tasks.to_owned());
 8241        Some((buffer, *row, tasks))
 8242    }
 8243
 8244    fn find_enclosing_node_task(
 8245        &mut self,
 8246        cx: &mut Context<Self>,
 8247    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8248        let snapshot = self.buffer.read(cx).snapshot(cx);
 8249        let offset = self.selections.newest::<usize>(cx).head();
 8250        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8251        let buffer_id = excerpt.buffer().remote_id();
 8252
 8253        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8254        let mut cursor = layer.node().walk();
 8255
 8256        while cursor.goto_first_child_for_byte(offset).is_some() {
 8257            if cursor.node().end_byte() == offset {
 8258                cursor.goto_next_sibling();
 8259            }
 8260        }
 8261
 8262        // Ascend to the smallest ancestor that contains the range and has a task.
 8263        loop {
 8264            let node = cursor.node();
 8265            let node_range = node.byte_range();
 8266            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8267
 8268            // Check if this node contains our offset
 8269            if node_range.start <= offset && node_range.end >= offset {
 8270                // If it contains offset, check for task
 8271                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8272                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8273                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8274                }
 8275            }
 8276
 8277            if !cursor.goto_parent() {
 8278                break;
 8279            }
 8280        }
 8281        None
 8282    }
 8283
 8284    fn render_run_indicator(
 8285        &self,
 8286        _style: &EditorStyle,
 8287        is_active: bool,
 8288        row: DisplayRow,
 8289        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8290        cx: &mut Context<Self>,
 8291    ) -> IconButton {
 8292        let color = Color::Muted;
 8293        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8294
 8295        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8296            .shape(ui::IconButtonShape::Square)
 8297            .icon_size(IconSize::XSmall)
 8298            .icon_color(color)
 8299            .toggle_state(is_active)
 8300            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8301                let quick_launch = e.down.button == MouseButton::Left;
 8302                window.focus(&editor.focus_handle(cx));
 8303                editor.toggle_code_actions(
 8304                    &ToggleCodeActions {
 8305                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8306                        quick_launch,
 8307                    },
 8308                    window,
 8309                    cx,
 8310                );
 8311            }))
 8312            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8313                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8314            }))
 8315    }
 8316
 8317    pub fn context_menu_visible(&self) -> bool {
 8318        !self.edit_prediction_preview_is_active()
 8319            && self
 8320                .context_menu
 8321                .borrow()
 8322                .as_ref()
 8323                .map_or(false, |menu| menu.visible())
 8324    }
 8325
 8326    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8327        self.context_menu
 8328            .borrow()
 8329            .as_ref()
 8330            .map(|menu| menu.origin())
 8331    }
 8332
 8333    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8334        self.context_menu_options = Some(options);
 8335    }
 8336
 8337    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8338    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8339
 8340    fn render_edit_prediction_popover(
 8341        &mut self,
 8342        text_bounds: &Bounds<Pixels>,
 8343        content_origin: gpui::Point<Pixels>,
 8344        right_margin: Pixels,
 8345        editor_snapshot: &EditorSnapshot,
 8346        visible_row_range: Range<DisplayRow>,
 8347        scroll_top: f32,
 8348        scroll_bottom: f32,
 8349        line_layouts: &[LineWithInvisibles],
 8350        line_height: Pixels,
 8351        scroll_pixel_position: gpui::Point<Pixels>,
 8352        newest_selection_head: Option<DisplayPoint>,
 8353        editor_width: Pixels,
 8354        style: &EditorStyle,
 8355        window: &mut Window,
 8356        cx: &mut App,
 8357    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8358        if self.mode().is_minimap() {
 8359            return None;
 8360        }
 8361        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8362
 8363        if self.edit_prediction_visible_in_cursor_popover(true) {
 8364            return None;
 8365        }
 8366
 8367        match &active_inline_completion.completion {
 8368            InlineCompletion::Move { target, .. } => {
 8369                let target_display_point = target.to_display_point(editor_snapshot);
 8370
 8371                if self.edit_prediction_requires_modifier() {
 8372                    if !self.edit_prediction_preview_is_active() {
 8373                        return None;
 8374                    }
 8375
 8376                    self.render_edit_prediction_modifier_jump_popover(
 8377                        text_bounds,
 8378                        content_origin,
 8379                        visible_row_range,
 8380                        line_layouts,
 8381                        line_height,
 8382                        scroll_pixel_position,
 8383                        newest_selection_head,
 8384                        target_display_point,
 8385                        window,
 8386                        cx,
 8387                    )
 8388                } else {
 8389                    self.render_edit_prediction_eager_jump_popover(
 8390                        text_bounds,
 8391                        content_origin,
 8392                        editor_snapshot,
 8393                        visible_row_range,
 8394                        scroll_top,
 8395                        scroll_bottom,
 8396                        line_height,
 8397                        scroll_pixel_position,
 8398                        target_display_point,
 8399                        editor_width,
 8400                        window,
 8401                        cx,
 8402                    )
 8403                }
 8404            }
 8405            InlineCompletion::Edit {
 8406                display_mode: EditDisplayMode::Inline,
 8407                ..
 8408            } => None,
 8409            InlineCompletion::Edit {
 8410                display_mode: EditDisplayMode::TabAccept,
 8411                edits,
 8412                ..
 8413            } => {
 8414                let range = &edits.first()?.0;
 8415                let target_display_point = range.end.to_display_point(editor_snapshot);
 8416
 8417                self.render_edit_prediction_end_of_line_popover(
 8418                    "Accept",
 8419                    editor_snapshot,
 8420                    visible_row_range,
 8421                    target_display_point,
 8422                    line_height,
 8423                    scroll_pixel_position,
 8424                    content_origin,
 8425                    editor_width,
 8426                    window,
 8427                    cx,
 8428                )
 8429            }
 8430            InlineCompletion::Edit {
 8431                edits,
 8432                edit_preview,
 8433                display_mode: EditDisplayMode::DiffPopover,
 8434                snapshot,
 8435            } => self.render_edit_prediction_diff_popover(
 8436                text_bounds,
 8437                content_origin,
 8438                right_margin,
 8439                editor_snapshot,
 8440                visible_row_range,
 8441                line_layouts,
 8442                line_height,
 8443                scroll_pixel_position,
 8444                newest_selection_head,
 8445                editor_width,
 8446                style,
 8447                edits,
 8448                edit_preview,
 8449                snapshot,
 8450                window,
 8451                cx,
 8452            ),
 8453        }
 8454    }
 8455
 8456    fn render_edit_prediction_modifier_jump_popover(
 8457        &mut self,
 8458        text_bounds: &Bounds<Pixels>,
 8459        content_origin: gpui::Point<Pixels>,
 8460        visible_row_range: Range<DisplayRow>,
 8461        line_layouts: &[LineWithInvisibles],
 8462        line_height: Pixels,
 8463        scroll_pixel_position: gpui::Point<Pixels>,
 8464        newest_selection_head: Option<DisplayPoint>,
 8465        target_display_point: DisplayPoint,
 8466        window: &mut Window,
 8467        cx: &mut App,
 8468    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8469        let scrolled_content_origin =
 8470            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8471
 8472        const SCROLL_PADDING_Y: Pixels = px(12.);
 8473
 8474        if target_display_point.row() < visible_row_range.start {
 8475            return self.render_edit_prediction_scroll_popover(
 8476                |_| SCROLL_PADDING_Y,
 8477                IconName::ArrowUp,
 8478                visible_row_range,
 8479                line_layouts,
 8480                newest_selection_head,
 8481                scrolled_content_origin,
 8482                window,
 8483                cx,
 8484            );
 8485        } else if target_display_point.row() >= visible_row_range.end {
 8486            return self.render_edit_prediction_scroll_popover(
 8487                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8488                IconName::ArrowDown,
 8489                visible_row_range,
 8490                line_layouts,
 8491                newest_selection_head,
 8492                scrolled_content_origin,
 8493                window,
 8494                cx,
 8495            );
 8496        }
 8497
 8498        const POLE_WIDTH: Pixels = px(2.);
 8499
 8500        let line_layout =
 8501            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8502        let target_column = target_display_point.column() as usize;
 8503
 8504        let target_x = line_layout.x_for_index(target_column);
 8505        let target_y =
 8506            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8507
 8508        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8509
 8510        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8511        border_color.l += 0.001;
 8512
 8513        let mut element = v_flex()
 8514            .items_end()
 8515            .when(flag_on_right, |el| el.items_start())
 8516            .child(if flag_on_right {
 8517                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8518                    .rounded_bl(px(0.))
 8519                    .rounded_tl(px(0.))
 8520                    .border_l_2()
 8521                    .border_color(border_color)
 8522            } else {
 8523                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8524                    .rounded_br(px(0.))
 8525                    .rounded_tr(px(0.))
 8526                    .border_r_2()
 8527                    .border_color(border_color)
 8528            })
 8529            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8530            .into_any();
 8531
 8532        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8533
 8534        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8535            - point(
 8536                if flag_on_right {
 8537                    POLE_WIDTH
 8538                } else {
 8539                    size.width - POLE_WIDTH
 8540                },
 8541                size.height - line_height,
 8542            );
 8543
 8544        origin.x = origin.x.max(content_origin.x);
 8545
 8546        element.prepaint_at(origin, window, cx);
 8547
 8548        Some((element, origin))
 8549    }
 8550
 8551    fn render_edit_prediction_scroll_popover(
 8552        &mut self,
 8553        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8554        scroll_icon: IconName,
 8555        visible_row_range: Range<DisplayRow>,
 8556        line_layouts: &[LineWithInvisibles],
 8557        newest_selection_head: Option<DisplayPoint>,
 8558        scrolled_content_origin: gpui::Point<Pixels>,
 8559        window: &mut Window,
 8560        cx: &mut App,
 8561    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8562        let mut element = self
 8563            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8564            .into_any();
 8565
 8566        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8567
 8568        let cursor = newest_selection_head?;
 8569        let cursor_row_layout =
 8570            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8571        let cursor_column = cursor.column() as usize;
 8572
 8573        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8574
 8575        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8576
 8577        element.prepaint_at(origin, window, cx);
 8578        Some((element, origin))
 8579    }
 8580
 8581    fn render_edit_prediction_eager_jump_popover(
 8582        &mut self,
 8583        text_bounds: &Bounds<Pixels>,
 8584        content_origin: gpui::Point<Pixels>,
 8585        editor_snapshot: &EditorSnapshot,
 8586        visible_row_range: Range<DisplayRow>,
 8587        scroll_top: f32,
 8588        scroll_bottom: f32,
 8589        line_height: Pixels,
 8590        scroll_pixel_position: gpui::Point<Pixels>,
 8591        target_display_point: DisplayPoint,
 8592        editor_width: Pixels,
 8593        window: &mut Window,
 8594        cx: &mut App,
 8595    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8596        if target_display_point.row().as_f32() < scroll_top {
 8597            let mut element = self
 8598                .render_edit_prediction_line_popover(
 8599                    "Jump to Edit",
 8600                    Some(IconName::ArrowUp),
 8601                    window,
 8602                    cx,
 8603                )?
 8604                .into_any();
 8605
 8606            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8607            let offset = point(
 8608                (text_bounds.size.width - size.width) / 2.,
 8609                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8610            );
 8611
 8612            let origin = text_bounds.origin + offset;
 8613            element.prepaint_at(origin, window, cx);
 8614            Some((element, origin))
 8615        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8616            let mut element = self
 8617                .render_edit_prediction_line_popover(
 8618                    "Jump to Edit",
 8619                    Some(IconName::ArrowDown),
 8620                    window,
 8621                    cx,
 8622                )?
 8623                .into_any();
 8624
 8625            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8626            let offset = point(
 8627                (text_bounds.size.width - size.width) / 2.,
 8628                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8629            );
 8630
 8631            let origin = text_bounds.origin + offset;
 8632            element.prepaint_at(origin, window, cx);
 8633            Some((element, origin))
 8634        } else {
 8635            self.render_edit_prediction_end_of_line_popover(
 8636                "Jump to Edit",
 8637                editor_snapshot,
 8638                visible_row_range,
 8639                target_display_point,
 8640                line_height,
 8641                scroll_pixel_position,
 8642                content_origin,
 8643                editor_width,
 8644                window,
 8645                cx,
 8646            )
 8647        }
 8648    }
 8649
 8650    fn render_edit_prediction_end_of_line_popover(
 8651        self: &mut Editor,
 8652        label: &'static str,
 8653        editor_snapshot: &EditorSnapshot,
 8654        visible_row_range: Range<DisplayRow>,
 8655        target_display_point: DisplayPoint,
 8656        line_height: Pixels,
 8657        scroll_pixel_position: gpui::Point<Pixels>,
 8658        content_origin: gpui::Point<Pixels>,
 8659        editor_width: Pixels,
 8660        window: &mut Window,
 8661        cx: &mut App,
 8662    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8663        let target_line_end = DisplayPoint::new(
 8664            target_display_point.row(),
 8665            editor_snapshot.line_len(target_display_point.row()),
 8666        );
 8667
 8668        let mut element = self
 8669            .render_edit_prediction_line_popover(label, None, window, cx)?
 8670            .into_any();
 8671
 8672        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8673
 8674        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8675
 8676        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8677        let mut origin = start_point
 8678            + line_origin
 8679            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8680        origin.x = origin.x.max(content_origin.x);
 8681
 8682        let max_x = content_origin.x + editor_width - size.width;
 8683
 8684        if origin.x > max_x {
 8685            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8686
 8687            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8688                origin.y += offset;
 8689                IconName::ArrowUp
 8690            } else {
 8691                origin.y -= offset;
 8692                IconName::ArrowDown
 8693            };
 8694
 8695            element = self
 8696                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8697                .into_any();
 8698
 8699            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8700
 8701            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8702        }
 8703
 8704        element.prepaint_at(origin, window, cx);
 8705        Some((element, origin))
 8706    }
 8707
 8708    fn render_edit_prediction_diff_popover(
 8709        self: &Editor,
 8710        text_bounds: &Bounds<Pixels>,
 8711        content_origin: gpui::Point<Pixels>,
 8712        right_margin: Pixels,
 8713        editor_snapshot: &EditorSnapshot,
 8714        visible_row_range: Range<DisplayRow>,
 8715        line_layouts: &[LineWithInvisibles],
 8716        line_height: Pixels,
 8717        scroll_pixel_position: gpui::Point<Pixels>,
 8718        newest_selection_head: Option<DisplayPoint>,
 8719        editor_width: Pixels,
 8720        style: &EditorStyle,
 8721        edits: &Vec<(Range<Anchor>, String)>,
 8722        edit_preview: &Option<language::EditPreview>,
 8723        snapshot: &language::BufferSnapshot,
 8724        window: &mut Window,
 8725        cx: &mut App,
 8726    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8727        let edit_start = edits
 8728            .first()
 8729            .unwrap()
 8730            .0
 8731            .start
 8732            .to_display_point(editor_snapshot);
 8733        let edit_end = edits
 8734            .last()
 8735            .unwrap()
 8736            .0
 8737            .end
 8738            .to_display_point(editor_snapshot);
 8739
 8740        let is_visible = visible_row_range.contains(&edit_start.row())
 8741            || visible_row_range.contains(&edit_end.row());
 8742        if !is_visible {
 8743            return None;
 8744        }
 8745
 8746        let highlighted_edits =
 8747            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8748
 8749        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8750        let line_count = highlighted_edits.text.lines().count();
 8751
 8752        const BORDER_WIDTH: Pixels = px(1.);
 8753
 8754        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8755        let has_keybind = keybind.is_some();
 8756
 8757        let mut element = h_flex()
 8758            .items_start()
 8759            .child(
 8760                h_flex()
 8761                    .bg(cx.theme().colors().editor_background)
 8762                    .border(BORDER_WIDTH)
 8763                    .shadow_xs()
 8764                    .border_color(cx.theme().colors().border)
 8765                    .rounded_l_lg()
 8766                    .when(line_count > 1, |el| el.rounded_br_lg())
 8767                    .pr_1()
 8768                    .child(styled_text),
 8769            )
 8770            .child(
 8771                h_flex()
 8772                    .h(line_height + BORDER_WIDTH * 2.)
 8773                    .px_1p5()
 8774                    .gap_1()
 8775                    // Workaround: For some reason, there's a gap if we don't do this
 8776                    .ml(-BORDER_WIDTH)
 8777                    .shadow(vec![gpui::BoxShadow {
 8778                        color: gpui::black().opacity(0.05),
 8779                        offset: point(px(1.), px(1.)),
 8780                        blur_radius: px(2.),
 8781                        spread_radius: px(0.),
 8782                    }])
 8783                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8784                    .border(BORDER_WIDTH)
 8785                    .border_color(cx.theme().colors().border)
 8786                    .rounded_r_lg()
 8787                    .id("edit_prediction_diff_popover_keybind")
 8788                    .when(!has_keybind, |el| {
 8789                        let status_colors = cx.theme().status();
 8790
 8791                        el.bg(status_colors.error_background)
 8792                            .border_color(status_colors.error.opacity(0.6))
 8793                            .child(Icon::new(IconName::Info).color(Color::Error))
 8794                            .cursor_default()
 8795                            .hoverable_tooltip(move |_window, cx| {
 8796                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8797                            })
 8798                    })
 8799                    .children(keybind),
 8800            )
 8801            .into_any();
 8802
 8803        let longest_row =
 8804            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8805        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8806            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8807        } else {
 8808            layout_line(
 8809                longest_row,
 8810                editor_snapshot,
 8811                style,
 8812                editor_width,
 8813                |_| false,
 8814                window,
 8815                cx,
 8816            )
 8817            .width
 8818        };
 8819
 8820        let viewport_bounds =
 8821            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8822                right: -right_margin,
 8823                ..Default::default()
 8824            });
 8825
 8826        let x_after_longest =
 8827            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8828                - scroll_pixel_position.x;
 8829
 8830        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8831
 8832        // Fully visible if it can be displayed within the window (allow overlapping other
 8833        // panes). However, this is only allowed if the popover starts within text_bounds.
 8834        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8835            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8836
 8837        let mut origin = if can_position_to_the_right {
 8838            point(
 8839                x_after_longest,
 8840                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8841                    - scroll_pixel_position.y,
 8842            )
 8843        } else {
 8844            let cursor_row = newest_selection_head.map(|head| head.row());
 8845            let above_edit = edit_start
 8846                .row()
 8847                .0
 8848                .checked_sub(line_count as u32)
 8849                .map(DisplayRow);
 8850            let below_edit = Some(edit_end.row() + 1);
 8851            let above_cursor =
 8852                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8853            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8854
 8855            // Place the edit popover adjacent to the edit if there is a location
 8856            // available that is onscreen and does not obscure the cursor. Otherwise,
 8857            // place it adjacent to the cursor.
 8858            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8859                .into_iter()
 8860                .flatten()
 8861                .find(|&start_row| {
 8862                    let end_row = start_row + line_count as u32;
 8863                    visible_row_range.contains(&start_row)
 8864                        && visible_row_range.contains(&end_row)
 8865                        && cursor_row.map_or(true, |cursor_row| {
 8866                            !((start_row..end_row).contains(&cursor_row))
 8867                        })
 8868                })?;
 8869
 8870            content_origin
 8871                + point(
 8872                    -scroll_pixel_position.x,
 8873                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8874                )
 8875        };
 8876
 8877        origin.x -= BORDER_WIDTH;
 8878
 8879        window.defer_draw(element, origin, 1);
 8880
 8881        // Do not return an element, since it will already be drawn due to defer_draw.
 8882        None
 8883    }
 8884
 8885    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8886        px(30.)
 8887    }
 8888
 8889    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8890        if self.read_only(cx) {
 8891            cx.theme().players().read_only()
 8892        } else {
 8893            self.style.as_ref().unwrap().local_player
 8894        }
 8895    }
 8896
 8897    fn render_edit_prediction_accept_keybind(
 8898        &self,
 8899        window: &mut Window,
 8900        cx: &App,
 8901    ) -> Option<AnyElement> {
 8902        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8903        let accept_keystroke = accept_binding.keystroke()?;
 8904
 8905        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8906
 8907        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8908            Color::Accent
 8909        } else {
 8910            Color::Muted
 8911        };
 8912
 8913        h_flex()
 8914            .px_0p5()
 8915            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8916            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8917            .text_size(TextSize::XSmall.rems(cx))
 8918            .child(h_flex().children(ui::render_modifiers(
 8919                &accept_keystroke.modifiers,
 8920                PlatformStyle::platform(),
 8921                Some(modifiers_color),
 8922                Some(IconSize::XSmall.rems().into()),
 8923                true,
 8924            )))
 8925            .when(is_platform_style_mac, |parent| {
 8926                parent.child(accept_keystroke.key.clone())
 8927            })
 8928            .when(!is_platform_style_mac, |parent| {
 8929                parent.child(
 8930                    Key::new(
 8931                        util::capitalize(&accept_keystroke.key),
 8932                        Some(Color::Default),
 8933                    )
 8934                    .size(Some(IconSize::XSmall.rems().into())),
 8935                )
 8936            })
 8937            .into_any()
 8938            .into()
 8939    }
 8940
 8941    fn render_edit_prediction_line_popover(
 8942        &self,
 8943        label: impl Into<SharedString>,
 8944        icon: Option<IconName>,
 8945        window: &mut Window,
 8946        cx: &App,
 8947    ) -> Option<Stateful<Div>> {
 8948        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8949
 8950        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8951        let has_keybind = keybind.is_some();
 8952
 8953        let result = h_flex()
 8954            .id("ep-line-popover")
 8955            .py_0p5()
 8956            .pl_1()
 8957            .pr(padding_right)
 8958            .gap_1()
 8959            .rounded_md()
 8960            .border_1()
 8961            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8962            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8963            .shadow_xs()
 8964            .when(!has_keybind, |el| {
 8965                let status_colors = cx.theme().status();
 8966
 8967                el.bg(status_colors.error_background)
 8968                    .border_color(status_colors.error.opacity(0.6))
 8969                    .pl_2()
 8970                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8971                    .cursor_default()
 8972                    .hoverable_tooltip(move |_window, cx| {
 8973                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8974                    })
 8975            })
 8976            .children(keybind)
 8977            .child(
 8978                Label::new(label)
 8979                    .size(LabelSize::Small)
 8980                    .when(!has_keybind, |el| {
 8981                        el.color(cx.theme().status().error.into()).strikethrough()
 8982                    }),
 8983            )
 8984            .when(!has_keybind, |el| {
 8985                el.child(
 8986                    h_flex().ml_1().child(
 8987                        Icon::new(IconName::Info)
 8988                            .size(IconSize::Small)
 8989                            .color(cx.theme().status().error.into()),
 8990                    ),
 8991                )
 8992            })
 8993            .when_some(icon, |element, icon| {
 8994                element.child(
 8995                    div()
 8996                        .mt(px(1.5))
 8997                        .child(Icon::new(icon).size(IconSize::Small)),
 8998                )
 8999            });
 9000
 9001        Some(result)
 9002    }
 9003
 9004    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9005        let accent_color = cx.theme().colors().text_accent;
 9006        let editor_bg_color = cx.theme().colors().editor_background;
 9007        editor_bg_color.blend(accent_color.opacity(0.1))
 9008    }
 9009
 9010    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9011        let accent_color = cx.theme().colors().text_accent;
 9012        let editor_bg_color = cx.theme().colors().editor_background;
 9013        editor_bg_color.blend(accent_color.opacity(0.6))
 9014    }
 9015
 9016    fn render_edit_prediction_cursor_popover(
 9017        &self,
 9018        min_width: Pixels,
 9019        max_width: Pixels,
 9020        cursor_point: Point,
 9021        style: &EditorStyle,
 9022        accept_keystroke: Option<&gpui::Keystroke>,
 9023        _window: &Window,
 9024        cx: &mut Context<Editor>,
 9025    ) -> Option<AnyElement> {
 9026        let provider = self.edit_prediction_provider.as_ref()?;
 9027
 9028        if provider.provider.needs_terms_acceptance(cx) {
 9029            return Some(
 9030                h_flex()
 9031                    .min_w(min_width)
 9032                    .flex_1()
 9033                    .px_2()
 9034                    .py_1()
 9035                    .gap_3()
 9036                    .elevation_2(cx)
 9037                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9038                    .id("accept-terms")
 9039                    .cursor_pointer()
 9040                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9041                    .on_click(cx.listener(|this, _event, window, cx| {
 9042                        cx.stop_propagation();
 9043                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9044                        window.dispatch_action(
 9045                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9046                            cx,
 9047                        );
 9048                    }))
 9049                    .child(
 9050                        h_flex()
 9051                            .flex_1()
 9052                            .gap_2()
 9053                            .child(Icon::new(IconName::ZedPredict))
 9054                            .child(Label::new("Accept Terms of Service"))
 9055                            .child(div().w_full())
 9056                            .child(
 9057                                Icon::new(IconName::ArrowUpRight)
 9058                                    .color(Color::Muted)
 9059                                    .size(IconSize::Small),
 9060                            )
 9061                            .into_any_element(),
 9062                    )
 9063                    .into_any(),
 9064            );
 9065        }
 9066
 9067        let is_refreshing = provider.provider.is_refreshing(cx);
 9068
 9069        fn pending_completion_container() -> Div {
 9070            h_flex()
 9071                .h_full()
 9072                .flex_1()
 9073                .gap_2()
 9074                .child(Icon::new(IconName::ZedPredict))
 9075        }
 9076
 9077        let completion = match &self.active_inline_completion {
 9078            Some(prediction) => {
 9079                if !self.has_visible_completions_menu() {
 9080                    const RADIUS: Pixels = px(6.);
 9081                    const BORDER_WIDTH: Pixels = px(1.);
 9082
 9083                    return Some(
 9084                        h_flex()
 9085                            .elevation_2(cx)
 9086                            .border(BORDER_WIDTH)
 9087                            .border_color(cx.theme().colors().border)
 9088                            .when(accept_keystroke.is_none(), |el| {
 9089                                el.border_color(cx.theme().status().error)
 9090                            })
 9091                            .rounded(RADIUS)
 9092                            .rounded_tl(px(0.))
 9093                            .overflow_hidden()
 9094                            .child(div().px_1p5().child(match &prediction.completion {
 9095                                InlineCompletion::Move { target, snapshot } => {
 9096                                    use text::ToPoint as _;
 9097                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9098                                    {
 9099                                        Icon::new(IconName::ZedPredictDown)
 9100                                    } else {
 9101                                        Icon::new(IconName::ZedPredictUp)
 9102                                    }
 9103                                }
 9104                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9105                            }))
 9106                            .child(
 9107                                h_flex()
 9108                                    .gap_1()
 9109                                    .py_1()
 9110                                    .px_2()
 9111                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9112                                    .border_l_1()
 9113                                    .border_color(cx.theme().colors().border)
 9114                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9115                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9116                                        el.child(
 9117                                            Label::new("Hold")
 9118                                                .size(LabelSize::Small)
 9119                                                .when(accept_keystroke.is_none(), |el| {
 9120                                                    el.strikethrough()
 9121                                                })
 9122                                                .line_height_style(LineHeightStyle::UiLabel),
 9123                                        )
 9124                                    })
 9125                                    .id("edit_prediction_cursor_popover_keybind")
 9126                                    .when(accept_keystroke.is_none(), |el| {
 9127                                        let status_colors = cx.theme().status();
 9128
 9129                                        el.bg(status_colors.error_background)
 9130                                            .border_color(status_colors.error.opacity(0.6))
 9131                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9132                                            .cursor_default()
 9133                                            .hoverable_tooltip(move |_window, cx| {
 9134                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9135                                                    .into()
 9136                                            })
 9137                                    })
 9138                                    .when_some(
 9139                                        accept_keystroke.as_ref(),
 9140                                        |el, accept_keystroke| {
 9141                                            el.child(h_flex().children(ui::render_modifiers(
 9142                                                &accept_keystroke.modifiers,
 9143                                                PlatformStyle::platform(),
 9144                                                Some(Color::Default),
 9145                                                Some(IconSize::XSmall.rems().into()),
 9146                                                false,
 9147                                            )))
 9148                                        },
 9149                                    ),
 9150                            )
 9151                            .into_any(),
 9152                    );
 9153                }
 9154
 9155                self.render_edit_prediction_cursor_popover_preview(
 9156                    prediction,
 9157                    cursor_point,
 9158                    style,
 9159                    cx,
 9160                )?
 9161            }
 9162
 9163            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9164                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9165                    stale_completion,
 9166                    cursor_point,
 9167                    style,
 9168                    cx,
 9169                )?,
 9170
 9171                None => {
 9172                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9173                }
 9174            },
 9175
 9176            None => pending_completion_container().child(Label::new("No Prediction")),
 9177        };
 9178
 9179        let completion = if is_refreshing {
 9180            completion
 9181                .with_animation(
 9182                    "loading-completion",
 9183                    Animation::new(Duration::from_secs(2))
 9184                        .repeat()
 9185                        .with_easing(pulsating_between(0.4, 0.8)),
 9186                    |label, delta| label.opacity(delta),
 9187                )
 9188                .into_any_element()
 9189        } else {
 9190            completion.into_any_element()
 9191        };
 9192
 9193        let has_completion = self.active_inline_completion.is_some();
 9194
 9195        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9196        Some(
 9197            h_flex()
 9198                .min_w(min_width)
 9199                .max_w(max_width)
 9200                .flex_1()
 9201                .elevation_2(cx)
 9202                .border_color(cx.theme().colors().border)
 9203                .child(
 9204                    div()
 9205                        .flex_1()
 9206                        .py_1()
 9207                        .px_2()
 9208                        .overflow_hidden()
 9209                        .child(completion),
 9210                )
 9211                .when_some(accept_keystroke, |el, accept_keystroke| {
 9212                    if !accept_keystroke.modifiers.modified() {
 9213                        return el;
 9214                    }
 9215
 9216                    el.child(
 9217                        h_flex()
 9218                            .h_full()
 9219                            .border_l_1()
 9220                            .rounded_r_lg()
 9221                            .border_color(cx.theme().colors().border)
 9222                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9223                            .gap_1()
 9224                            .py_1()
 9225                            .px_2()
 9226                            .child(
 9227                                h_flex()
 9228                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9229                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9230                                    .child(h_flex().children(ui::render_modifiers(
 9231                                        &accept_keystroke.modifiers,
 9232                                        PlatformStyle::platform(),
 9233                                        Some(if !has_completion {
 9234                                            Color::Muted
 9235                                        } else {
 9236                                            Color::Default
 9237                                        }),
 9238                                        None,
 9239                                        false,
 9240                                    ))),
 9241                            )
 9242                            .child(Label::new("Preview").into_any_element())
 9243                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9244                    )
 9245                })
 9246                .into_any(),
 9247        )
 9248    }
 9249
 9250    fn render_edit_prediction_cursor_popover_preview(
 9251        &self,
 9252        completion: &InlineCompletionState,
 9253        cursor_point: Point,
 9254        style: &EditorStyle,
 9255        cx: &mut Context<Editor>,
 9256    ) -> Option<Div> {
 9257        use text::ToPoint as _;
 9258
 9259        fn render_relative_row_jump(
 9260            prefix: impl Into<String>,
 9261            current_row: u32,
 9262            target_row: u32,
 9263        ) -> Div {
 9264            let (row_diff, arrow) = if target_row < current_row {
 9265                (current_row - target_row, IconName::ArrowUp)
 9266            } else {
 9267                (target_row - current_row, IconName::ArrowDown)
 9268            };
 9269
 9270            h_flex()
 9271                .child(
 9272                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9273                        .color(Color::Muted)
 9274                        .size(LabelSize::Small),
 9275                )
 9276                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9277        }
 9278
 9279        match &completion.completion {
 9280            InlineCompletion::Move {
 9281                target, snapshot, ..
 9282            } => Some(
 9283                h_flex()
 9284                    .px_2()
 9285                    .gap_2()
 9286                    .flex_1()
 9287                    .child(
 9288                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9289                            Icon::new(IconName::ZedPredictDown)
 9290                        } else {
 9291                            Icon::new(IconName::ZedPredictUp)
 9292                        },
 9293                    )
 9294                    .child(Label::new("Jump to Edit")),
 9295            ),
 9296
 9297            InlineCompletion::Edit {
 9298                edits,
 9299                edit_preview,
 9300                snapshot,
 9301                display_mode: _,
 9302            } => {
 9303                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9304
 9305                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9306                    &snapshot,
 9307                    &edits,
 9308                    edit_preview.as_ref()?,
 9309                    true,
 9310                    cx,
 9311                )
 9312                .first_line_preview();
 9313
 9314                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9315                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9316
 9317                let preview = h_flex()
 9318                    .gap_1()
 9319                    .min_w_16()
 9320                    .child(styled_text)
 9321                    .when(has_more_lines, |parent| parent.child(""));
 9322
 9323                let left = if first_edit_row != cursor_point.row {
 9324                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9325                        .into_any_element()
 9326                } else {
 9327                    Icon::new(IconName::ZedPredict).into_any_element()
 9328                };
 9329
 9330                Some(
 9331                    h_flex()
 9332                        .h_full()
 9333                        .flex_1()
 9334                        .gap_2()
 9335                        .pr_1()
 9336                        .overflow_x_hidden()
 9337                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9338                        .child(left)
 9339                        .child(preview),
 9340                )
 9341            }
 9342        }
 9343    }
 9344
 9345    pub fn render_context_menu(
 9346        &self,
 9347        style: &EditorStyle,
 9348        max_height_in_lines: u32,
 9349        window: &mut Window,
 9350        cx: &mut Context<Editor>,
 9351    ) -> Option<AnyElement> {
 9352        let menu = self.context_menu.borrow();
 9353        let menu = menu.as_ref()?;
 9354        if !menu.visible() {
 9355            return None;
 9356        };
 9357        Some(menu.render(style, max_height_in_lines, window, cx))
 9358    }
 9359
 9360    fn render_context_menu_aside(
 9361        &mut self,
 9362        max_size: Size<Pixels>,
 9363        window: &mut Window,
 9364        cx: &mut Context<Editor>,
 9365    ) -> Option<AnyElement> {
 9366        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9367            if menu.visible() {
 9368                menu.render_aside(max_size, window, cx)
 9369            } else {
 9370                None
 9371            }
 9372        })
 9373    }
 9374
 9375    fn hide_context_menu(
 9376        &mut self,
 9377        window: &mut Window,
 9378        cx: &mut Context<Self>,
 9379    ) -> Option<CodeContextMenu> {
 9380        cx.notify();
 9381        self.completion_tasks.clear();
 9382        let context_menu = self.context_menu.borrow_mut().take();
 9383        self.stale_inline_completion_in_menu.take();
 9384        self.update_visible_inline_completion(window, cx);
 9385        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9386            if let Some(completion_provider) = &self.completion_provider {
 9387                completion_provider.selection_changed(None, window, cx);
 9388            }
 9389        }
 9390        context_menu
 9391    }
 9392
 9393    fn show_snippet_choices(
 9394        &mut self,
 9395        choices: &Vec<String>,
 9396        selection: Range<Anchor>,
 9397        cx: &mut Context<Self>,
 9398    ) {
 9399        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9400            (Some(a), Some(b)) if a == b => a,
 9401            _ => {
 9402                log::error!("expected anchor range to have matching buffer IDs");
 9403                return;
 9404            }
 9405        };
 9406        let multi_buffer = self.buffer().read(cx);
 9407        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9408            return;
 9409        };
 9410
 9411        let id = post_inc(&mut self.next_completion_id);
 9412        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9413        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9414            CompletionsMenu::new_snippet_choices(
 9415                id,
 9416                true,
 9417                choices,
 9418                selection,
 9419                buffer,
 9420                snippet_sort_order,
 9421            ),
 9422        ));
 9423    }
 9424
 9425    pub fn insert_snippet(
 9426        &mut self,
 9427        insertion_ranges: &[Range<usize>],
 9428        snippet: Snippet,
 9429        window: &mut Window,
 9430        cx: &mut Context<Self>,
 9431    ) -> Result<()> {
 9432        struct Tabstop<T> {
 9433            is_end_tabstop: bool,
 9434            ranges: Vec<Range<T>>,
 9435            choices: Option<Vec<String>>,
 9436        }
 9437
 9438        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9439            let snippet_text: Arc<str> = snippet.text.clone().into();
 9440            let edits = insertion_ranges
 9441                .iter()
 9442                .cloned()
 9443                .map(|range| (range, snippet_text.clone()));
 9444            let autoindent_mode = AutoindentMode::Block {
 9445                original_indent_columns: Vec::new(),
 9446            };
 9447            buffer.edit(edits, Some(autoindent_mode), cx);
 9448
 9449            let snapshot = &*buffer.read(cx);
 9450            let snippet = &snippet;
 9451            snippet
 9452                .tabstops
 9453                .iter()
 9454                .map(|tabstop| {
 9455                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9456                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9457                    });
 9458                    let mut tabstop_ranges = tabstop
 9459                        .ranges
 9460                        .iter()
 9461                        .flat_map(|tabstop_range| {
 9462                            let mut delta = 0_isize;
 9463                            insertion_ranges.iter().map(move |insertion_range| {
 9464                                let insertion_start = insertion_range.start as isize + delta;
 9465                                delta +=
 9466                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9467
 9468                                let start = ((insertion_start + tabstop_range.start) as usize)
 9469                                    .min(snapshot.len());
 9470                                let end = ((insertion_start + tabstop_range.end) as usize)
 9471                                    .min(snapshot.len());
 9472                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9473                            })
 9474                        })
 9475                        .collect::<Vec<_>>();
 9476                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9477
 9478                    Tabstop {
 9479                        is_end_tabstop,
 9480                        ranges: tabstop_ranges,
 9481                        choices: tabstop.choices.clone(),
 9482                    }
 9483                })
 9484                .collect::<Vec<_>>()
 9485        });
 9486        if let Some(tabstop) = tabstops.first() {
 9487            self.change_selections(Default::default(), window, cx, |s| {
 9488                // Reverse order so that the first range is the newest created selection.
 9489                // Completions will use it and autoscroll will prioritize it.
 9490                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9491            });
 9492
 9493            if let Some(choices) = &tabstop.choices {
 9494                if let Some(selection) = tabstop.ranges.first() {
 9495                    self.show_snippet_choices(choices, selection.clone(), cx)
 9496                }
 9497            }
 9498
 9499            // If we're already at the last tabstop and it's at the end of the snippet,
 9500            // we're done, we don't need to keep the state around.
 9501            if !tabstop.is_end_tabstop {
 9502                let choices = tabstops
 9503                    .iter()
 9504                    .map(|tabstop| tabstop.choices.clone())
 9505                    .collect();
 9506
 9507                let ranges = tabstops
 9508                    .into_iter()
 9509                    .map(|tabstop| tabstop.ranges)
 9510                    .collect::<Vec<_>>();
 9511
 9512                self.snippet_stack.push(SnippetState {
 9513                    active_index: 0,
 9514                    ranges,
 9515                    choices,
 9516                });
 9517            }
 9518
 9519            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9520            if self.autoclose_regions.is_empty() {
 9521                let snapshot = self.buffer.read(cx).snapshot(cx);
 9522                for selection in &mut self.selections.all::<Point>(cx) {
 9523                    let selection_head = selection.head();
 9524                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9525                        continue;
 9526                    };
 9527
 9528                    let mut bracket_pair = None;
 9529                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9530                    let prev_chars = snapshot
 9531                        .reversed_chars_at(selection_head)
 9532                        .collect::<String>();
 9533                    for (pair, enabled) in scope.brackets() {
 9534                        if enabled
 9535                            && pair.close
 9536                            && prev_chars.starts_with(pair.start.as_str())
 9537                            && next_chars.starts_with(pair.end.as_str())
 9538                        {
 9539                            bracket_pair = Some(pair.clone());
 9540                            break;
 9541                        }
 9542                    }
 9543                    if let Some(pair) = bracket_pair {
 9544                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9545                        let autoclose_enabled =
 9546                            self.use_autoclose && snapshot_settings.use_autoclose;
 9547                        if autoclose_enabled {
 9548                            let start = snapshot.anchor_after(selection_head);
 9549                            let end = snapshot.anchor_after(selection_head);
 9550                            self.autoclose_regions.push(AutocloseRegion {
 9551                                selection_id: selection.id,
 9552                                range: start..end,
 9553                                pair,
 9554                            });
 9555                        }
 9556                    }
 9557                }
 9558            }
 9559        }
 9560        Ok(())
 9561    }
 9562
 9563    pub fn move_to_next_snippet_tabstop(
 9564        &mut self,
 9565        window: &mut Window,
 9566        cx: &mut Context<Self>,
 9567    ) -> bool {
 9568        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9569    }
 9570
 9571    pub fn move_to_prev_snippet_tabstop(
 9572        &mut self,
 9573        window: &mut Window,
 9574        cx: &mut Context<Self>,
 9575    ) -> bool {
 9576        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9577    }
 9578
 9579    pub fn move_to_snippet_tabstop(
 9580        &mut self,
 9581        bias: Bias,
 9582        window: &mut Window,
 9583        cx: &mut Context<Self>,
 9584    ) -> bool {
 9585        if let Some(mut snippet) = self.snippet_stack.pop() {
 9586            match bias {
 9587                Bias::Left => {
 9588                    if snippet.active_index > 0 {
 9589                        snippet.active_index -= 1;
 9590                    } else {
 9591                        self.snippet_stack.push(snippet);
 9592                        return false;
 9593                    }
 9594                }
 9595                Bias::Right => {
 9596                    if snippet.active_index + 1 < snippet.ranges.len() {
 9597                        snippet.active_index += 1;
 9598                    } else {
 9599                        self.snippet_stack.push(snippet);
 9600                        return false;
 9601                    }
 9602                }
 9603            }
 9604            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9605                self.change_selections(Default::default(), window, cx, |s| {
 9606                    // Reverse order so that the first range is the newest created selection.
 9607                    // Completions will use it and autoscroll will prioritize it.
 9608                    s.select_ranges(current_ranges.iter().rev().cloned())
 9609                });
 9610
 9611                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9612                    if let Some(selection) = current_ranges.first() {
 9613                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9614                    }
 9615                }
 9616
 9617                // If snippet state is not at the last tabstop, push it back on the stack
 9618                if snippet.active_index + 1 < snippet.ranges.len() {
 9619                    self.snippet_stack.push(snippet);
 9620                }
 9621                return true;
 9622            }
 9623        }
 9624
 9625        false
 9626    }
 9627
 9628    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9629        self.transact(window, cx, |this, window, cx| {
 9630            this.select_all(&SelectAll, window, cx);
 9631            this.insert("", window, cx);
 9632        });
 9633    }
 9634
 9635    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9636        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9637        self.transact(window, cx, |this, window, cx| {
 9638            this.select_autoclose_pair(window, cx);
 9639            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9640            if !this.linked_edit_ranges.is_empty() {
 9641                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9642                let snapshot = this.buffer.read(cx).snapshot(cx);
 9643
 9644                for selection in selections.iter() {
 9645                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9646                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9647                    if selection_start.buffer_id != selection_end.buffer_id {
 9648                        continue;
 9649                    }
 9650                    if let Some(ranges) =
 9651                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9652                    {
 9653                        for (buffer, entries) in ranges {
 9654                            linked_ranges.entry(buffer).or_default().extend(entries);
 9655                        }
 9656                    }
 9657                }
 9658            }
 9659
 9660            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9661            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9662            for selection in &mut selections {
 9663                if selection.is_empty() {
 9664                    let old_head = selection.head();
 9665                    let mut new_head =
 9666                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9667                            .to_point(&display_map);
 9668                    if let Some((buffer, line_buffer_range)) = display_map
 9669                        .buffer_snapshot
 9670                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9671                    {
 9672                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9673                        let indent_len = match indent_size.kind {
 9674                            IndentKind::Space => {
 9675                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9676                            }
 9677                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9678                        };
 9679                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9680                            let indent_len = indent_len.get();
 9681                            new_head = cmp::min(
 9682                                new_head,
 9683                                MultiBufferPoint::new(
 9684                                    old_head.row,
 9685                                    ((old_head.column - 1) / indent_len) * indent_len,
 9686                                ),
 9687                            );
 9688                        }
 9689                    }
 9690
 9691                    selection.set_head(new_head, SelectionGoal::None);
 9692                }
 9693            }
 9694
 9695            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9696            this.insert("", window, cx);
 9697            let empty_str: Arc<str> = Arc::from("");
 9698            for (buffer, edits) in linked_ranges {
 9699                let snapshot = buffer.read(cx).snapshot();
 9700                use text::ToPoint as TP;
 9701
 9702                let edits = edits
 9703                    .into_iter()
 9704                    .map(|range| {
 9705                        let end_point = TP::to_point(&range.end, &snapshot);
 9706                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9707
 9708                        if end_point == start_point {
 9709                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9710                                .saturating_sub(1);
 9711                            start_point =
 9712                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9713                        };
 9714
 9715                        (start_point..end_point, empty_str.clone())
 9716                    })
 9717                    .sorted_by_key(|(range, _)| range.start)
 9718                    .collect::<Vec<_>>();
 9719                buffer.update(cx, |this, cx| {
 9720                    this.edit(edits, None, cx);
 9721                })
 9722            }
 9723            this.refresh_inline_completion(true, false, window, cx);
 9724            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9725        });
 9726    }
 9727
 9728    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9729        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9730        self.transact(window, cx, |this, window, cx| {
 9731            this.change_selections(Default::default(), window, cx, |s| {
 9732                s.move_with(|map, selection| {
 9733                    if selection.is_empty() {
 9734                        let cursor = movement::right(map, selection.head());
 9735                        selection.end = cursor;
 9736                        selection.reversed = true;
 9737                        selection.goal = SelectionGoal::None;
 9738                    }
 9739                })
 9740            });
 9741            this.insert("", window, cx);
 9742            this.refresh_inline_completion(true, false, window, cx);
 9743        });
 9744    }
 9745
 9746    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9747        if self.mode.is_single_line() {
 9748            cx.propagate();
 9749            return;
 9750        }
 9751
 9752        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9753        if self.move_to_prev_snippet_tabstop(window, cx) {
 9754            return;
 9755        }
 9756        self.outdent(&Outdent, window, cx);
 9757    }
 9758
 9759    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9760        if self.mode.is_single_line() {
 9761            cx.propagate();
 9762            return;
 9763        }
 9764
 9765        if self.move_to_next_snippet_tabstop(window, cx) {
 9766            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9767            return;
 9768        }
 9769        if self.read_only(cx) {
 9770            return;
 9771        }
 9772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9773        let mut selections = self.selections.all_adjusted(cx);
 9774        let buffer = self.buffer.read(cx);
 9775        let snapshot = buffer.snapshot(cx);
 9776        let rows_iter = selections.iter().map(|s| s.head().row);
 9777        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9778
 9779        let has_some_cursor_in_whitespace = selections
 9780            .iter()
 9781            .filter(|selection| selection.is_empty())
 9782            .any(|selection| {
 9783                let cursor = selection.head();
 9784                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9785                cursor.column < current_indent.len
 9786            });
 9787
 9788        let mut edits = Vec::new();
 9789        let mut prev_edited_row = 0;
 9790        let mut row_delta = 0;
 9791        for selection in &mut selections {
 9792            if selection.start.row != prev_edited_row {
 9793                row_delta = 0;
 9794            }
 9795            prev_edited_row = selection.end.row;
 9796
 9797            // If the selection is non-empty, then increase the indentation of the selected lines.
 9798            if !selection.is_empty() {
 9799                row_delta =
 9800                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9801                continue;
 9802            }
 9803
 9804            let cursor = selection.head();
 9805            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9806            if let Some(suggested_indent) =
 9807                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9808            {
 9809                // Don't do anything if already at suggested indent
 9810                // and there is any other cursor which is not
 9811                if has_some_cursor_in_whitespace
 9812                    && cursor.column == current_indent.len
 9813                    && current_indent.len == suggested_indent.len
 9814                {
 9815                    continue;
 9816                }
 9817
 9818                // Adjust line and move cursor to suggested indent
 9819                // if cursor is not at suggested indent
 9820                if cursor.column < suggested_indent.len
 9821                    && cursor.column <= current_indent.len
 9822                    && current_indent.len <= suggested_indent.len
 9823                {
 9824                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9825                    selection.end = selection.start;
 9826                    if row_delta == 0 {
 9827                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9828                            cursor.row,
 9829                            current_indent,
 9830                            suggested_indent,
 9831                        ));
 9832                        row_delta = suggested_indent.len - current_indent.len;
 9833                    }
 9834                    continue;
 9835                }
 9836
 9837                // If current indent is more than suggested indent
 9838                // only move cursor to current indent and skip indent
 9839                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9840                    selection.start = Point::new(cursor.row, current_indent.len);
 9841                    selection.end = selection.start;
 9842                    continue;
 9843                }
 9844            }
 9845
 9846            // Otherwise, insert a hard or soft tab.
 9847            let settings = buffer.language_settings_at(cursor, cx);
 9848            let tab_size = if settings.hard_tabs {
 9849                IndentSize::tab()
 9850            } else {
 9851                let tab_size = settings.tab_size.get();
 9852                let indent_remainder = snapshot
 9853                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9854                    .flat_map(str::chars)
 9855                    .fold(row_delta % tab_size, |counter: u32, c| {
 9856                        if c == '\t' {
 9857                            0
 9858                        } else {
 9859                            (counter + 1) % tab_size
 9860                        }
 9861                    });
 9862
 9863                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9864                IndentSize::spaces(chars_to_next_tab_stop)
 9865            };
 9866            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9867            selection.end = selection.start;
 9868            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9869            row_delta += tab_size.len;
 9870        }
 9871
 9872        self.transact(window, cx, |this, window, cx| {
 9873            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9874            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9875            this.refresh_inline_completion(true, false, window, cx);
 9876        });
 9877    }
 9878
 9879    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9880        if self.read_only(cx) {
 9881            return;
 9882        }
 9883        if self.mode.is_single_line() {
 9884            cx.propagate();
 9885            return;
 9886        }
 9887
 9888        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9889        let mut selections = self.selections.all::<Point>(cx);
 9890        let mut prev_edited_row = 0;
 9891        let mut row_delta = 0;
 9892        let mut edits = Vec::new();
 9893        let buffer = self.buffer.read(cx);
 9894        let snapshot = buffer.snapshot(cx);
 9895        for selection in &mut selections {
 9896            if selection.start.row != prev_edited_row {
 9897                row_delta = 0;
 9898            }
 9899            prev_edited_row = selection.end.row;
 9900
 9901            row_delta =
 9902                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9903        }
 9904
 9905        self.transact(window, cx, |this, window, cx| {
 9906            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9907            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9908        });
 9909    }
 9910
 9911    fn indent_selection(
 9912        buffer: &MultiBuffer,
 9913        snapshot: &MultiBufferSnapshot,
 9914        selection: &mut Selection<Point>,
 9915        edits: &mut Vec<(Range<Point>, String)>,
 9916        delta_for_start_row: u32,
 9917        cx: &App,
 9918    ) -> u32 {
 9919        let settings = buffer.language_settings_at(selection.start, cx);
 9920        let tab_size = settings.tab_size.get();
 9921        let indent_kind = if settings.hard_tabs {
 9922            IndentKind::Tab
 9923        } else {
 9924            IndentKind::Space
 9925        };
 9926        let mut start_row = selection.start.row;
 9927        let mut end_row = selection.end.row + 1;
 9928
 9929        // If a selection ends at the beginning of a line, don't indent
 9930        // that last line.
 9931        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9932            end_row -= 1;
 9933        }
 9934
 9935        // Avoid re-indenting a row that has already been indented by a
 9936        // previous selection, but still update this selection's column
 9937        // to reflect that indentation.
 9938        if delta_for_start_row > 0 {
 9939            start_row += 1;
 9940            selection.start.column += delta_for_start_row;
 9941            if selection.end.row == selection.start.row {
 9942                selection.end.column += delta_for_start_row;
 9943            }
 9944        }
 9945
 9946        let mut delta_for_end_row = 0;
 9947        let has_multiple_rows = start_row + 1 != end_row;
 9948        for row in start_row..end_row {
 9949            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9950            let indent_delta = match (current_indent.kind, indent_kind) {
 9951                (IndentKind::Space, IndentKind::Space) => {
 9952                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9953                    IndentSize::spaces(columns_to_next_tab_stop)
 9954                }
 9955                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9956                (_, IndentKind::Tab) => IndentSize::tab(),
 9957            };
 9958
 9959            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9960                0
 9961            } else {
 9962                selection.start.column
 9963            };
 9964            let row_start = Point::new(row, start);
 9965            edits.push((
 9966                row_start..row_start,
 9967                indent_delta.chars().collect::<String>(),
 9968            ));
 9969
 9970            // Update this selection's endpoints to reflect the indentation.
 9971            if row == selection.start.row {
 9972                selection.start.column += indent_delta.len;
 9973            }
 9974            if row == selection.end.row {
 9975                selection.end.column += indent_delta.len;
 9976                delta_for_end_row = indent_delta.len;
 9977            }
 9978        }
 9979
 9980        if selection.start.row == selection.end.row {
 9981            delta_for_start_row + delta_for_end_row
 9982        } else {
 9983            delta_for_end_row
 9984        }
 9985    }
 9986
 9987    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9988        if self.read_only(cx) {
 9989            return;
 9990        }
 9991        if self.mode.is_single_line() {
 9992            cx.propagate();
 9993            return;
 9994        }
 9995
 9996        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9997        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9998        let selections = self.selections.all::<Point>(cx);
 9999        let mut deletion_ranges = Vec::new();
10000        let mut last_outdent = None;
10001        {
10002            let buffer = self.buffer.read(cx);
10003            let snapshot = buffer.snapshot(cx);
10004            for selection in &selections {
10005                let settings = buffer.language_settings_at(selection.start, cx);
10006                let tab_size = settings.tab_size.get();
10007                let mut rows = selection.spanned_rows(false, &display_map);
10008
10009                // Avoid re-outdenting a row that has already been outdented by a
10010                // previous selection.
10011                if let Some(last_row) = last_outdent {
10012                    if last_row == rows.start {
10013                        rows.start = rows.start.next_row();
10014                    }
10015                }
10016                let has_multiple_rows = rows.len() > 1;
10017                for row in rows.iter_rows() {
10018                    let indent_size = snapshot.indent_size_for_line(row);
10019                    if indent_size.len > 0 {
10020                        let deletion_len = match indent_size.kind {
10021                            IndentKind::Space => {
10022                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10023                                if columns_to_prev_tab_stop == 0 {
10024                                    tab_size
10025                                } else {
10026                                    columns_to_prev_tab_stop
10027                                }
10028                            }
10029                            IndentKind::Tab => 1,
10030                        };
10031                        let start = if has_multiple_rows
10032                            || deletion_len > selection.start.column
10033                            || indent_size.len < selection.start.column
10034                        {
10035                            0
10036                        } else {
10037                            selection.start.column - deletion_len
10038                        };
10039                        deletion_ranges.push(
10040                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10041                        );
10042                        last_outdent = Some(row);
10043                    }
10044                }
10045            }
10046        }
10047
10048        self.transact(window, cx, |this, window, cx| {
10049            this.buffer.update(cx, |buffer, cx| {
10050                let empty_str: Arc<str> = Arc::default();
10051                buffer.edit(
10052                    deletion_ranges
10053                        .into_iter()
10054                        .map(|range| (range, empty_str.clone())),
10055                    None,
10056                    cx,
10057                );
10058            });
10059            let selections = this.selections.all::<usize>(cx);
10060            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10061        });
10062    }
10063
10064    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10065        if self.read_only(cx) {
10066            return;
10067        }
10068        if self.mode.is_single_line() {
10069            cx.propagate();
10070            return;
10071        }
10072
10073        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10074        let selections = self
10075            .selections
10076            .all::<usize>(cx)
10077            .into_iter()
10078            .map(|s| s.range());
10079
10080        self.transact(window, cx, |this, window, cx| {
10081            this.buffer.update(cx, |buffer, cx| {
10082                buffer.autoindent_ranges(selections, cx);
10083            });
10084            let selections = this.selections.all::<usize>(cx);
10085            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10086        });
10087    }
10088
10089    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10090        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10091        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10092        let selections = self.selections.all::<Point>(cx);
10093
10094        let mut new_cursors = Vec::new();
10095        let mut edit_ranges = Vec::new();
10096        let mut selections = selections.iter().peekable();
10097        while let Some(selection) = selections.next() {
10098            let mut rows = selection.spanned_rows(false, &display_map);
10099            let goal_display_column = selection.head().to_display_point(&display_map).column();
10100
10101            // Accumulate contiguous regions of rows that we want to delete.
10102            while let Some(next_selection) = selections.peek() {
10103                let next_rows = next_selection.spanned_rows(false, &display_map);
10104                if next_rows.start <= rows.end {
10105                    rows.end = next_rows.end;
10106                    selections.next().unwrap();
10107                } else {
10108                    break;
10109                }
10110            }
10111
10112            let buffer = &display_map.buffer_snapshot;
10113            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10114            let edit_end;
10115            let cursor_buffer_row;
10116            if buffer.max_point().row >= rows.end.0 {
10117                // If there's a line after the range, delete the \n from the end of the row range
10118                // and position the cursor on the next line.
10119                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10120                cursor_buffer_row = rows.end;
10121            } else {
10122                // If there isn't a line after the range, delete the \n from the line before the
10123                // start of the row range and position the cursor there.
10124                edit_start = edit_start.saturating_sub(1);
10125                edit_end = buffer.len();
10126                cursor_buffer_row = rows.start.previous_row();
10127            }
10128
10129            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10130            *cursor.column_mut() =
10131                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10132
10133            new_cursors.push((
10134                selection.id,
10135                buffer.anchor_after(cursor.to_point(&display_map)),
10136            ));
10137            edit_ranges.push(edit_start..edit_end);
10138        }
10139
10140        self.transact(window, cx, |this, window, cx| {
10141            let buffer = this.buffer.update(cx, |buffer, cx| {
10142                let empty_str: Arc<str> = Arc::default();
10143                buffer.edit(
10144                    edit_ranges
10145                        .into_iter()
10146                        .map(|range| (range, empty_str.clone())),
10147                    None,
10148                    cx,
10149                );
10150                buffer.snapshot(cx)
10151            });
10152            let new_selections = new_cursors
10153                .into_iter()
10154                .map(|(id, cursor)| {
10155                    let cursor = cursor.to_point(&buffer);
10156                    Selection {
10157                        id,
10158                        start: cursor,
10159                        end: cursor,
10160                        reversed: false,
10161                        goal: SelectionGoal::None,
10162                    }
10163                })
10164                .collect();
10165
10166            this.change_selections(Default::default(), window, cx, |s| {
10167                s.select(new_selections);
10168            });
10169        });
10170    }
10171
10172    pub fn join_lines_impl(
10173        &mut self,
10174        insert_whitespace: bool,
10175        window: &mut Window,
10176        cx: &mut Context<Self>,
10177    ) {
10178        if self.read_only(cx) {
10179            return;
10180        }
10181        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10182        for selection in self.selections.all::<Point>(cx) {
10183            let start = MultiBufferRow(selection.start.row);
10184            // Treat single line selections as if they include the next line. Otherwise this action
10185            // would do nothing for single line selections individual cursors.
10186            let end = if selection.start.row == selection.end.row {
10187                MultiBufferRow(selection.start.row + 1)
10188            } else {
10189                MultiBufferRow(selection.end.row)
10190            };
10191
10192            if let Some(last_row_range) = row_ranges.last_mut() {
10193                if start <= last_row_range.end {
10194                    last_row_range.end = end;
10195                    continue;
10196                }
10197            }
10198            row_ranges.push(start..end);
10199        }
10200
10201        let snapshot = self.buffer.read(cx).snapshot(cx);
10202        let mut cursor_positions = Vec::new();
10203        for row_range in &row_ranges {
10204            let anchor = snapshot.anchor_before(Point::new(
10205                row_range.end.previous_row().0,
10206                snapshot.line_len(row_range.end.previous_row()),
10207            ));
10208            cursor_positions.push(anchor..anchor);
10209        }
10210
10211        self.transact(window, cx, |this, window, cx| {
10212            for row_range in row_ranges.into_iter().rev() {
10213                for row in row_range.iter_rows().rev() {
10214                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10215                    let next_line_row = row.next_row();
10216                    let indent = snapshot.indent_size_for_line(next_line_row);
10217                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10218
10219                    let replace =
10220                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10221                            " "
10222                        } else {
10223                            ""
10224                        };
10225
10226                    this.buffer.update(cx, |buffer, cx| {
10227                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10228                    });
10229                }
10230            }
10231
10232            this.change_selections(Default::default(), window, cx, |s| {
10233                s.select_anchor_ranges(cursor_positions)
10234            });
10235        });
10236    }
10237
10238    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10240        self.join_lines_impl(true, window, cx);
10241    }
10242
10243    pub fn sort_lines_case_sensitive(
10244        &mut self,
10245        _: &SortLinesCaseSensitive,
10246        window: &mut Window,
10247        cx: &mut Context<Self>,
10248    ) {
10249        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10250    }
10251
10252    pub fn sort_lines_by_length(
10253        &mut self,
10254        _: &SortLinesByLength,
10255        window: &mut Window,
10256        cx: &mut Context<Self>,
10257    ) {
10258        self.manipulate_immutable_lines(window, cx, |lines| {
10259            lines.sort_by_key(|&line| line.chars().count())
10260        })
10261    }
10262
10263    pub fn sort_lines_case_insensitive(
10264        &mut self,
10265        _: &SortLinesCaseInsensitive,
10266        window: &mut Window,
10267        cx: &mut Context<Self>,
10268    ) {
10269        self.manipulate_immutable_lines(window, cx, |lines| {
10270            lines.sort_by_key(|line| line.to_lowercase())
10271        })
10272    }
10273
10274    pub fn unique_lines_case_insensitive(
10275        &mut self,
10276        _: &UniqueLinesCaseInsensitive,
10277        window: &mut Window,
10278        cx: &mut Context<Self>,
10279    ) {
10280        self.manipulate_immutable_lines(window, cx, |lines| {
10281            let mut seen = HashSet::default();
10282            lines.retain(|line| seen.insert(line.to_lowercase()));
10283        })
10284    }
10285
10286    pub fn unique_lines_case_sensitive(
10287        &mut self,
10288        _: &UniqueLinesCaseSensitive,
10289        window: &mut Window,
10290        cx: &mut Context<Self>,
10291    ) {
10292        self.manipulate_immutable_lines(window, cx, |lines| {
10293            let mut seen = HashSet::default();
10294            lines.retain(|line| seen.insert(*line));
10295        })
10296    }
10297
10298    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10299        let Some(project) = self.project.clone() else {
10300            return;
10301        };
10302        self.reload(project, window, cx)
10303            .detach_and_notify_err(window, cx);
10304    }
10305
10306    pub fn restore_file(
10307        &mut self,
10308        _: &::git::RestoreFile,
10309        window: &mut Window,
10310        cx: &mut Context<Self>,
10311    ) {
10312        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10313        let mut buffer_ids = HashSet::default();
10314        let snapshot = self.buffer().read(cx).snapshot(cx);
10315        for selection in self.selections.all::<usize>(cx) {
10316            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10317        }
10318
10319        let buffer = self.buffer().read(cx);
10320        let ranges = buffer_ids
10321            .into_iter()
10322            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10323            .collect::<Vec<_>>();
10324
10325        self.restore_hunks_in_ranges(ranges, window, cx);
10326    }
10327
10328    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10329        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10330        let selections = self
10331            .selections
10332            .all(cx)
10333            .into_iter()
10334            .map(|s| s.range())
10335            .collect();
10336        self.restore_hunks_in_ranges(selections, window, cx);
10337    }
10338
10339    pub fn restore_hunks_in_ranges(
10340        &mut self,
10341        ranges: Vec<Range<Point>>,
10342        window: &mut Window,
10343        cx: &mut Context<Editor>,
10344    ) {
10345        let mut revert_changes = HashMap::default();
10346        let chunk_by = self
10347            .snapshot(window, cx)
10348            .hunks_for_ranges(ranges)
10349            .into_iter()
10350            .chunk_by(|hunk| hunk.buffer_id);
10351        for (buffer_id, hunks) in &chunk_by {
10352            let hunks = hunks.collect::<Vec<_>>();
10353            for hunk in &hunks {
10354                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10355            }
10356            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10357        }
10358        drop(chunk_by);
10359        if !revert_changes.is_empty() {
10360            self.transact(window, cx, |editor, window, cx| {
10361                editor.restore(revert_changes, window, cx);
10362            });
10363        }
10364    }
10365
10366    pub fn open_active_item_in_terminal(
10367        &mut self,
10368        _: &OpenInTerminal,
10369        window: &mut Window,
10370        cx: &mut Context<Self>,
10371    ) {
10372        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10373            let project_path = buffer.read(cx).project_path(cx)?;
10374            let project = self.project.as_ref()?.read(cx);
10375            let entry = project.entry_for_path(&project_path, cx)?;
10376            let parent = match &entry.canonical_path {
10377                Some(canonical_path) => canonical_path.to_path_buf(),
10378                None => project.absolute_path(&project_path, cx)?,
10379            }
10380            .parent()?
10381            .to_path_buf();
10382            Some(parent)
10383        }) {
10384            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10385        }
10386    }
10387
10388    fn set_breakpoint_context_menu(
10389        &mut self,
10390        display_row: DisplayRow,
10391        position: Option<Anchor>,
10392        clicked_point: gpui::Point<Pixels>,
10393        window: &mut Window,
10394        cx: &mut Context<Self>,
10395    ) {
10396        let source = self
10397            .buffer
10398            .read(cx)
10399            .snapshot(cx)
10400            .anchor_before(Point::new(display_row.0, 0u32));
10401
10402        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10403
10404        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10405            self,
10406            source,
10407            clicked_point,
10408            context_menu,
10409            window,
10410            cx,
10411        );
10412    }
10413
10414    fn add_edit_breakpoint_block(
10415        &mut self,
10416        anchor: Anchor,
10417        breakpoint: &Breakpoint,
10418        edit_action: BreakpointPromptEditAction,
10419        window: &mut Window,
10420        cx: &mut Context<Self>,
10421    ) {
10422        let weak_editor = cx.weak_entity();
10423        let bp_prompt = cx.new(|cx| {
10424            BreakpointPromptEditor::new(
10425                weak_editor,
10426                anchor,
10427                breakpoint.clone(),
10428                edit_action,
10429                window,
10430                cx,
10431            )
10432        });
10433
10434        let height = bp_prompt.update(cx, |this, cx| {
10435            this.prompt
10436                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10437        });
10438        let cloned_prompt = bp_prompt.clone();
10439        let blocks = vec![BlockProperties {
10440            style: BlockStyle::Sticky,
10441            placement: BlockPlacement::Above(anchor),
10442            height: Some(height),
10443            render: Arc::new(move |cx| {
10444                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10445                cloned_prompt.clone().into_any_element()
10446            }),
10447            priority: 0,
10448            render_in_minimap: true,
10449        }];
10450
10451        let focus_handle = bp_prompt.focus_handle(cx);
10452        window.focus(&focus_handle);
10453
10454        let block_ids = self.insert_blocks(blocks, None, cx);
10455        bp_prompt.update(cx, |prompt, _| {
10456            prompt.add_block_ids(block_ids);
10457        });
10458    }
10459
10460    pub(crate) fn breakpoint_at_row(
10461        &self,
10462        row: u32,
10463        window: &mut Window,
10464        cx: &mut Context<Self>,
10465    ) -> Option<(Anchor, Breakpoint)> {
10466        let snapshot = self.snapshot(window, cx);
10467        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10468
10469        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10470    }
10471
10472    pub(crate) fn breakpoint_at_anchor(
10473        &self,
10474        breakpoint_position: Anchor,
10475        snapshot: &EditorSnapshot,
10476        cx: &mut Context<Self>,
10477    ) -> Option<(Anchor, Breakpoint)> {
10478        let project = self.project.clone()?;
10479
10480        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10481            snapshot
10482                .buffer_snapshot
10483                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10484        })?;
10485
10486        let enclosing_excerpt = breakpoint_position.excerpt_id;
10487        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10488        let buffer_snapshot = buffer.read(cx).snapshot();
10489
10490        let row = buffer_snapshot
10491            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10492            .row;
10493
10494        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10495        let anchor_end = snapshot
10496            .buffer_snapshot
10497            .anchor_after(Point::new(row, line_len));
10498
10499        let bp = self
10500            .breakpoint_store
10501            .as_ref()?
10502            .read_with(cx, |breakpoint_store, cx| {
10503                breakpoint_store
10504                    .breakpoints(
10505                        &buffer,
10506                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10507                        &buffer_snapshot,
10508                        cx,
10509                    )
10510                    .next()
10511                    .and_then(|(bp, _)| {
10512                        let breakpoint_row = buffer_snapshot
10513                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10514                            .row;
10515
10516                        if breakpoint_row == row {
10517                            snapshot
10518                                .buffer_snapshot
10519                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10520                                .map(|position| (position, bp.bp.clone()))
10521                        } else {
10522                            None
10523                        }
10524                    })
10525            });
10526        bp
10527    }
10528
10529    pub fn edit_log_breakpoint(
10530        &mut self,
10531        _: &EditLogBreakpoint,
10532        window: &mut Window,
10533        cx: &mut Context<Self>,
10534    ) {
10535        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10536            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10537                message: None,
10538                state: BreakpointState::Enabled,
10539                condition: None,
10540                hit_condition: None,
10541            });
10542
10543            self.add_edit_breakpoint_block(
10544                anchor,
10545                &breakpoint,
10546                BreakpointPromptEditAction::Log,
10547                window,
10548                cx,
10549            );
10550        }
10551    }
10552
10553    fn breakpoints_at_cursors(
10554        &self,
10555        window: &mut Window,
10556        cx: &mut Context<Self>,
10557    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10558        let snapshot = self.snapshot(window, cx);
10559        let cursors = self
10560            .selections
10561            .disjoint_anchors()
10562            .into_iter()
10563            .map(|selection| {
10564                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10565
10566                let breakpoint_position = self
10567                    .breakpoint_at_row(cursor_position.row, window, cx)
10568                    .map(|bp| bp.0)
10569                    .unwrap_or_else(|| {
10570                        snapshot
10571                            .display_snapshot
10572                            .buffer_snapshot
10573                            .anchor_after(Point::new(cursor_position.row, 0))
10574                    });
10575
10576                let breakpoint = self
10577                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10578                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10579
10580                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10581            })
10582            // 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.
10583            .collect::<HashMap<Anchor, _>>();
10584
10585        cursors.into_iter().collect()
10586    }
10587
10588    pub fn enable_breakpoint(
10589        &mut self,
10590        _: &crate::actions::EnableBreakpoint,
10591        window: &mut Window,
10592        cx: &mut Context<Self>,
10593    ) {
10594        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10595            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10596                continue;
10597            };
10598            self.edit_breakpoint_at_anchor(
10599                anchor,
10600                breakpoint,
10601                BreakpointEditAction::InvertState,
10602                cx,
10603            );
10604        }
10605    }
10606
10607    pub fn disable_breakpoint(
10608        &mut self,
10609        _: &crate::actions::DisableBreakpoint,
10610        window: &mut Window,
10611        cx: &mut Context<Self>,
10612    ) {
10613        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10614            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10615                continue;
10616            };
10617            self.edit_breakpoint_at_anchor(
10618                anchor,
10619                breakpoint,
10620                BreakpointEditAction::InvertState,
10621                cx,
10622            );
10623        }
10624    }
10625
10626    pub fn toggle_breakpoint(
10627        &mut self,
10628        _: &crate::actions::ToggleBreakpoint,
10629        window: &mut Window,
10630        cx: &mut Context<Self>,
10631    ) {
10632        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10633            if let Some(breakpoint) = breakpoint {
10634                self.edit_breakpoint_at_anchor(
10635                    anchor,
10636                    breakpoint,
10637                    BreakpointEditAction::Toggle,
10638                    cx,
10639                );
10640            } else {
10641                self.edit_breakpoint_at_anchor(
10642                    anchor,
10643                    Breakpoint::new_standard(),
10644                    BreakpointEditAction::Toggle,
10645                    cx,
10646                );
10647            }
10648        }
10649    }
10650
10651    pub fn edit_breakpoint_at_anchor(
10652        &mut self,
10653        breakpoint_position: Anchor,
10654        breakpoint: Breakpoint,
10655        edit_action: BreakpointEditAction,
10656        cx: &mut Context<Self>,
10657    ) {
10658        let Some(breakpoint_store) = &self.breakpoint_store else {
10659            return;
10660        };
10661
10662        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10663            if breakpoint_position == Anchor::min() {
10664                self.buffer()
10665                    .read(cx)
10666                    .excerpt_buffer_ids()
10667                    .into_iter()
10668                    .next()
10669            } else {
10670                None
10671            }
10672        }) else {
10673            return;
10674        };
10675
10676        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10677            return;
10678        };
10679
10680        breakpoint_store.update(cx, |breakpoint_store, cx| {
10681            breakpoint_store.toggle_breakpoint(
10682                buffer,
10683                BreakpointWithPosition {
10684                    position: breakpoint_position.text_anchor,
10685                    bp: breakpoint,
10686                },
10687                edit_action,
10688                cx,
10689            );
10690        });
10691
10692        cx.notify();
10693    }
10694
10695    #[cfg(any(test, feature = "test-support"))]
10696    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10697        self.breakpoint_store.clone()
10698    }
10699
10700    pub fn prepare_restore_change(
10701        &self,
10702        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10703        hunk: &MultiBufferDiffHunk,
10704        cx: &mut App,
10705    ) -> Option<()> {
10706        if hunk.is_created_file() {
10707            return None;
10708        }
10709        let buffer = self.buffer.read(cx);
10710        let diff = buffer.diff_for(hunk.buffer_id)?;
10711        let buffer = buffer.buffer(hunk.buffer_id)?;
10712        let buffer = buffer.read(cx);
10713        let original_text = diff
10714            .read(cx)
10715            .base_text()
10716            .as_rope()
10717            .slice(hunk.diff_base_byte_range.clone());
10718        let buffer_snapshot = buffer.snapshot();
10719        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10720        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10721            probe
10722                .0
10723                .start
10724                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10725                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10726        }) {
10727            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10728            Some(())
10729        } else {
10730            None
10731        }
10732    }
10733
10734    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10735        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10736    }
10737
10738    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10739        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10740    }
10741
10742    fn manipulate_lines<M>(
10743        &mut self,
10744        window: &mut Window,
10745        cx: &mut Context<Self>,
10746        mut manipulate: M,
10747    ) where
10748        M: FnMut(&str) -> LineManipulationResult,
10749    {
10750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10751
10752        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10753        let buffer = self.buffer.read(cx).snapshot(cx);
10754
10755        let mut edits = Vec::new();
10756
10757        let selections = self.selections.all::<Point>(cx);
10758        let mut selections = selections.iter().peekable();
10759        let mut contiguous_row_selections = Vec::new();
10760        let mut new_selections = Vec::new();
10761        let mut added_lines = 0;
10762        let mut removed_lines = 0;
10763
10764        while let Some(selection) = selections.next() {
10765            let (start_row, end_row) = consume_contiguous_rows(
10766                &mut contiguous_row_selections,
10767                selection,
10768                &display_map,
10769                &mut selections,
10770            );
10771
10772            let start_point = Point::new(start_row.0, 0);
10773            let end_point = Point::new(
10774                end_row.previous_row().0,
10775                buffer.line_len(end_row.previous_row()),
10776            );
10777            let text = buffer
10778                .text_for_range(start_point..end_point)
10779                .collect::<String>();
10780
10781            let LineManipulationResult {
10782                new_text,
10783                line_count_before,
10784                line_count_after,
10785            } = manipulate(&text);
10786
10787            edits.push((start_point..end_point, new_text));
10788
10789            // Selections must change based on added and removed line count
10790            let start_row =
10791                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10792            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10793            new_selections.push(Selection {
10794                id: selection.id,
10795                start: start_row,
10796                end: end_row,
10797                goal: SelectionGoal::None,
10798                reversed: selection.reversed,
10799            });
10800
10801            if line_count_after > line_count_before {
10802                added_lines += line_count_after - line_count_before;
10803            } else if line_count_before > line_count_after {
10804                removed_lines += line_count_before - line_count_after;
10805            }
10806        }
10807
10808        self.transact(window, cx, |this, window, cx| {
10809            let buffer = this.buffer.update(cx, |buffer, cx| {
10810                buffer.edit(edits, None, cx);
10811                buffer.snapshot(cx)
10812            });
10813
10814            // Recalculate offsets on newly edited buffer
10815            let new_selections = new_selections
10816                .iter()
10817                .map(|s| {
10818                    let start_point = Point::new(s.start.0, 0);
10819                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10820                    Selection {
10821                        id: s.id,
10822                        start: buffer.point_to_offset(start_point),
10823                        end: buffer.point_to_offset(end_point),
10824                        goal: s.goal,
10825                        reversed: s.reversed,
10826                    }
10827                })
10828                .collect();
10829
10830            this.change_selections(Default::default(), window, cx, |s| {
10831                s.select(new_selections);
10832            });
10833
10834            this.request_autoscroll(Autoscroll::fit(), cx);
10835        });
10836    }
10837
10838    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10839        self.manipulate_text(window, cx, |text| {
10840            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10841            if has_upper_case_characters {
10842                text.to_lowercase()
10843            } else {
10844                text.to_uppercase()
10845            }
10846        })
10847    }
10848
10849    fn manipulate_immutable_lines<Fn>(
10850        &mut self,
10851        window: &mut Window,
10852        cx: &mut Context<Self>,
10853        mut callback: Fn,
10854    ) where
10855        Fn: FnMut(&mut Vec<&str>),
10856    {
10857        self.manipulate_lines(window, cx, |text| {
10858            let mut lines: Vec<&str> = text.split('\n').collect();
10859            let line_count_before = lines.len();
10860
10861            callback(&mut lines);
10862
10863            LineManipulationResult {
10864                new_text: lines.join("\n"),
10865                line_count_before,
10866                line_count_after: lines.len(),
10867            }
10868        });
10869    }
10870
10871    fn manipulate_mutable_lines<Fn>(
10872        &mut self,
10873        window: &mut Window,
10874        cx: &mut Context<Self>,
10875        mut callback: Fn,
10876    ) where
10877        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10878    {
10879        self.manipulate_lines(window, cx, |text| {
10880            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10881            let line_count_before = lines.len();
10882
10883            callback(&mut lines);
10884
10885            LineManipulationResult {
10886                new_text: lines.join("\n"),
10887                line_count_before,
10888                line_count_after: lines.len(),
10889            }
10890        });
10891    }
10892
10893    pub fn convert_indentation_to_spaces(
10894        &mut self,
10895        _: &ConvertIndentationToSpaces,
10896        window: &mut Window,
10897        cx: &mut Context<Self>,
10898    ) {
10899        let settings = self.buffer.read(cx).language_settings(cx);
10900        let tab_size = settings.tab_size.get() as usize;
10901
10902        self.manipulate_mutable_lines(window, cx, |lines| {
10903            // Allocates a reasonably sized scratch buffer once for the whole loop
10904            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10905            // Avoids recomputing spaces that could be inserted many times
10906            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10907                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10908                .collect();
10909
10910            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10911                let mut chars = line.as_ref().chars();
10912                let mut col = 0;
10913                let mut changed = false;
10914
10915                while let Some(ch) = chars.next() {
10916                    match ch {
10917                        ' ' => {
10918                            reindented_line.push(' ');
10919                            col += 1;
10920                        }
10921                        '\t' => {
10922                            // \t are converted to spaces depending on the current column
10923                            let spaces_len = tab_size - (col % tab_size);
10924                            reindented_line.extend(&space_cache[spaces_len - 1]);
10925                            col += spaces_len;
10926                            changed = true;
10927                        }
10928                        _ => {
10929                            // If we dont append before break, the character is consumed
10930                            reindented_line.push(ch);
10931                            break;
10932                        }
10933                    }
10934                }
10935
10936                if !changed {
10937                    reindented_line.clear();
10938                    continue;
10939                }
10940                // Append the rest of the line and replace old reference with new one
10941                reindented_line.extend(chars);
10942                *line = Cow::Owned(reindented_line.clone());
10943                reindented_line.clear();
10944            }
10945        });
10946    }
10947
10948    pub fn convert_indentation_to_tabs(
10949        &mut self,
10950        _: &ConvertIndentationToTabs,
10951        window: &mut Window,
10952        cx: &mut Context<Self>,
10953    ) {
10954        let settings = self.buffer.read(cx).language_settings(cx);
10955        let tab_size = settings.tab_size.get() as usize;
10956
10957        self.manipulate_mutable_lines(window, cx, |lines| {
10958            // Allocates a reasonably sized buffer once for the whole loop
10959            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10960            // Avoids recomputing spaces that could be inserted many times
10961            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10962                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10963                .collect();
10964
10965            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10966                let mut chars = line.chars();
10967                let mut spaces_count = 0;
10968                let mut first_non_indent_char = None;
10969                let mut changed = false;
10970
10971                while let Some(ch) = chars.next() {
10972                    match ch {
10973                        ' ' => {
10974                            // Keep track of spaces. Append \t when we reach tab_size
10975                            spaces_count += 1;
10976                            changed = true;
10977                            if spaces_count == tab_size {
10978                                reindented_line.push('\t');
10979                                spaces_count = 0;
10980                            }
10981                        }
10982                        '\t' => {
10983                            reindented_line.push('\t');
10984                            spaces_count = 0;
10985                        }
10986                        _ => {
10987                            // Dont append it yet, we might have remaining spaces
10988                            first_non_indent_char = Some(ch);
10989                            break;
10990                        }
10991                    }
10992                }
10993
10994                if !changed {
10995                    reindented_line.clear();
10996                    continue;
10997                }
10998                // Remaining spaces that didn't make a full tab stop
10999                if spaces_count > 0 {
11000                    reindented_line.extend(&space_cache[spaces_count - 1]);
11001                }
11002                // If we consume an extra character that was not indentation, add it back
11003                if let Some(extra_char) = first_non_indent_char {
11004                    reindented_line.push(extra_char);
11005                }
11006                // Append the rest of the line and replace old reference with new one
11007                reindented_line.extend(chars);
11008                *line = Cow::Owned(reindented_line.clone());
11009                reindented_line.clear();
11010            }
11011        });
11012    }
11013
11014    pub fn convert_to_upper_case(
11015        &mut self,
11016        _: &ConvertToUpperCase,
11017        window: &mut Window,
11018        cx: &mut Context<Self>,
11019    ) {
11020        self.manipulate_text(window, cx, |text| text.to_uppercase())
11021    }
11022
11023    pub fn convert_to_lower_case(
11024        &mut self,
11025        _: &ConvertToLowerCase,
11026        window: &mut Window,
11027        cx: &mut Context<Self>,
11028    ) {
11029        self.manipulate_text(window, cx, |text| text.to_lowercase())
11030    }
11031
11032    pub fn convert_to_title_case(
11033        &mut self,
11034        _: &ConvertToTitleCase,
11035        window: &mut Window,
11036        cx: &mut Context<Self>,
11037    ) {
11038        self.manipulate_text(window, cx, |text| {
11039            text.split('\n')
11040                .map(|line| line.to_case(Case::Title))
11041                .join("\n")
11042        })
11043    }
11044
11045    pub fn convert_to_snake_case(
11046        &mut self,
11047        _: &ConvertToSnakeCase,
11048        window: &mut Window,
11049        cx: &mut Context<Self>,
11050    ) {
11051        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11052    }
11053
11054    pub fn convert_to_kebab_case(
11055        &mut self,
11056        _: &ConvertToKebabCase,
11057        window: &mut Window,
11058        cx: &mut Context<Self>,
11059    ) {
11060        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11061    }
11062
11063    pub fn convert_to_upper_camel_case(
11064        &mut self,
11065        _: &ConvertToUpperCamelCase,
11066        window: &mut Window,
11067        cx: &mut Context<Self>,
11068    ) {
11069        self.manipulate_text(window, cx, |text| {
11070            text.split('\n')
11071                .map(|line| line.to_case(Case::UpperCamel))
11072                .join("\n")
11073        })
11074    }
11075
11076    pub fn convert_to_lower_camel_case(
11077        &mut self,
11078        _: &ConvertToLowerCamelCase,
11079        window: &mut Window,
11080        cx: &mut Context<Self>,
11081    ) {
11082        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11083    }
11084
11085    pub fn convert_to_opposite_case(
11086        &mut self,
11087        _: &ConvertToOppositeCase,
11088        window: &mut Window,
11089        cx: &mut Context<Self>,
11090    ) {
11091        self.manipulate_text(window, cx, |text| {
11092            text.chars()
11093                .fold(String::with_capacity(text.len()), |mut t, c| {
11094                    if c.is_uppercase() {
11095                        t.extend(c.to_lowercase());
11096                    } else {
11097                        t.extend(c.to_uppercase());
11098                    }
11099                    t
11100                })
11101        })
11102    }
11103
11104    pub fn convert_to_rot13(
11105        &mut self,
11106        _: &ConvertToRot13,
11107        window: &mut Window,
11108        cx: &mut Context<Self>,
11109    ) {
11110        self.manipulate_text(window, cx, |text| {
11111            text.chars()
11112                .map(|c| match c {
11113                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11114                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11115                    _ => c,
11116                })
11117                .collect()
11118        })
11119    }
11120
11121    pub fn convert_to_rot47(
11122        &mut self,
11123        _: &ConvertToRot47,
11124        window: &mut Window,
11125        cx: &mut Context<Self>,
11126    ) {
11127        self.manipulate_text(window, cx, |text| {
11128            text.chars()
11129                .map(|c| {
11130                    let code_point = c as u32;
11131                    if code_point >= 33 && code_point <= 126 {
11132                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11133                    }
11134                    c
11135                })
11136                .collect()
11137        })
11138    }
11139
11140    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11141    where
11142        Fn: FnMut(&str) -> String,
11143    {
11144        let buffer = self.buffer.read(cx).snapshot(cx);
11145
11146        let mut new_selections = Vec::new();
11147        let mut edits = Vec::new();
11148        let mut selection_adjustment = 0i32;
11149
11150        for selection in self.selections.all::<usize>(cx) {
11151            let selection_is_empty = selection.is_empty();
11152
11153            let (start, end) = if selection_is_empty {
11154                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11155                (word_range.start, word_range.end)
11156            } else {
11157                (selection.start, selection.end)
11158            };
11159
11160            let text = buffer.text_for_range(start..end).collect::<String>();
11161            let old_length = text.len() as i32;
11162            let text = callback(&text);
11163
11164            new_selections.push(Selection {
11165                start: (start as i32 - selection_adjustment) as usize,
11166                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11167                goal: SelectionGoal::None,
11168                ..selection
11169            });
11170
11171            selection_adjustment += old_length - text.len() as i32;
11172
11173            edits.push((start..end, text));
11174        }
11175
11176        self.transact(window, cx, |this, window, cx| {
11177            this.buffer.update(cx, |buffer, cx| {
11178                buffer.edit(edits, None, cx);
11179            });
11180
11181            this.change_selections(Default::default(), window, cx, |s| {
11182                s.select(new_selections);
11183            });
11184
11185            this.request_autoscroll(Autoscroll::fit(), cx);
11186        });
11187    }
11188
11189    pub fn move_selection_on_drop(
11190        &mut self,
11191        selection: &Selection<Anchor>,
11192        target: DisplayPoint,
11193        is_cut: bool,
11194        window: &mut Window,
11195        cx: &mut Context<Self>,
11196    ) {
11197        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11198        let buffer = &display_map.buffer_snapshot;
11199        let mut edits = Vec::new();
11200        let insert_point = display_map
11201            .clip_point(target, Bias::Left)
11202            .to_point(&display_map);
11203        let text = buffer
11204            .text_for_range(selection.start..selection.end)
11205            .collect::<String>();
11206        if is_cut {
11207            edits.push(((selection.start..selection.end), String::new()));
11208        }
11209        let insert_anchor = buffer.anchor_before(insert_point);
11210        edits.push(((insert_anchor..insert_anchor), text));
11211        let last_edit_start = insert_anchor.bias_left(buffer);
11212        let last_edit_end = insert_anchor.bias_right(buffer);
11213        self.transact(window, cx, |this, window, cx| {
11214            this.buffer.update(cx, |buffer, cx| {
11215                buffer.edit(edits, None, cx);
11216            });
11217            this.change_selections(Default::default(), window, cx, |s| {
11218                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11219            });
11220        });
11221    }
11222
11223    pub fn clear_selection_drag_state(&mut self) {
11224        self.selection_drag_state = SelectionDragState::None;
11225    }
11226
11227    pub fn duplicate(
11228        &mut self,
11229        upwards: bool,
11230        whole_lines: bool,
11231        window: &mut Window,
11232        cx: &mut Context<Self>,
11233    ) {
11234        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11235
11236        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11237        let buffer = &display_map.buffer_snapshot;
11238        let selections = self.selections.all::<Point>(cx);
11239
11240        let mut edits = Vec::new();
11241        let mut selections_iter = selections.iter().peekable();
11242        while let Some(selection) = selections_iter.next() {
11243            let mut rows = selection.spanned_rows(false, &display_map);
11244            // duplicate line-wise
11245            if whole_lines || selection.start == selection.end {
11246                // Avoid duplicating the same lines twice.
11247                while let Some(next_selection) = selections_iter.peek() {
11248                    let next_rows = next_selection.spanned_rows(false, &display_map);
11249                    if next_rows.start < rows.end {
11250                        rows.end = next_rows.end;
11251                        selections_iter.next().unwrap();
11252                    } else {
11253                        break;
11254                    }
11255                }
11256
11257                // Copy the text from the selected row region and splice it either at the start
11258                // or end of the region.
11259                let start = Point::new(rows.start.0, 0);
11260                let end = Point::new(
11261                    rows.end.previous_row().0,
11262                    buffer.line_len(rows.end.previous_row()),
11263                );
11264                let text = buffer
11265                    .text_for_range(start..end)
11266                    .chain(Some("\n"))
11267                    .collect::<String>();
11268                let insert_location = if upwards {
11269                    Point::new(rows.end.0, 0)
11270                } else {
11271                    start
11272                };
11273                edits.push((insert_location..insert_location, text));
11274            } else {
11275                // duplicate character-wise
11276                let start = selection.start;
11277                let end = selection.end;
11278                let text = buffer.text_for_range(start..end).collect::<String>();
11279                edits.push((selection.end..selection.end, text));
11280            }
11281        }
11282
11283        self.transact(window, cx, |this, _, cx| {
11284            this.buffer.update(cx, |buffer, cx| {
11285                buffer.edit(edits, None, cx);
11286            });
11287
11288            this.request_autoscroll(Autoscroll::fit(), cx);
11289        });
11290    }
11291
11292    pub fn duplicate_line_up(
11293        &mut self,
11294        _: &DuplicateLineUp,
11295        window: &mut Window,
11296        cx: &mut Context<Self>,
11297    ) {
11298        self.duplicate(true, true, window, cx);
11299    }
11300
11301    pub fn duplicate_line_down(
11302        &mut self,
11303        _: &DuplicateLineDown,
11304        window: &mut Window,
11305        cx: &mut Context<Self>,
11306    ) {
11307        self.duplicate(false, true, window, cx);
11308    }
11309
11310    pub fn duplicate_selection(
11311        &mut self,
11312        _: &DuplicateSelection,
11313        window: &mut Window,
11314        cx: &mut Context<Self>,
11315    ) {
11316        self.duplicate(false, false, window, cx);
11317    }
11318
11319    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11321        if self.mode.is_single_line() {
11322            cx.propagate();
11323            return;
11324        }
11325
11326        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11327        let buffer = self.buffer.read(cx).snapshot(cx);
11328
11329        let mut edits = Vec::new();
11330        let mut unfold_ranges = Vec::new();
11331        let mut refold_creases = Vec::new();
11332
11333        let selections = self.selections.all::<Point>(cx);
11334        let mut selections = selections.iter().peekable();
11335        let mut contiguous_row_selections = Vec::new();
11336        let mut new_selections = Vec::new();
11337
11338        while let Some(selection) = selections.next() {
11339            // Find all the selections that span a contiguous row range
11340            let (start_row, end_row) = consume_contiguous_rows(
11341                &mut contiguous_row_selections,
11342                selection,
11343                &display_map,
11344                &mut selections,
11345            );
11346
11347            // Move the text spanned by the row range to be before the line preceding the row range
11348            if start_row.0 > 0 {
11349                let range_to_move = Point::new(
11350                    start_row.previous_row().0,
11351                    buffer.line_len(start_row.previous_row()),
11352                )
11353                    ..Point::new(
11354                        end_row.previous_row().0,
11355                        buffer.line_len(end_row.previous_row()),
11356                    );
11357                let insertion_point = display_map
11358                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11359                    .0;
11360
11361                // Don't move lines across excerpts
11362                if buffer
11363                    .excerpt_containing(insertion_point..range_to_move.end)
11364                    .is_some()
11365                {
11366                    let text = buffer
11367                        .text_for_range(range_to_move.clone())
11368                        .flat_map(|s| s.chars())
11369                        .skip(1)
11370                        .chain(['\n'])
11371                        .collect::<String>();
11372
11373                    edits.push((
11374                        buffer.anchor_after(range_to_move.start)
11375                            ..buffer.anchor_before(range_to_move.end),
11376                        String::new(),
11377                    ));
11378                    let insertion_anchor = buffer.anchor_after(insertion_point);
11379                    edits.push((insertion_anchor..insertion_anchor, text));
11380
11381                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11382
11383                    // Move selections up
11384                    new_selections.extend(contiguous_row_selections.drain(..).map(
11385                        |mut selection| {
11386                            selection.start.row -= row_delta;
11387                            selection.end.row -= row_delta;
11388                            selection
11389                        },
11390                    ));
11391
11392                    // Move folds up
11393                    unfold_ranges.push(range_to_move.clone());
11394                    for fold in display_map.folds_in_range(
11395                        buffer.anchor_before(range_to_move.start)
11396                            ..buffer.anchor_after(range_to_move.end),
11397                    ) {
11398                        let mut start = fold.range.start.to_point(&buffer);
11399                        let mut end = fold.range.end.to_point(&buffer);
11400                        start.row -= row_delta;
11401                        end.row -= row_delta;
11402                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11403                    }
11404                }
11405            }
11406
11407            // If we didn't move line(s), preserve the existing selections
11408            new_selections.append(&mut contiguous_row_selections);
11409        }
11410
11411        self.transact(window, cx, |this, window, cx| {
11412            this.unfold_ranges(&unfold_ranges, true, true, cx);
11413            this.buffer.update(cx, |buffer, cx| {
11414                for (range, text) in edits {
11415                    buffer.edit([(range, text)], None, cx);
11416                }
11417            });
11418            this.fold_creases(refold_creases, true, window, cx);
11419            this.change_selections(Default::default(), window, cx, |s| {
11420                s.select(new_selections);
11421            })
11422        });
11423    }
11424
11425    pub fn move_line_down(
11426        &mut self,
11427        _: &MoveLineDown,
11428        window: &mut Window,
11429        cx: &mut Context<Self>,
11430    ) {
11431        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11432        if self.mode.is_single_line() {
11433            cx.propagate();
11434            return;
11435        }
11436
11437        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11438        let buffer = self.buffer.read(cx).snapshot(cx);
11439
11440        let mut edits = Vec::new();
11441        let mut unfold_ranges = Vec::new();
11442        let mut refold_creases = Vec::new();
11443
11444        let selections = self.selections.all::<Point>(cx);
11445        let mut selections = selections.iter().peekable();
11446        let mut contiguous_row_selections = Vec::new();
11447        let mut new_selections = Vec::new();
11448
11449        while let Some(selection) = selections.next() {
11450            // Find all the selections that span a contiguous row range
11451            let (start_row, end_row) = consume_contiguous_rows(
11452                &mut contiguous_row_selections,
11453                selection,
11454                &display_map,
11455                &mut selections,
11456            );
11457
11458            // Move the text spanned by the row range to be after the last line of the row range
11459            if end_row.0 <= buffer.max_point().row {
11460                let range_to_move =
11461                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11462                let insertion_point = display_map
11463                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11464                    .0;
11465
11466                // Don't move lines across excerpt boundaries
11467                if buffer
11468                    .excerpt_containing(range_to_move.start..insertion_point)
11469                    .is_some()
11470                {
11471                    let mut text = String::from("\n");
11472                    text.extend(buffer.text_for_range(range_to_move.clone()));
11473                    text.pop(); // Drop trailing newline
11474                    edits.push((
11475                        buffer.anchor_after(range_to_move.start)
11476                            ..buffer.anchor_before(range_to_move.end),
11477                        String::new(),
11478                    ));
11479                    let insertion_anchor = buffer.anchor_after(insertion_point);
11480                    edits.push((insertion_anchor..insertion_anchor, text));
11481
11482                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11483
11484                    // Move selections down
11485                    new_selections.extend(contiguous_row_selections.drain(..).map(
11486                        |mut selection| {
11487                            selection.start.row += row_delta;
11488                            selection.end.row += row_delta;
11489                            selection
11490                        },
11491                    ));
11492
11493                    // Move folds down
11494                    unfold_ranges.push(range_to_move.clone());
11495                    for fold in display_map.folds_in_range(
11496                        buffer.anchor_before(range_to_move.start)
11497                            ..buffer.anchor_after(range_to_move.end),
11498                    ) {
11499                        let mut start = fold.range.start.to_point(&buffer);
11500                        let mut end = fold.range.end.to_point(&buffer);
11501                        start.row += row_delta;
11502                        end.row += row_delta;
11503                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11504                    }
11505                }
11506            }
11507
11508            // If we didn't move line(s), preserve the existing selections
11509            new_selections.append(&mut contiguous_row_selections);
11510        }
11511
11512        self.transact(window, cx, |this, window, cx| {
11513            this.unfold_ranges(&unfold_ranges, true, true, cx);
11514            this.buffer.update(cx, |buffer, cx| {
11515                for (range, text) in edits {
11516                    buffer.edit([(range, text)], None, cx);
11517                }
11518            });
11519            this.fold_creases(refold_creases, true, window, cx);
11520            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11521        });
11522    }
11523
11524    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11525        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11526        let text_layout_details = &self.text_layout_details(window);
11527        self.transact(window, cx, |this, window, cx| {
11528            let edits = this.change_selections(Default::default(), window, cx, |s| {
11529                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11530                s.move_with(|display_map, selection| {
11531                    if !selection.is_empty() {
11532                        return;
11533                    }
11534
11535                    let mut head = selection.head();
11536                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11537                    if head.column() == display_map.line_len(head.row()) {
11538                        transpose_offset = display_map
11539                            .buffer_snapshot
11540                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11541                    }
11542
11543                    if transpose_offset == 0 {
11544                        return;
11545                    }
11546
11547                    *head.column_mut() += 1;
11548                    head = display_map.clip_point(head, Bias::Right);
11549                    let goal = SelectionGoal::HorizontalPosition(
11550                        display_map
11551                            .x_for_display_point(head, text_layout_details)
11552                            .into(),
11553                    );
11554                    selection.collapse_to(head, goal);
11555
11556                    let transpose_start = display_map
11557                        .buffer_snapshot
11558                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11559                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11560                        let transpose_end = display_map
11561                            .buffer_snapshot
11562                            .clip_offset(transpose_offset + 1, Bias::Right);
11563                        if let Some(ch) =
11564                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11565                        {
11566                            edits.push((transpose_start..transpose_offset, String::new()));
11567                            edits.push((transpose_end..transpose_end, ch.to_string()));
11568                        }
11569                    }
11570                });
11571                edits
11572            });
11573            this.buffer
11574                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11575            let selections = this.selections.all::<usize>(cx);
11576            this.change_selections(Default::default(), window, cx, |s| {
11577                s.select(selections);
11578            });
11579        });
11580    }
11581
11582    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11583        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11584        if self.mode.is_single_line() {
11585            cx.propagate();
11586            return;
11587        }
11588
11589        self.rewrap_impl(RewrapOptions::default(), cx)
11590    }
11591
11592    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11593        let buffer = self.buffer.read(cx).snapshot(cx);
11594        let selections = self.selections.all::<Point>(cx);
11595
11596        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11597        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11598            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11599                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11600                .peekable();
11601
11602            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11603                row
11604            } else {
11605                return Vec::new();
11606            };
11607
11608            let language_settings = buffer.language_settings_at(selection.head(), cx);
11609            let language_scope = buffer.language_scope_at(selection.head());
11610
11611            let indent_and_prefix_for_row =
11612                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11613                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11614                    let (comment_prefix, rewrap_prefix) =
11615                        if let Some(language_scope) = &language_scope {
11616                            let indent_end = Point::new(row, indent.len);
11617                            let comment_prefix = language_scope
11618                                .line_comment_prefixes()
11619                                .iter()
11620                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11621                                .map(|prefix| prefix.to_string());
11622                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11623                            let line_text_after_indent = buffer
11624                                .text_for_range(indent_end..line_end)
11625                                .collect::<String>();
11626                            let rewrap_prefix = language_scope
11627                                .rewrap_prefixes()
11628                                .iter()
11629                                .find_map(|prefix_regex| {
11630                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11631                                        if mat.start() == 0 {
11632                                            Some(mat.as_str().to_string())
11633                                        } else {
11634                                            None
11635                                        }
11636                                    })
11637                                })
11638                                .flatten();
11639                            (comment_prefix, rewrap_prefix)
11640                        } else {
11641                            (None, None)
11642                        };
11643                    (indent, comment_prefix, rewrap_prefix)
11644                };
11645
11646            let mut ranges = Vec::new();
11647            let from_empty_selection = selection.is_empty();
11648
11649            let mut current_range_start = first_row;
11650            let mut prev_row = first_row;
11651            let (
11652                mut current_range_indent,
11653                mut current_range_comment_prefix,
11654                mut current_range_rewrap_prefix,
11655            ) = indent_and_prefix_for_row(first_row);
11656
11657            for row in non_blank_rows_iter.skip(1) {
11658                let has_paragraph_break = row > prev_row + 1;
11659
11660                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11661                    indent_and_prefix_for_row(row);
11662
11663                let has_indent_change = row_indent != current_range_indent;
11664                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11665
11666                let has_boundary_change = has_comment_change
11667                    || row_rewrap_prefix.is_some()
11668                    || (has_indent_change && current_range_comment_prefix.is_some());
11669
11670                if has_paragraph_break || has_boundary_change {
11671                    ranges.push((
11672                        language_settings.clone(),
11673                        Point::new(current_range_start, 0)
11674                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11675                        current_range_indent,
11676                        current_range_comment_prefix.clone(),
11677                        current_range_rewrap_prefix.clone(),
11678                        from_empty_selection,
11679                    ));
11680                    current_range_start = row;
11681                    current_range_indent = row_indent;
11682                    current_range_comment_prefix = row_comment_prefix;
11683                    current_range_rewrap_prefix = row_rewrap_prefix;
11684                }
11685                prev_row = row;
11686            }
11687
11688            ranges.push((
11689                language_settings.clone(),
11690                Point::new(current_range_start, 0)
11691                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11692                current_range_indent,
11693                current_range_comment_prefix,
11694                current_range_rewrap_prefix,
11695                from_empty_selection,
11696            ));
11697
11698            ranges
11699        });
11700
11701        let mut edits = Vec::new();
11702        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11703
11704        for (
11705            language_settings,
11706            wrap_range,
11707            indent_size,
11708            comment_prefix,
11709            rewrap_prefix,
11710            from_empty_selection,
11711        ) in wrap_ranges
11712        {
11713            let mut start_row = wrap_range.start.row;
11714            let mut end_row = wrap_range.end.row;
11715
11716            // Skip selections that overlap with a range that has already been rewrapped.
11717            let selection_range = start_row..end_row;
11718            if rewrapped_row_ranges
11719                .iter()
11720                .any(|range| range.overlaps(&selection_range))
11721            {
11722                continue;
11723            }
11724
11725            let tab_size = language_settings.tab_size;
11726
11727            let indent_prefix = indent_size.chars().collect::<String>();
11728            let mut line_prefix = indent_prefix.clone();
11729            let mut inside_comment = false;
11730            if let Some(prefix) = &comment_prefix {
11731                line_prefix.push_str(prefix);
11732                inside_comment = true;
11733            }
11734            if let Some(prefix) = &rewrap_prefix {
11735                line_prefix.push_str(prefix);
11736            }
11737
11738            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11739                RewrapBehavior::InComments => inside_comment,
11740                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11741                RewrapBehavior::Anywhere => true,
11742            };
11743
11744            let should_rewrap = options.override_language_settings
11745                || allow_rewrap_based_on_language
11746                || self.hard_wrap.is_some();
11747            if !should_rewrap {
11748                continue;
11749            }
11750
11751            if from_empty_selection {
11752                'expand_upwards: while start_row > 0 {
11753                    let prev_row = start_row - 1;
11754                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11755                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11756                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11757                    {
11758                        start_row = prev_row;
11759                    } else {
11760                        break 'expand_upwards;
11761                    }
11762                }
11763
11764                'expand_downwards: while end_row < buffer.max_point().row {
11765                    let next_row = end_row + 1;
11766                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11767                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11768                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11769                    {
11770                        end_row = next_row;
11771                    } else {
11772                        break 'expand_downwards;
11773                    }
11774                }
11775            }
11776
11777            let start = Point::new(start_row, 0);
11778            let start_offset = start.to_offset(&buffer);
11779            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11780            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11781            let Some(lines_without_prefixes) = selection_text
11782                .lines()
11783                .enumerate()
11784                .map(|(ix, line)| {
11785                    let line_trimmed = line.trim_start();
11786                    if rewrap_prefix.is_some() && ix > 0 {
11787                        Ok(line_trimmed)
11788                    } else {
11789                        line_trimmed
11790                            .strip_prefix(&line_prefix.trim_start())
11791                            .with_context(|| {
11792                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11793                            })
11794                    }
11795                })
11796                .collect::<Result<Vec<_>, _>>()
11797                .log_err()
11798            else {
11799                continue;
11800            };
11801
11802            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11803                buffer
11804                    .language_settings_at(Point::new(start_row, 0), cx)
11805                    .preferred_line_length as usize
11806            });
11807
11808            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11809                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11810            } else {
11811                line_prefix.clone()
11812            };
11813
11814            let wrapped_text = wrap_with_prefix(
11815                line_prefix,
11816                subsequent_lines_prefix,
11817                lines_without_prefixes.join("\n"),
11818                wrap_column,
11819                tab_size,
11820                options.preserve_existing_whitespace,
11821            );
11822
11823            // TODO: should always use char-based diff while still supporting cursor behavior that
11824            // matches vim.
11825            let mut diff_options = DiffOptions::default();
11826            if options.override_language_settings {
11827                diff_options.max_word_diff_len = 0;
11828                diff_options.max_word_diff_line_count = 0;
11829            } else {
11830                diff_options.max_word_diff_len = usize::MAX;
11831                diff_options.max_word_diff_line_count = usize::MAX;
11832            }
11833
11834            for (old_range, new_text) in
11835                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11836            {
11837                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11838                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11839                edits.push((edit_start..edit_end, new_text));
11840            }
11841
11842            rewrapped_row_ranges.push(start_row..=end_row);
11843        }
11844
11845        self.buffer
11846            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11847    }
11848
11849    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11850        let mut text = String::new();
11851        let buffer = self.buffer.read(cx).snapshot(cx);
11852        let mut selections = self.selections.all::<Point>(cx);
11853        let mut clipboard_selections = Vec::with_capacity(selections.len());
11854        {
11855            let max_point = buffer.max_point();
11856            let mut is_first = true;
11857            for selection in &mut selections {
11858                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11859                if is_entire_line {
11860                    selection.start = Point::new(selection.start.row, 0);
11861                    if !selection.is_empty() && selection.end.column == 0 {
11862                        selection.end = cmp::min(max_point, selection.end);
11863                    } else {
11864                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11865                    }
11866                    selection.goal = SelectionGoal::None;
11867                }
11868                if is_first {
11869                    is_first = false;
11870                } else {
11871                    text += "\n";
11872                }
11873                let mut len = 0;
11874                for chunk in buffer.text_for_range(selection.start..selection.end) {
11875                    text.push_str(chunk);
11876                    len += chunk.len();
11877                }
11878                clipboard_selections.push(ClipboardSelection {
11879                    len,
11880                    is_entire_line,
11881                    first_line_indent: buffer
11882                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11883                        .len,
11884                });
11885            }
11886        }
11887
11888        self.transact(window, cx, |this, window, cx| {
11889            this.change_selections(Default::default(), window, cx, |s| {
11890                s.select(selections);
11891            });
11892            this.insert("", window, cx);
11893        });
11894        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11895    }
11896
11897    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11898        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11899        let item = self.cut_common(window, cx);
11900        cx.write_to_clipboard(item);
11901    }
11902
11903    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11904        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11905        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11906            s.move_with(|snapshot, sel| {
11907                if sel.is_empty() {
11908                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11909                }
11910            });
11911        });
11912        let item = self.cut_common(window, cx);
11913        cx.set_global(KillRing(item))
11914    }
11915
11916    pub fn kill_ring_yank(
11917        &mut self,
11918        _: &KillRingYank,
11919        window: &mut Window,
11920        cx: &mut Context<Self>,
11921    ) {
11922        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11923        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11924            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11925                (kill_ring.text().to_string(), kill_ring.metadata_json())
11926            } else {
11927                return;
11928            }
11929        } else {
11930            return;
11931        };
11932        self.do_paste(&text, metadata, false, window, cx);
11933    }
11934
11935    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11936        self.do_copy(true, cx);
11937    }
11938
11939    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11940        self.do_copy(false, cx);
11941    }
11942
11943    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11944        let selections = self.selections.all::<Point>(cx);
11945        let buffer = self.buffer.read(cx).read(cx);
11946        let mut text = String::new();
11947
11948        let mut clipboard_selections = Vec::with_capacity(selections.len());
11949        {
11950            let max_point = buffer.max_point();
11951            let mut is_first = true;
11952            for selection in &selections {
11953                let mut start = selection.start;
11954                let mut end = selection.end;
11955                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11956                if is_entire_line {
11957                    start = Point::new(start.row, 0);
11958                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11959                }
11960
11961                let mut trimmed_selections = Vec::new();
11962                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11963                    let row = MultiBufferRow(start.row);
11964                    let first_indent = buffer.indent_size_for_line(row);
11965                    if first_indent.len == 0 || start.column > first_indent.len {
11966                        trimmed_selections.push(start..end);
11967                    } else {
11968                        trimmed_selections.push(
11969                            Point::new(row.0, first_indent.len)
11970                                ..Point::new(row.0, buffer.line_len(row)),
11971                        );
11972                        for row in start.row + 1..=end.row {
11973                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11974                            if row == end.row {
11975                                line_len = end.column;
11976                            }
11977                            if line_len == 0 {
11978                                trimmed_selections
11979                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11980                                continue;
11981                            }
11982                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11983                            if row_indent_size.len >= first_indent.len {
11984                                trimmed_selections.push(
11985                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11986                                );
11987                            } else {
11988                                trimmed_selections.clear();
11989                                trimmed_selections.push(start..end);
11990                                break;
11991                            }
11992                        }
11993                    }
11994                } else {
11995                    trimmed_selections.push(start..end);
11996                }
11997
11998                for trimmed_range in trimmed_selections {
11999                    if is_first {
12000                        is_first = false;
12001                    } else {
12002                        text += "\n";
12003                    }
12004                    let mut len = 0;
12005                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12006                        text.push_str(chunk);
12007                        len += chunk.len();
12008                    }
12009                    clipboard_selections.push(ClipboardSelection {
12010                        len,
12011                        is_entire_line,
12012                        first_line_indent: buffer
12013                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12014                            .len,
12015                    });
12016                }
12017            }
12018        }
12019
12020        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12021            text,
12022            clipboard_selections,
12023        ));
12024    }
12025
12026    pub fn do_paste(
12027        &mut self,
12028        text: &String,
12029        clipboard_selections: Option<Vec<ClipboardSelection>>,
12030        handle_entire_lines: bool,
12031        window: &mut Window,
12032        cx: &mut Context<Self>,
12033    ) {
12034        if self.read_only(cx) {
12035            return;
12036        }
12037
12038        let clipboard_text = Cow::Borrowed(text);
12039
12040        self.transact(window, cx, |this, window, cx| {
12041            if let Some(mut clipboard_selections) = clipboard_selections {
12042                let old_selections = this.selections.all::<usize>(cx);
12043                let all_selections_were_entire_line =
12044                    clipboard_selections.iter().all(|s| s.is_entire_line);
12045                let first_selection_indent_column =
12046                    clipboard_selections.first().map(|s| s.first_line_indent);
12047                if clipboard_selections.len() != old_selections.len() {
12048                    clipboard_selections.drain(..);
12049                }
12050                let cursor_offset = this.selections.last::<usize>(cx).head();
12051                let mut auto_indent_on_paste = true;
12052
12053                this.buffer.update(cx, |buffer, cx| {
12054                    let snapshot = buffer.read(cx);
12055                    auto_indent_on_paste = snapshot
12056                        .language_settings_at(cursor_offset, cx)
12057                        .auto_indent_on_paste;
12058
12059                    let mut start_offset = 0;
12060                    let mut edits = Vec::new();
12061                    let mut original_indent_columns = Vec::new();
12062                    for (ix, selection) in old_selections.iter().enumerate() {
12063                        let to_insert;
12064                        let entire_line;
12065                        let original_indent_column;
12066                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12067                            let end_offset = start_offset + clipboard_selection.len;
12068                            to_insert = &clipboard_text[start_offset..end_offset];
12069                            entire_line = clipboard_selection.is_entire_line;
12070                            start_offset = end_offset + 1;
12071                            original_indent_column = Some(clipboard_selection.first_line_indent);
12072                        } else {
12073                            to_insert = clipboard_text.as_str();
12074                            entire_line = all_selections_were_entire_line;
12075                            original_indent_column = first_selection_indent_column
12076                        }
12077
12078                        // If the corresponding selection was empty when this slice of the
12079                        // clipboard text was written, then the entire line containing the
12080                        // selection was copied. If this selection is also currently empty,
12081                        // then paste the line before the current line of the buffer.
12082                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12083                            let column = selection.start.to_point(&snapshot).column as usize;
12084                            let line_start = selection.start - column;
12085                            line_start..line_start
12086                        } else {
12087                            selection.range()
12088                        };
12089
12090                        edits.push((range, to_insert));
12091                        original_indent_columns.push(original_indent_column);
12092                    }
12093                    drop(snapshot);
12094
12095                    buffer.edit(
12096                        edits,
12097                        if auto_indent_on_paste {
12098                            Some(AutoindentMode::Block {
12099                                original_indent_columns,
12100                            })
12101                        } else {
12102                            None
12103                        },
12104                        cx,
12105                    );
12106                });
12107
12108                let selections = this.selections.all::<usize>(cx);
12109                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12110            } else {
12111                this.insert(&clipboard_text, window, cx);
12112            }
12113        });
12114    }
12115
12116    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12117        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12118        if let Some(item) = cx.read_from_clipboard() {
12119            let entries = item.entries();
12120
12121            match entries.first() {
12122                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12123                // of all the pasted entries.
12124                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12125                    .do_paste(
12126                        clipboard_string.text(),
12127                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12128                        true,
12129                        window,
12130                        cx,
12131                    ),
12132                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12133            }
12134        }
12135    }
12136
12137    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12138        if self.read_only(cx) {
12139            return;
12140        }
12141
12142        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12143
12144        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12145            if let Some((selections, _)) =
12146                self.selection_history.transaction(transaction_id).cloned()
12147            {
12148                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12149                    s.select_anchors(selections.to_vec());
12150                });
12151            } else {
12152                log::error!(
12153                    "No entry in selection_history found for undo. \
12154                     This may correspond to a bug where undo does not update the selection. \
12155                     If this is occurring, please add details to \
12156                     https://github.com/zed-industries/zed/issues/22692"
12157                );
12158            }
12159            self.request_autoscroll(Autoscroll::fit(), cx);
12160            self.unmark_text(window, cx);
12161            self.refresh_inline_completion(true, false, window, cx);
12162            cx.emit(EditorEvent::Edited { transaction_id });
12163            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12164        }
12165    }
12166
12167    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12168        if self.read_only(cx) {
12169            return;
12170        }
12171
12172        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12173
12174        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12175            if let Some((_, Some(selections))) =
12176                self.selection_history.transaction(transaction_id).cloned()
12177            {
12178                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12179                    s.select_anchors(selections.to_vec());
12180                });
12181            } else {
12182                log::error!(
12183                    "No entry in selection_history found for redo. \
12184                     This may correspond to a bug where undo does not update the selection. \
12185                     If this is occurring, please add details to \
12186                     https://github.com/zed-industries/zed/issues/22692"
12187                );
12188            }
12189            self.request_autoscroll(Autoscroll::fit(), cx);
12190            self.unmark_text(window, cx);
12191            self.refresh_inline_completion(true, false, window, cx);
12192            cx.emit(EditorEvent::Edited { transaction_id });
12193        }
12194    }
12195
12196    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12197        self.buffer
12198            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12199    }
12200
12201    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12202        self.buffer
12203            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12204    }
12205
12206    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12207        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12208        self.change_selections(Default::default(), window, cx, |s| {
12209            s.move_with(|map, selection| {
12210                let cursor = if selection.is_empty() {
12211                    movement::left(map, selection.start)
12212                } else {
12213                    selection.start
12214                };
12215                selection.collapse_to(cursor, SelectionGoal::None);
12216            });
12217        })
12218    }
12219
12220    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12221        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12222        self.change_selections(Default::default(), window, cx, |s| {
12223            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12224        })
12225    }
12226
12227    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12228        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12229        self.change_selections(Default::default(), window, cx, |s| {
12230            s.move_with(|map, selection| {
12231                let cursor = if selection.is_empty() {
12232                    movement::right(map, selection.end)
12233                } else {
12234                    selection.end
12235                };
12236                selection.collapse_to(cursor, SelectionGoal::None)
12237            });
12238        })
12239    }
12240
12241    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12243        self.change_selections(Default::default(), window, cx, |s| {
12244            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12245        })
12246    }
12247
12248    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12249        if self.take_rename(true, window, cx).is_some() {
12250            return;
12251        }
12252
12253        if self.mode.is_single_line() {
12254            cx.propagate();
12255            return;
12256        }
12257
12258        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12259
12260        let text_layout_details = &self.text_layout_details(window);
12261        let selection_count = self.selections.count();
12262        let first_selection = self.selections.first_anchor();
12263
12264        self.change_selections(Default::default(), window, cx, |s| {
12265            s.move_with(|map, selection| {
12266                if !selection.is_empty() {
12267                    selection.goal = SelectionGoal::None;
12268                }
12269                let (cursor, goal) = movement::up(
12270                    map,
12271                    selection.start,
12272                    selection.goal,
12273                    false,
12274                    text_layout_details,
12275                );
12276                selection.collapse_to(cursor, goal);
12277            });
12278        });
12279
12280        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12281        {
12282            cx.propagate();
12283        }
12284    }
12285
12286    pub fn move_up_by_lines(
12287        &mut self,
12288        action: &MoveUpByLines,
12289        window: &mut Window,
12290        cx: &mut Context<Self>,
12291    ) {
12292        if self.take_rename(true, window, cx).is_some() {
12293            return;
12294        }
12295
12296        if self.mode.is_single_line() {
12297            cx.propagate();
12298            return;
12299        }
12300
12301        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12302
12303        let text_layout_details = &self.text_layout_details(window);
12304
12305        self.change_selections(Default::default(), window, cx, |s| {
12306            s.move_with(|map, selection| {
12307                if !selection.is_empty() {
12308                    selection.goal = SelectionGoal::None;
12309                }
12310                let (cursor, goal) = movement::up_by_rows(
12311                    map,
12312                    selection.start,
12313                    action.lines,
12314                    selection.goal,
12315                    false,
12316                    text_layout_details,
12317                );
12318                selection.collapse_to(cursor, goal);
12319            });
12320        })
12321    }
12322
12323    pub fn move_down_by_lines(
12324        &mut self,
12325        action: &MoveDownByLines,
12326        window: &mut Window,
12327        cx: &mut Context<Self>,
12328    ) {
12329        if self.take_rename(true, window, cx).is_some() {
12330            return;
12331        }
12332
12333        if self.mode.is_single_line() {
12334            cx.propagate();
12335            return;
12336        }
12337
12338        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12339
12340        let text_layout_details = &self.text_layout_details(window);
12341
12342        self.change_selections(Default::default(), window, cx, |s| {
12343            s.move_with(|map, selection| {
12344                if !selection.is_empty() {
12345                    selection.goal = SelectionGoal::None;
12346                }
12347                let (cursor, goal) = movement::down_by_rows(
12348                    map,
12349                    selection.start,
12350                    action.lines,
12351                    selection.goal,
12352                    false,
12353                    text_layout_details,
12354                );
12355                selection.collapse_to(cursor, goal);
12356            });
12357        })
12358    }
12359
12360    pub fn select_down_by_lines(
12361        &mut self,
12362        action: &SelectDownByLines,
12363        window: &mut Window,
12364        cx: &mut Context<Self>,
12365    ) {
12366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12367        let text_layout_details = &self.text_layout_details(window);
12368        self.change_selections(Default::default(), window, cx, |s| {
12369            s.move_heads_with(|map, head, goal| {
12370                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12371            })
12372        })
12373    }
12374
12375    pub fn select_up_by_lines(
12376        &mut self,
12377        action: &SelectUpByLines,
12378        window: &mut Window,
12379        cx: &mut Context<Self>,
12380    ) {
12381        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12382        let text_layout_details = &self.text_layout_details(window);
12383        self.change_selections(Default::default(), window, cx, |s| {
12384            s.move_heads_with(|map, head, goal| {
12385                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12386            })
12387        })
12388    }
12389
12390    pub fn select_page_up(
12391        &mut self,
12392        _: &SelectPageUp,
12393        window: &mut Window,
12394        cx: &mut Context<Self>,
12395    ) {
12396        let Some(row_count) = self.visible_row_count() else {
12397            return;
12398        };
12399
12400        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12401
12402        let text_layout_details = &self.text_layout_details(window);
12403
12404        self.change_selections(Default::default(), window, cx, |s| {
12405            s.move_heads_with(|map, head, goal| {
12406                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12407            })
12408        })
12409    }
12410
12411    pub fn move_page_up(
12412        &mut self,
12413        action: &MovePageUp,
12414        window: &mut Window,
12415        cx: &mut Context<Self>,
12416    ) {
12417        if self.take_rename(true, window, cx).is_some() {
12418            return;
12419        }
12420
12421        if self
12422            .context_menu
12423            .borrow_mut()
12424            .as_mut()
12425            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12426            .unwrap_or(false)
12427        {
12428            return;
12429        }
12430
12431        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12432            cx.propagate();
12433            return;
12434        }
12435
12436        let Some(row_count) = self.visible_row_count() else {
12437            return;
12438        };
12439
12440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12441
12442        let effects = if action.center_cursor {
12443            SelectionEffects::scroll(Autoscroll::center())
12444        } else {
12445            SelectionEffects::default()
12446        };
12447
12448        let text_layout_details = &self.text_layout_details(window);
12449
12450        self.change_selections(effects, window, cx, |s| {
12451            s.move_with(|map, selection| {
12452                if !selection.is_empty() {
12453                    selection.goal = SelectionGoal::None;
12454                }
12455                let (cursor, goal) = movement::up_by_rows(
12456                    map,
12457                    selection.end,
12458                    row_count,
12459                    selection.goal,
12460                    false,
12461                    text_layout_details,
12462                );
12463                selection.collapse_to(cursor, goal);
12464            });
12465        });
12466    }
12467
12468    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12469        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12470        let text_layout_details = &self.text_layout_details(window);
12471        self.change_selections(Default::default(), window, cx, |s| {
12472            s.move_heads_with(|map, head, goal| {
12473                movement::up(map, head, goal, false, text_layout_details)
12474            })
12475        })
12476    }
12477
12478    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12479        self.take_rename(true, window, cx);
12480
12481        if self.mode.is_single_line() {
12482            cx.propagate();
12483            return;
12484        }
12485
12486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12487
12488        let text_layout_details = &self.text_layout_details(window);
12489        let selection_count = self.selections.count();
12490        let first_selection = self.selections.first_anchor();
12491
12492        self.change_selections(Default::default(), window, cx, |s| {
12493            s.move_with(|map, selection| {
12494                if !selection.is_empty() {
12495                    selection.goal = SelectionGoal::None;
12496                }
12497                let (cursor, goal) = movement::down(
12498                    map,
12499                    selection.end,
12500                    selection.goal,
12501                    false,
12502                    text_layout_details,
12503                );
12504                selection.collapse_to(cursor, goal);
12505            });
12506        });
12507
12508        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12509        {
12510            cx.propagate();
12511        }
12512    }
12513
12514    pub fn select_page_down(
12515        &mut self,
12516        _: &SelectPageDown,
12517        window: &mut Window,
12518        cx: &mut Context<Self>,
12519    ) {
12520        let Some(row_count) = self.visible_row_count() else {
12521            return;
12522        };
12523
12524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12525
12526        let text_layout_details = &self.text_layout_details(window);
12527
12528        self.change_selections(Default::default(), window, cx, |s| {
12529            s.move_heads_with(|map, head, goal| {
12530                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12531            })
12532        })
12533    }
12534
12535    pub fn move_page_down(
12536        &mut self,
12537        action: &MovePageDown,
12538        window: &mut Window,
12539        cx: &mut Context<Self>,
12540    ) {
12541        if self.take_rename(true, window, cx).is_some() {
12542            return;
12543        }
12544
12545        if self
12546            .context_menu
12547            .borrow_mut()
12548            .as_mut()
12549            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12550            .unwrap_or(false)
12551        {
12552            return;
12553        }
12554
12555        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12556            cx.propagate();
12557            return;
12558        }
12559
12560        let Some(row_count) = self.visible_row_count() else {
12561            return;
12562        };
12563
12564        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12565
12566        let effects = if action.center_cursor {
12567            SelectionEffects::scroll(Autoscroll::center())
12568        } else {
12569            SelectionEffects::default()
12570        };
12571
12572        let text_layout_details = &self.text_layout_details(window);
12573        self.change_selections(effects, window, cx, |s| {
12574            s.move_with(|map, selection| {
12575                if !selection.is_empty() {
12576                    selection.goal = SelectionGoal::None;
12577                }
12578                let (cursor, goal) = movement::down_by_rows(
12579                    map,
12580                    selection.end,
12581                    row_count,
12582                    selection.goal,
12583                    false,
12584                    text_layout_details,
12585                );
12586                selection.collapse_to(cursor, goal);
12587            });
12588        });
12589    }
12590
12591    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12593        let text_layout_details = &self.text_layout_details(window);
12594        self.change_selections(Default::default(), window, cx, |s| {
12595            s.move_heads_with(|map, head, goal| {
12596                movement::down(map, head, goal, false, text_layout_details)
12597            })
12598        });
12599    }
12600
12601    pub fn context_menu_first(
12602        &mut self,
12603        _: &ContextMenuFirst,
12604        window: &mut Window,
12605        cx: &mut Context<Self>,
12606    ) {
12607        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12608            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12609        }
12610    }
12611
12612    pub fn context_menu_prev(
12613        &mut self,
12614        _: &ContextMenuPrevious,
12615        window: &mut Window,
12616        cx: &mut Context<Self>,
12617    ) {
12618        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12619            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12620        }
12621    }
12622
12623    pub fn context_menu_next(
12624        &mut self,
12625        _: &ContextMenuNext,
12626        window: &mut Window,
12627        cx: &mut Context<Self>,
12628    ) {
12629        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12630            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12631        }
12632    }
12633
12634    pub fn context_menu_last(
12635        &mut self,
12636        _: &ContextMenuLast,
12637        window: &mut Window,
12638        cx: &mut Context<Self>,
12639    ) {
12640        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12641            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12642        }
12643    }
12644
12645    pub fn signature_help_prev(
12646        &mut self,
12647        _: &SignatureHelpPrevious,
12648        _: &mut Window,
12649        cx: &mut Context<Self>,
12650    ) {
12651        if let Some(popover) = self.signature_help_state.popover_mut() {
12652            if popover.current_signature == 0 {
12653                popover.current_signature = popover.signatures.len() - 1;
12654            } else {
12655                popover.current_signature -= 1;
12656            }
12657            cx.notify();
12658        }
12659    }
12660
12661    pub fn signature_help_next(
12662        &mut self,
12663        _: &SignatureHelpNext,
12664        _: &mut Window,
12665        cx: &mut Context<Self>,
12666    ) {
12667        if let Some(popover) = self.signature_help_state.popover_mut() {
12668            if popover.current_signature + 1 == popover.signatures.len() {
12669                popover.current_signature = 0;
12670            } else {
12671                popover.current_signature += 1;
12672            }
12673            cx.notify();
12674        }
12675    }
12676
12677    pub fn move_to_previous_word_start(
12678        &mut self,
12679        _: &MoveToPreviousWordStart,
12680        window: &mut Window,
12681        cx: &mut Context<Self>,
12682    ) {
12683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12684        self.change_selections(Default::default(), window, cx, |s| {
12685            s.move_cursors_with(|map, head, _| {
12686                (
12687                    movement::previous_word_start(map, head),
12688                    SelectionGoal::None,
12689                )
12690            });
12691        })
12692    }
12693
12694    pub fn move_to_previous_subword_start(
12695        &mut self,
12696        _: &MoveToPreviousSubwordStart,
12697        window: &mut Window,
12698        cx: &mut Context<Self>,
12699    ) {
12700        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12701        self.change_selections(Default::default(), window, cx, |s| {
12702            s.move_cursors_with(|map, head, _| {
12703                (
12704                    movement::previous_subword_start(map, head),
12705                    SelectionGoal::None,
12706                )
12707            });
12708        })
12709    }
12710
12711    pub fn select_to_previous_word_start(
12712        &mut self,
12713        _: &SelectToPreviousWordStart,
12714        window: &mut Window,
12715        cx: &mut Context<Self>,
12716    ) {
12717        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12718        self.change_selections(Default::default(), window, cx, |s| {
12719            s.move_heads_with(|map, head, _| {
12720                (
12721                    movement::previous_word_start(map, head),
12722                    SelectionGoal::None,
12723                )
12724            });
12725        })
12726    }
12727
12728    pub fn select_to_previous_subword_start(
12729        &mut self,
12730        _: &SelectToPreviousSubwordStart,
12731        window: &mut Window,
12732        cx: &mut Context<Self>,
12733    ) {
12734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12735        self.change_selections(Default::default(), window, cx, |s| {
12736            s.move_heads_with(|map, head, _| {
12737                (
12738                    movement::previous_subword_start(map, head),
12739                    SelectionGoal::None,
12740                )
12741            });
12742        })
12743    }
12744
12745    pub fn delete_to_previous_word_start(
12746        &mut self,
12747        action: &DeleteToPreviousWordStart,
12748        window: &mut Window,
12749        cx: &mut Context<Self>,
12750    ) {
12751        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12752        self.transact(window, cx, |this, window, cx| {
12753            this.select_autoclose_pair(window, cx);
12754            this.change_selections(Default::default(), window, cx, |s| {
12755                s.move_with(|map, selection| {
12756                    if selection.is_empty() {
12757                        let cursor = if action.ignore_newlines {
12758                            movement::previous_word_start(map, selection.head())
12759                        } else {
12760                            movement::previous_word_start_or_newline(map, selection.head())
12761                        };
12762                        selection.set_head(cursor, SelectionGoal::None);
12763                    }
12764                });
12765            });
12766            this.insert("", window, cx);
12767        });
12768    }
12769
12770    pub fn delete_to_previous_subword_start(
12771        &mut self,
12772        _: &DeleteToPreviousSubwordStart,
12773        window: &mut Window,
12774        cx: &mut Context<Self>,
12775    ) {
12776        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12777        self.transact(window, cx, |this, window, cx| {
12778            this.select_autoclose_pair(window, cx);
12779            this.change_selections(Default::default(), window, cx, |s| {
12780                s.move_with(|map, selection| {
12781                    if selection.is_empty() {
12782                        let cursor = movement::previous_subword_start(map, selection.head());
12783                        selection.set_head(cursor, SelectionGoal::None);
12784                    }
12785                });
12786            });
12787            this.insert("", window, cx);
12788        });
12789    }
12790
12791    pub fn move_to_next_word_end(
12792        &mut self,
12793        _: &MoveToNextWordEnd,
12794        window: &mut Window,
12795        cx: &mut Context<Self>,
12796    ) {
12797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12798        self.change_selections(Default::default(), window, cx, |s| {
12799            s.move_cursors_with(|map, head, _| {
12800                (movement::next_word_end(map, head), SelectionGoal::None)
12801            });
12802        })
12803    }
12804
12805    pub fn move_to_next_subword_end(
12806        &mut self,
12807        _: &MoveToNextSubwordEnd,
12808        window: &mut Window,
12809        cx: &mut Context<Self>,
12810    ) {
12811        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12812        self.change_selections(Default::default(), window, cx, |s| {
12813            s.move_cursors_with(|map, head, _| {
12814                (movement::next_subword_end(map, head), SelectionGoal::None)
12815            });
12816        })
12817    }
12818
12819    pub fn select_to_next_word_end(
12820        &mut self,
12821        _: &SelectToNextWordEnd,
12822        window: &mut Window,
12823        cx: &mut Context<Self>,
12824    ) {
12825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12826        self.change_selections(Default::default(), window, cx, |s| {
12827            s.move_heads_with(|map, head, _| {
12828                (movement::next_word_end(map, head), SelectionGoal::None)
12829            });
12830        })
12831    }
12832
12833    pub fn select_to_next_subword_end(
12834        &mut self,
12835        _: &SelectToNextSubwordEnd,
12836        window: &mut Window,
12837        cx: &mut Context<Self>,
12838    ) {
12839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12840        self.change_selections(Default::default(), window, cx, |s| {
12841            s.move_heads_with(|map, head, _| {
12842                (movement::next_subword_end(map, head), SelectionGoal::None)
12843            });
12844        })
12845    }
12846
12847    pub fn delete_to_next_word_end(
12848        &mut self,
12849        action: &DeleteToNextWordEnd,
12850        window: &mut Window,
12851        cx: &mut Context<Self>,
12852    ) {
12853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12854        self.transact(window, cx, |this, window, cx| {
12855            this.change_selections(Default::default(), window, cx, |s| {
12856                s.move_with(|map, selection| {
12857                    if selection.is_empty() {
12858                        let cursor = if action.ignore_newlines {
12859                            movement::next_word_end(map, selection.head())
12860                        } else {
12861                            movement::next_word_end_or_newline(map, selection.head())
12862                        };
12863                        selection.set_head(cursor, SelectionGoal::None);
12864                    }
12865                });
12866            });
12867            this.insert("", window, cx);
12868        });
12869    }
12870
12871    pub fn delete_to_next_subword_end(
12872        &mut self,
12873        _: &DeleteToNextSubwordEnd,
12874        window: &mut Window,
12875        cx: &mut Context<Self>,
12876    ) {
12877        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12878        self.transact(window, cx, |this, window, cx| {
12879            this.change_selections(Default::default(), window, cx, |s| {
12880                s.move_with(|map, selection| {
12881                    if selection.is_empty() {
12882                        let cursor = movement::next_subword_end(map, selection.head());
12883                        selection.set_head(cursor, SelectionGoal::None);
12884                    }
12885                });
12886            });
12887            this.insert("", window, cx);
12888        });
12889    }
12890
12891    pub fn move_to_beginning_of_line(
12892        &mut self,
12893        action: &MoveToBeginningOfLine,
12894        window: &mut Window,
12895        cx: &mut Context<Self>,
12896    ) {
12897        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12898        self.change_selections(Default::default(), window, cx, |s| {
12899            s.move_cursors_with(|map, head, _| {
12900                (
12901                    movement::indented_line_beginning(
12902                        map,
12903                        head,
12904                        action.stop_at_soft_wraps,
12905                        action.stop_at_indent,
12906                    ),
12907                    SelectionGoal::None,
12908                )
12909            });
12910        })
12911    }
12912
12913    pub fn select_to_beginning_of_line(
12914        &mut self,
12915        action: &SelectToBeginningOfLine,
12916        window: &mut Window,
12917        cx: &mut Context<Self>,
12918    ) {
12919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12920        self.change_selections(Default::default(), window, cx, |s| {
12921            s.move_heads_with(|map, head, _| {
12922                (
12923                    movement::indented_line_beginning(
12924                        map,
12925                        head,
12926                        action.stop_at_soft_wraps,
12927                        action.stop_at_indent,
12928                    ),
12929                    SelectionGoal::None,
12930                )
12931            });
12932        });
12933    }
12934
12935    pub fn delete_to_beginning_of_line(
12936        &mut self,
12937        action: &DeleteToBeginningOfLine,
12938        window: &mut Window,
12939        cx: &mut Context<Self>,
12940    ) {
12941        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12942        self.transact(window, cx, |this, window, cx| {
12943            this.change_selections(Default::default(), window, cx, |s| {
12944                s.move_with(|_, selection| {
12945                    selection.reversed = true;
12946                });
12947            });
12948
12949            this.select_to_beginning_of_line(
12950                &SelectToBeginningOfLine {
12951                    stop_at_soft_wraps: false,
12952                    stop_at_indent: action.stop_at_indent,
12953                },
12954                window,
12955                cx,
12956            );
12957            this.backspace(&Backspace, window, cx);
12958        });
12959    }
12960
12961    pub fn move_to_end_of_line(
12962        &mut self,
12963        action: &MoveToEndOfLine,
12964        window: &mut Window,
12965        cx: &mut Context<Self>,
12966    ) {
12967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12968        self.change_selections(Default::default(), window, cx, |s| {
12969            s.move_cursors_with(|map, head, _| {
12970                (
12971                    movement::line_end(map, head, action.stop_at_soft_wraps),
12972                    SelectionGoal::None,
12973                )
12974            });
12975        })
12976    }
12977
12978    pub fn select_to_end_of_line(
12979        &mut self,
12980        action: &SelectToEndOfLine,
12981        window: &mut Window,
12982        cx: &mut Context<Self>,
12983    ) {
12984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12985        self.change_selections(Default::default(), window, cx, |s| {
12986            s.move_heads_with(|map, head, _| {
12987                (
12988                    movement::line_end(map, head, action.stop_at_soft_wraps),
12989                    SelectionGoal::None,
12990                )
12991            });
12992        })
12993    }
12994
12995    pub fn delete_to_end_of_line(
12996        &mut self,
12997        _: &DeleteToEndOfLine,
12998        window: &mut Window,
12999        cx: &mut Context<Self>,
13000    ) {
13001        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13002        self.transact(window, cx, |this, window, cx| {
13003            this.select_to_end_of_line(
13004                &SelectToEndOfLine {
13005                    stop_at_soft_wraps: false,
13006                },
13007                window,
13008                cx,
13009            );
13010            this.delete(&Delete, window, cx);
13011        });
13012    }
13013
13014    pub fn cut_to_end_of_line(
13015        &mut self,
13016        _: &CutToEndOfLine,
13017        window: &mut Window,
13018        cx: &mut Context<Self>,
13019    ) {
13020        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13021        self.transact(window, cx, |this, window, cx| {
13022            this.select_to_end_of_line(
13023                &SelectToEndOfLine {
13024                    stop_at_soft_wraps: false,
13025                },
13026                window,
13027                cx,
13028            );
13029            this.cut(&Cut, window, cx);
13030        });
13031    }
13032
13033    pub fn move_to_start_of_paragraph(
13034        &mut self,
13035        _: &MoveToStartOfParagraph,
13036        window: &mut Window,
13037        cx: &mut Context<Self>,
13038    ) {
13039        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13040            cx.propagate();
13041            return;
13042        }
13043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13044        self.change_selections(Default::default(), window, cx, |s| {
13045            s.move_with(|map, selection| {
13046                selection.collapse_to(
13047                    movement::start_of_paragraph(map, selection.head(), 1),
13048                    SelectionGoal::None,
13049                )
13050            });
13051        })
13052    }
13053
13054    pub fn move_to_end_of_paragraph(
13055        &mut self,
13056        _: &MoveToEndOfParagraph,
13057        window: &mut Window,
13058        cx: &mut Context<Self>,
13059    ) {
13060        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13061            cx.propagate();
13062            return;
13063        }
13064        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13065        self.change_selections(Default::default(), window, cx, |s| {
13066            s.move_with(|map, selection| {
13067                selection.collapse_to(
13068                    movement::end_of_paragraph(map, selection.head(), 1),
13069                    SelectionGoal::None,
13070                )
13071            });
13072        })
13073    }
13074
13075    pub fn select_to_start_of_paragraph(
13076        &mut self,
13077        _: &SelectToStartOfParagraph,
13078        window: &mut Window,
13079        cx: &mut Context<Self>,
13080    ) {
13081        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13082            cx.propagate();
13083            return;
13084        }
13085        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13086        self.change_selections(Default::default(), window, cx, |s| {
13087            s.move_heads_with(|map, head, _| {
13088                (
13089                    movement::start_of_paragraph(map, head, 1),
13090                    SelectionGoal::None,
13091                )
13092            });
13093        })
13094    }
13095
13096    pub fn select_to_end_of_paragraph(
13097        &mut self,
13098        _: &SelectToEndOfParagraph,
13099        window: &mut Window,
13100        cx: &mut Context<Self>,
13101    ) {
13102        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13103            cx.propagate();
13104            return;
13105        }
13106        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13107        self.change_selections(Default::default(), window, cx, |s| {
13108            s.move_heads_with(|map, head, _| {
13109                (
13110                    movement::end_of_paragraph(map, head, 1),
13111                    SelectionGoal::None,
13112                )
13113            });
13114        })
13115    }
13116
13117    pub fn move_to_start_of_excerpt(
13118        &mut self,
13119        _: &MoveToStartOfExcerpt,
13120        window: &mut Window,
13121        cx: &mut Context<Self>,
13122    ) {
13123        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13124            cx.propagate();
13125            return;
13126        }
13127        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13128        self.change_selections(Default::default(), window, cx, |s| {
13129            s.move_with(|map, selection| {
13130                selection.collapse_to(
13131                    movement::start_of_excerpt(
13132                        map,
13133                        selection.head(),
13134                        workspace::searchable::Direction::Prev,
13135                    ),
13136                    SelectionGoal::None,
13137                )
13138            });
13139        })
13140    }
13141
13142    pub fn move_to_start_of_next_excerpt(
13143        &mut self,
13144        _: &MoveToStartOfNextExcerpt,
13145        window: &mut Window,
13146        cx: &mut Context<Self>,
13147    ) {
13148        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13149            cx.propagate();
13150            return;
13151        }
13152
13153        self.change_selections(Default::default(), window, cx, |s| {
13154            s.move_with(|map, selection| {
13155                selection.collapse_to(
13156                    movement::start_of_excerpt(
13157                        map,
13158                        selection.head(),
13159                        workspace::searchable::Direction::Next,
13160                    ),
13161                    SelectionGoal::None,
13162                )
13163            });
13164        })
13165    }
13166
13167    pub fn move_to_end_of_excerpt(
13168        &mut self,
13169        _: &MoveToEndOfExcerpt,
13170        window: &mut Window,
13171        cx: &mut Context<Self>,
13172    ) {
13173        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13174            cx.propagate();
13175            return;
13176        }
13177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13178        self.change_selections(Default::default(), window, cx, |s| {
13179            s.move_with(|map, selection| {
13180                selection.collapse_to(
13181                    movement::end_of_excerpt(
13182                        map,
13183                        selection.head(),
13184                        workspace::searchable::Direction::Next,
13185                    ),
13186                    SelectionGoal::None,
13187                )
13188            });
13189        })
13190    }
13191
13192    pub fn move_to_end_of_previous_excerpt(
13193        &mut self,
13194        _: &MoveToEndOfPreviousExcerpt,
13195        window: &mut Window,
13196        cx: &mut Context<Self>,
13197    ) {
13198        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13199            cx.propagate();
13200            return;
13201        }
13202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13203        self.change_selections(Default::default(), window, cx, |s| {
13204            s.move_with(|map, selection| {
13205                selection.collapse_to(
13206                    movement::end_of_excerpt(
13207                        map,
13208                        selection.head(),
13209                        workspace::searchable::Direction::Prev,
13210                    ),
13211                    SelectionGoal::None,
13212                )
13213            });
13214        })
13215    }
13216
13217    pub fn select_to_start_of_excerpt(
13218        &mut self,
13219        _: &SelectToStartOfExcerpt,
13220        window: &mut Window,
13221        cx: &mut Context<Self>,
13222    ) {
13223        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13224            cx.propagate();
13225            return;
13226        }
13227        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13228        self.change_selections(Default::default(), window, cx, |s| {
13229            s.move_heads_with(|map, head, _| {
13230                (
13231                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13232                    SelectionGoal::None,
13233                )
13234            });
13235        })
13236    }
13237
13238    pub fn select_to_start_of_next_excerpt(
13239        &mut self,
13240        _: &SelectToStartOfNextExcerpt,
13241        window: &mut Window,
13242        cx: &mut Context<Self>,
13243    ) {
13244        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13245            cx.propagate();
13246            return;
13247        }
13248        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13249        self.change_selections(Default::default(), window, cx, |s| {
13250            s.move_heads_with(|map, head, _| {
13251                (
13252                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13253                    SelectionGoal::None,
13254                )
13255            });
13256        })
13257    }
13258
13259    pub fn select_to_end_of_excerpt(
13260        &mut self,
13261        _: &SelectToEndOfExcerpt,
13262        window: &mut Window,
13263        cx: &mut Context<Self>,
13264    ) {
13265        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13266            cx.propagate();
13267            return;
13268        }
13269        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13270        self.change_selections(Default::default(), window, cx, |s| {
13271            s.move_heads_with(|map, head, _| {
13272                (
13273                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13274                    SelectionGoal::None,
13275                )
13276            });
13277        })
13278    }
13279
13280    pub fn select_to_end_of_previous_excerpt(
13281        &mut self,
13282        _: &SelectToEndOfPreviousExcerpt,
13283        window: &mut Window,
13284        cx: &mut Context<Self>,
13285    ) {
13286        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13287            cx.propagate();
13288            return;
13289        }
13290        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13291        self.change_selections(Default::default(), window, cx, |s| {
13292            s.move_heads_with(|map, head, _| {
13293                (
13294                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13295                    SelectionGoal::None,
13296                )
13297            });
13298        })
13299    }
13300
13301    pub fn move_to_beginning(
13302        &mut self,
13303        _: &MoveToBeginning,
13304        window: &mut Window,
13305        cx: &mut Context<Self>,
13306    ) {
13307        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13308            cx.propagate();
13309            return;
13310        }
13311        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13312        self.change_selections(Default::default(), window, cx, |s| {
13313            s.select_ranges(vec![0..0]);
13314        });
13315    }
13316
13317    pub fn select_to_beginning(
13318        &mut self,
13319        _: &SelectToBeginning,
13320        window: &mut Window,
13321        cx: &mut Context<Self>,
13322    ) {
13323        let mut selection = self.selections.last::<Point>(cx);
13324        selection.set_head(Point::zero(), SelectionGoal::None);
13325        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13326        self.change_selections(Default::default(), window, cx, |s| {
13327            s.select(vec![selection]);
13328        });
13329    }
13330
13331    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13332        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13333            cx.propagate();
13334            return;
13335        }
13336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13337        let cursor = self.buffer.read(cx).read(cx).len();
13338        self.change_selections(Default::default(), window, cx, |s| {
13339            s.select_ranges(vec![cursor..cursor])
13340        });
13341    }
13342
13343    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13344        self.nav_history = nav_history;
13345    }
13346
13347    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13348        self.nav_history.as_ref()
13349    }
13350
13351    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13352        self.push_to_nav_history(
13353            self.selections.newest_anchor().head(),
13354            None,
13355            false,
13356            true,
13357            cx,
13358        );
13359    }
13360
13361    fn push_to_nav_history(
13362        &mut self,
13363        cursor_anchor: Anchor,
13364        new_position: Option<Point>,
13365        is_deactivate: bool,
13366        always: bool,
13367        cx: &mut Context<Self>,
13368    ) {
13369        if let Some(nav_history) = self.nav_history.as_mut() {
13370            let buffer = self.buffer.read(cx).read(cx);
13371            let cursor_position = cursor_anchor.to_point(&buffer);
13372            let scroll_state = self.scroll_manager.anchor();
13373            let scroll_top_row = scroll_state.top_row(&buffer);
13374            drop(buffer);
13375
13376            if let Some(new_position) = new_position {
13377                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13378                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13379                    return;
13380                }
13381            }
13382
13383            nav_history.push(
13384                Some(NavigationData {
13385                    cursor_anchor,
13386                    cursor_position,
13387                    scroll_anchor: scroll_state,
13388                    scroll_top_row,
13389                }),
13390                cx,
13391            );
13392            cx.emit(EditorEvent::PushedToNavHistory {
13393                anchor: cursor_anchor,
13394                is_deactivate,
13395            })
13396        }
13397    }
13398
13399    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13400        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13401        let buffer = self.buffer.read(cx).snapshot(cx);
13402        let mut selection = self.selections.first::<usize>(cx);
13403        selection.set_head(buffer.len(), SelectionGoal::None);
13404        self.change_selections(Default::default(), window, cx, |s| {
13405            s.select(vec![selection]);
13406        });
13407    }
13408
13409    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13410        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13411        let end = self.buffer.read(cx).read(cx).len();
13412        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13413            s.select_ranges(vec![0..end]);
13414        });
13415    }
13416
13417    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13419        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13420        let mut selections = self.selections.all::<Point>(cx);
13421        let max_point = display_map.buffer_snapshot.max_point();
13422        for selection in &mut selections {
13423            let rows = selection.spanned_rows(true, &display_map);
13424            selection.start = Point::new(rows.start.0, 0);
13425            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13426            selection.reversed = false;
13427        }
13428        self.change_selections(Default::default(), window, cx, |s| {
13429            s.select(selections);
13430        });
13431    }
13432
13433    pub fn split_selection_into_lines(
13434        &mut self,
13435        _: &SplitSelectionIntoLines,
13436        window: &mut Window,
13437        cx: &mut Context<Self>,
13438    ) {
13439        let selections = self
13440            .selections
13441            .all::<Point>(cx)
13442            .into_iter()
13443            .map(|selection| selection.start..selection.end)
13444            .collect::<Vec<_>>();
13445        self.unfold_ranges(&selections, true, true, cx);
13446
13447        let mut new_selection_ranges = Vec::new();
13448        {
13449            let buffer = self.buffer.read(cx).read(cx);
13450            for selection in selections {
13451                for row in selection.start.row..selection.end.row {
13452                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13453                    new_selection_ranges.push(cursor..cursor);
13454                }
13455
13456                let is_multiline_selection = selection.start.row != selection.end.row;
13457                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13458                // so this action feels more ergonomic when paired with other selection operations
13459                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13460                if !should_skip_last {
13461                    new_selection_ranges.push(selection.end..selection.end);
13462                }
13463            }
13464        }
13465        self.change_selections(Default::default(), window, cx, |s| {
13466            s.select_ranges(new_selection_ranges);
13467        });
13468    }
13469
13470    pub fn add_selection_above(
13471        &mut self,
13472        _: &AddSelectionAbove,
13473        window: &mut Window,
13474        cx: &mut Context<Self>,
13475    ) {
13476        self.add_selection(true, window, cx);
13477    }
13478
13479    pub fn add_selection_below(
13480        &mut self,
13481        _: &AddSelectionBelow,
13482        window: &mut Window,
13483        cx: &mut Context<Self>,
13484    ) {
13485        self.add_selection(false, window, cx);
13486    }
13487
13488    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13489        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13490
13491        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13492        let all_selections = self.selections.all::<Point>(cx);
13493        let text_layout_details = self.text_layout_details(window);
13494
13495        let (mut columnar_selections, new_selections_to_columnarize) = {
13496            if let Some(state) = self.add_selections_state.as_ref() {
13497                let columnar_selection_ids: HashSet<_> = state
13498                    .groups
13499                    .iter()
13500                    .flat_map(|group| group.stack.iter())
13501                    .copied()
13502                    .collect();
13503
13504                all_selections
13505                    .into_iter()
13506                    .partition(|s| columnar_selection_ids.contains(&s.id))
13507            } else {
13508                (Vec::new(), all_selections)
13509            }
13510        };
13511
13512        let mut state = self
13513            .add_selections_state
13514            .take()
13515            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13516
13517        for selection in new_selections_to_columnarize {
13518            let range = selection.display_range(&display_map).sorted();
13519            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13520            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13521            let positions = start_x.min(end_x)..start_x.max(end_x);
13522            let mut stack = Vec::new();
13523            for row in range.start.row().0..=range.end.row().0 {
13524                if let Some(selection) = self.selections.build_columnar_selection(
13525                    &display_map,
13526                    DisplayRow(row),
13527                    &positions,
13528                    selection.reversed,
13529                    &text_layout_details,
13530                ) {
13531                    stack.push(selection.id);
13532                    columnar_selections.push(selection);
13533                }
13534            }
13535            if !stack.is_empty() {
13536                if above {
13537                    stack.reverse();
13538                }
13539                state.groups.push(AddSelectionsGroup { above, stack });
13540            }
13541        }
13542
13543        let mut final_selections = Vec::new();
13544        let end_row = if above {
13545            DisplayRow(0)
13546        } else {
13547            display_map.max_point().row()
13548        };
13549
13550        let mut last_added_item_per_group = HashMap::default();
13551        for group in state.groups.iter_mut() {
13552            if let Some(last_id) = group.stack.last() {
13553                last_added_item_per_group.insert(*last_id, group);
13554            }
13555        }
13556
13557        for selection in columnar_selections {
13558            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13559                if above == group.above {
13560                    let range = selection.display_range(&display_map).sorted();
13561                    debug_assert_eq!(range.start.row(), range.end.row());
13562                    let mut row = range.start.row();
13563                    let positions =
13564                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13565                            px(start)..px(end)
13566                        } else {
13567                            let start_x =
13568                                display_map.x_for_display_point(range.start, &text_layout_details);
13569                            let end_x =
13570                                display_map.x_for_display_point(range.end, &text_layout_details);
13571                            start_x.min(end_x)..start_x.max(end_x)
13572                        };
13573
13574                    let mut maybe_new_selection = None;
13575                    while row != end_row {
13576                        if above {
13577                            row.0 -= 1;
13578                        } else {
13579                            row.0 += 1;
13580                        }
13581                        if let Some(new_selection) = self.selections.build_columnar_selection(
13582                            &display_map,
13583                            row,
13584                            &positions,
13585                            selection.reversed,
13586                            &text_layout_details,
13587                        ) {
13588                            maybe_new_selection = Some(new_selection);
13589                            break;
13590                        }
13591                    }
13592
13593                    if let Some(new_selection) = maybe_new_selection {
13594                        group.stack.push(new_selection.id);
13595                        if above {
13596                            final_selections.push(new_selection);
13597                            final_selections.push(selection);
13598                        } else {
13599                            final_selections.push(selection);
13600                            final_selections.push(new_selection);
13601                        }
13602                    } else {
13603                        final_selections.push(selection);
13604                    }
13605                } else {
13606                    group.stack.pop();
13607                }
13608            } else {
13609                final_selections.push(selection);
13610            }
13611        }
13612
13613        self.change_selections(Default::default(), window, cx, |s| {
13614            s.select(final_selections);
13615        });
13616
13617        let final_selection_ids: HashSet<_> = self
13618            .selections
13619            .all::<Point>(cx)
13620            .iter()
13621            .map(|s| s.id)
13622            .collect();
13623        state.groups.retain_mut(|group| {
13624            // selections might get merged above so we remove invalid items from stacks
13625            group.stack.retain(|id| final_selection_ids.contains(id));
13626
13627            // single selection in stack can be treated as initial state
13628            group.stack.len() > 1
13629        });
13630
13631        if !state.groups.is_empty() {
13632            self.add_selections_state = Some(state);
13633        }
13634    }
13635
13636    fn select_match_ranges(
13637        &mut self,
13638        range: Range<usize>,
13639        reversed: bool,
13640        replace_newest: bool,
13641        auto_scroll: Option<Autoscroll>,
13642        window: &mut Window,
13643        cx: &mut Context<Editor>,
13644    ) {
13645        self.unfold_ranges(
13646            std::slice::from_ref(&range),
13647            false,
13648            auto_scroll.is_some(),
13649            cx,
13650        );
13651        let effects = if let Some(scroll) = auto_scroll {
13652            SelectionEffects::scroll(scroll)
13653        } else {
13654            SelectionEffects::no_scroll()
13655        };
13656        self.change_selections(effects, window, cx, |s| {
13657            if replace_newest {
13658                s.delete(s.newest_anchor().id);
13659            }
13660            if reversed {
13661                s.insert_range(range.end..range.start);
13662            } else {
13663                s.insert_range(range);
13664            }
13665        });
13666    }
13667
13668    pub fn select_next_match_internal(
13669        &mut self,
13670        display_map: &DisplaySnapshot,
13671        replace_newest: bool,
13672        autoscroll: Option<Autoscroll>,
13673        window: &mut Window,
13674        cx: &mut Context<Self>,
13675    ) -> Result<()> {
13676        let buffer = &display_map.buffer_snapshot;
13677        let mut selections = self.selections.all::<usize>(cx);
13678        if let Some(mut select_next_state) = self.select_next_state.take() {
13679            let query = &select_next_state.query;
13680            if !select_next_state.done {
13681                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13682                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13683                let mut next_selected_range = None;
13684
13685                let bytes_after_last_selection =
13686                    buffer.bytes_in_range(last_selection.end..buffer.len());
13687                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13688                let query_matches = query
13689                    .stream_find_iter(bytes_after_last_selection)
13690                    .map(|result| (last_selection.end, result))
13691                    .chain(
13692                        query
13693                            .stream_find_iter(bytes_before_first_selection)
13694                            .map(|result| (0, result)),
13695                    );
13696
13697                for (start_offset, query_match) in query_matches {
13698                    let query_match = query_match.unwrap(); // can only fail due to I/O
13699                    let offset_range =
13700                        start_offset + query_match.start()..start_offset + query_match.end();
13701
13702                    if !select_next_state.wordwise
13703                        || (!buffer.is_inside_word(offset_range.start, false)
13704                            && !buffer.is_inside_word(offset_range.end, false))
13705                    {
13706                        // TODO: This is n^2, because we might check all the selections
13707                        if !selections
13708                            .iter()
13709                            .any(|selection| selection.range().overlaps(&offset_range))
13710                        {
13711                            next_selected_range = Some(offset_range);
13712                            break;
13713                        }
13714                    }
13715                }
13716
13717                if let Some(next_selected_range) = next_selected_range {
13718                    self.select_match_ranges(
13719                        next_selected_range,
13720                        last_selection.reversed,
13721                        replace_newest,
13722                        autoscroll,
13723                        window,
13724                        cx,
13725                    );
13726                } else {
13727                    select_next_state.done = true;
13728                }
13729            }
13730
13731            self.select_next_state = Some(select_next_state);
13732        } else {
13733            let mut only_carets = true;
13734            let mut same_text_selected = true;
13735            let mut selected_text = None;
13736
13737            let mut selections_iter = selections.iter().peekable();
13738            while let Some(selection) = selections_iter.next() {
13739                if selection.start != selection.end {
13740                    only_carets = false;
13741                }
13742
13743                if same_text_selected {
13744                    if selected_text.is_none() {
13745                        selected_text =
13746                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13747                    }
13748
13749                    if let Some(next_selection) = selections_iter.peek() {
13750                        if next_selection.range().len() == selection.range().len() {
13751                            let next_selected_text = buffer
13752                                .text_for_range(next_selection.range())
13753                                .collect::<String>();
13754                            if Some(next_selected_text) != selected_text {
13755                                same_text_selected = false;
13756                                selected_text = None;
13757                            }
13758                        } else {
13759                            same_text_selected = false;
13760                            selected_text = None;
13761                        }
13762                    }
13763                }
13764            }
13765
13766            if only_carets {
13767                for selection in &mut selections {
13768                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13769                    selection.start = word_range.start;
13770                    selection.end = word_range.end;
13771                    selection.goal = SelectionGoal::None;
13772                    selection.reversed = false;
13773                    self.select_match_ranges(
13774                        selection.start..selection.end,
13775                        selection.reversed,
13776                        replace_newest,
13777                        autoscroll,
13778                        window,
13779                        cx,
13780                    );
13781                }
13782
13783                if selections.len() == 1 {
13784                    let selection = selections
13785                        .last()
13786                        .expect("ensured that there's only one selection");
13787                    let query = buffer
13788                        .text_for_range(selection.start..selection.end)
13789                        .collect::<String>();
13790                    let is_empty = query.is_empty();
13791                    let select_state = SelectNextState {
13792                        query: AhoCorasick::new(&[query])?,
13793                        wordwise: true,
13794                        done: is_empty,
13795                    };
13796                    self.select_next_state = Some(select_state);
13797                } else {
13798                    self.select_next_state = None;
13799                }
13800            } else if let Some(selected_text) = selected_text {
13801                self.select_next_state = Some(SelectNextState {
13802                    query: AhoCorasick::new(&[selected_text])?,
13803                    wordwise: false,
13804                    done: false,
13805                });
13806                self.select_next_match_internal(
13807                    display_map,
13808                    replace_newest,
13809                    autoscroll,
13810                    window,
13811                    cx,
13812                )?;
13813            }
13814        }
13815        Ok(())
13816    }
13817
13818    pub fn select_all_matches(
13819        &mut self,
13820        _action: &SelectAllMatches,
13821        window: &mut Window,
13822        cx: &mut Context<Self>,
13823    ) -> Result<()> {
13824        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13825
13826        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13827
13828        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13829        let Some(select_next_state) = self.select_next_state.as_mut() else {
13830            return Ok(());
13831        };
13832        if select_next_state.done {
13833            return Ok(());
13834        }
13835
13836        let mut new_selections = Vec::new();
13837
13838        let reversed = self.selections.oldest::<usize>(cx).reversed;
13839        let buffer = &display_map.buffer_snapshot;
13840        let query_matches = select_next_state
13841            .query
13842            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13843
13844        for query_match in query_matches.into_iter() {
13845            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13846            let offset_range = if reversed {
13847                query_match.end()..query_match.start()
13848            } else {
13849                query_match.start()..query_match.end()
13850            };
13851
13852            if !select_next_state.wordwise
13853                || (!buffer.is_inside_word(offset_range.start, false)
13854                    && !buffer.is_inside_word(offset_range.end, false))
13855            {
13856                new_selections.push(offset_range.start..offset_range.end);
13857            }
13858        }
13859
13860        select_next_state.done = true;
13861
13862        if new_selections.is_empty() {
13863            log::error!("bug: new_selections is empty in select_all_matches");
13864            return Ok(());
13865        }
13866
13867        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13868        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13869            selections.select_ranges(new_selections)
13870        });
13871
13872        Ok(())
13873    }
13874
13875    pub fn select_next(
13876        &mut self,
13877        action: &SelectNext,
13878        window: &mut Window,
13879        cx: &mut Context<Self>,
13880    ) -> Result<()> {
13881        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13882        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13883        self.select_next_match_internal(
13884            &display_map,
13885            action.replace_newest,
13886            Some(Autoscroll::newest()),
13887            window,
13888            cx,
13889        )?;
13890        Ok(())
13891    }
13892
13893    pub fn select_previous(
13894        &mut self,
13895        action: &SelectPrevious,
13896        window: &mut Window,
13897        cx: &mut Context<Self>,
13898    ) -> Result<()> {
13899        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13900        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13901        let buffer = &display_map.buffer_snapshot;
13902        let mut selections = self.selections.all::<usize>(cx);
13903        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13904            let query = &select_prev_state.query;
13905            if !select_prev_state.done {
13906                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13907                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13908                let mut next_selected_range = None;
13909                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13910                let bytes_before_last_selection =
13911                    buffer.reversed_bytes_in_range(0..last_selection.start);
13912                let bytes_after_first_selection =
13913                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13914                let query_matches = query
13915                    .stream_find_iter(bytes_before_last_selection)
13916                    .map(|result| (last_selection.start, result))
13917                    .chain(
13918                        query
13919                            .stream_find_iter(bytes_after_first_selection)
13920                            .map(|result| (buffer.len(), result)),
13921                    );
13922                for (end_offset, query_match) in query_matches {
13923                    let query_match = query_match.unwrap(); // can only fail due to I/O
13924                    let offset_range =
13925                        end_offset - query_match.end()..end_offset - query_match.start();
13926
13927                    if !select_prev_state.wordwise
13928                        || (!buffer.is_inside_word(offset_range.start, false)
13929                            && !buffer.is_inside_word(offset_range.end, false))
13930                    {
13931                        next_selected_range = Some(offset_range);
13932                        break;
13933                    }
13934                }
13935
13936                if let Some(next_selected_range) = next_selected_range {
13937                    self.select_match_ranges(
13938                        next_selected_range,
13939                        last_selection.reversed,
13940                        action.replace_newest,
13941                        Some(Autoscroll::newest()),
13942                        window,
13943                        cx,
13944                    );
13945                } else {
13946                    select_prev_state.done = true;
13947                }
13948            }
13949
13950            self.select_prev_state = Some(select_prev_state);
13951        } else {
13952            let mut only_carets = true;
13953            let mut same_text_selected = true;
13954            let mut selected_text = None;
13955
13956            let mut selections_iter = selections.iter().peekable();
13957            while let Some(selection) = selections_iter.next() {
13958                if selection.start != selection.end {
13959                    only_carets = false;
13960                }
13961
13962                if same_text_selected {
13963                    if selected_text.is_none() {
13964                        selected_text =
13965                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13966                    }
13967
13968                    if let Some(next_selection) = selections_iter.peek() {
13969                        if next_selection.range().len() == selection.range().len() {
13970                            let next_selected_text = buffer
13971                                .text_for_range(next_selection.range())
13972                                .collect::<String>();
13973                            if Some(next_selected_text) != selected_text {
13974                                same_text_selected = false;
13975                                selected_text = None;
13976                            }
13977                        } else {
13978                            same_text_selected = false;
13979                            selected_text = None;
13980                        }
13981                    }
13982                }
13983            }
13984
13985            if only_carets {
13986                for selection in &mut selections {
13987                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13988                    selection.start = word_range.start;
13989                    selection.end = word_range.end;
13990                    selection.goal = SelectionGoal::None;
13991                    selection.reversed = false;
13992                    self.select_match_ranges(
13993                        selection.start..selection.end,
13994                        selection.reversed,
13995                        action.replace_newest,
13996                        Some(Autoscroll::newest()),
13997                        window,
13998                        cx,
13999                    );
14000                }
14001                if selections.len() == 1 {
14002                    let selection = selections
14003                        .last()
14004                        .expect("ensured that there's only one selection");
14005                    let query = buffer
14006                        .text_for_range(selection.start..selection.end)
14007                        .collect::<String>();
14008                    let is_empty = query.is_empty();
14009                    let select_state = SelectNextState {
14010                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14011                        wordwise: true,
14012                        done: is_empty,
14013                    };
14014                    self.select_prev_state = Some(select_state);
14015                } else {
14016                    self.select_prev_state = None;
14017                }
14018            } else if let Some(selected_text) = selected_text {
14019                self.select_prev_state = Some(SelectNextState {
14020                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14021                    wordwise: false,
14022                    done: false,
14023                });
14024                self.select_previous(action, window, cx)?;
14025            }
14026        }
14027        Ok(())
14028    }
14029
14030    pub fn find_next_match(
14031        &mut self,
14032        _: &FindNextMatch,
14033        window: &mut Window,
14034        cx: &mut Context<Self>,
14035    ) -> Result<()> {
14036        let selections = self.selections.disjoint_anchors();
14037        match selections.first() {
14038            Some(first) if selections.len() >= 2 => {
14039                self.change_selections(Default::default(), window, cx, |s| {
14040                    s.select_ranges([first.range()]);
14041                });
14042            }
14043            _ => self.select_next(
14044                &SelectNext {
14045                    replace_newest: true,
14046                },
14047                window,
14048                cx,
14049            )?,
14050        }
14051        Ok(())
14052    }
14053
14054    pub fn find_previous_match(
14055        &mut self,
14056        _: &FindPreviousMatch,
14057        window: &mut Window,
14058        cx: &mut Context<Self>,
14059    ) -> Result<()> {
14060        let selections = self.selections.disjoint_anchors();
14061        match selections.last() {
14062            Some(last) if selections.len() >= 2 => {
14063                self.change_selections(Default::default(), window, cx, |s| {
14064                    s.select_ranges([last.range()]);
14065                });
14066            }
14067            _ => self.select_previous(
14068                &SelectPrevious {
14069                    replace_newest: true,
14070                },
14071                window,
14072                cx,
14073            )?,
14074        }
14075        Ok(())
14076    }
14077
14078    pub fn toggle_comments(
14079        &mut self,
14080        action: &ToggleComments,
14081        window: &mut Window,
14082        cx: &mut Context<Self>,
14083    ) {
14084        if self.read_only(cx) {
14085            return;
14086        }
14087        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14088        let text_layout_details = &self.text_layout_details(window);
14089        self.transact(window, cx, |this, window, cx| {
14090            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14091            let mut edits = Vec::new();
14092            let mut selection_edit_ranges = Vec::new();
14093            let mut last_toggled_row = None;
14094            let snapshot = this.buffer.read(cx).read(cx);
14095            let empty_str: Arc<str> = Arc::default();
14096            let mut suffixes_inserted = Vec::new();
14097            let ignore_indent = action.ignore_indent;
14098
14099            fn comment_prefix_range(
14100                snapshot: &MultiBufferSnapshot,
14101                row: MultiBufferRow,
14102                comment_prefix: &str,
14103                comment_prefix_whitespace: &str,
14104                ignore_indent: bool,
14105            ) -> Range<Point> {
14106                let indent_size = if ignore_indent {
14107                    0
14108                } else {
14109                    snapshot.indent_size_for_line(row).len
14110                };
14111
14112                let start = Point::new(row.0, indent_size);
14113
14114                let mut line_bytes = snapshot
14115                    .bytes_in_range(start..snapshot.max_point())
14116                    .flatten()
14117                    .copied();
14118
14119                // If this line currently begins with the line comment prefix, then record
14120                // the range containing the prefix.
14121                if line_bytes
14122                    .by_ref()
14123                    .take(comment_prefix.len())
14124                    .eq(comment_prefix.bytes())
14125                {
14126                    // Include any whitespace that matches the comment prefix.
14127                    let matching_whitespace_len = line_bytes
14128                        .zip(comment_prefix_whitespace.bytes())
14129                        .take_while(|(a, b)| a == b)
14130                        .count() as u32;
14131                    let end = Point::new(
14132                        start.row,
14133                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14134                    );
14135                    start..end
14136                } else {
14137                    start..start
14138                }
14139            }
14140
14141            fn comment_suffix_range(
14142                snapshot: &MultiBufferSnapshot,
14143                row: MultiBufferRow,
14144                comment_suffix: &str,
14145                comment_suffix_has_leading_space: bool,
14146            ) -> Range<Point> {
14147                let end = Point::new(row.0, snapshot.line_len(row));
14148                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14149
14150                let mut line_end_bytes = snapshot
14151                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14152                    .flatten()
14153                    .copied();
14154
14155                let leading_space_len = if suffix_start_column > 0
14156                    && line_end_bytes.next() == Some(b' ')
14157                    && comment_suffix_has_leading_space
14158                {
14159                    1
14160                } else {
14161                    0
14162                };
14163
14164                // If this line currently begins with the line comment prefix, then record
14165                // the range containing the prefix.
14166                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14167                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14168                    start..end
14169                } else {
14170                    end..end
14171                }
14172            }
14173
14174            // TODO: Handle selections that cross excerpts
14175            for selection in &mut selections {
14176                let start_column = snapshot
14177                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14178                    .len;
14179                let language = if let Some(language) =
14180                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14181                {
14182                    language
14183                } else {
14184                    continue;
14185                };
14186
14187                selection_edit_ranges.clear();
14188
14189                // If multiple selections contain a given row, avoid processing that
14190                // row more than once.
14191                let mut start_row = MultiBufferRow(selection.start.row);
14192                if last_toggled_row == Some(start_row) {
14193                    start_row = start_row.next_row();
14194                }
14195                let end_row =
14196                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14197                        MultiBufferRow(selection.end.row - 1)
14198                    } else {
14199                        MultiBufferRow(selection.end.row)
14200                    };
14201                last_toggled_row = Some(end_row);
14202
14203                if start_row > end_row {
14204                    continue;
14205                }
14206
14207                // If the language has line comments, toggle those.
14208                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14209
14210                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14211                if ignore_indent {
14212                    full_comment_prefixes = full_comment_prefixes
14213                        .into_iter()
14214                        .map(|s| Arc::from(s.trim_end()))
14215                        .collect();
14216                }
14217
14218                if !full_comment_prefixes.is_empty() {
14219                    let first_prefix = full_comment_prefixes
14220                        .first()
14221                        .expect("prefixes is non-empty");
14222                    let prefix_trimmed_lengths = full_comment_prefixes
14223                        .iter()
14224                        .map(|p| p.trim_end_matches(' ').len())
14225                        .collect::<SmallVec<[usize; 4]>>();
14226
14227                    let mut all_selection_lines_are_comments = true;
14228
14229                    for row in start_row.0..=end_row.0 {
14230                        let row = MultiBufferRow(row);
14231                        if start_row < end_row && snapshot.is_line_blank(row) {
14232                            continue;
14233                        }
14234
14235                        let prefix_range = full_comment_prefixes
14236                            .iter()
14237                            .zip(prefix_trimmed_lengths.iter().copied())
14238                            .map(|(prefix, trimmed_prefix_len)| {
14239                                comment_prefix_range(
14240                                    snapshot.deref(),
14241                                    row,
14242                                    &prefix[..trimmed_prefix_len],
14243                                    &prefix[trimmed_prefix_len..],
14244                                    ignore_indent,
14245                                )
14246                            })
14247                            .max_by_key(|range| range.end.column - range.start.column)
14248                            .expect("prefixes is non-empty");
14249
14250                        if prefix_range.is_empty() {
14251                            all_selection_lines_are_comments = false;
14252                        }
14253
14254                        selection_edit_ranges.push(prefix_range);
14255                    }
14256
14257                    if all_selection_lines_are_comments {
14258                        edits.extend(
14259                            selection_edit_ranges
14260                                .iter()
14261                                .cloned()
14262                                .map(|range| (range, empty_str.clone())),
14263                        );
14264                    } else {
14265                        let min_column = selection_edit_ranges
14266                            .iter()
14267                            .map(|range| range.start.column)
14268                            .min()
14269                            .unwrap_or(0);
14270                        edits.extend(selection_edit_ranges.iter().map(|range| {
14271                            let position = Point::new(range.start.row, min_column);
14272                            (position..position, first_prefix.clone())
14273                        }));
14274                    }
14275                } else if let Some((full_comment_prefix, comment_suffix)) =
14276                    language.block_comment_delimiters()
14277                {
14278                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14279                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14280                    let prefix_range = comment_prefix_range(
14281                        snapshot.deref(),
14282                        start_row,
14283                        comment_prefix,
14284                        comment_prefix_whitespace,
14285                        ignore_indent,
14286                    );
14287                    let suffix_range = comment_suffix_range(
14288                        snapshot.deref(),
14289                        end_row,
14290                        comment_suffix.trim_start_matches(' '),
14291                        comment_suffix.starts_with(' '),
14292                    );
14293
14294                    if prefix_range.is_empty() || suffix_range.is_empty() {
14295                        edits.push((
14296                            prefix_range.start..prefix_range.start,
14297                            full_comment_prefix.clone(),
14298                        ));
14299                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14300                        suffixes_inserted.push((end_row, comment_suffix.len()));
14301                    } else {
14302                        edits.push((prefix_range, empty_str.clone()));
14303                        edits.push((suffix_range, empty_str.clone()));
14304                    }
14305                } else {
14306                    continue;
14307                }
14308            }
14309
14310            drop(snapshot);
14311            this.buffer.update(cx, |buffer, cx| {
14312                buffer.edit(edits, None, cx);
14313            });
14314
14315            // Adjust selections so that they end before any comment suffixes that
14316            // were inserted.
14317            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14318            let mut selections = this.selections.all::<Point>(cx);
14319            let snapshot = this.buffer.read(cx).read(cx);
14320            for selection in &mut selections {
14321                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14322                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14323                        Ordering::Less => {
14324                            suffixes_inserted.next();
14325                            continue;
14326                        }
14327                        Ordering::Greater => break,
14328                        Ordering::Equal => {
14329                            if selection.end.column == snapshot.line_len(row) {
14330                                if selection.is_empty() {
14331                                    selection.start.column -= suffix_len as u32;
14332                                }
14333                                selection.end.column -= suffix_len as u32;
14334                            }
14335                            break;
14336                        }
14337                    }
14338                }
14339            }
14340
14341            drop(snapshot);
14342            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14343
14344            let selections = this.selections.all::<Point>(cx);
14345            let selections_on_single_row = selections.windows(2).all(|selections| {
14346                selections[0].start.row == selections[1].start.row
14347                    && selections[0].end.row == selections[1].end.row
14348                    && selections[0].start.row == selections[0].end.row
14349            });
14350            let selections_selecting = selections
14351                .iter()
14352                .any(|selection| selection.start != selection.end);
14353            let advance_downwards = action.advance_downwards
14354                && selections_on_single_row
14355                && !selections_selecting
14356                && !matches!(this.mode, EditorMode::SingleLine { .. });
14357
14358            if advance_downwards {
14359                let snapshot = this.buffer.read(cx).snapshot(cx);
14360
14361                this.change_selections(Default::default(), window, cx, |s| {
14362                    s.move_cursors_with(|display_snapshot, display_point, _| {
14363                        let mut point = display_point.to_point(display_snapshot);
14364                        point.row += 1;
14365                        point = snapshot.clip_point(point, Bias::Left);
14366                        let display_point = point.to_display_point(display_snapshot);
14367                        let goal = SelectionGoal::HorizontalPosition(
14368                            display_snapshot
14369                                .x_for_display_point(display_point, text_layout_details)
14370                                .into(),
14371                        );
14372                        (display_point, goal)
14373                    })
14374                });
14375            }
14376        });
14377    }
14378
14379    pub fn select_enclosing_symbol(
14380        &mut self,
14381        _: &SelectEnclosingSymbol,
14382        window: &mut Window,
14383        cx: &mut Context<Self>,
14384    ) {
14385        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14386
14387        let buffer = self.buffer.read(cx).snapshot(cx);
14388        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14389
14390        fn update_selection(
14391            selection: &Selection<usize>,
14392            buffer_snap: &MultiBufferSnapshot,
14393        ) -> Option<Selection<usize>> {
14394            let cursor = selection.head();
14395            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14396            for symbol in symbols.iter().rev() {
14397                let start = symbol.range.start.to_offset(buffer_snap);
14398                let end = symbol.range.end.to_offset(buffer_snap);
14399                let new_range = start..end;
14400                if start < selection.start || end > selection.end {
14401                    return Some(Selection {
14402                        id: selection.id,
14403                        start: new_range.start,
14404                        end: new_range.end,
14405                        goal: SelectionGoal::None,
14406                        reversed: selection.reversed,
14407                    });
14408                }
14409            }
14410            None
14411        }
14412
14413        let mut selected_larger_symbol = false;
14414        let new_selections = old_selections
14415            .iter()
14416            .map(|selection| match update_selection(selection, &buffer) {
14417                Some(new_selection) => {
14418                    if new_selection.range() != selection.range() {
14419                        selected_larger_symbol = true;
14420                    }
14421                    new_selection
14422                }
14423                None => selection.clone(),
14424            })
14425            .collect::<Vec<_>>();
14426
14427        if selected_larger_symbol {
14428            self.change_selections(Default::default(), window, cx, |s| {
14429                s.select(new_selections);
14430            });
14431        }
14432    }
14433
14434    pub fn select_larger_syntax_node(
14435        &mut self,
14436        _: &SelectLargerSyntaxNode,
14437        window: &mut Window,
14438        cx: &mut Context<Self>,
14439    ) {
14440        let Some(visible_row_count) = self.visible_row_count() else {
14441            return;
14442        };
14443        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14444        if old_selections.is_empty() {
14445            return;
14446        }
14447
14448        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14449
14450        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14451        let buffer = self.buffer.read(cx).snapshot(cx);
14452
14453        let mut selected_larger_node = false;
14454        let mut new_selections = old_selections
14455            .iter()
14456            .map(|selection| {
14457                let old_range = selection.start..selection.end;
14458
14459                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14460                    // manually select word at selection
14461                    if ["string_content", "inline"].contains(&node.kind()) {
14462                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14463                        // ignore if word is already selected
14464                        if !word_range.is_empty() && old_range != word_range {
14465                            let (last_word_range, _) =
14466                                buffer.surrounding_word(old_range.end, false);
14467                            // only select word if start and end point belongs to same word
14468                            if word_range == last_word_range {
14469                                selected_larger_node = true;
14470                                return Selection {
14471                                    id: selection.id,
14472                                    start: word_range.start,
14473                                    end: word_range.end,
14474                                    goal: SelectionGoal::None,
14475                                    reversed: selection.reversed,
14476                                };
14477                            }
14478                        }
14479                    }
14480                }
14481
14482                let mut new_range = old_range.clone();
14483                while let Some((_node, containing_range)) =
14484                    buffer.syntax_ancestor(new_range.clone())
14485                {
14486                    new_range = match containing_range {
14487                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14488                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14489                    };
14490                    if !display_map.intersects_fold(new_range.start)
14491                        && !display_map.intersects_fold(new_range.end)
14492                    {
14493                        break;
14494                    }
14495                }
14496
14497                selected_larger_node |= new_range != old_range;
14498                Selection {
14499                    id: selection.id,
14500                    start: new_range.start,
14501                    end: new_range.end,
14502                    goal: SelectionGoal::None,
14503                    reversed: selection.reversed,
14504                }
14505            })
14506            .collect::<Vec<_>>();
14507
14508        if !selected_larger_node {
14509            return; // don't put this call in the history
14510        }
14511
14512        // scroll based on transformation done to the last selection created by the user
14513        let (last_old, last_new) = old_selections
14514            .last()
14515            .zip(new_selections.last().cloned())
14516            .expect("old_selections isn't empty");
14517
14518        // revert selection
14519        let is_selection_reversed = {
14520            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14521            new_selections.last_mut().expect("checked above").reversed =
14522                should_newest_selection_be_reversed;
14523            should_newest_selection_be_reversed
14524        };
14525
14526        if selected_larger_node {
14527            self.select_syntax_node_history.disable_clearing = true;
14528            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14529                s.select(new_selections.clone());
14530            });
14531            self.select_syntax_node_history.disable_clearing = false;
14532        }
14533
14534        let start_row = last_new.start.to_display_point(&display_map).row().0;
14535        let end_row = last_new.end.to_display_point(&display_map).row().0;
14536        let selection_height = end_row - start_row + 1;
14537        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14538
14539        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14540        let scroll_behavior = if fits_on_the_screen {
14541            self.request_autoscroll(Autoscroll::fit(), cx);
14542            SelectSyntaxNodeScrollBehavior::FitSelection
14543        } else if is_selection_reversed {
14544            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14545            SelectSyntaxNodeScrollBehavior::CursorTop
14546        } else {
14547            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14548            SelectSyntaxNodeScrollBehavior::CursorBottom
14549        };
14550
14551        self.select_syntax_node_history.push((
14552            old_selections,
14553            scroll_behavior,
14554            is_selection_reversed,
14555        ));
14556    }
14557
14558    pub fn select_smaller_syntax_node(
14559        &mut self,
14560        _: &SelectSmallerSyntaxNode,
14561        window: &mut Window,
14562        cx: &mut Context<Self>,
14563    ) {
14564        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14565
14566        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14567            self.select_syntax_node_history.pop()
14568        {
14569            if let Some(selection) = selections.last_mut() {
14570                selection.reversed = is_selection_reversed;
14571            }
14572
14573            self.select_syntax_node_history.disable_clearing = true;
14574            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14575                s.select(selections.to_vec());
14576            });
14577            self.select_syntax_node_history.disable_clearing = false;
14578
14579            match scroll_behavior {
14580                SelectSyntaxNodeScrollBehavior::CursorTop => {
14581                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14582                }
14583                SelectSyntaxNodeScrollBehavior::FitSelection => {
14584                    self.request_autoscroll(Autoscroll::fit(), cx);
14585                }
14586                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14587                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14588                }
14589            }
14590        }
14591    }
14592
14593    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14594        if !EditorSettings::get_global(cx).gutter.runnables {
14595            self.clear_tasks();
14596            return Task::ready(());
14597        }
14598        let project = self.project.as_ref().map(Entity::downgrade);
14599        let task_sources = self.lsp_task_sources(cx);
14600        let multi_buffer = self.buffer.downgrade();
14601        cx.spawn_in(window, async move |editor, cx| {
14602            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14603            let Some(project) = project.and_then(|p| p.upgrade()) else {
14604                return;
14605            };
14606            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14607                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14608            }) else {
14609                return;
14610            };
14611
14612            let hide_runnables = project
14613                .update(cx, |project, cx| {
14614                    // Do not display any test indicators in non-dev server remote projects.
14615                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14616                })
14617                .unwrap_or(true);
14618            if hide_runnables {
14619                return;
14620            }
14621            let new_rows =
14622                cx.background_spawn({
14623                    let snapshot = display_snapshot.clone();
14624                    async move {
14625                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14626                    }
14627                })
14628                    .await;
14629            let Ok(lsp_tasks) =
14630                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14631            else {
14632                return;
14633            };
14634            let lsp_tasks = lsp_tasks.await;
14635
14636            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14637                lsp_tasks
14638                    .into_iter()
14639                    .flat_map(|(kind, tasks)| {
14640                        tasks.into_iter().filter_map(move |(location, task)| {
14641                            Some((kind.clone(), location?, task))
14642                        })
14643                    })
14644                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14645                        let buffer = location.target.buffer;
14646                        let buffer_snapshot = buffer.read(cx).snapshot();
14647                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14648                            |(excerpt_id, snapshot, _)| {
14649                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14650                                    display_snapshot
14651                                        .buffer_snapshot
14652                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14653                                } else {
14654                                    None
14655                                }
14656                            },
14657                        );
14658                        if let Some(offset) = offset {
14659                            let task_buffer_range =
14660                                location.target.range.to_point(&buffer_snapshot);
14661                            let context_buffer_range =
14662                                task_buffer_range.to_offset(&buffer_snapshot);
14663                            let context_range = BufferOffset(context_buffer_range.start)
14664                                ..BufferOffset(context_buffer_range.end);
14665
14666                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14667                                .or_insert_with(|| RunnableTasks {
14668                                    templates: Vec::new(),
14669                                    offset,
14670                                    column: task_buffer_range.start.column,
14671                                    extra_variables: HashMap::default(),
14672                                    context_range,
14673                                })
14674                                .templates
14675                                .push((kind, task.original_task().clone()));
14676                        }
14677
14678                        acc
14679                    })
14680            }) else {
14681                return;
14682            };
14683
14684            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14685                buffer.language_settings(cx).tasks.prefer_lsp
14686            }) else {
14687                return;
14688            };
14689
14690            let rows = Self::runnable_rows(
14691                project,
14692                display_snapshot,
14693                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14694                new_rows,
14695                cx.clone(),
14696            )
14697            .await;
14698            editor
14699                .update(cx, |editor, _| {
14700                    editor.clear_tasks();
14701                    for (key, mut value) in rows {
14702                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14703                            value.templates.extend(lsp_tasks.templates);
14704                        }
14705
14706                        editor.insert_tasks(key, value);
14707                    }
14708                    for (key, value) in lsp_tasks_by_rows {
14709                        editor.insert_tasks(key, value);
14710                    }
14711                })
14712                .ok();
14713        })
14714    }
14715    fn fetch_runnable_ranges(
14716        snapshot: &DisplaySnapshot,
14717        range: Range<Anchor>,
14718    ) -> Vec<language::RunnableRange> {
14719        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14720    }
14721
14722    fn runnable_rows(
14723        project: Entity<Project>,
14724        snapshot: DisplaySnapshot,
14725        prefer_lsp: bool,
14726        runnable_ranges: Vec<RunnableRange>,
14727        cx: AsyncWindowContext,
14728    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14729        cx.spawn(async move |cx| {
14730            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14731            for mut runnable in runnable_ranges {
14732                let Some(tasks) = cx
14733                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14734                    .ok()
14735                else {
14736                    continue;
14737                };
14738                let mut tasks = tasks.await;
14739
14740                if prefer_lsp {
14741                    tasks.retain(|(task_kind, _)| {
14742                        !matches!(task_kind, TaskSourceKind::Language { .. })
14743                    });
14744                }
14745                if tasks.is_empty() {
14746                    continue;
14747                }
14748
14749                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14750                let Some(row) = snapshot
14751                    .buffer_snapshot
14752                    .buffer_line_for_row(MultiBufferRow(point.row))
14753                    .map(|(_, range)| range.start.row)
14754                else {
14755                    continue;
14756                };
14757
14758                let context_range =
14759                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14760                runnable_rows.push((
14761                    (runnable.buffer_id, row),
14762                    RunnableTasks {
14763                        templates: tasks,
14764                        offset: snapshot
14765                            .buffer_snapshot
14766                            .anchor_before(runnable.run_range.start),
14767                        context_range,
14768                        column: point.column,
14769                        extra_variables: runnable.extra_captures,
14770                    },
14771                ));
14772            }
14773            runnable_rows
14774        })
14775    }
14776
14777    fn templates_with_tags(
14778        project: &Entity<Project>,
14779        runnable: &mut Runnable,
14780        cx: &mut App,
14781    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14782        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14783            let (worktree_id, file) = project
14784                .buffer_for_id(runnable.buffer, cx)
14785                .and_then(|buffer| buffer.read(cx).file())
14786                .map(|file| (file.worktree_id(cx), file.clone()))
14787                .unzip();
14788
14789            (
14790                project.task_store().read(cx).task_inventory().cloned(),
14791                worktree_id,
14792                file,
14793            )
14794        });
14795
14796        let tags = mem::take(&mut runnable.tags);
14797        let language = runnable.language.clone();
14798        cx.spawn(async move |cx| {
14799            let mut templates_with_tags = Vec::new();
14800            if let Some(inventory) = inventory {
14801                for RunnableTag(tag) in tags {
14802                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14803                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14804                    }) else {
14805                        return templates_with_tags;
14806                    };
14807                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14808                        move |(_, template)| {
14809                            template.tags.iter().any(|source_tag| source_tag == &tag)
14810                        },
14811                    ));
14812                }
14813            }
14814            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14815
14816            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14817                // Strongest source wins; if we have worktree tag binding, prefer that to
14818                // global and language bindings;
14819                // if we have a global binding, prefer that to language binding.
14820                let first_mismatch = templates_with_tags
14821                    .iter()
14822                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14823                if let Some(index) = first_mismatch {
14824                    templates_with_tags.truncate(index);
14825                }
14826            }
14827
14828            templates_with_tags
14829        })
14830    }
14831
14832    pub fn move_to_enclosing_bracket(
14833        &mut self,
14834        _: &MoveToEnclosingBracket,
14835        window: &mut Window,
14836        cx: &mut Context<Self>,
14837    ) {
14838        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14839        self.change_selections(Default::default(), window, cx, |s| {
14840            s.move_offsets_with(|snapshot, selection| {
14841                let Some(enclosing_bracket_ranges) =
14842                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14843                else {
14844                    return;
14845                };
14846
14847                let mut best_length = usize::MAX;
14848                let mut best_inside = false;
14849                let mut best_in_bracket_range = false;
14850                let mut best_destination = None;
14851                for (open, close) in enclosing_bracket_ranges {
14852                    let close = close.to_inclusive();
14853                    let length = close.end() - open.start;
14854                    let inside = selection.start >= open.end && selection.end <= *close.start();
14855                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14856                        || close.contains(&selection.head());
14857
14858                    // If best is next to a bracket and current isn't, skip
14859                    if !in_bracket_range && best_in_bracket_range {
14860                        continue;
14861                    }
14862
14863                    // Prefer smaller lengths unless best is inside and current isn't
14864                    if length > best_length && (best_inside || !inside) {
14865                        continue;
14866                    }
14867
14868                    best_length = length;
14869                    best_inside = inside;
14870                    best_in_bracket_range = in_bracket_range;
14871                    best_destination = Some(
14872                        if close.contains(&selection.start) && close.contains(&selection.end) {
14873                            if inside { open.end } else { open.start }
14874                        } else if inside {
14875                            *close.start()
14876                        } else {
14877                            *close.end()
14878                        },
14879                    );
14880                }
14881
14882                if let Some(destination) = best_destination {
14883                    selection.collapse_to(destination, SelectionGoal::None);
14884                }
14885            })
14886        });
14887    }
14888
14889    pub fn undo_selection(
14890        &mut self,
14891        _: &UndoSelection,
14892        window: &mut Window,
14893        cx: &mut Context<Self>,
14894    ) {
14895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14896        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14897            self.selection_history.mode = SelectionHistoryMode::Undoing;
14898            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14899                this.end_selection(window, cx);
14900                this.change_selections(
14901                    SelectionEffects::scroll(Autoscroll::newest()),
14902                    window,
14903                    cx,
14904                    |s| s.select_anchors(entry.selections.to_vec()),
14905                );
14906            });
14907            self.selection_history.mode = SelectionHistoryMode::Normal;
14908
14909            self.select_next_state = entry.select_next_state;
14910            self.select_prev_state = entry.select_prev_state;
14911            self.add_selections_state = entry.add_selections_state;
14912        }
14913    }
14914
14915    pub fn redo_selection(
14916        &mut self,
14917        _: &RedoSelection,
14918        window: &mut Window,
14919        cx: &mut Context<Self>,
14920    ) {
14921        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14922        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14923            self.selection_history.mode = SelectionHistoryMode::Redoing;
14924            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14925                this.end_selection(window, cx);
14926                this.change_selections(
14927                    SelectionEffects::scroll(Autoscroll::newest()),
14928                    window,
14929                    cx,
14930                    |s| s.select_anchors(entry.selections.to_vec()),
14931                );
14932            });
14933            self.selection_history.mode = SelectionHistoryMode::Normal;
14934
14935            self.select_next_state = entry.select_next_state;
14936            self.select_prev_state = entry.select_prev_state;
14937            self.add_selections_state = entry.add_selections_state;
14938        }
14939    }
14940
14941    pub fn expand_excerpts(
14942        &mut self,
14943        action: &ExpandExcerpts,
14944        _: &mut Window,
14945        cx: &mut Context<Self>,
14946    ) {
14947        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14948    }
14949
14950    pub fn expand_excerpts_down(
14951        &mut self,
14952        action: &ExpandExcerptsDown,
14953        _: &mut Window,
14954        cx: &mut Context<Self>,
14955    ) {
14956        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14957    }
14958
14959    pub fn expand_excerpts_up(
14960        &mut self,
14961        action: &ExpandExcerptsUp,
14962        _: &mut Window,
14963        cx: &mut Context<Self>,
14964    ) {
14965        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14966    }
14967
14968    pub fn expand_excerpts_for_direction(
14969        &mut self,
14970        lines: u32,
14971        direction: ExpandExcerptDirection,
14972
14973        cx: &mut Context<Self>,
14974    ) {
14975        let selections = self.selections.disjoint_anchors();
14976
14977        let lines = if lines == 0 {
14978            EditorSettings::get_global(cx).expand_excerpt_lines
14979        } else {
14980            lines
14981        };
14982
14983        self.buffer.update(cx, |buffer, cx| {
14984            let snapshot = buffer.snapshot(cx);
14985            let mut excerpt_ids = selections
14986                .iter()
14987                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14988                .collect::<Vec<_>>();
14989            excerpt_ids.sort();
14990            excerpt_ids.dedup();
14991            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14992        })
14993    }
14994
14995    pub fn expand_excerpt(
14996        &mut self,
14997        excerpt: ExcerptId,
14998        direction: ExpandExcerptDirection,
14999        window: &mut Window,
15000        cx: &mut Context<Self>,
15001    ) {
15002        let current_scroll_position = self.scroll_position(cx);
15003        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15004        let mut should_scroll_up = false;
15005
15006        if direction == ExpandExcerptDirection::Down {
15007            let multi_buffer = self.buffer.read(cx);
15008            let snapshot = multi_buffer.snapshot(cx);
15009            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15010                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15011                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15012                        let buffer_snapshot = buffer.read(cx).snapshot();
15013                        let excerpt_end_row =
15014                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15015                        let last_row = buffer_snapshot.max_point().row;
15016                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15017                        should_scroll_up = lines_below >= lines_to_expand;
15018                    }
15019                }
15020            }
15021        }
15022
15023        self.buffer.update(cx, |buffer, cx| {
15024            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15025        });
15026
15027        if should_scroll_up {
15028            let new_scroll_position =
15029                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15030            self.set_scroll_position(new_scroll_position, window, cx);
15031        }
15032    }
15033
15034    pub fn go_to_singleton_buffer_point(
15035        &mut self,
15036        point: Point,
15037        window: &mut Window,
15038        cx: &mut Context<Self>,
15039    ) {
15040        self.go_to_singleton_buffer_range(point..point, window, cx);
15041    }
15042
15043    pub fn go_to_singleton_buffer_range(
15044        &mut self,
15045        range: Range<Point>,
15046        window: &mut Window,
15047        cx: &mut Context<Self>,
15048    ) {
15049        let multibuffer = self.buffer().read(cx);
15050        let Some(buffer) = multibuffer.as_singleton() else {
15051            return;
15052        };
15053        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15054            return;
15055        };
15056        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15057            return;
15058        };
15059        self.change_selections(
15060            SelectionEffects::default().nav_history(true),
15061            window,
15062            cx,
15063            |s| s.select_anchor_ranges([start..end]),
15064        );
15065    }
15066
15067    pub fn go_to_diagnostic(
15068        &mut self,
15069        _: &GoToDiagnostic,
15070        window: &mut Window,
15071        cx: &mut Context<Self>,
15072    ) {
15073        if !self.diagnostics_enabled() {
15074            return;
15075        }
15076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15077        self.go_to_diagnostic_impl(Direction::Next, window, cx)
15078    }
15079
15080    pub fn go_to_prev_diagnostic(
15081        &mut self,
15082        _: &GoToPreviousDiagnostic,
15083        window: &mut Window,
15084        cx: &mut Context<Self>,
15085    ) {
15086        if !self.diagnostics_enabled() {
15087            return;
15088        }
15089        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15090        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
15091    }
15092
15093    pub fn go_to_diagnostic_impl(
15094        &mut self,
15095        direction: Direction,
15096        window: &mut Window,
15097        cx: &mut Context<Self>,
15098    ) {
15099        let buffer = self.buffer.read(cx).snapshot(cx);
15100        let selection = self.selections.newest::<usize>(cx);
15101
15102        let mut active_group_id = None;
15103        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15104            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15105                active_group_id = Some(active_group.group_id);
15106            }
15107        }
15108
15109        fn filtered(
15110            snapshot: EditorSnapshot,
15111            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15112        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15113            diagnostics
15114                .filter(|entry| entry.range.start != entry.range.end)
15115                .filter(|entry| !entry.diagnostic.is_unnecessary)
15116                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15117        }
15118
15119        let snapshot = self.snapshot(window, cx);
15120        let before = filtered(
15121            snapshot.clone(),
15122            buffer
15123                .diagnostics_in_range(0..selection.start)
15124                .filter(|entry| entry.range.start <= selection.start),
15125        );
15126        let after = filtered(
15127            snapshot,
15128            buffer
15129                .diagnostics_in_range(selection.start..buffer.len())
15130                .filter(|entry| entry.range.start >= selection.start),
15131        );
15132
15133        let mut found: Option<DiagnosticEntry<usize>> = None;
15134        if direction == Direction::Prev {
15135            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15136            {
15137                for diagnostic in prev_diagnostics.into_iter().rev() {
15138                    if diagnostic.range.start != selection.start
15139                        || active_group_id
15140                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15141                    {
15142                        found = Some(diagnostic);
15143                        break 'outer;
15144                    }
15145                }
15146            }
15147        } else {
15148            for diagnostic in after.chain(before) {
15149                if diagnostic.range.start != selection.start
15150                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15151                {
15152                    found = Some(diagnostic);
15153                    break;
15154                }
15155            }
15156        }
15157        let Some(next_diagnostic) = found else {
15158            return;
15159        };
15160
15161        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15162            return;
15163        };
15164        self.change_selections(Default::default(), window, cx, |s| {
15165            s.select_ranges(vec![
15166                next_diagnostic.range.start..next_diagnostic.range.start,
15167            ])
15168        });
15169        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15170        self.refresh_inline_completion(false, true, window, cx);
15171    }
15172
15173    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15174        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15175        let snapshot = self.snapshot(window, cx);
15176        let selection = self.selections.newest::<Point>(cx);
15177        self.go_to_hunk_before_or_after_position(
15178            &snapshot,
15179            selection.head(),
15180            Direction::Next,
15181            window,
15182            cx,
15183        );
15184    }
15185
15186    pub fn go_to_hunk_before_or_after_position(
15187        &mut self,
15188        snapshot: &EditorSnapshot,
15189        position: Point,
15190        direction: Direction,
15191        window: &mut Window,
15192        cx: &mut Context<Editor>,
15193    ) {
15194        let row = if direction == Direction::Next {
15195            self.hunk_after_position(snapshot, position)
15196                .map(|hunk| hunk.row_range.start)
15197        } else {
15198            self.hunk_before_position(snapshot, position)
15199        };
15200
15201        if let Some(row) = row {
15202            let destination = Point::new(row.0, 0);
15203            let autoscroll = Autoscroll::center();
15204
15205            self.unfold_ranges(&[destination..destination], false, false, cx);
15206            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15207                s.select_ranges([destination..destination]);
15208            });
15209        }
15210    }
15211
15212    fn hunk_after_position(
15213        &mut self,
15214        snapshot: &EditorSnapshot,
15215        position: Point,
15216    ) -> Option<MultiBufferDiffHunk> {
15217        snapshot
15218            .buffer_snapshot
15219            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15220            .find(|hunk| hunk.row_range.start.0 > position.row)
15221            .or_else(|| {
15222                snapshot
15223                    .buffer_snapshot
15224                    .diff_hunks_in_range(Point::zero()..position)
15225                    .find(|hunk| hunk.row_range.end.0 < position.row)
15226            })
15227    }
15228
15229    fn go_to_prev_hunk(
15230        &mut self,
15231        _: &GoToPreviousHunk,
15232        window: &mut Window,
15233        cx: &mut Context<Self>,
15234    ) {
15235        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15236        let snapshot = self.snapshot(window, cx);
15237        let selection = self.selections.newest::<Point>(cx);
15238        self.go_to_hunk_before_or_after_position(
15239            &snapshot,
15240            selection.head(),
15241            Direction::Prev,
15242            window,
15243            cx,
15244        );
15245    }
15246
15247    fn hunk_before_position(
15248        &mut self,
15249        snapshot: &EditorSnapshot,
15250        position: Point,
15251    ) -> Option<MultiBufferRow> {
15252        snapshot
15253            .buffer_snapshot
15254            .diff_hunk_before(position)
15255            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15256    }
15257
15258    fn go_to_next_change(
15259        &mut self,
15260        _: &GoToNextChange,
15261        window: &mut Window,
15262        cx: &mut Context<Self>,
15263    ) {
15264        if let Some(selections) = self
15265            .change_list
15266            .next_change(1, Direction::Next)
15267            .map(|s| s.to_vec())
15268        {
15269            self.change_selections(Default::default(), window, cx, |s| {
15270                let map = s.display_map();
15271                s.select_display_ranges(selections.iter().map(|a| {
15272                    let point = a.to_display_point(&map);
15273                    point..point
15274                }))
15275            })
15276        }
15277    }
15278
15279    fn go_to_previous_change(
15280        &mut self,
15281        _: &GoToPreviousChange,
15282        window: &mut Window,
15283        cx: &mut Context<Self>,
15284    ) {
15285        if let Some(selections) = self
15286            .change_list
15287            .next_change(1, Direction::Prev)
15288            .map(|s| s.to_vec())
15289        {
15290            self.change_selections(Default::default(), window, cx, |s| {
15291                let map = s.display_map();
15292                s.select_display_ranges(selections.iter().map(|a| {
15293                    let point = a.to_display_point(&map);
15294                    point..point
15295                }))
15296            })
15297        }
15298    }
15299
15300    fn go_to_line<T: 'static>(
15301        &mut self,
15302        position: Anchor,
15303        highlight_color: Option<Hsla>,
15304        window: &mut Window,
15305        cx: &mut Context<Self>,
15306    ) {
15307        let snapshot = self.snapshot(window, cx).display_snapshot;
15308        let position = position.to_point(&snapshot.buffer_snapshot);
15309        let start = snapshot
15310            .buffer_snapshot
15311            .clip_point(Point::new(position.row, 0), Bias::Left);
15312        let end = start + Point::new(1, 0);
15313        let start = snapshot.buffer_snapshot.anchor_before(start);
15314        let end = snapshot.buffer_snapshot.anchor_before(end);
15315
15316        self.highlight_rows::<T>(
15317            start..end,
15318            highlight_color
15319                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15320            Default::default(),
15321            cx,
15322        );
15323
15324        if self.buffer.read(cx).is_singleton() {
15325            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15326        }
15327    }
15328
15329    pub fn go_to_definition(
15330        &mut self,
15331        _: &GoToDefinition,
15332        window: &mut Window,
15333        cx: &mut Context<Self>,
15334    ) -> Task<Result<Navigated>> {
15335        let definition =
15336            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15337        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15338        cx.spawn_in(window, async move |editor, cx| {
15339            if definition.await? == Navigated::Yes {
15340                return Ok(Navigated::Yes);
15341            }
15342            match fallback_strategy {
15343                GoToDefinitionFallback::None => Ok(Navigated::No),
15344                GoToDefinitionFallback::FindAllReferences => {
15345                    match editor.update_in(cx, |editor, window, cx| {
15346                        editor.find_all_references(&FindAllReferences, window, cx)
15347                    })? {
15348                        Some(references) => references.await,
15349                        None => Ok(Navigated::No),
15350                    }
15351                }
15352            }
15353        })
15354    }
15355
15356    pub fn go_to_declaration(
15357        &mut self,
15358        _: &GoToDeclaration,
15359        window: &mut Window,
15360        cx: &mut Context<Self>,
15361    ) -> Task<Result<Navigated>> {
15362        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15363    }
15364
15365    pub fn go_to_declaration_split(
15366        &mut self,
15367        _: &GoToDeclaration,
15368        window: &mut Window,
15369        cx: &mut Context<Self>,
15370    ) -> Task<Result<Navigated>> {
15371        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15372    }
15373
15374    pub fn go_to_implementation(
15375        &mut self,
15376        _: &GoToImplementation,
15377        window: &mut Window,
15378        cx: &mut Context<Self>,
15379    ) -> Task<Result<Navigated>> {
15380        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15381    }
15382
15383    pub fn go_to_implementation_split(
15384        &mut self,
15385        _: &GoToImplementationSplit,
15386        window: &mut Window,
15387        cx: &mut Context<Self>,
15388    ) -> Task<Result<Navigated>> {
15389        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15390    }
15391
15392    pub fn go_to_type_definition(
15393        &mut self,
15394        _: &GoToTypeDefinition,
15395        window: &mut Window,
15396        cx: &mut Context<Self>,
15397    ) -> Task<Result<Navigated>> {
15398        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15399    }
15400
15401    pub fn go_to_definition_split(
15402        &mut self,
15403        _: &GoToDefinitionSplit,
15404        window: &mut Window,
15405        cx: &mut Context<Self>,
15406    ) -> Task<Result<Navigated>> {
15407        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15408    }
15409
15410    pub fn go_to_type_definition_split(
15411        &mut self,
15412        _: &GoToTypeDefinitionSplit,
15413        window: &mut Window,
15414        cx: &mut Context<Self>,
15415    ) -> Task<Result<Navigated>> {
15416        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15417    }
15418
15419    fn go_to_definition_of_kind(
15420        &mut self,
15421        kind: GotoDefinitionKind,
15422        split: bool,
15423        window: &mut Window,
15424        cx: &mut Context<Self>,
15425    ) -> Task<Result<Navigated>> {
15426        let Some(provider) = self.semantics_provider.clone() else {
15427            return Task::ready(Ok(Navigated::No));
15428        };
15429        let head = self.selections.newest::<usize>(cx).head();
15430        let buffer = self.buffer.read(cx);
15431        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15432            text_anchor
15433        } else {
15434            return Task::ready(Ok(Navigated::No));
15435        };
15436
15437        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15438            return Task::ready(Ok(Navigated::No));
15439        };
15440
15441        cx.spawn_in(window, async move |editor, cx| {
15442            let definitions = definitions.await?;
15443            let navigated = editor
15444                .update_in(cx, |editor, window, cx| {
15445                    editor.navigate_to_hover_links(
15446                        Some(kind),
15447                        definitions
15448                            .into_iter()
15449                            .filter(|location| {
15450                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15451                            })
15452                            .map(HoverLink::Text)
15453                            .collect::<Vec<_>>(),
15454                        split,
15455                        window,
15456                        cx,
15457                    )
15458                })?
15459                .await?;
15460            anyhow::Ok(navigated)
15461        })
15462    }
15463
15464    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15465        let selection = self.selections.newest_anchor();
15466        let head = selection.head();
15467        let tail = selection.tail();
15468
15469        let Some((buffer, start_position)) =
15470            self.buffer.read(cx).text_anchor_for_position(head, cx)
15471        else {
15472            return;
15473        };
15474
15475        let end_position = if head != tail {
15476            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15477                return;
15478            };
15479            Some(pos)
15480        } else {
15481            None
15482        };
15483
15484        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15485            let url = if let Some(end_pos) = end_position {
15486                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15487            } else {
15488                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15489            };
15490
15491            if let Some(url) = url {
15492                editor.update(cx, |_, cx| {
15493                    cx.open_url(&url);
15494                })
15495            } else {
15496                Ok(())
15497            }
15498        });
15499
15500        url_finder.detach();
15501    }
15502
15503    pub fn open_selected_filename(
15504        &mut self,
15505        _: &OpenSelectedFilename,
15506        window: &mut Window,
15507        cx: &mut Context<Self>,
15508    ) {
15509        let Some(workspace) = self.workspace() else {
15510            return;
15511        };
15512
15513        let position = self.selections.newest_anchor().head();
15514
15515        let Some((buffer, buffer_position)) =
15516            self.buffer.read(cx).text_anchor_for_position(position, cx)
15517        else {
15518            return;
15519        };
15520
15521        let project = self.project.clone();
15522
15523        cx.spawn_in(window, async move |_, cx| {
15524            let result = find_file(&buffer, project, buffer_position, cx).await;
15525
15526            if let Some((_, path)) = result {
15527                workspace
15528                    .update_in(cx, |workspace, window, cx| {
15529                        workspace.open_resolved_path(path, window, cx)
15530                    })?
15531                    .await?;
15532            }
15533            anyhow::Ok(())
15534        })
15535        .detach();
15536    }
15537
15538    pub(crate) fn navigate_to_hover_links(
15539        &mut self,
15540        kind: Option<GotoDefinitionKind>,
15541        mut definitions: Vec<HoverLink>,
15542        split: bool,
15543        window: &mut Window,
15544        cx: &mut Context<Editor>,
15545    ) -> Task<Result<Navigated>> {
15546        // If there is one definition, just open it directly
15547        if definitions.len() == 1 {
15548            let definition = definitions.pop().unwrap();
15549
15550            enum TargetTaskResult {
15551                Location(Option<Location>),
15552                AlreadyNavigated,
15553            }
15554
15555            let target_task = match definition {
15556                HoverLink::Text(link) => {
15557                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15558                }
15559                HoverLink::InlayHint(lsp_location, server_id) => {
15560                    let computation =
15561                        self.compute_target_location(lsp_location, server_id, window, cx);
15562                    cx.background_spawn(async move {
15563                        let location = computation.await?;
15564                        Ok(TargetTaskResult::Location(location))
15565                    })
15566                }
15567                HoverLink::Url(url) => {
15568                    cx.open_url(&url);
15569                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15570                }
15571                HoverLink::File(path) => {
15572                    if let Some(workspace) = self.workspace() {
15573                        cx.spawn_in(window, async move |_, cx| {
15574                            workspace
15575                                .update_in(cx, |workspace, window, cx| {
15576                                    workspace.open_resolved_path(path, window, cx)
15577                                })?
15578                                .await
15579                                .map(|_| TargetTaskResult::AlreadyNavigated)
15580                        })
15581                    } else {
15582                        Task::ready(Ok(TargetTaskResult::Location(None)))
15583                    }
15584                }
15585            };
15586            cx.spawn_in(window, async move |editor, cx| {
15587                let target = match target_task.await.context("target resolution task")? {
15588                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15589                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15590                    TargetTaskResult::Location(Some(target)) => target,
15591                };
15592
15593                editor.update_in(cx, |editor, window, cx| {
15594                    let Some(workspace) = editor.workspace() else {
15595                        return Navigated::No;
15596                    };
15597                    let pane = workspace.read(cx).active_pane().clone();
15598
15599                    let range = target.range.to_point(target.buffer.read(cx));
15600                    let range = editor.range_for_match(&range);
15601                    let range = collapse_multiline_range(range);
15602
15603                    if !split
15604                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15605                    {
15606                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15607                    } else {
15608                        window.defer(cx, move |window, cx| {
15609                            let target_editor: Entity<Self> =
15610                                workspace.update(cx, |workspace, cx| {
15611                                    let pane = if split {
15612                                        workspace.adjacent_pane(window, cx)
15613                                    } else {
15614                                        workspace.active_pane().clone()
15615                                    };
15616
15617                                    workspace.open_project_item(
15618                                        pane,
15619                                        target.buffer.clone(),
15620                                        true,
15621                                        true,
15622                                        window,
15623                                        cx,
15624                                    )
15625                                });
15626                            target_editor.update(cx, |target_editor, cx| {
15627                                // When selecting a definition in a different buffer, disable the nav history
15628                                // to avoid creating a history entry at the previous cursor location.
15629                                pane.update(cx, |pane, _| pane.disable_history());
15630                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15631                                pane.update(cx, |pane, _| pane.enable_history());
15632                            });
15633                        });
15634                    }
15635                    Navigated::Yes
15636                })
15637            })
15638        } else if !definitions.is_empty() {
15639            cx.spawn_in(window, async move |editor, cx| {
15640                let (title, location_tasks, workspace) = editor
15641                    .update_in(cx, |editor, window, cx| {
15642                        let tab_kind = match kind {
15643                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15644                            _ => "Definitions",
15645                        };
15646                        let title = definitions
15647                            .iter()
15648                            .find_map(|definition| match definition {
15649                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15650                                    let buffer = origin.buffer.read(cx);
15651                                    format!(
15652                                        "{} for {}",
15653                                        tab_kind,
15654                                        buffer
15655                                            .text_for_range(origin.range.clone())
15656                                            .collect::<String>()
15657                                    )
15658                                }),
15659                                HoverLink::InlayHint(_, _) => None,
15660                                HoverLink::Url(_) => None,
15661                                HoverLink::File(_) => None,
15662                            })
15663                            .unwrap_or(tab_kind.to_string());
15664                        let location_tasks = definitions
15665                            .into_iter()
15666                            .map(|definition| match definition {
15667                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15668                                HoverLink::InlayHint(lsp_location, server_id) => editor
15669                                    .compute_target_location(lsp_location, server_id, window, cx),
15670                                HoverLink::Url(_) => Task::ready(Ok(None)),
15671                                HoverLink::File(_) => Task::ready(Ok(None)),
15672                            })
15673                            .collect::<Vec<_>>();
15674                        (title, location_tasks, editor.workspace().clone())
15675                    })
15676                    .context("location tasks preparation")?;
15677
15678                let locations: Vec<Location> = future::join_all(location_tasks)
15679                    .await
15680                    .into_iter()
15681                    .filter_map(|location| location.transpose())
15682                    .collect::<Result<_>>()
15683                    .context("location tasks")?;
15684
15685                if locations.is_empty() {
15686                    return Ok(Navigated::No);
15687                }
15688
15689                let Some(workspace) = workspace else {
15690                    return Ok(Navigated::No);
15691                };
15692
15693                let opened = workspace
15694                    .update_in(cx, |workspace, window, cx| {
15695                        Self::open_locations_in_multibuffer(
15696                            workspace,
15697                            locations,
15698                            title,
15699                            split,
15700                            MultibufferSelectionMode::First,
15701                            window,
15702                            cx,
15703                        )
15704                    })
15705                    .ok();
15706
15707                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15708            })
15709        } else {
15710            Task::ready(Ok(Navigated::No))
15711        }
15712    }
15713
15714    fn compute_target_location(
15715        &self,
15716        lsp_location: lsp::Location,
15717        server_id: LanguageServerId,
15718        window: &mut Window,
15719        cx: &mut Context<Self>,
15720    ) -> Task<anyhow::Result<Option<Location>>> {
15721        let Some(project) = self.project.clone() else {
15722            return Task::ready(Ok(None));
15723        };
15724
15725        cx.spawn_in(window, async move |editor, cx| {
15726            let location_task = editor.update(cx, |_, cx| {
15727                project.update(cx, |project, cx| {
15728                    let language_server_name = project
15729                        .language_server_statuses(cx)
15730                        .find(|(id, _)| server_id == *id)
15731                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15732                    language_server_name.map(|language_server_name| {
15733                        project.open_local_buffer_via_lsp(
15734                            lsp_location.uri.clone(),
15735                            server_id,
15736                            language_server_name,
15737                            cx,
15738                        )
15739                    })
15740                })
15741            })?;
15742            let location = match location_task {
15743                Some(task) => Some({
15744                    let target_buffer_handle = task.await.context("open local buffer")?;
15745                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15746                        let target_start = target_buffer
15747                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15748                        let target_end = target_buffer
15749                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15750                        target_buffer.anchor_after(target_start)
15751                            ..target_buffer.anchor_before(target_end)
15752                    })?;
15753                    Location {
15754                        buffer: target_buffer_handle,
15755                        range,
15756                    }
15757                }),
15758                None => None,
15759            };
15760            Ok(location)
15761        })
15762    }
15763
15764    pub fn find_all_references(
15765        &mut self,
15766        _: &FindAllReferences,
15767        window: &mut Window,
15768        cx: &mut Context<Self>,
15769    ) -> Option<Task<Result<Navigated>>> {
15770        let selection = self.selections.newest::<usize>(cx);
15771        let multi_buffer = self.buffer.read(cx);
15772        let head = selection.head();
15773
15774        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15775        let head_anchor = multi_buffer_snapshot.anchor_at(
15776            head,
15777            if head < selection.tail() {
15778                Bias::Right
15779            } else {
15780                Bias::Left
15781            },
15782        );
15783
15784        match self
15785            .find_all_references_task_sources
15786            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15787        {
15788            Ok(_) => {
15789                log::info!(
15790                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15791                );
15792                return None;
15793            }
15794            Err(i) => {
15795                self.find_all_references_task_sources.insert(i, head_anchor);
15796            }
15797        }
15798
15799        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15800        let workspace = self.workspace()?;
15801        let project = workspace.read(cx).project().clone();
15802        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15803        Some(cx.spawn_in(window, async move |editor, cx| {
15804            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15805                if let Ok(i) = editor
15806                    .find_all_references_task_sources
15807                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15808                {
15809                    editor.find_all_references_task_sources.remove(i);
15810                }
15811            });
15812
15813            let locations = references.await?;
15814            if locations.is_empty() {
15815                return anyhow::Ok(Navigated::No);
15816            }
15817
15818            workspace.update_in(cx, |workspace, window, cx| {
15819                let title = locations
15820                    .first()
15821                    .as_ref()
15822                    .map(|location| {
15823                        let buffer = location.buffer.read(cx);
15824                        format!(
15825                            "References to `{}`",
15826                            buffer
15827                                .text_for_range(location.range.clone())
15828                                .collect::<String>()
15829                        )
15830                    })
15831                    .unwrap();
15832                Self::open_locations_in_multibuffer(
15833                    workspace,
15834                    locations,
15835                    title,
15836                    false,
15837                    MultibufferSelectionMode::First,
15838                    window,
15839                    cx,
15840                );
15841                Navigated::Yes
15842            })
15843        }))
15844    }
15845
15846    /// Opens a multibuffer with the given project locations in it
15847    pub fn open_locations_in_multibuffer(
15848        workspace: &mut Workspace,
15849        mut locations: Vec<Location>,
15850        title: String,
15851        split: bool,
15852        multibuffer_selection_mode: MultibufferSelectionMode,
15853        window: &mut Window,
15854        cx: &mut Context<Workspace>,
15855    ) {
15856        if locations.is_empty() {
15857            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15858            return;
15859        }
15860
15861        // If there are multiple definitions, open them in a multibuffer
15862        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15863        let mut locations = locations.into_iter().peekable();
15864        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15865        let capability = workspace.project().read(cx).capability();
15866
15867        let excerpt_buffer = cx.new(|cx| {
15868            let mut multibuffer = MultiBuffer::new(capability);
15869            while let Some(location) = locations.next() {
15870                let buffer = location.buffer.read(cx);
15871                let mut ranges_for_buffer = Vec::new();
15872                let range = location.range.to_point(buffer);
15873                ranges_for_buffer.push(range.clone());
15874
15875                while let Some(next_location) = locations.peek() {
15876                    if next_location.buffer == location.buffer {
15877                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15878                        locations.next();
15879                    } else {
15880                        break;
15881                    }
15882                }
15883
15884                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15885                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15886                    PathKey::for_buffer(&location.buffer, cx),
15887                    location.buffer.clone(),
15888                    ranges_for_buffer,
15889                    DEFAULT_MULTIBUFFER_CONTEXT,
15890                    cx,
15891                );
15892                ranges.extend(new_ranges)
15893            }
15894
15895            multibuffer.with_title(title)
15896        });
15897
15898        let editor = cx.new(|cx| {
15899            Editor::for_multibuffer(
15900                excerpt_buffer,
15901                Some(workspace.project().clone()),
15902                window,
15903                cx,
15904            )
15905        });
15906        editor.update(cx, |editor, cx| {
15907            match multibuffer_selection_mode {
15908                MultibufferSelectionMode::First => {
15909                    if let Some(first_range) = ranges.first() {
15910                        editor.change_selections(
15911                            SelectionEffects::no_scroll(),
15912                            window,
15913                            cx,
15914                            |selections| {
15915                                selections.clear_disjoint();
15916                                selections
15917                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
15918                            },
15919                        );
15920                    }
15921                    editor.highlight_background::<Self>(
15922                        &ranges,
15923                        |theme| theme.colors().editor_highlighted_line_background,
15924                        cx,
15925                    );
15926                }
15927                MultibufferSelectionMode::All => {
15928                    editor.change_selections(
15929                        SelectionEffects::no_scroll(),
15930                        window,
15931                        cx,
15932                        |selections| {
15933                            selections.clear_disjoint();
15934                            selections.select_anchor_ranges(ranges);
15935                        },
15936                    );
15937                }
15938            }
15939            editor.register_buffers_with_language_servers(cx);
15940        });
15941
15942        let item = Box::new(editor);
15943        let item_id = item.item_id();
15944
15945        if split {
15946            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15947        } else {
15948            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15949                let (preview_item_id, preview_item_idx) =
15950                    workspace.active_pane().read_with(cx, |pane, _| {
15951                        (pane.preview_item_id(), pane.preview_item_idx())
15952                    });
15953
15954                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15955
15956                if let Some(preview_item_id) = preview_item_id {
15957                    workspace.active_pane().update(cx, |pane, cx| {
15958                        pane.remove_item(preview_item_id, false, false, window, cx);
15959                    });
15960                }
15961            } else {
15962                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15963            }
15964        }
15965        workspace.active_pane().update(cx, |pane, cx| {
15966            pane.set_preview_item_id(Some(item_id), cx);
15967        });
15968    }
15969
15970    pub fn rename(
15971        &mut self,
15972        _: &Rename,
15973        window: &mut Window,
15974        cx: &mut Context<Self>,
15975    ) -> Option<Task<Result<()>>> {
15976        use language::ToOffset as _;
15977
15978        let provider = self.semantics_provider.clone()?;
15979        let selection = self.selections.newest_anchor().clone();
15980        let (cursor_buffer, cursor_buffer_position) = self
15981            .buffer
15982            .read(cx)
15983            .text_anchor_for_position(selection.head(), cx)?;
15984        let (tail_buffer, cursor_buffer_position_end) = self
15985            .buffer
15986            .read(cx)
15987            .text_anchor_for_position(selection.tail(), cx)?;
15988        if tail_buffer != cursor_buffer {
15989            return None;
15990        }
15991
15992        let snapshot = cursor_buffer.read(cx).snapshot();
15993        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15994        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15995        let prepare_rename = provider
15996            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15997            .unwrap_or_else(|| Task::ready(Ok(None)));
15998        drop(snapshot);
15999
16000        Some(cx.spawn_in(window, async move |this, cx| {
16001            let rename_range = if let Some(range) = prepare_rename.await? {
16002                Some(range)
16003            } else {
16004                this.update(cx, |this, cx| {
16005                    let buffer = this.buffer.read(cx).snapshot(cx);
16006                    let mut buffer_highlights = this
16007                        .document_highlights_for_position(selection.head(), &buffer)
16008                        .filter(|highlight| {
16009                            highlight.start.excerpt_id == selection.head().excerpt_id
16010                                && highlight.end.excerpt_id == selection.head().excerpt_id
16011                        });
16012                    buffer_highlights
16013                        .next()
16014                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16015                })?
16016            };
16017            if let Some(rename_range) = rename_range {
16018                this.update_in(cx, |this, window, cx| {
16019                    let snapshot = cursor_buffer.read(cx).snapshot();
16020                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16021                    let cursor_offset_in_rename_range =
16022                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16023                    let cursor_offset_in_rename_range_end =
16024                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16025
16026                    this.take_rename(false, window, cx);
16027                    let buffer = this.buffer.read(cx).read(cx);
16028                    let cursor_offset = selection.head().to_offset(&buffer);
16029                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16030                    let rename_end = rename_start + rename_buffer_range.len();
16031                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16032                    let mut old_highlight_id = None;
16033                    let old_name: Arc<str> = buffer
16034                        .chunks(rename_start..rename_end, true)
16035                        .map(|chunk| {
16036                            if old_highlight_id.is_none() {
16037                                old_highlight_id = chunk.syntax_highlight_id;
16038                            }
16039                            chunk.text
16040                        })
16041                        .collect::<String>()
16042                        .into();
16043
16044                    drop(buffer);
16045
16046                    // Position the selection in the rename editor so that it matches the current selection.
16047                    this.show_local_selections = false;
16048                    let rename_editor = cx.new(|cx| {
16049                        let mut editor = Editor::single_line(window, cx);
16050                        editor.buffer.update(cx, |buffer, cx| {
16051                            buffer.edit([(0..0, old_name.clone())], None, cx)
16052                        });
16053                        let rename_selection_range = match cursor_offset_in_rename_range
16054                            .cmp(&cursor_offset_in_rename_range_end)
16055                        {
16056                            Ordering::Equal => {
16057                                editor.select_all(&SelectAll, window, cx);
16058                                return editor;
16059                            }
16060                            Ordering::Less => {
16061                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16062                            }
16063                            Ordering::Greater => {
16064                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16065                            }
16066                        };
16067                        if rename_selection_range.end > old_name.len() {
16068                            editor.select_all(&SelectAll, window, cx);
16069                        } else {
16070                            editor.change_selections(Default::default(), window, cx, |s| {
16071                                s.select_ranges([rename_selection_range]);
16072                            });
16073                        }
16074                        editor
16075                    });
16076                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16077                        if e == &EditorEvent::Focused {
16078                            cx.emit(EditorEvent::FocusedIn)
16079                        }
16080                    })
16081                    .detach();
16082
16083                    let write_highlights =
16084                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16085                    let read_highlights =
16086                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16087                    let ranges = write_highlights
16088                        .iter()
16089                        .flat_map(|(_, ranges)| ranges.iter())
16090                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16091                        .cloned()
16092                        .collect();
16093
16094                    this.highlight_text::<Rename>(
16095                        ranges,
16096                        HighlightStyle {
16097                            fade_out: Some(0.6),
16098                            ..Default::default()
16099                        },
16100                        cx,
16101                    );
16102                    let rename_focus_handle = rename_editor.focus_handle(cx);
16103                    window.focus(&rename_focus_handle);
16104                    let block_id = this.insert_blocks(
16105                        [BlockProperties {
16106                            style: BlockStyle::Flex,
16107                            placement: BlockPlacement::Below(range.start),
16108                            height: Some(1),
16109                            render: Arc::new({
16110                                let rename_editor = rename_editor.clone();
16111                                move |cx: &mut BlockContext| {
16112                                    let mut text_style = cx.editor_style.text.clone();
16113                                    if let Some(highlight_style) = old_highlight_id
16114                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16115                                    {
16116                                        text_style = text_style.highlight(highlight_style);
16117                                    }
16118                                    div()
16119                                        .block_mouse_except_scroll()
16120                                        .pl(cx.anchor_x)
16121                                        .child(EditorElement::new(
16122                                            &rename_editor,
16123                                            EditorStyle {
16124                                                background: cx.theme().system().transparent,
16125                                                local_player: cx.editor_style.local_player,
16126                                                text: text_style,
16127                                                scrollbar_width: cx.editor_style.scrollbar_width,
16128                                                syntax: cx.editor_style.syntax.clone(),
16129                                                status: cx.editor_style.status.clone(),
16130                                                inlay_hints_style: HighlightStyle {
16131                                                    font_weight: Some(FontWeight::BOLD),
16132                                                    ..make_inlay_hints_style(cx.app)
16133                                                },
16134                                                inline_completion_styles: make_suggestion_styles(
16135                                                    cx.app,
16136                                                ),
16137                                                ..EditorStyle::default()
16138                                            },
16139                                        ))
16140                                        .into_any_element()
16141                                }
16142                            }),
16143                            priority: 0,
16144                            render_in_minimap: true,
16145                        }],
16146                        Some(Autoscroll::fit()),
16147                        cx,
16148                    )[0];
16149                    this.pending_rename = Some(RenameState {
16150                        range,
16151                        old_name,
16152                        editor: rename_editor,
16153                        block_id,
16154                    });
16155                })?;
16156            }
16157
16158            Ok(())
16159        }))
16160    }
16161
16162    pub fn confirm_rename(
16163        &mut self,
16164        _: &ConfirmRename,
16165        window: &mut Window,
16166        cx: &mut Context<Self>,
16167    ) -> Option<Task<Result<()>>> {
16168        let rename = self.take_rename(false, window, cx)?;
16169        let workspace = self.workspace()?.downgrade();
16170        let (buffer, start) = self
16171            .buffer
16172            .read(cx)
16173            .text_anchor_for_position(rename.range.start, cx)?;
16174        let (end_buffer, _) = self
16175            .buffer
16176            .read(cx)
16177            .text_anchor_for_position(rename.range.end, cx)?;
16178        if buffer != end_buffer {
16179            return None;
16180        }
16181
16182        let old_name = rename.old_name;
16183        let new_name = rename.editor.read(cx).text(cx);
16184
16185        let rename = self.semantics_provider.as_ref()?.perform_rename(
16186            &buffer,
16187            start,
16188            new_name.clone(),
16189            cx,
16190        )?;
16191
16192        Some(cx.spawn_in(window, async move |editor, cx| {
16193            let project_transaction = rename.await?;
16194            Self::open_project_transaction(
16195                &editor,
16196                workspace,
16197                project_transaction,
16198                format!("Rename: {}{}", old_name, new_name),
16199                cx,
16200            )
16201            .await?;
16202
16203            editor.update(cx, |editor, cx| {
16204                editor.refresh_document_highlights(cx);
16205            })?;
16206            Ok(())
16207        }))
16208    }
16209
16210    fn take_rename(
16211        &mut self,
16212        moving_cursor: bool,
16213        window: &mut Window,
16214        cx: &mut Context<Self>,
16215    ) -> Option<RenameState> {
16216        let rename = self.pending_rename.take()?;
16217        if rename.editor.focus_handle(cx).is_focused(window) {
16218            window.focus(&self.focus_handle);
16219        }
16220
16221        self.remove_blocks(
16222            [rename.block_id].into_iter().collect(),
16223            Some(Autoscroll::fit()),
16224            cx,
16225        );
16226        self.clear_highlights::<Rename>(cx);
16227        self.show_local_selections = true;
16228
16229        if moving_cursor {
16230            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16231                editor.selections.newest::<usize>(cx).head()
16232            });
16233
16234            // Update the selection to match the position of the selection inside
16235            // the rename editor.
16236            let snapshot = self.buffer.read(cx).read(cx);
16237            let rename_range = rename.range.to_offset(&snapshot);
16238            let cursor_in_editor = snapshot
16239                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16240                .min(rename_range.end);
16241            drop(snapshot);
16242
16243            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16244                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16245            });
16246        } else {
16247            self.refresh_document_highlights(cx);
16248        }
16249
16250        Some(rename)
16251    }
16252
16253    pub fn pending_rename(&self) -> Option<&RenameState> {
16254        self.pending_rename.as_ref()
16255    }
16256
16257    fn format(
16258        &mut self,
16259        _: &Format,
16260        window: &mut Window,
16261        cx: &mut Context<Self>,
16262    ) -> Option<Task<Result<()>>> {
16263        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16264
16265        let project = match &self.project {
16266            Some(project) => project.clone(),
16267            None => return None,
16268        };
16269
16270        Some(self.perform_format(
16271            project,
16272            FormatTrigger::Manual,
16273            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16274            window,
16275            cx,
16276        ))
16277    }
16278
16279    fn format_selections(
16280        &mut self,
16281        _: &FormatSelections,
16282        window: &mut Window,
16283        cx: &mut Context<Self>,
16284    ) -> Option<Task<Result<()>>> {
16285        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16286
16287        let project = match &self.project {
16288            Some(project) => project.clone(),
16289            None => return None,
16290        };
16291
16292        let ranges = self
16293            .selections
16294            .all_adjusted(cx)
16295            .into_iter()
16296            .map(|selection| selection.range())
16297            .collect_vec();
16298
16299        Some(self.perform_format(
16300            project,
16301            FormatTrigger::Manual,
16302            FormatTarget::Ranges(ranges),
16303            window,
16304            cx,
16305        ))
16306    }
16307
16308    fn perform_format(
16309        &mut self,
16310        project: Entity<Project>,
16311        trigger: FormatTrigger,
16312        target: FormatTarget,
16313        window: &mut Window,
16314        cx: &mut Context<Self>,
16315    ) -> Task<Result<()>> {
16316        let buffer = self.buffer.clone();
16317        let (buffers, target) = match target {
16318            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16319            FormatTarget::Ranges(selection_ranges) => {
16320                let multi_buffer = buffer.read(cx);
16321                let snapshot = multi_buffer.read(cx);
16322                let mut buffers = HashSet::default();
16323                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16324                    BTreeMap::new();
16325                for selection_range in selection_ranges {
16326                    for (buffer, buffer_range, _) in
16327                        snapshot.range_to_buffer_ranges(selection_range)
16328                    {
16329                        let buffer_id = buffer.remote_id();
16330                        let start = buffer.anchor_before(buffer_range.start);
16331                        let end = buffer.anchor_after(buffer_range.end);
16332                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16333                        buffer_id_to_ranges
16334                            .entry(buffer_id)
16335                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16336                            .or_insert_with(|| vec![start..end]);
16337                    }
16338                }
16339                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16340            }
16341        };
16342
16343        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16344        let selections_prev = transaction_id_prev
16345            .and_then(|transaction_id_prev| {
16346                // default to selections as they were after the last edit, if we have them,
16347                // instead of how they are now.
16348                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16349                // will take you back to where you made the last edit, instead of staying where you scrolled
16350                self.selection_history
16351                    .transaction(transaction_id_prev)
16352                    .map(|t| t.0.clone())
16353            })
16354            .unwrap_or_else(|| {
16355                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16356                self.selections.disjoint_anchors()
16357            });
16358
16359        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16360        let format = project.update(cx, |project, cx| {
16361            project.format(buffers, target, true, trigger, cx)
16362        });
16363
16364        cx.spawn_in(window, async move |editor, cx| {
16365            let transaction = futures::select_biased! {
16366                transaction = format.log_err().fuse() => transaction,
16367                () = timeout => {
16368                    log::warn!("timed out waiting for formatting");
16369                    None
16370                }
16371            };
16372
16373            buffer
16374                .update(cx, |buffer, cx| {
16375                    if let Some(transaction) = transaction {
16376                        if !buffer.is_singleton() {
16377                            buffer.push_transaction(&transaction.0, cx);
16378                        }
16379                    }
16380                    cx.notify();
16381                })
16382                .ok();
16383
16384            if let Some(transaction_id_now) =
16385                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16386            {
16387                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16388                if has_new_transaction {
16389                    _ = editor.update(cx, |editor, _| {
16390                        editor
16391                            .selection_history
16392                            .insert_transaction(transaction_id_now, selections_prev);
16393                    });
16394                }
16395            }
16396
16397            Ok(())
16398        })
16399    }
16400
16401    fn organize_imports(
16402        &mut self,
16403        _: &OrganizeImports,
16404        window: &mut Window,
16405        cx: &mut Context<Self>,
16406    ) -> Option<Task<Result<()>>> {
16407        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16408        let project = match &self.project {
16409            Some(project) => project.clone(),
16410            None => return None,
16411        };
16412        Some(self.perform_code_action_kind(
16413            project,
16414            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16415            window,
16416            cx,
16417        ))
16418    }
16419
16420    fn perform_code_action_kind(
16421        &mut self,
16422        project: Entity<Project>,
16423        kind: CodeActionKind,
16424        window: &mut Window,
16425        cx: &mut Context<Self>,
16426    ) -> Task<Result<()>> {
16427        let buffer = self.buffer.clone();
16428        let buffers = buffer.read(cx).all_buffers();
16429        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16430        let apply_action = project.update(cx, |project, cx| {
16431            project.apply_code_action_kind(buffers, kind, true, cx)
16432        });
16433        cx.spawn_in(window, async move |_, cx| {
16434            let transaction = futures::select_biased! {
16435                () = timeout => {
16436                    log::warn!("timed out waiting for executing code action");
16437                    None
16438                }
16439                transaction = apply_action.log_err().fuse() => transaction,
16440            };
16441            buffer
16442                .update(cx, |buffer, cx| {
16443                    // check if we need this
16444                    if let Some(transaction) = transaction {
16445                        if !buffer.is_singleton() {
16446                            buffer.push_transaction(&transaction.0, cx);
16447                        }
16448                    }
16449                    cx.notify();
16450                })
16451                .ok();
16452            Ok(())
16453        })
16454    }
16455
16456    pub fn restart_language_server(
16457        &mut self,
16458        _: &RestartLanguageServer,
16459        _: &mut Window,
16460        cx: &mut Context<Self>,
16461    ) {
16462        if let Some(project) = self.project.clone() {
16463            self.buffer.update(cx, |multi_buffer, cx| {
16464                project.update(cx, |project, cx| {
16465                    project.restart_language_servers_for_buffers(
16466                        multi_buffer.all_buffers().into_iter().collect(),
16467                        HashSet::default(),
16468                        cx,
16469                    );
16470                });
16471            })
16472        }
16473    }
16474
16475    pub fn stop_language_server(
16476        &mut self,
16477        _: &StopLanguageServer,
16478        _: &mut Window,
16479        cx: &mut Context<Self>,
16480    ) {
16481        if let Some(project) = self.project.clone() {
16482            self.buffer.update(cx, |multi_buffer, cx| {
16483                project.update(cx, |project, cx| {
16484                    project.stop_language_servers_for_buffers(
16485                        multi_buffer.all_buffers().into_iter().collect(),
16486                        HashSet::default(),
16487                        cx,
16488                    );
16489                    cx.emit(project::Event::RefreshInlayHints);
16490                });
16491            });
16492        }
16493    }
16494
16495    fn cancel_language_server_work(
16496        workspace: &mut Workspace,
16497        _: &actions::CancelLanguageServerWork,
16498        _: &mut Window,
16499        cx: &mut Context<Workspace>,
16500    ) {
16501        let project = workspace.project();
16502        let buffers = workspace
16503            .active_item(cx)
16504            .and_then(|item| item.act_as::<Editor>(cx))
16505            .map_or(HashSet::default(), |editor| {
16506                editor.read(cx).buffer.read(cx).all_buffers()
16507            });
16508        project.update(cx, |project, cx| {
16509            project.cancel_language_server_work_for_buffers(buffers, cx);
16510        });
16511    }
16512
16513    fn show_character_palette(
16514        &mut self,
16515        _: &ShowCharacterPalette,
16516        window: &mut Window,
16517        _: &mut Context<Self>,
16518    ) {
16519        window.show_character_palette();
16520    }
16521
16522    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16523        if !self.diagnostics_enabled() {
16524            return;
16525        }
16526
16527        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16528            let buffer = self.buffer.read(cx).snapshot(cx);
16529            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16530            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16531            let is_valid = buffer
16532                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16533                .any(|entry| {
16534                    entry.diagnostic.is_primary
16535                        && !entry.range.is_empty()
16536                        && entry.range.start == primary_range_start
16537                        && entry.diagnostic.message == active_diagnostics.active_message
16538                });
16539
16540            if !is_valid {
16541                self.dismiss_diagnostics(cx);
16542            }
16543        }
16544    }
16545
16546    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16547        match &self.active_diagnostics {
16548            ActiveDiagnostic::Group(group) => Some(group),
16549            _ => None,
16550        }
16551    }
16552
16553    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16554        if !self.diagnostics_enabled() {
16555            return;
16556        }
16557        self.dismiss_diagnostics(cx);
16558        self.active_diagnostics = ActiveDiagnostic::All;
16559    }
16560
16561    fn activate_diagnostics(
16562        &mut self,
16563        buffer_id: BufferId,
16564        diagnostic: DiagnosticEntry<usize>,
16565        window: &mut Window,
16566        cx: &mut Context<Self>,
16567    ) {
16568        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16569            return;
16570        }
16571        self.dismiss_diagnostics(cx);
16572        let snapshot = self.snapshot(window, cx);
16573        let buffer = self.buffer.read(cx).snapshot(cx);
16574        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16575            return;
16576        };
16577
16578        let diagnostic_group = buffer
16579            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16580            .collect::<Vec<_>>();
16581
16582        let blocks =
16583            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16584
16585        let blocks = self.display_map.update(cx, |display_map, cx| {
16586            display_map.insert_blocks(blocks, cx).into_iter().collect()
16587        });
16588        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16589            active_range: buffer.anchor_before(diagnostic.range.start)
16590                ..buffer.anchor_after(diagnostic.range.end),
16591            active_message: diagnostic.diagnostic.message.clone(),
16592            group_id: diagnostic.diagnostic.group_id,
16593            blocks,
16594        });
16595        cx.notify();
16596    }
16597
16598    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16599        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16600            return;
16601        };
16602
16603        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16604        if let ActiveDiagnostic::Group(group) = prev {
16605            self.display_map.update(cx, |display_map, cx| {
16606                display_map.remove_blocks(group.blocks, cx);
16607            });
16608            cx.notify();
16609        }
16610    }
16611
16612    /// Disable inline diagnostics rendering for this editor.
16613    pub fn disable_inline_diagnostics(&mut self) {
16614        self.inline_diagnostics_enabled = false;
16615        self.inline_diagnostics_update = Task::ready(());
16616        self.inline_diagnostics.clear();
16617    }
16618
16619    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16620        self.diagnostics_enabled = false;
16621        self.dismiss_diagnostics(cx);
16622        self.inline_diagnostics_update = Task::ready(());
16623        self.inline_diagnostics.clear();
16624    }
16625
16626    pub fn diagnostics_enabled(&self) -> bool {
16627        self.diagnostics_enabled && self.mode.is_full()
16628    }
16629
16630    pub fn inline_diagnostics_enabled(&self) -> bool {
16631        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16632    }
16633
16634    pub fn show_inline_diagnostics(&self) -> bool {
16635        self.show_inline_diagnostics
16636    }
16637
16638    pub fn toggle_inline_diagnostics(
16639        &mut self,
16640        _: &ToggleInlineDiagnostics,
16641        window: &mut Window,
16642        cx: &mut Context<Editor>,
16643    ) {
16644        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16645        self.refresh_inline_diagnostics(false, window, cx);
16646    }
16647
16648    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16649        self.diagnostics_max_severity = severity;
16650        self.display_map.update(cx, |display_map, _| {
16651            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16652        });
16653    }
16654
16655    pub fn toggle_diagnostics(
16656        &mut self,
16657        _: &ToggleDiagnostics,
16658        window: &mut Window,
16659        cx: &mut Context<Editor>,
16660    ) {
16661        if !self.diagnostics_enabled() {
16662            return;
16663        }
16664
16665        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16666            EditorSettings::get_global(cx)
16667                .diagnostics_max_severity
16668                .filter(|severity| severity != &DiagnosticSeverity::Off)
16669                .unwrap_or(DiagnosticSeverity::Hint)
16670        } else {
16671            DiagnosticSeverity::Off
16672        };
16673        self.set_max_diagnostics_severity(new_severity, cx);
16674        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16675            self.active_diagnostics = ActiveDiagnostic::None;
16676            self.inline_diagnostics_update = Task::ready(());
16677            self.inline_diagnostics.clear();
16678        } else {
16679            self.refresh_inline_diagnostics(false, window, cx);
16680        }
16681
16682        cx.notify();
16683    }
16684
16685    pub fn toggle_minimap(
16686        &mut self,
16687        _: &ToggleMinimap,
16688        window: &mut Window,
16689        cx: &mut Context<Editor>,
16690    ) {
16691        if self.supports_minimap(cx) {
16692            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16693        }
16694    }
16695
16696    fn refresh_inline_diagnostics(
16697        &mut self,
16698        debounce: bool,
16699        window: &mut Window,
16700        cx: &mut Context<Self>,
16701    ) {
16702        let max_severity = ProjectSettings::get_global(cx)
16703            .diagnostics
16704            .inline
16705            .max_severity
16706            .unwrap_or(self.diagnostics_max_severity);
16707
16708        if !self.inline_diagnostics_enabled()
16709            || !self.show_inline_diagnostics
16710            || max_severity == DiagnosticSeverity::Off
16711        {
16712            self.inline_diagnostics_update = Task::ready(());
16713            self.inline_diagnostics.clear();
16714            return;
16715        }
16716
16717        let debounce_ms = ProjectSettings::get_global(cx)
16718            .diagnostics
16719            .inline
16720            .update_debounce_ms;
16721        let debounce = if debounce && debounce_ms > 0 {
16722            Some(Duration::from_millis(debounce_ms))
16723        } else {
16724            None
16725        };
16726        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16727            if let Some(debounce) = debounce {
16728                cx.background_executor().timer(debounce).await;
16729            }
16730            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16731                editor
16732                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16733                    .ok()
16734            }) else {
16735                return;
16736            };
16737
16738            let new_inline_diagnostics = cx
16739                .background_spawn(async move {
16740                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16741                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16742                        let message = diagnostic_entry
16743                            .diagnostic
16744                            .message
16745                            .split_once('\n')
16746                            .map(|(line, _)| line)
16747                            .map(SharedString::new)
16748                            .unwrap_or_else(|| {
16749                                SharedString::from(diagnostic_entry.diagnostic.message)
16750                            });
16751                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16752                        let (Ok(i) | Err(i)) = inline_diagnostics
16753                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16754                        inline_diagnostics.insert(
16755                            i,
16756                            (
16757                                start_anchor,
16758                                InlineDiagnostic {
16759                                    message,
16760                                    group_id: diagnostic_entry.diagnostic.group_id,
16761                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16762                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16763                                    severity: diagnostic_entry.diagnostic.severity,
16764                                },
16765                            ),
16766                        );
16767                    }
16768                    inline_diagnostics
16769                })
16770                .await;
16771
16772            editor
16773                .update(cx, |editor, cx| {
16774                    editor.inline_diagnostics = new_inline_diagnostics;
16775                    cx.notify();
16776                })
16777                .ok();
16778        });
16779    }
16780
16781    fn pull_diagnostics(
16782        &mut self,
16783        buffer_id: Option<BufferId>,
16784        window: &Window,
16785        cx: &mut Context<Self>,
16786    ) -> Option<()> {
16787        if !self.mode().is_full() {
16788            return None;
16789        }
16790        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16791            .diagnostics
16792            .lsp_pull_diagnostics;
16793        if !pull_diagnostics_settings.enabled {
16794            return None;
16795        }
16796        let project = self.project.as_ref()?.downgrade();
16797        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16798        let mut buffers = self.buffer.read(cx).all_buffers();
16799        if let Some(buffer_id) = buffer_id {
16800            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16801        }
16802
16803        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16804            cx.background_executor().timer(debounce).await;
16805
16806            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16807                buffers
16808                    .into_iter()
16809                    .filter_map(|buffer| {
16810                        project
16811                            .update(cx, |project, cx| {
16812                                project.lsp_store().update(cx, |lsp_store, cx| {
16813                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16814                                })
16815                            })
16816                            .ok()
16817                    })
16818                    .collect::<FuturesUnordered<_>>()
16819            }) else {
16820                return;
16821            };
16822
16823            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16824                match pull_task {
16825                    Ok(()) => {
16826                        if editor
16827                            .update_in(cx, |editor, window, cx| {
16828                                editor.update_diagnostics_state(window, cx);
16829                            })
16830                            .is_err()
16831                        {
16832                            return;
16833                        }
16834                    }
16835                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16836                }
16837            }
16838        });
16839
16840        Some(())
16841    }
16842
16843    pub fn set_selections_from_remote(
16844        &mut self,
16845        selections: Vec<Selection<Anchor>>,
16846        pending_selection: Option<Selection<Anchor>>,
16847        window: &mut Window,
16848        cx: &mut Context<Self>,
16849    ) {
16850        let old_cursor_position = self.selections.newest_anchor().head();
16851        self.selections.change_with(cx, |s| {
16852            s.select_anchors(selections);
16853            if let Some(pending_selection) = pending_selection {
16854                s.set_pending(pending_selection, SelectMode::Character);
16855            } else {
16856                s.clear_pending();
16857            }
16858        });
16859        self.selections_did_change(
16860            false,
16861            &old_cursor_position,
16862            SelectionEffects::default(),
16863            window,
16864            cx,
16865        );
16866    }
16867
16868    pub fn transact(
16869        &mut self,
16870        window: &mut Window,
16871        cx: &mut Context<Self>,
16872        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16873    ) -> Option<TransactionId> {
16874        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16875            this.start_transaction_at(Instant::now(), window, cx);
16876            update(this, window, cx);
16877            this.end_transaction_at(Instant::now(), cx)
16878        })
16879    }
16880
16881    pub fn start_transaction_at(
16882        &mut self,
16883        now: Instant,
16884        window: &mut Window,
16885        cx: &mut Context<Self>,
16886    ) {
16887        self.end_selection(window, cx);
16888        if let Some(tx_id) = self
16889            .buffer
16890            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16891        {
16892            self.selection_history
16893                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16894            cx.emit(EditorEvent::TransactionBegun {
16895                transaction_id: tx_id,
16896            })
16897        }
16898    }
16899
16900    pub fn end_transaction_at(
16901        &mut self,
16902        now: Instant,
16903        cx: &mut Context<Self>,
16904    ) -> Option<TransactionId> {
16905        if let Some(transaction_id) = self
16906            .buffer
16907            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16908        {
16909            if let Some((_, end_selections)) =
16910                self.selection_history.transaction_mut(transaction_id)
16911            {
16912                *end_selections = Some(self.selections.disjoint_anchors());
16913            } else {
16914                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16915            }
16916
16917            cx.emit(EditorEvent::Edited { transaction_id });
16918            Some(transaction_id)
16919        } else {
16920            None
16921        }
16922    }
16923
16924    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16925        if self.selection_mark_mode {
16926            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16927                s.move_with(|_, sel| {
16928                    sel.collapse_to(sel.head(), SelectionGoal::None);
16929                });
16930            })
16931        }
16932        self.selection_mark_mode = true;
16933        cx.notify();
16934    }
16935
16936    pub fn swap_selection_ends(
16937        &mut self,
16938        _: &actions::SwapSelectionEnds,
16939        window: &mut Window,
16940        cx: &mut Context<Self>,
16941    ) {
16942        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16943            s.move_with(|_, sel| {
16944                if sel.start != sel.end {
16945                    sel.reversed = !sel.reversed
16946                }
16947            });
16948        });
16949        self.request_autoscroll(Autoscroll::newest(), cx);
16950        cx.notify();
16951    }
16952
16953    pub fn toggle_fold(
16954        &mut self,
16955        _: &actions::ToggleFold,
16956        window: &mut Window,
16957        cx: &mut Context<Self>,
16958    ) {
16959        if self.is_singleton(cx) {
16960            let selection = self.selections.newest::<Point>(cx);
16961
16962            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16963            let range = if selection.is_empty() {
16964                let point = selection.head().to_display_point(&display_map);
16965                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16966                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16967                    .to_point(&display_map);
16968                start..end
16969            } else {
16970                selection.range()
16971            };
16972            if display_map.folds_in_range(range).next().is_some() {
16973                self.unfold_lines(&Default::default(), window, cx)
16974            } else {
16975                self.fold(&Default::default(), window, cx)
16976            }
16977        } else {
16978            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16979            let buffer_ids: HashSet<_> = self
16980                .selections
16981                .disjoint_anchor_ranges()
16982                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16983                .collect();
16984
16985            let should_unfold = buffer_ids
16986                .iter()
16987                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16988
16989            for buffer_id in buffer_ids {
16990                if should_unfold {
16991                    self.unfold_buffer(buffer_id, cx);
16992                } else {
16993                    self.fold_buffer(buffer_id, cx);
16994                }
16995            }
16996        }
16997    }
16998
16999    pub fn toggle_fold_recursive(
17000        &mut self,
17001        _: &actions::ToggleFoldRecursive,
17002        window: &mut Window,
17003        cx: &mut Context<Self>,
17004    ) {
17005        let selection = self.selections.newest::<Point>(cx);
17006
17007        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17008        let range = if selection.is_empty() {
17009            let point = selection.head().to_display_point(&display_map);
17010            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17011            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17012                .to_point(&display_map);
17013            start..end
17014        } else {
17015            selection.range()
17016        };
17017        if display_map.folds_in_range(range).next().is_some() {
17018            self.unfold_recursive(&Default::default(), window, cx)
17019        } else {
17020            self.fold_recursive(&Default::default(), window, cx)
17021        }
17022    }
17023
17024    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17025        if self.is_singleton(cx) {
17026            let mut to_fold = Vec::new();
17027            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17028            let selections = self.selections.all_adjusted(cx);
17029
17030            for selection in selections {
17031                let range = selection.range().sorted();
17032                let buffer_start_row = range.start.row;
17033
17034                if range.start.row != range.end.row {
17035                    let mut found = false;
17036                    let mut row = range.start.row;
17037                    while row <= range.end.row {
17038                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17039                        {
17040                            found = true;
17041                            row = crease.range().end.row + 1;
17042                            to_fold.push(crease);
17043                        } else {
17044                            row += 1
17045                        }
17046                    }
17047                    if found {
17048                        continue;
17049                    }
17050                }
17051
17052                for row in (0..=range.start.row).rev() {
17053                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17054                        if crease.range().end.row >= buffer_start_row {
17055                            to_fold.push(crease);
17056                            if row <= range.start.row {
17057                                break;
17058                            }
17059                        }
17060                    }
17061                }
17062            }
17063
17064            self.fold_creases(to_fold, true, window, cx);
17065        } else {
17066            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17067            let buffer_ids = self
17068                .selections
17069                .disjoint_anchor_ranges()
17070                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17071                .collect::<HashSet<_>>();
17072            for buffer_id in buffer_ids {
17073                self.fold_buffer(buffer_id, cx);
17074            }
17075        }
17076    }
17077
17078    fn fold_at_level(
17079        &mut self,
17080        fold_at: &FoldAtLevel,
17081        window: &mut Window,
17082        cx: &mut Context<Self>,
17083    ) {
17084        if !self.buffer.read(cx).is_singleton() {
17085            return;
17086        }
17087
17088        let fold_at_level = fold_at.0;
17089        let snapshot = self.buffer.read(cx).snapshot(cx);
17090        let mut to_fold = Vec::new();
17091        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17092
17093        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17094            while start_row < end_row {
17095                match self
17096                    .snapshot(window, cx)
17097                    .crease_for_buffer_row(MultiBufferRow(start_row))
17098                {
17099                    Some(crease) => {
17100                        let nested_start_row = crease.range().start.row + 1;
17101                        let nested_end_row = crease.range().end.row;
17102
17103                        if current_level < fold_at_level {
17104                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17105                        } else if current_level == fold_at_level {
17106                            to_fold.push(crease);
17107                        }
17108
17109                        start_row = nested_end_row + 1;
17110                    }
17111                    None => start_row += 1,
17112                }
17113            }
17114        }
17115
17116        self.fold_creases(to_fold, true, window, cx);
17117    }
17118
17119    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17120        if self.buffer.read(cx).is_singleton() {
17121            let mut fold_ranges = Vec::new();
17122            let snapshot = self.buffer.read(cx).snapshot(cx);
17123
17124            for row in 0..snapshot.max_row().0 {
17125                if let Some(foldable_range) = self
17126                    .snapshot(window, cx)
17127                    .crease_for_buffer_row(MultiBufferRow(row))
17128                {
17129                    fold_ranges.push(foldable_range);
17130                }
17131            }
17132
17133            self.fold_creases(fold_ranges, true, window, cx);
17134        } else {
17135            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17136                editor
17137                    .update_in(cx, |editor, _, cx| {
17138                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17139                            editor.fold_buffer(buffer_id, cx);
17140                        }
17141                    })
17142                    .ok();
17143            });
17144        }
17145    }
17146
17147    pub fn fold_function_bodies(
17148        &mut self,
17149        _: &actions::FoldFunctionBodies,
17150        window: &mut Window,
17151        cx: &mut Context<Self>,
17152    ) {
17153        let snapshot = self.buffer.read(cx).snapshot(cx);
17154
17155        let ranges = snapshot
17156            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17157            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17158            .collect::<Vec<_>>();
17159
17160        let creases = ranges
17161            .into_iter()
17162            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17163            .collect();
17164
17165        self.fold_creases(creases, true, window, cx);
17166    }
17167
17168    pub fn fold_recursive(
17169        &mut self,
17170        _: &actions::FoldRecursive,
17171        window: &mut Window,
17172        cx: &mut Context<Self>,
17173    ) {
17174        let mut to_fold = Vec::new();
17175        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17176        let selections = self.selections.all_adjusted(cx);
17177
17178        for selection in selections {
17179            let range = selection.range().sorted();
17180            let buffer_start_row = range.start.row;
17181
17182            if range.start.row != range.end.row {
17183                let mut found = false;
17184                for row in range.start.row..=range.end.row {
17185                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17186                        found = true;
17187                        to_fold.push(crease);
17188                    }
17189                }
17190                if found {
17191                    continue;
17192                }
17193            }
17194
17195            for row in (0..=range.start.row).rev() {
17196                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17197                    if crease.range().end.row >= buffer_start_row {
17198                        to_fold.push(crease);
17199                    } else {
17200                        break;
17201                    }
17202                }
17203            }
17204        }
17205
17206        self.fold_creases(to_fold, true, window, cx);
17207    }
17208
17209    pub fn fold_at(
17210        &mut self,
17211        buffer_row: MultiBufferRow,
17212        window: &mut Window,
17213        cx: &mut Context<Self>,
17214    ) {
17215        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17216
17217        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17218            let autoscroll = self
17219                .selections
17220                .all::<Point>(cx)
17221                .iter()
17222                .any(|selection| crease.range().overlaps(&selection.range()));
17223
17224            self.fold_creases(vec![crease], autoscroll, window, cx);
17225        }
17226    }
17227
17228    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17229        if self.is_singleton(cx) {
17230            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17231            let buffer = &display_map.buffer_snapshot;
17232            let selections = self.selections.all::<Point>(cx);
17233            let ranges = selections
17234                .iter()
17235                .map(|s| {
17236                    let range = s.display_range(&display_map).sorted();
17237                    let mut start = range.start.to_point(&display_map);
17238                    let mut end = range.end.to_point(&display_map);
17239                    start.column = 0;
17240                    end.column = buffer.line_len(MultiBufferRow(end.row));
17241                    start..end
17242                })
17243                .collect::<Vec<_>>();
17244
17245            self.unfold_ranges(&ranges, true, true, cx);
17246        } else {
17247            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17248            let buffer_ids = self
17249                .selections
17250                .disjoint_anchor_ranges()
17251                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17252                .collect::<HashSet<_>>();
17253            for buffer_id in buffer_ids {
17254                self.unfold_buffer(buffer_id, cx);
17255            }
17256        }
17257    }
17258
17259    pub fn unfold_recursive(
17260        &mut self,
17261        _: &UnfoldRecursive,
17262        _window: &mut Window,
17263        cx: &mut Context<Self>,
17264    ) {
17265        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17266        let selections = self.selections.all::<Point>(cx);
17267        let ranges = selections
17268            .iter()
17269            .map(|s| {
17270                let mut range = s.display_range(&display_map).sorted();
17271                *range.start.column_mut() = 0;
17272                *range.end.column_mut() = display_map.line_len(range.end.row());
17273                let start = range.start.to_point(&display_map);
17274                let end = range.end.to_point(&display_map);
17275                start..end
17276            })
17277            .collect::<Vec<_>>();
17278
17279        self.unfold_ranges(&ranges, true, true, cx);
17280    }
17281
17282    pub fn unfold_at(
17283        &mut self,
17284        buffer_row: MultiBufferRow,
17285        _window: &mut Window,
17286        cx: &mut Context<Self>,
17287    ) {
17288        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17289
17290        let intersection_range = Point::new(buffer_row.0, 0)
17291            ..Point::new(
17292                buffer_row.0,
17293                display_map.buffer_snapshot.line_len(buffer_row),
17294            );
17295
17296        let autoscroll = self
17297            .selections
17298            .all::<Point>(cx)
17299            .iter()
17300            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17301
17302        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17303    }
17304
17305    pub fn unfold_all(
17306        &mut self,
17307        _: &actions::UnfoldAll,
17308        _window: &mut Window,
17309        cx: &mut Context<Self>,
17310    ) {
17311        if self.buffer.read(cx).is_singleton() {
17312            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17313            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17314        } else {
17315            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17316                editor
17317                    .update(cx, |editor, cx| {
17318                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17319                            editor.unfold_buffer(buffer_id, cx);
17320                        }
17321                    })
17322                    .ok();
17323            });
17324        }
17325    }
17326
17327    pub fn fold_selected_ranges(
17328        &mut self,
17329        _: &FoldSelectedRanges,
17330        window: &mut Window,
17331        cx: &mut Context<Self>,
17332    ) {
17333        let selections = self.selections.all_adjusted(cx);
17334        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17335        let ranges = selections
17336            .into_iter()
17337            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17338            .collect::<Vec<_>>();
17339        self.fold_creases(ranges, true, window, cx);
17340    }
17341
17342    pub fn fold_ranges<T: ToOffset + Clone>(
17343        &mut self,
17344        ranges: Vec<Range<T>>,
17345        auto_scroll: bool,
17346        window: &mut Window,
17347        cx: &mut Context<Self>,
17348    ) {
17349        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17350        let ranges = ranges
17351            .into_iter()
17352            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17353            .collect::<Vec<_>>();
17354        self.fold_creases(ranges, auto_scroll, window, cx);
17355    }
17356
17357    pub fn fold_creases<T: ToOffset + Clone>(
17358        &mut self,
17359        creases: Vec<Crease<T>>,
17360        auto_scroll: bool,
17361        _window: &mut Window,
17362        cx: &mut Context<Self>,
17363    ) {
17364        if creases.is_empty() {
17365            return;
17366        }
17367
17368        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17369
17370        if auto_scroll {
17371            self.request_autoscroll(Autoscroll::fit(), cx);
17372        }
17373
17374        cx.notify();
17375
17376        self.scrollbar_marker_state.dirty = true;
17377        self.folds_did_change(cx);
17378    }
17379
17380    /// Removes any folds whose ranges intersect any of the given ranges.
17381    pub fn unfold_ranges<T: ToOffset + Clone>(
17382        &mut self,
17383        ranges: &[Range<T>],
17384        inclusive: bool,
17385        auto_scroll: bool,
17386        cx: &mut Context<Self>,
17387    ) {
17388        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17389            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17390        });
17391        self.folds_did_change(cx);
17392    }
17393
17394    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17395        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17396            return;
17397        }
17398        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17399        self.display_map.update(cx, |display_map, cx| {
17400            display_map.fold_buffers([buffer_id], cx)
17401        });
17402        cx.emit(EditorEvent::BufferFoldToggled {
17403            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17404            folded: true,
17405        });
17406        cx.notify();
17407    }
17408
17409    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17410        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17411            return;
17412        }
17413        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17414        self.display_map.update(cx, |display_map, cx| {
17415            display_map.unfold_buffers([buffer_id], cx);
17416        });
17417        cx.emit(EditorEvent::BufferFoldToggled {
17418            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17419            folded: false,
17420        });
17421        cx.notify();
17422    }
17423
17424    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17425        self.display_map.read(cx).is_buffer_folded(buffer)
17426    }
17427
17428    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17429        self.display_map.read(cx).folded_buffers()
17430    }
17431
17432    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17433        self.display_map.update(cx, |display_map, cx| {
17434            display_map.disable_header_for_buffer(buffer_id, cx);
17435        });
17436        cx.notify();
17437    }
17438
17439    /// Removes any folds with the given ranges.
17440    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17441        &mut self,
17442        ranges: &[Range<T>],
17443        type_id: TypeId,
17444        auto_scroll: bool,
17445        cx: &mut Context<Self>,
17446    ) {
17447        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17448            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17449        });
17450        self.folds_did_change(cx);
17451    }
17452
17453    fn remove_folds_with<T: ToOffset + Clone>(
17454        &mut self,
17455        ranges: &[Range<T>],
17456        auto_scroll: bool,
17457        cx: &mut Context<Self>,
17458        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17459    ) {
17460        if ranges.is_empty() {
17461            return;
17462        }
17463
17464        let mut buffers_affected = HashSet::default();
17465        let multi_buffer = self.buffer().read(cx);
17466        for range in ranges {
17467            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17468                buffers_affected.insert(buffer.read(cx).remote_id());
17469            };
17470        }
17471
17472        self.display_map.update(cx, update);
17473
17474        if auto_scroll {
17475            self.request_autoscroll(Autoscroll::fit(), cx);
17476        }
17477
17478        cx.notify();
17479        self.scrollbar_marker_state.dirty = true;
17480        self.active_indent_guides_state.dirty = true;
17481    }
17482
17483    pub fn update_renderer_widths(
17484        &mut self,
17485        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17486        cx: &mut Context<Self>,
17487    ) -> bool {
17488        self.display_map
17489            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17490    }
17491
17492    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17493        self.display_map.read(cx).fold_placeholder.clone()
17494    }
17495
17496    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17497        self.buffer.update(cx, |buffer, cx| {
17498            buffer.set_all_diff_hunks_expanded(cx);
17499        });
17500    }
17501
17502    pub fn expand_all_diff_hunks(
17503        &mut self,
17504        _: &ExpandAllDiffHunks,
17505        _window: &mut Window,
17506        cx: &mut Context<Self>,
17507    ) {
17508        self.buffer.update(cx, |buffer, cx| {
17509            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17510        });
17511    }
17512
17513    pub fn toggle_selected_diff_hunks(
17514        &mut self,
17515        _: &ToggleSelectedDiffHunks,
17516        _window: &mut Window,
17517        cx: &mut Context<Self>,
17518    ) {
17519        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17520        self.toggle_diff_hunks_in_ranges(ranges, cx);
17521    }
17522
17523    pub fn diff_hunks_in_ranges<'a>(
17524        &'a self,
17525        ranges: &'a [Range<Anchor>],
17526        buffer: &'a MultiBufferSnapshot,
17527    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17528        ranges.iter().flat_map(move |range| {
17529            let end_excerpt_id = range.end.excerpt_id;
17530            let range = range.to_point(buffer);
17531            let mut peek_end = range.end;
17532            if range.end.row < buffer.max_row().0 {
17533                peek_end = Point::new(range.end.row + 1, 0);
17534            }
17535            buffer
17536                .diff_hunks_in_range(range.start..peek_end)
17537                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17538        })
17539    }
17540
17541    pub fn has_stageable_diff_hunks_in_ranges(
17542        &self,
17543        ranges: &[Range<Anchor>],
17544        snapshot: &MultiBufferSnapshot,
17545    ) -> bool {
17546        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17547        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17548    }
17549
17550    pub fn toggle_staged_selected_diff_hunks(
17551        &mut self,
17552        _: &::git::ToggleStaged,
17553        _: &mut Window,
17554        cx: &mut Context<Self>,
17555    ) {
17556        let snapshot = self.buffer.read(cx).snapshot(cx);
17557        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17558        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17559        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17560    }
17561
17562    pub fn set_render_diff_hunk_controls(
17563        &mut self,
17564        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17565        cx: &mut Context<Self>,
17566    ) {
17567        self.render_diff_hunk_controls = render_diff_hunk_controls;
17568        cx.notify();
17569    }
17570
17571    pub fn stage_and_next(
17572        &mut self,
17573        _: &::git::StageAndNext,
17574        window: &mut Window,
17575        cx: &mut Context<Self>,
17576    ) {
17577        self.do_stage_or_unstage_and_next(true, window, cx);
17578    }
17579
17580    pub fn unstage_and_next(
17581        &mut self,
17582        _: &::git::UnstageAndNext,
17583        window: &mut Window,
17584        cx: &mut Context<Self>,
17585    ) {
17586        self.do_stage_or_unstage_and_next(false, window, cx);
17587    }
17588
17589    pub fn stage_or_unstage_diff_hunks(
17590        &mut self,
17591        stage: bool,
17592        ranges: Vec<Range<Anchor>>,
17593        cx: &mut Context<Self>,
17594    ) {
17595        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17596        cx.spawn(async move |this, cx| {
17597            task.await?;
17598            this.update(cx, |this, cx| {
17599                let snapshot = this.buffer.read(cx).snapshot(cx);
17600                let chunk_by = this
17601                    .diff_hunks_in_ranges(&ranges, &snapshot)
17602                    .chunk_by(|hunk| hunk.buffer_id);
17603                for (buffer_id, hunks) in &chunk_by {
17604                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17605                }
17606            })
17607        })
17608        .detach_and_log_err(cx);
17609    }
17610
17611    fn save_buffers_for_ranges_if_needed(
17612        &mut self,
17613        ranges: &[Range<Anchor>],
17614        cx: &mut Context<Editor>,
17615    ) -> Task<Result<()>> {
17616        let multibuffer = self.buffer.read(cx);
17617        let snapshot = multibuffer.read(cx);
17618        let buffer_ids: HashSet<_> = ranges
17619            .iter()
17620            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17621            .collect();
17622        drop(snapshot);
17623
17624        let mut buffers = HashSet::default();
17625        for buffer_id in buffer_ids {
17626            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17627                let buffer = buffer_entity.read(cx);
17628                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17629                {
17630                    buffers.insert(buffer_entity);
17631                }
17632            }
17633        }
17634
17635        if let Some(project) = &self.project {
17636            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17637        } else {
17638            Task::ready(Ok(()))
17639        }
17640    }
17641
17642    fn do_stage_or_unstage_and_next(
17643        &mut self,
17644        stage: bool,
17645        window: &mut Window,
17646        cx: &mut Context<Self>,
17647    ) {
17648        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17649
17650        if ranges.iter().any(|range| range.start != range.end) {
17651            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17652            return;
17653        }
17654
17655        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17656        let snapshot = self.snapshot(window, cx);
17657        let position = self.selections.newest::<Point>(cx).head();
17658        let mut row = snapshot
17659            .buffer_snapshot
17660            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17661            .find(|hunk| hunk.row_range.start.0 > position.row)
17662            .map(|hunk| hunk.row_range.start);
17663
17664        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17665        // Outside of the project diff editor, wrap around to the beginning.
17666        if !all_diff_hunks_expanded {
17667            row = row.or_else(|| {
17668                snapshot
17669                    .buffer_snapshot
17670                    .diff_hunks_in_range(Point::zero()..position)
17671                    .find(|hunk| hunk.row_range.end.0 < position.row)
17672                    .map(|hunk| hunk.row_range.start)
17673            });
17674        }
17675
17676        if let Some(row) = row {
17677            let destination = Point::new(row.0, 0);
17678            let autoscroll = Autoscroll::center();
17679
17680            self.unfold_ranges(&[destination..destination], false, false, cx);
17681            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17682                s.select_ranges([destination..destination]);
17683            });
17684        }
17685    }
17686
17687    fn do_stage_or_unstage(
17688        &self,
17689        stage: bool,
17690        buffer_id: BufferId,
17691        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17692        cx: &mut App,
17693    ) -> Option<()> {
17694        let project = self.project.as_ref()?;
17695        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17696        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17697        let buffer_snapshot = buffer.read(cx).snapshot();
17698        let file_exists = buffer_snapshot
17699            .file()
17700            .is_some_and(|file| file.disk_state().exists());
17701        diff.update(cx, |diff, cx| {
17702            diff.stage_or_unstage_hunks(
17703                stage,
17704                &hunks
17705                    .map(|hunk| buffer_diff::DiffHunk {
17706                        buffer_range: hunk.buffer_range,
17707                        diff_base_byte_range: hunk.diff_base_byte_range,
17708                        secondary_status: hunk.secondary_status,
17709                        range: Point::zero()..Point::zero(), // unused
17710                    })
17711                    .collect::<Vec<_>>(),
17712                &buffer_snapshot,
17713                file_exists,
17714                cx,
17715            )
17716        });
17717        None
17718    }
17719
17720    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17721        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17722        self.buffer
17723            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17724    }
17725
17726    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17727        self.buffer.update(cx, |buffer, cx| {
17728            let ranges = vec![Anchor::min()..Anchor::max()];
17729            if !buffer.all_diff_hunks_expanded()
17730                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17731            {
17732                buffer.collapse_diff_hunks(ranges, cx);
17733                true
17734            } else {
17735                false
17736            }
17737        })
17738    }
17739
17740    fn toggle_diff_hunks_in_ranges(
17741        &mut self,
17742        ranges: Vec<Range<Anchor>>,
17743        cx: &mut Context<Editor>,
17744    ) {
17745        self.buffer.update(cx, |buffer, cx| {
17746            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17747            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17748        })
17749    }
17750
17751    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17752        self.buffer.update(cx, |buffer, cx| {
17753            let snapshot = buffer.snapshot(cx);
17754            let excerpt_id = range.end.excerpt_id;
17755            let point_range = range.to_point(&snapshot);
17756            let expand = !buffer.single_hunk_is_expanded(range, cx);
17757            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17758        })
17759    }
17760
17761    pub(crate) fn apply_all_diff_hunks(
17762        &mut self,
17763        _: &ApplyAllDiffHunks,
17764        window: &mut Window,
17765        cx: &mut Context<Self>,
17766    ) {
17767        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17768
17769        let buffers = self.buffer.read(cx).all_buffers();
17770        for branch_buffer in buffers {
17771            branch_buffer.update(cx, |branch_buffer, cx| {
17772                branch_buffer.merge_into_base(Vec::new(), cx);
17773            });
17774        }
17775
17776        if let Some(project) = self.project.clone() {
17777            self.save(
17778                SaveOptions {
17779                    format: true,
17780                    autosave: false,
17781                },
17782                project,
17783                window,
17784                cx,
17785            )
17786            .detach_and_log_err(cx);
17787        }
17788    }
17789
17790    pub(crate) fn apply_selected_diff_hunks(
17791        &mut self,
17792        _: &ApplyDiffHunk,
17793        window: &mut Window,
17794        cx: &mut Context<Self>,
17795    ) {
17796        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17797        let snapshot = self.snapshot(window, cx);
17798        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17799        let mut ranges_by_buffer = HashMap::default();
17800        self.transact(window, cx, |editor, _window, cx| {
17801            for hunk in hunks {
17802                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17803                    ranges_by_buffer
17804                        .entry(buffer.clone())
17805                        .or_insert_with(Vec::new)
17806                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17807                }
17808            }
17809
17810            for (buffer, ranges) in ranges_by_buffer {
17811                buffer.update(cx, |buffer, cx| {
17812                    buffer.merge_into_base(ranges, cx);
17813                });
17814            }
17815        });
17816
17817        if let Some(project) = self.project.clone() {
17818            self.save(
17819                SaveOptions {
17820                    format: true,
17821                    autosave: false,
17822                },
17823                project,
17824                window,
17825                cx,
17826            )
17827            .detach_and_log_err(cx);
17828        }
17829    }
17830
17831    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17832        if hovered != self.gutter_hovered {
17833            self.gutter_hovered = hovered;
17834            cx.notify();
17835        }
17836    }
17837
17838    pub fn insert_blocks(
17839        &mut self,
17840        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17841        autoscroll: Option<Autoscroll>,
17842        cx: &mut Context<Self>,
17843    ) -> Vec<CustomBlockId> {
17844        let blocks = self
17845            .display_map
17846            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17847        if let Some(autoscroll) = autoscroll {
17848            self.request_autoscroll(autoscroll, cx);
17849        }
17850        cx.notify();
17851        blocks
17852    }
17853
17854    pub fn resize_blocks(
17855        &mut self,
17856        heights: HashMap<CustomBlockId, u32>,
17857        autoscroll: Option<Autoscroll>,
17858        cx: &mut Context<Self>,
17859    ) {
17860        self.display_map
17861            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17862        if let Some(autoscroll) = autoscroll {
17863            self.request_autoscroll(autoscroll, cx);
17864        }
17865        cx.notify();
17866    }
17867
17868    pub fn replace_blocks(
17869        &mut self,
17870        renderers: HashMap<CustomBlockId, RenderBlock>,
17871        autoscroll: Option<Autoscroll>,
17872        cx: &mut Context<Self>,
17873    ) {
17874        self.display_map
17875            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17876        if let Some(autoscroll) = autoscroll {
17877            self.request_autoscroll(autoscroll, cx);
17878        }
17879        cx.notify();
17880    }
17881
17882    pub fn remove_blocks(
17883        &mut self,
17884        block_ids: HashSet<CustomBlockId>,
17885        autoscroll: Option<Autoscroll>,
17886        cx: &mut Context<Self>,
17887    ) {
17888        self.display_map.update(cx, |display_map, cx| {
17889            display_map.remove_blocks(block_ids, cx)
17890        });
17891        if let Some(autoscroll) = autoscroll {
17892            self.request_autoscroll(autoscroll, cx);
17893        }
17894        cx.notify();
17895    }
17896
17897    pub fn row_for_block(
17898        &self,
17899        block_id: CustomBlockId,
17900        cx: &mut Context<Self>,
17901    ) -> Option<DisplayRow> {
17902        self.display_map
17903            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17904    }
17905
17906    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17907        self.focused_block = Some(focused_block);
17908    }
17909
17910    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17911        self.focused_block.take()
17912    }
17913
17914    pub fn insert_creases(
17915        &mut self,
17916        creases: impl IntoIterator<Item = Crease<Anchor>>,
17917        cx: &mut Context<Self>,
17918    ) -> Vec<CreaseId> {
17919        self.display_map
17920            .update(cx, |map, cx| map.insert_creases(creases, cx))
17921    }
17922
17923    pub fn remove_creases(
17924        &mut self,
17925        ids: impl IntoIterator<Item = CreaseId>,
17926        cx: &mut Context<Self>,
17927    ) -> Vec<(CreaseId, Range<Anchor>)> {
17928        self.display_map
17929            .update(cx, |map, cx| map.remove_creases(ids, cx))
17930    }
17931
17932    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17933        self.display_map
17934            .update(cx, |map, cx| map.snapshot(cx))
17935            .longest_row()
17936    }
17937
17938    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17939        self.display_map
17940            .update(cx, |map, cx| map.snapshot(cx))
17941            .max_point()
17942    }
17943
17944    pub fn text(&self, cx: &App) -> String {
17945        self.buffer.read(cx).read(cx).text()
17946    }
17947
17948    pub fn is_empty(&self, cx: &App) -> bool {
17949        self.buffer.read(cx).read(cx).is_empty()
17950    }
17951
17952    pub fn text_option(&self, cx: &App) -> Option<String> {
17953        let text = self.text(cx);
17954        let text = text.trim();
17955
17956        if text.is_empty() {
17957            return None;
17958        }
17959
17960        Some(text.to_string())
17961    }
17962
17963    pub fn set_text(
17964        &mut self,
17965        text: impl Into<Arc<str>>,
17966        window: &mut Window,
17967        cx: &mut Context<Self>,
17968    ) {
17969        self.transact(window, cx, |this, _, cx| {
17970            this.buffer
17971                .read(cx)
17972                .as_singleton()
17973                .expect("you can only call set_text on editors for singleton buffers")
17974                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17975        });
17976    }
17977
17978    pub fn display_text(&self, cx: &mut App) -> String {
17979        self.display_map
17980            .update(cx, |map, cx| map.snapshot(cx))
17981            .text()
17982    }
17983
17984    fn create_minimap(
17985        &self,
17986        minimap_settings: MinimapSettings,
17987        window: &mut Window,
17988        cx: &mut Context<Self>,
17989    ) -> Option<Entity<Self>> {
17990        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17991            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17992    }
17993
17994    fn initialize_new_minimap(
17995        &self,
17996        minimap_settings: MinimapSettings,
17997        window: &mut Window,
17998        cx: &mut Context<Self>,
17999    ) -> Entity<Self> {
18000        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18001
18002        let mut minimap = Editor::new_internal(
18003            EditorMode::Minimap {
18004                parent: cx.weak_entity(),
18005            },
18006            self.buffer.clone(),
18007            self.project.clone(),
18008            Some(self.display_map.clone()),
18009            window,
18010            cx,
18011        );
18012        minimap.scroll_manager.clone_state(&self.scroll_manager);
18013        minimap.set_text_style_refinement(TextStyleRefinement {
18014            font_size: Some(MINIMAP_FONT_SIZE),
18015            font_weight: Some(MINIMAP_FONT_WEIGHT),
18016            ..Default::default()
18017        });
18018        minimap.update_minimap_configuration(minimap_settings, cx);
18019        cx.new(|_| minimap)
18020    }
18021
18022    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18023        let current_line_highlight = minimap_settings
18024            .current_line_highlight
18025            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18026        self.set_current_line_highlight(Some(current_line_highlight));
18027    }
18028
18029    pub fn minimap(&self) -> Option<&Entity<Self>> {
18030        self.minimap
18031            .as_ref()
18032            .filter(|_| self.minimap_visibility.visible())
18033    }
18034
18035    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18036        let mut wrap_guides = smallvec![];
18037
18038        if self.show_wrap_guides == Some(false) {
18039            return wrap_guides;
18040        }
18041
18042        let settings = self.buffer.read(cx).language_settings(cx);
18043        if settings.show_wrap_guides {
18044            match self.soft_wrap_mode(cx) {
18045                SoftWrap::Column(soft_wrap) => {
18046                    wrap_guides.push((soft_wrap as usize, true));
18047                }
18048                SoftWrap::Bounded(soft_wrap) => {
18049                    wrap_guides.push((soft_wrap as usize, true));
18050                }
18051                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18052            }
18053            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18054        }
18055
18056        wrap_guides
18057    }
18058
18059    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18060        let settings = self.buffer.read(cx).language_settings(cx);
18061        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18062        match mode {
18063            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18064                SoftWrap::None
18065            }
18066            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18067            language_settings::SoftWrap::PreferredLineLength => {
18068                SoftWrap::Column(settings.preferred_line_length)
18069            }
18070            language_settings::SoftWrap::Bounded => {
18071                SoftWrap::Bounded(settings.preferred_line_length)
18072            }
18073        }
18074    }
18075
18076    pub fn set_soft_wrap_mode(
18077        &mut self,
18078        mode: language_settings::SoftWrap,
18079
18080        cx: &mut Context<Self>,
18081    ) {
18082        self.soft_wrap_mode_override = Some(mode);
18083        cx.notify();
18084    }
18085
18086    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18087        self.hard_wrap = hard_wrap;
18088        cx.notify();
18089    }
18090
18091    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18092        self.text_style_refinement = Some(style);
18093    }
18094
18095    /// called by the Element so we know what style we were most recently rendered with.
18096    pub(crate) fn set_style(
18097        &mut self,
18098        style: EditorStyle,
18099        window: &mut Window,
18100        cx: &mut Context<Self>,
18101    ) {
18102        // We intentionally do not inform the display map about the minimap style
18103        // so that wrapping is not recalculated and stays consistent for the editor
18104        // and its linked minimap.
18105        if !self.mode.is_minimap() {
18106            let rem_size = window.rem_size();
18107            self.display_map.update(cx, |map, cx| {
18108                map.set_font(
18109                    style.text.font(),
18110                    style.text.font_size.to_pixels(rem_size),
18111                    cx,
18112                )
18113            });
18114        }
18115        self.style = Some(style);
18116    }
18117
18118    pub fn style(&self) -> Option<&EditorStyle> {
18119        self.style.as_ref()
18120    }
18121
18122    // Called by the element. This method is not designed to be called outside of the editor
18123    // element's layout code because it does not notify when rewrapping is computed synchronously.
18124    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18125        self.display_map
18126            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18127    }
18128
18129    pub fn set_soft_wrap(&mut self) {
18130        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18131    }
18132
18133    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18134        if self.soft_wrap_mode_override.is_some() {
18135            self.soft_wrap_mode_override.take();
18136        } else {
18137            let soft_wrap = match self.soft_wrap_mode(cx) {
18138                SoftWrap::GitDiff => return,
18139                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18140                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18141                    language_settings::SoftWrap::None
18142                }
18143            };
18144            self.soft_wrap_mode_override = Some(soft_wrap);
18145        }
18146        cx.notify();
18147    }
18148
18149    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18150        let Some(workspace) = self.workspace() else {
18151            return;
18152        };
18153        let fs = workspace.read(cx).app_state().fs.clone();
18154        let current_show = TabBarSettings::get_global(cx).show;
18155        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18156            setting.show = Some(!current_show);
18157        });
18158    }
18159
18160    pub fn toggle_indent_guides(
18161        &mut self,
18162        _: &ToggleIndentGuides,
18163        _: &mut Window,
18164        cx: &mut Context<Self>,
18165    ) {
18166        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18167            self.buffer
18168                .read(cx)
18169                .language_settings(cx)
18170                .indent_guides
18171                .enabled
18172        });
18173        self.show_indent_guides = Some(!currently_enabled);
18174        cx.notify();
18175    }
18176
18177    fn should_show_indent_guides(&self) -> Option<bool> {
18178        self.show_indent_guides
18179    }
18180
18181    pub fn toggle_line_numbers(
18182        &mut self,
18183        _: &ToggleLineNumbers,
18184        _: &mut Window,
18185        cx: &mut Context<Self>,
18186    ) {
18187        let mut editor_settings = EditorSettings::get_global(cx).clone();
18188        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18189        EditorSettings::override_global(editor_settings, cx);
18190    }
18191
18192    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18193        if let Some(show_line_numbers) = self.show_line_numbers {
18194            return show_line_numbers;
18195        }
18196        EditorSettings::get_global(cx).gutter.line_numbers
18197    }
18198
18199    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18200        self.use_relative_line_numbers
18201            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18202    }
18203
18204    pub fn toggle_relative_line_numbers(
18205        &mut self,
18206        _: &ToggleRelativeLineNumbers,
18207        _: &mut Window,
18208        cx: &mut Context<Self>,
18209    ) {
18210        let is_relative = self.should_use_relative_line_numbers(cx);
18211        self.set_relative_line_number(Some(!is_relative), cx)
18212    }
18213
18214    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18215        self.use_relative_line_numbers = is_relative;
18216        cx.notify();
18217    }
18218
18219    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18220        self.show_gutter = show_gutter;
18221        cx.notify();
18222    }
18223
18224    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18225        self.show_scrollbars = ScrollbarAxes {
18226            horizontal: show,
18227            vertical: show,
18228        };
18229        cx.notify();
18230    }
18231
18232    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18233        self.show_scrollbars.vertical = show;
18234        cx.notify();
18235    }
18236
18237    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18238        self.show_scrollbars.horizontal = show;
18239        cx.notify();
18240    }
18241
18242    pub fn set_minimap_visibility(
18243        &mut self,
18244        minimap_visibility: MinimapVisibility,
18245        window: &mut Window,
18246        cx: &mut Context<Self>,
18247    ) {
18248        if self.minimap_visibility != minimap_visibility {
18249            if minimap_visibility.visible() && self.minimap.is_none() {
18250                let minimap_settings = EditorSettings::get_global(cx).minimap;
18251                self.minimap =
18252                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18253            }
18254            self.minimap_visibility = minimap_visibility;
18255            cx.notify();
18256        }
18257    }
18258
18259    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18260        self.set_show_scrollbars(false, cx);
18261        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18262    }
18263
18264    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18265        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18266    }
18267
18268    /// Normally the text in full mode and auto height editors is padded on the
18269    /// left side by roughly half a character width for improved hit testing.
18270    ///
18271    /// Use this method to disable this for cases where this is not wanted (e.g.
18272    /// if you want to align the editor text with some other text above or below)
18273    /// or if you want to add this padding to single-line editors.
18274    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18275        self.offset_content = offset_content;
18276        cx.notify();
18277    }
18278
18279    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18280        self.show_line_numbers = Some(show_line_numbers);
18281        cx.notify();
18282    }
18283
18284    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18285        self.disable_expand_excerpt_buttons = true;
18286        cx.notify();
18287    }
18288
18289    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18290        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18291        cx.notify();
18292    }
18293
18294    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18295        self.show_code_actions = Some(show_code_actions);
18296        cx.notify();
18297    }
18298
18299    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18300        self.show_runnables = Some(show_runnables);
18301        cx.notify();
18302    }
18303
18304    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18305        self.show_breakpoints = Some(show_breakpoints);
18306        cx.notify();
18307    }
18308
18309    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18310        if self.display_map.read(cx).masked != masked {
18311            self.display_map.update(cx, |map, _| map.masked = masked);
18312        }
18313        cx.notify()
18314    }
18315
18316    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18317        self.show_wrap_guides = Some(show_wrap_guides);
18318        cx.notify();
18319    }
18320
18321    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18322        self.show_indent_guides = Some(show_indent_guides);
18323        cx.notify();
18324    }
18325
18326    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18327        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18328            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18329                if let Some(dir) = file.abs_path(cx).parent() {
18330                    return Some(dir.to_owned());
18331                }
18332            }
18333
18334            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18335                return Some(project_path.path.to_path_buf());
18336            }
18337        }
18338
18339        None
18340    }
18341
18342    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18343        self.active_excerpt(cx)?
18344            .1
18345            .read(cx)
18346            .file()
18347            .and_then(|f| f.as_local())
18348    }
18349
18350    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18351        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18352            let buffer = buffer.read(cx);
18353            if let Some(project_path) = buffer.project_path(cx) {
18354                let project = self.project.as_ref()?.read(cx);
18355                project.absolute_path(&project_path, cx)
18356            } else {
18357                buffer
18358                    .file()
18359                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18360            }
18361        })
18362    }
18363
18364    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18365        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18366            let project_path = buffer.read(cx).project_path(cx)?;
18367            let project = self.project.as_ref()?.read(cx);
18368            let entry = project.entry_for_path(&project_path, cx)?;
18369            let path = entry.path.to_path_buf();
18370            Some(path)
18371        })
18372    }
18373
18374    pub fn reveal_in_finder(
18375        &mut self,
18376        _: &RevealInFileManager,
18377        _window: &mut Window,
18378        cx: &mut Context<Self>,
18379    ) {
18380        if let Some(target) = self.target_file(cx) {
18381            cx.reveal_path(&target.abs_path(cx));
18382        }
18383    }
18384
18385    pub fn copy_path(
18386        &mut self,
18387        _: &zed_actions::workspace::CopyPath,
18388        _window: &mut Window,
18389        cx: &mut Context<Self>,
18390    ) {
18391        if let Some(path) = self.target_file_abs_path(cx) {
18392            if let Some(path) = path.to_str() {
18393                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18394            }
18395        }
18396    }
18397
18398    pub fn copy_relative_path(
18399        &mut self,
18400        _: &zed_actions::workspace::CopyRelativePath,
18401        _window: &mut Window,
18402        cx: &mut Context<Self>,
18403    ) {
18404        if let Some(path) = self.target_file_path(cx) {
18405            if let Some(path) = path.to_str() {
18406                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18407            }
18408        }
18409    }
18410
18411    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18412        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18413            buffer.read(cx).project_path(cx)
18414        } else {
18415            None
18416        }
18417    }
18418
18419    // Returns true if the editor handled a go-to-line request
18420    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18421        maybe!({
18422            let breakpoint_store = self.breakpoint_store.as_ref()?;
18423
18424            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18425            else {
18426                self.clear_row_highlights::<ActiveDebugLine>();
18427                return None;
18428            };
18429
18430            let position = active_stack_frame.position;
18431            let buffer_id = position.buffer_id?;
18432            let snapshot = self
18433                .project
18434                .as_ref()?
18435                .read(cx)
18436                .buffer_for_id(buffer_id, cx)?
18437                .read(cx)
18438                .snapshot();
18439
18440            let mut handled = false;
18441            for (id, ExcerptRange { context, .. }) in
18442                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18443            {
18444                if context.start.cmp(&position, &snapshot).is_ge()
18445                    || context.end.cmp(&position, &snapshot).is_lt()
18446                {
18447                    continue;
18448                }
18449                let snapshot = self.buffer.read(cx).snapshot(cx);
18450                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18451
18452                handled = true;
18453                self.clear_row_highlights::<ActiveDebugLine>();
18454
18455                self.go_to_line::<ActiveDebugLine>(
18456                    multibuffer_anchor,
18457                    Some(cx.theme().colors().editor_debugger_active_line_background),
18458                    window,
18459                    cx,
18460                );
18461
18462                cx.notify();
18463            }
18464
18465            handled.then_some(())
18466        })
18467        .is_some()
18468    }
18469
18470    pub fn copy_file_name_without_extension(
18471        &mut self,
18472        _: &CopyFileNameWithoutExtension,
18473        _: &mut Window,
18474        cx: &mut Context<Self>,
18475    ) {
18476        if let Some(file) = self.target_file(cx) {
18477            if let Some(file_stem) = file.path().file_stem() {
18478                if let Some(name) = file_stem.to_str() {
18479                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18480                }
18481            }
18482        }
18483    }
18484
18485    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18486        if let Some(file) = self.target_file(cx) {
18487            if let Some(file_name) = file.path().file_name() {
18488                if let Some(name) = file_name.to_str() {
18489                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18490                }
18491            }
18492        }
18493    }
18494
18495    pub fn toggle_git_blame(
18496        &mut self,
18497        _: &::git::Blame,
18498        window: &mut Window,
18499        cx: &mut Context<Self>,
18500    ) {
18501        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18502
18503        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18504            self.start_git_blame(true, window, cx);
18505        }
18506
18507        cx.notify();
18508    }
18509
18510    pub fn toggle_git_blame_inline(
18511        &mut self,
18512        _: &ToggleGitBlameInline,
18513        window: &mut Window,
18514        cx: &mut Context<Self>,
18515    ) {
18516        self.toggle_git_blame_inline_internal(true, window, cx);
18517        cx.notify();
18518    }
18519
18520    pub fn open_git_blame_commit(
18521        &mut self,
18522        _: &OpenGitBlameCommit,
18523        window: &mut Window,
18524        cx: &mut Context<Self>,
18525    ) {
18526        self.open_git_blame_commit_internal(window, cx);
18527    }
18528
18529    fn open_git_blame_commit_internal(
18530        &mut self,
18531        window: &mut Window,
18532        cx: &mut Context<Self>,
18533    ) -> Option<()> {
18534        let blame = self.blame.as_ref()?;
18535        let snapshot = self.snapshot(window, cx);
18536        let cursor = self.selections.newest::<Point>(cx).head();
18537        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18538        let blame_entry = blame
18539            .update(cx, |blame, cx| {
18540                blame
18541                    .blame_for_rows(
18542                        &[RowInfo {
18543                            buffer_id: Some(buffer.remote_id()),
18544                            buffer_row: Some(point.row),
18545                            ..Default::default()
18546                        }],
18547                        cx,
18548                    )
18549                    .next()
18550            })
18551            .flatten()?;
18552        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18553        let repo = blame.read(cx).repository(cx)?;
18554        let workspace = self.workspace()?.downgrade();
18555        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18556        None
18557    }
18558
18559    pub fn git_blame_inline_enabled(&self) -> bool {
18560        self.git_blame_inline_enabled
18561    }
18562
18563    pub fn toggle_selection_menu(
18564        &mut self,
18565        _: &ToggleSelectionMenu,
18566        _: &mut Window,
18567        cx: &mut Context<Self>,
18568    ) {
18569        self.show_selection_menu = self
18570            .show_selection_menu
18571            .map(|show_selections_menu| !show_selections_menu)
18572            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18573
18574        cx.notify();
18575    }
18576
18577    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18578        self.show_selection_menu
18579            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18580    }
18581
18582    fn start_git_blame(
18583        &mut self,
18584        user_triggered: bool,
18585        window: &mut Window,
18586        cx: &mut Context<Self>,
18587    ) {
18588        if let Some(project) = self.project.as_ref() {
18589            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18590                return;
18591            };
18592
18593            if buffer.read(cx).file().is_none() {
18594                return;
18595            }
18596
18597            let focused = self.focus_handle(cx).contains_focused(window, cx);
18598
18599            let project = project.clone();
18600            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18601            self.blame_subscription =
18602                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18603            self.blame = Some(blame);
18604        }
18605    }
18606
18607    fn toggle_git_blame_inline_internal(
18608        &mut self,
18609        user_triggered: bool,
18610        window: &mut Window,
18611        cx: &mut Context<Self>,
18612    ) {
18613        if self.git_blame_inline_enabled {
18614            self.git_blame_inline_enabled = false;
18615            self.show_git_blame_inline = false;
18616            self.show_git_blame_inline_delay_task.take();
18617        } else {
18618            self.git_blame_inline_enabled = true;
18619            self.start_git_blame_inline(user_triggered, window, cx);
18620        }
18621
18622        cx.notify();
18623    }
18624
18625    fn start_git_blame_inline(
18626        &mut self,
18627        user_triggered: bool,
18628        window: &mut Window,
18629        cx: &mut Context<Self>,
18630    ) {
18631        self.start_git_blame(user_triggered, window, cx);
18632
18633        if ProjectSettings::get_global(cx)
18634            .git
18635            .inline_blame_delay()
18636            .is_some()
18637        {
18638            self.start_inline_blame_timer(window, cx);
18639        } else {
18640            self.show_git_blame_inline = true
18641        }
18642    }
18643
18644    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18645        self.blame.as_ref()
18646    }
18647
18648    pub fn show_git_blame_gutter(&self) -> bool {
18649        self.show_git_blame_gutter
18650    }
18651
18652    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18653        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18654    }
18655
18656    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18657        self.show_git_blame_inline
18658            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18659            && !self.newest_selection_head_on_empty_line(cx)
18660            && self.has_blame_entries(cx)
18661    }
18662
18663    fn has_blame_entries(&self, cx: &App) -> bool {
18664        self.blame()
18665            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18666    }
18667
18668    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18669        let cursor_anchor = self.selections.newest_anchor().head();
18670
18671        let snapshot = self.buffer.read(cx).snapshot(cx);
18672        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18673
18674        snapshot.line_len(buffer_row) == 0
18675    }
18676
18677    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18678        let buffer_and_selection = maybe!({
18679            let selection = self.selections.newest::<Point>(cx);
18680            let selection_range = selection.range();
18681
18682            let multi_buffer = self.buffer().read(cx);
18683            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18684            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18685
18686            let (buffer, range, _) = if selection.reversed {
18687                buffer_ranges.first()
18688            } else {
18689                buffer_ranges.last()
18690            }?;
18691
18692            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18693                ..text::ToPoint::to_point(&range.end, &buffer).row;
18694            Some((
18695                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18696                selection,
18697            ))
18698        });
18699
18700        let Some((buffer, selection)) = buffer_and_selection else {
18701            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18702        };
18703
18704        let Some(project) = self.project.as_ref() else {
18705            return Task::ready(Err(anyhow!("editor does not have project")));
18706        };
18707
18708        project.update(cx, |project, cx| {
18709            project.get_permalink_to_line(&buffer, selection, cx)
18710        })
18711    }
18712
18713    pub fn copy_permalink_to_line(
18714        &mut self,
18715        _: &CopyPermalinkToLine,
18716        window: &mut Window,
18717        cx: &mut Context<Self>,
18718    ) {
18719        let permalink_task = self.get_permalink_to_line(cx);
18720        let workspace = self.workspace();
18721
18722        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18723            Ok(permalink) => {
18724                cx.update(|_, cx| {
18725                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18726                })
18727                .ok();
18728            }
18729            Err(err) => {
18730                let message = format!("Failed to copy permalink: {err}");
18731
18732                anyhow::Result::<()>::Err(err).log_err();
18733
18734                if let Some(workspace) = workspace {
18735                    workspace
18736                        .update_in(cx, |workspace, _, cx| {
18737                            struct CopyPermalinkToLine;
18738
18739                            workspace.show_toast(
18740                                Toast::new(
18741                                    NotificationId::unique::<CopyPermalinkToLine>(),
18742                                    message,
18743                                ),
18744                                cx,
18745                            )
18746                        })
18747                        .ok();
18748                }
18749            }
18750        })
18751        .detach();
18752    }
18753
18754    pub fn copy_file_location(
18755        &mut self,
18756        _: &CopyFileLocation,
18757        _: &mut Window,
18758        cx: &mut Context<Self>,
18759    ) {
18760        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18761        if let Some(file) = self.target_file(cx) {
18762            if let Some(path) = file.path().to_str() {
18763                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18764            }
18765        }
18766    }
18767
18768    pub fn open_permalink_to_line(
18769        &mut self,
18770        _: &OpenPermalinkToLine,
18771        window: &mut Window,
18772        cx: &mut Context<Self>,
18773    ) {
18774        let permalink_task = self.get_permalink_to_line(cx);
18775        let workspace = self.workspace();
18776
18777        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18778            Ok(permalink) => {
18779                cx.update(|_, cx| {
18780                    cx.open_url(permalink.as_ref());
18781                })
18782                .ok();
18783            }
18784            Err(err) => {
18785                let message = format!("Failed to open permalink: {err}");
18786
18787                anyhow::Result::<()>::Err(err).log_err();
18788
18789                if let Some(workspace) = workspace {
18790                    workspace
18791                        .update(cx, |workspace, cx| {
18792                            struct OpenPermalinkToLine;
18793
18794                            workspace.show_toast(
18795                                Toast::new(
18796                                    NotificationId::unique::<OpenPermalinkToLine>(),
18797                                    message,
18798                                ),
18799                                cx,
18800                            )
18801                        })
18802                        .ok();
18803                }
18804            }
18805        })
18806        .detach();
18807    }
18808
18809    pub fn insert_uuid_v4(
18810        &mut self,
18811        _: &InsertUuidV4,
18812        window: &mut Window,
18813        cx: &mut Context<Self>,
18814    ) {
18815        self.insert_uuid(UuidVersion::V4, window, cx);
18816    }
18817
18818    pub fn insert_uuid_v7(
18819        &mut self,
18820        _: &InsertUuidV7,
18821        window: &mut Window,
18822        cx: &mut Context<Self>,
18823    ) {
18824        self.insert_uuid(UuidVersion::V7, window, cx);
18825    }
18826
18827    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18828        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18829        self.transact(window, cx, |this, window, cx| {
18830            let edits = this
18831                .selections
18832                .all::<Point>(cx)
18833                .into_iter()
18834                .map(|selection| {
18835                    let uuid = match version {
18836                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18837                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18838                    };
18839
18840                    (selection.range(), uuid.to_string())
18841                });
18842            this.edit(edits, cx);
18843            this.refresh_inline_completion(true, false, window, cx);
18844        });
18845    }
18846
18847    pub fn open_selections_in_multibuffer(
18848        &mut self,
18849        _: &OpenSelectionsInMultibuffer,
18850        window: &mut Window,
18851        cx: &mut Context<Self>,
18852    ) {
18853        let multibuffer = self.buffer.read(cx);
18854
18855        let Some(buffer) = multibuffer.as_singleton() else {
18856            return;
18857        };
18858
18859        let Some(workspace) = self.workspace() else {
18860            return;
18861        };
18862
18863        let title = multibuffer.title(cx).to_string();
18864
18865        let locations = self
18866            .selections
18867            .all_anchors(cx)
18868            .into_iter()
18869            .map(|selection| Location {
18870                buffer: buffer.clone(),
18871                range: selection.start.text_anchor..selection.end.text_anchor,
18872            })
18873            .collect::<Vec<_>>();
18874
18875        cx.spawn_in(window, async move |_, cx| {
18876            workspace.update_in(cx, |workspace, window, cx| {
18877                Self::open_locations_in_multibuffer(
18878                    workspace,
18879                    locations,
18880                    format!("Selections for '{title}'"),
18881                    false,
18882                    MultibufferSelectionMode::All,
18883                    window,
18884                    cx,
18885                );
18886            })
18887        })
18888        .detach();
18889    }
18890
18891    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18892    /// last highlight added will be used.
18893    ///
18894    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18895    pub fn highlight_rows<T: 'static>(
18896        &mut self,
18897        range: Range<Anchor>,
18898        color: Hsla,
18899        options: RowHighlightOptions,
18900        cx: &mut Context<Self>,
18901    ) {
18902        let snapshot = self.buffer().read(cx).snapshot(cx);
18903        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18904        let ix = row_highlights.binary_search_by(|highlight| {
18905            Ordering::Equal
18906                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18907                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18908        });
18909
18910        if let Err(mut ix) = ix {
18911            let index = post_inc(&mut self.highlight_order);
18912
18913            // If this range intersects with the preceding highlight, then merge it with
18914            // the preceding highlight. Otherwise insert a new highlight.
18915            let mut merged = false;
18916            if ix > 0 {
18917                let prev_highlight = &mut row_highlights[ix - 1];
18918                if prev_highlight
18919                    .range
18920                    .end
18921                    .cmp(&range.start, &snapshot)
18922                    .is_ge()
18923                {
18924                    ix -= 1;
18925                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18926                        prev_highlight.range.end = range.end;
18927                    }
18928                    merged = true;
18929                    prev_highlight.index = index;
18930                    prev_highlight.color = color;
18931                    prev_highlight.options = options;
18932                }
18933            }
18934
18935            if !merged {
18936                row_highlights.insert(
18937                    ix,
18938                    RowHighlight {
18939                        range: range.clone(),
18940                        index,
18941                        color,
18942                        options,
18943                        type_id: TypeId::of::<T>(),
18944                    },
18945                );
18946            }
18947
18948            // If any of the following highlights intersect with this one, merge them.
18949            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18950                let highlight = &row_highlights[ix];
18951                if next_highlight
18952                    .range
18953                    .start
18954                    .cmp(&highlight.range.end, &snapshot)
18955                    .is_le()
18956                {
18957                    if next_highlight
18958                        .range
18959                        .end
18960                        .cmp(&highlight.range.end, &snapshot)
18961                        .is_gt()
18962                    {
18963                        row_highlights[ix].range.end = next_highlight.range.end;
18964                    }
18965                    row_highlights.remove(ix + 1);
18966                } else {
18967                    break;
18968                }
18969            }
18970        }
18971    }
18972
18973    /// Remove any highlighted row ranges of the given type that intersect the
18974    /// given ranges.
18975    pub fn remove_highlighted_rows<T: 'static>(
18976        &mut self,
18977        ranges_to_remove: Vec<Range<Anchor>>,
18978        cx: &mut Context<Self>,
18979    ) {
18980        let snapshot = self.buffer().read(cx).snapshot(cx);
18981        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18982        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18983        row_highlights.retain(|highlight| {
18984            while let Some(range_to_remove) = ranges_to_remove.peek() {
18985                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18986                    Ordering::Less | Ordering::Equal => {
18987                        ranges_to_remove.next();
18988                    }
18989                    Ordering::Greater => {
18990                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18991                            Ordering::Less | Ordering::Equal => {
18992                                return false;
18993                            }
18994                            Ordering::Greater => break,
18995                        }
18996                    }
18997                }
18998            }
18999
19000            true
19001        })
19002    }
19003
19004    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19005    pub fn clear_row_highlights<T: 'static>(&mut self) {
19006        self.highlighted_rows.remove(&TypeId::of::<T>());
19007    }
19008
19009    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19010    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19011        self.highlighted_rows
19012            .get(&TypeId::of::<T>())
19013            .map_or(&[] as &[_], |vec| vec.as_slice())
19014            .iter()
19015            .map(|highlight| (highlight.range.clone(), highlight.color))
19016    }
19017
19018    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19019    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19020    /// Allows to ignore certain kinds of highlights.
19021    pub fn highlighted_display_rows(
19022        &self,
19023        window: &mut Window,
19024        cx: &mut App,
19025    ) -> BTreeMap<DisplayRow, LineHighlight> {
19026        let snapshot = self.snapshot(window, cx);
19027        let mut used_highlight_orders = HashMap::default();
19028        self.highlighted_rows
19029            .iter()
19030            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19031            .fold(
19032                BTreeMap::<DisplayRow, LineHighlight>::new(),
19033                |mut unique_rows, highlight| {
19034                    let start = highlight.range.start.to_display_point(&snapshot);
19035                    let end = highlight.range.end.to_display_point(&snapshot);
19036                    let start_row = start.row().0;
19037                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19038                        && end.column() == 0
19039                    {
19040                        end.row().0.saturating_sub(1)
19041                    } else {
19042                        end.row().0
19043                    };
19044                    for row in start_row..=end_row {
19045                        let used_index =
19046                            used_highlight_orders.entry(row).or_insert(highlight.index);
19047                        if highlight.index >= *used_index {
19048                            *used_index = highlight.index;
19049                            unique_rows.insert(
19050                                DisplayRow(row),
19051                                LineHighlight {
19052                                    include_gutter: highlight.options.include_gutter,
19053                                    border: None,
19054                                    background: highlight.color.into(),
19055                                    type_id: Some(highlight.type_id),
19056                                },
19057                            );
19058                        }
19059                    }
19060                    unique_rows
19061                },
19062            )
19063    }
19064
19065    pub fn highlighted_display_row_for_autoscroll(
19066        &self,
19067        snapshot: &DisplaySnapshot,
19068    ) -> Option<DisplayRow> {
19069        self.highlighted_rows
19070            .values()
19071            .flat_map(|highlighted_rows| highlighted_rows.iter())
19072            .filter_map(|highlight| {
19073                if highlight.options.autoscroll {
19074                    Some(highlight.range.start.to_display_point(snapshot).row())
19075                } else {
19076                    None
19077                }
19078            })
19079            .min()
19080    }
19081
19082    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19083        self.highlight_background::<SearchWithinRange>(
19084            ranges,
19085            |colors| colors.colors().editor_document_highlight_read_background,
19086            cx,
19087        )
19088    }
19089
19090    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19091        self.breadcrumb_header = Some(new_header);
19092    }
19093
19094    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19095        self.clear_background_highlights::<SearchWithinRange>(cx);
19096    }
19097
19098    pub fn highlight_background<T: 'static>(
19099        &mut self,
19100        ranges: &[Range<Anchor>],
19101        color_fetcher: fn(&Theme) -> Hsla,
19102        cx: &mut Context<Self>,
19103    ) {
19104        self.background_highlights.insert(
19105            HighlightKey::Type(TypeId::of::<T>()),
19106            (color_fetcher, Arc::from(ranges)),
19107        );
19108        self.scrollbar_marker_state.dirty = true;
19109        cx.notify();
19110    }
19111
19112    pub fn highlight_background_key<T: 'static>(
19113        &mut self,
19114        key: usize,
19115        ranges: &[Range<Anchor>],
19116        color_fetcher: fn(&Theme) -> Hsla,
19117        cx: &mut Context<Self>,
19118    ) {
19119        self.background_highlights.insert(
19120            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19121            (color_fetcher, Arc::from(ranges)),
19122        );
19123        self.scrollbar_marker_state.dirty = true;
19124        cx.notify();
19125    }
19126
19127    pub fn clear_background_highlights<T: 'static>(
19128        &mut self,
19129        cx: &mut Context<Self>,
19130    ) -> Option<BackgroundHighlight> {
19131        let text_highlights = self
19132            .background_highlights
19133            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19134        if !text_highlights.1.is_empty() {
19135            self.scrollbar_marker_state.dirty = true;
19136            cx.notify();
19137        }
19138        Some(text_highlights)
19139    }
19140
19141    pub fn highlight_gutter<T: 'static>(
19142        &mut self,
19143        ranges: impl Into<Vec<Range<Anchor>>>,
19144        color_fetcher: fn(&App) -> Hsla,
19145        cx: &mut Context<Self>,
19146    ) {
19147        self.gutter_highlights
19148            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19149        cx.notify();
19150    }
19151
19152    pub fn clear_gutter_highlights<T: 'static>(
19153        &mut self,
19154        cx: &mut Context<Self>,
19155    ) -> Option<GutterHighlight> {
19156        cx.notify();
19157        self.gutter_highlights.remove(&TypeId::of::<T>())
19158    }
19159
19160    pub fn insert_gutter_highlight<T: 'static>(
19161        &mut self,
19162        range: Range<Anchor>,
19163        color_fetcher: fn(&App) -> Hsla,
19164        cx: &mut Context<Self>,
19165    ) {
19166        let snapshot = self.buffer().read(cx).snapshot(cx);
19167        let mut highlights = self
19168            .gutter_highlights
19169            .remove(&TypeId::of::<T>())
19170            .map(|(_, highlights)| highlights)
19171            .unwrap_or_default();
19172        let ix = highlights.binary_search_by(|highlight| {
19173            Ordering::Equal
19174                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19175                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19176        });
19177        if let Err(ix) = ix {
19178            highlights.insert(ix, range);
19179        }
19180        self.gutter_highlights
19181            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19182    }
19183
19184    pub fn remove_gutter_highlights<T: 'static>(
19185        &mut self,
19186        ranges_to_remove: Vec<Range<Anchor>>,
19187        cx: &mut Context<Self>,
19188    ) {
19189        let snapshot = self.buffer().read(cx).snapshot(cx);
19190        let Some((color_fetcher, mut gutter_highlights)) =
19191            self.gutter_highlights.remove(&TypeId::of::<T>())
19192        else {
19193            return;
19194        };
19195        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19196        gutter_highlights.retain(|highlight| {
19197            while let Some(range_to_remove) = ranges_to_remove.peek() {
19198                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19199                    Ordering::Less | Ordering::Equal => {
19200                        ranges_to_remove.next();
19201                    }
19202                    Ordering::Greater => {
19203                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19204                            Ordering::Less | Ordering::Equal => {
19205                                return false;
19206                            }
19207                            Ordering::Greater => break,
19208                        }
19209                    }
19210                }
19211            }
19212
19213            true
19214        });
19215        self.gutter_highlights
19216            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19217    }
19218
19219    #[cfg(feature = "test-support")]
19220    pub fn all_text_highlights(
19221        &self,
19222        window: &mut Window,
19223        cx: &mut Context<Self>,
19224    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19225        let snapshot = self.snapshot(window, cx);
19226        self.display_map.update(cx, |display_map, _| {
19227            display_map
19228                .all_text_highlights()
19229                .map(|highlight| {
19230                    let (style, ranges) = highlight.as_ref();
19231                    (
19232                        *style,
19233                        ranges
19234                            .iter()
19235                            .map(|range| range.clone().to_display_points(&snapshot))
19236                            .collect(),
19237                    )
19238                })
19239                .collect()
19240        })
19241    }
19242
19243    #[cfg(feature = "test-support")]
19244    pub fn all_text_background_highlights(
19245        &self,
19246        window: &mut Window,
19247        cx: &mut Context<Self>,
19248    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19249        let snapshot = self.snapshot(window, cx);
19250        let buffer = &snapshot.buffer_snapshot;
19251        let start = buffer.anchor_before(0);
19252        let end = buffer.anchor_after(buffer.len());
19253        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19254    }
19255
19256    #[cfg(feature = "test-support")]
19257    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19258        let snapshot = self.buffer().read(cx).snapshot(cx);
19259
19260        let highlights = self
19261            .background_highlights
19262            .get(&HighlightKey::Type(TypeId::of::<
19263                items::BufferSearchHighlights,
19264            >()));
19265
19266        if let Some((_color, ranges)) = highlights {
19267            ranges
19268                .iter()
19269                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19270                .collect_vec()
19271        } else {
19272            vec![]
19273        }
19274    }
19275
19276    fn document_highlights_for_position<'a>(
19277        &'a self,
19278        position: Anchor,
19279        buffer: &'a MultiBufferSnapshot,
19280    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19281        let read_highlights = self
19282            .background_highlights
19283            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19284            .map(|h| &h.1);
19285        let write_highlights = self
19286            .background_highlights
19287            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19288            .map(|h| &h.1);
19289        let left_position = position.bias_left(buffer);
19290        let right_position = position.bias_right(buffer);
19291        read_highlights
19292            .into_iter()
19293            .chain(write_highlights)
19294            .flat_map(move |ranges| {
19295                let start_ix = match ranges.binary_search_by(|probe| {
19296                    let cmp = probe.end.cmp(&left_position, buffer);
19297                    if cmp.is_ge() {
19298                        Ordering::Greater
19299                    } else {
19300                        Ordering::Less
19301                    }
19302                }) {
19303                    Ok(i) | Err(i) => i,
19304                };
19305
19306                ranges[start_ix..]
19307                    .iter()
19308                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19309            })
19310    }
19311
19312    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19313        self.background_highlights
19314            .get(&HighlightKey::Type(TypeId::of::<T>()))
19315            .map_or(false, |(_, highlights)| !highlights.is_empty())
19316    }
19317
19318    pub fn background_highlights_in_range(
19319        &self,
19320        search_range: Range<Anchor>,
19321        display_snapshot: &DisplaySnapshot,
19322        theme: &Theme,
19323    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19324        let mut results = Vec::new();
19325        for (color_fetcher, ranges) in self.background_highlights.values() {
19326            let color = color_fetcher(theme);
19327            let start_ix = match ranges.binary_search_by(|probe| {
19328                let cmp = probe
19329                    .end
19330                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19331                if cmp.is_gt() {
19332                    Ordering::Greater
19333                } else {
19334                    Ordering::Less
19335                }
19336            }) {
19337                Ok(i) | Err(i) => i,
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
19348                let start = range.start.to_display_point(display_snapshot);
19349                let end = range.end.to_display_point(display_snapshot);
19350                results.push((start..end, color))
19351            }
19352        }
19353        results
19354    }
19355
19356    pub fn background_highlight_row_ranges<T: 'static>(
19357        &self,
19358        search_range: Range<Anchor>,
19359        display_snapshot: &DisplaySnapshot,
19360        count: usize,
19361    ) -> Vec<RangeInclusive<DisplayPoint>> {
19362        let mut results = Vec::new();
19363        let Some((_, ranges)) = self
19364            .background_highlights
19365            .get(&HighlightKey::Type(TypeId::of::<T>()))
19366        else {
19367            return vec![];
19368        };
19369
19370        let start_ix = match ranges.binary_search_by(|probe| {
19371            let cmp = probe
19372                .end
19373                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19374            if cmp.is_gt() {
19375                Ordering::Greater
19376            } else {
19377                Ordering::Less
19378            }
19379        }) {
19380            Ok(i) | Err(i) => i,
19381        };
19382        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19383            if let (Some(start_display), Some(end_display)) = (start, end) {
19384                results.push(
19385                    start_display.to_display_point(display_snapshot)
19386                        ..=end_display.to_display_point(display_snapshot),
19387                );
19388            }
19389        };
19390        let mut start_row: Option<Point> = None;
19391        let mut end_row: Option<Point> = None;
19392        if ranges.len() > count {
19393            return Vec::new();
19394        }
19395        for range in &ranges[start_ix..] {
19396            if range
19397                .start
19398                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19399                .is_ge()
19400            {
19401                break;
19402            }
19403            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19404            if let Some(current_row) = &end_row {
19405                if end.row == current_row.row {
19406                    continue;
19407                }
19408            }
19409            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19410            if start_row.is_none() {
19411                assert_eq!(end_row, None);
19412                start_row = Some(start);
19413                end_row = Some(end);
19414                continue;
19415            }
19416            if let Some(current_end) = end_row.as_mut() {
19417                if start.row > current_end.row + 1 {
19418                    push_region(start_row, end_row);
19419                    start_row = Some(start);
19420                    end_row = Some(end);
19421                } else {
19422                    // Merge two hunks.
19423                    *current_end = end;
19424                }
19425            } else {
19426                unreachable!();
19427            }
19428        }
19429        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19430        push_region(start_row, end_row);
19431        results
19432    }
19433
19434    pub fn gutter_highlights_in_range(
19435        &self,
19436        search_range: Range<Anchor>,
19437        display_snapshot: &DisplaySnapshot,
19438        cx: &App,
19439    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19440        let mut results = Vec::new();
19441        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19442            let color = color_fetcher(cx);
19443            let start_ix = match ranges.binary_search_by(|probe| {
19444                let cmp = probe
19445                    .end
19446                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19447                if cmp.is_gt() {
19448                    Ordering::Greater
19449                } else {
19450                    Ordering::Less
19451                }
19452            }) {
19453                Ok(i) | Err(i) => i,
19454            };
19455            for range in &ranges[start_ix..] {
19456                if range
19457                    .start
19458                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19459                    .is_ge()
19460                {
19461                    break;
19462                }
19463
19464                let start = range.start.to_display_point(display_snapshot);
19465                let end = range.end.to_display_point(display_snapshot);
19466                results.push((start..end, color))
19467            }
19468        }
19469        results
19470    }
19471
19472    /// Get the text ranges corresponding to the redaction query
19473    pub fn redacted_ranges(
19474        &self,
19475        search_range: Range<Anchor>,
19476        display_snapshot: &DisplaySnapshot,
19477        cx: &App,
19478    ) -> Vec<Range<DisplayPoint>> {
19479        display_snapshot
19480            .buffer_snapshot
19481            .redacted_ranges(search_range, |file| {
19482                if let Some(file) = file {
19483                    file.is_private()
19484                        && EditorSettings::get(
19485                            Some(SettingsLocation {
19486                                worktree_id: file.worktree_id(cx),
19487                                path: file.path().as_ref(),
19488                            }),
19489                            cx,
19490                        )
19491                        .redact_private_values
19492                } else {
19493                    false
19494                }
19495            })
19496            .map(|range| {
19497                range.start.to_display_point(display_snapshot)
19498                    ..range.end.to_display_point(display_snapshot)
19499            })
19500            .collect()
19501    }
19502
19503    pub fn highlight_text_key<T: 'static>(
19504        &mut self,
19505        key: usize,
19506        ranges: Vec<Range<Anchor>>,
19507        style: HighlightStyle,
19508        cx: &mut Context<Self>,
19509    ) {
19510        self.display_map.update(cx, |map, _| {
19511            map.highlight_text(
19512                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19513                ranges,
19514                style,
19515            );
19516        });
19517        cx.notify();
19518    }
19519
19520    pub fn highlight_text<T: 'static>(
19521        &mut self,
19522        ranges: Vec<Range<Anchor>>,
19523        style: HighlightStyle,
19524        cx: &mut Context<Self>,
19525    ) {
19526        self.display_map.update(cx, |map, _| {
19527            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19528        });
19529        cx.notify();
19530    }
19531
19532    pub(crate) fn highlight_inlays<T: 'static>(
19533        &mut self,
19534        highlights: Vec<InlayHighlight>,
19535        style: HighlightStyle,
19536        cx: &mut Context<Self>,
19537    ) {
19538        self.display_map.update(cx, |map, _| {
19539            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19540        });
19541        cx.notify();
19542    }
19543
19544    pub fn text_highlights<'a, T: 'static>(
19545        &'a self,
19546        cx: &'a App,
19547    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19548        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19549    }
19550
19551    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19552        let cleared = self
19553            .display_map
19554            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19555        if cleared {
19556            cx.notify();
19557        }
19558    }
19559
19560    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19561        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19562            && self.focus_handle.is_focused(window)
19563    }
19564
19565    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19566        self.show_cursor_when_unfocused = is_enabled;
19567        cx.notify();
19568    }
19569
19570    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19571        cx.notify();
19572    }
19573
19574    fn on_debug_session_event(
19575        &mut self,
19576        _session: Entity<Session>,
19577        event: &SessionEvent,
19578        cx: &mut Context<Self>,
19579    ) {
19580        match event {
19581            SessionEvent::InvalidateInlineValue => {
19582                self.refresh_inline_values(cx);
19583            }
19584            _ => {}
19585        }
19586    }
19587
19588    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19589        let Some(project) = self.project.clone() else {
19590            return;
19591        };
19592
19593        if !self.inline_value_cache.enabled {
19594            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19595            self.splice_inlays(&inlays, Vec::new(), cx);
19596            return;
19597        }
19598
19599        let current_execution_position = self
19600            .highlighted_rows
19601            .get(&TypeId::of::<ActiveDebugLine>())
19602            .and_then(|lines| lines.last().map(|line| line.range.end));
19603
19604        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19605            let inline_values = editor
19606                .update(cx, |editor, cx| {
19607                    let Some(current_execution_position) = current_execution_position else {
19608                        return Some(Task::ready(Ok(Vec::new())));
19609                    };
19610
19611                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19612                        let snapshot = buffer.snapshot(cx);
19613
19614                        let excerpt = snapshot.excerpt_containing(
19615                            current_execution_position..current_execution_position,
19616                        )?;
19617
19618                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19619                    })?;
19620
19621                    let range =
19622                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19623
19624                    project.inline_values(buffer, range, cx)
19625                })
19626                .ok()
19627                .flatten()?
19628                .await
19629                .context("refreshing debugger inlays")
19630                .log_err()?;
19631
19632            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19633
19634            for (buffer_id, inline_value) in inline_values
19635                .into_iter()
19636                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19637            {
19638                buffer_inline_values
19639                    .entry(buffer_id)
19640                    .or_default()
19641                    .push(inline_value);
19642            }
19643
19644            editor
19645                .update(cx, |editor, cx| {
19646                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19647                    let mut new_inlays = Vec::default();
19648
19649                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19650                        let buffer_id = buffer_snapshot.remote_id();
19651                        buffer_inline_values
19652                            .get(&buffer_id)
19653                            .into_iter()
19654                            .flatten()
19655                            .for_each(|hint| {
19656                                let inlay = Inlay::debugger(
19657                                    post_inc(&mut editor.next_inlay_id),
19658                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19659                                    hint.text(),
19660                                );
19661                                if !inlay.text.chars().contains(&'\n') {
19662                                    new_inlays.push(inlay);
19663                                }
19664                            });
19665                    }
19666
19667                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19668                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19669
19670                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19671                })
19672                .ok()?;
19673            Some(())
19674        });
19675    }
19676
19677    fn on_buffer_event(
19678        &mut self,
19679        multibuffer: &Entity<MultiBuffer>,
19680        event: &multi_buffer::Event,
19681        window: &mut Window,
19682        cx: &mut Context<Self>,
19683    ) {
19684        match event {
19685            multi_buffer::Event::Edited {
19686                singleton_buffer_edited,
19687                edited_buffer,
19688            } => {
19689                self.scrollbar_marker_state.dirty = true;
19690                self.active_indent_guides_state.dirty = true;
19691                self.refresh_active_diagnostics(cx);
19692                self.refresh_code_actions(window, cx);
19693                self.refresh_selected_text_highlights(true, window, cx);
19694                self.refresh_single_line_folds(window, cx);
19695                refresh_matching_bracket_highlights(self, window, cx);
19696                if self.has_active_inline_completion() {
19697                    self.update_visible_inline_completion(window, cx);
19698                }
19699                if let Some(project) = self.project.as_ref() {
19700                    if let Some(edited_buffer) = edited_buffer {
19701                        project.update(cx, |project, cx| {
19702                            self.registered_buffers
19703                                .entry(edited_buffer.read(cx).remote_id())
19704                                .or_insert_with(|| {
19705                                    project
19706                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19707                                });
19708                        });
19709                    }
19710                }
19711                cx.emit(EditorEvent::BufferEdited);
19712                cx.emit(SearchEvent::MatchesInvalidated);
19713
19714                if let Some(buffer) = edited_buffer {
19715                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19716                }
19717
19718                if *singleton_buffer_edited {
19719                    if let Some(buffer) = edited_buffer {
19720                        if buffer.read(cx).file().is_none() {
19721                            cx.emit(EditorEvent::TitleChanged);
19722                        }
19723                    }
19724                    if let Some(project) = &self.project {
19725                        #[allow(clippy::mutable_key_type)]
19726                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19727                            multibuffer
19728                                .all_buffers()
19729                                .into_iter()
19730                                .filter_map(|buffer| {
19731                                    buffer.update(cx, |buffer, cx| {
19732                                        let language = buffer.language()?;
19733                                        let should_discard = project.update(cx, |project, cx| {
19734                                            project.is_local()
19735                                                && !project.has_language_servers_for(buffer, cx)
19736                                        });
19737                                        should_discard.not().then_some(language.clone())
19738                                    })
19739                                })
19740                                .collect::<HashSet<_>>()
19741                        });
19742                        if !languages_affected.is_empty() {
19743                            self.refresh_inlay_hints(
19744                                InlayHintRefreshReason::BufferEdited(languages_affected),
19745                                cx,
19746                            );
19747                        }
19748                    }
19749                }
19750
19751                let Some(project) = &self.project else { return };
19752                let (telemetry, is_via_ssh) = {
19753                    let project = project.read(cx);
19754                    let telemetry = project.client().telemetry().clone();
19755                    let is_via_ssh = project.is_via_ssh();
19756                    (telemetry, is_via_ssh)
19757                };
19758                refresh_linked_ranges(self, window, cx);
19759                telemetry.log_edit_event("editor", is_via_ssh);
19760            }
19761            multi_buffer::Event::ExcerptsAdded {
19762                buffer,
19763                predecessor,
19764                excerpts,
19765            } => {
19766                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19767                let buffer_id = buffer.read(cx).remote_id();
19768                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19769                    if let Some(project) = &self.project {
19770                        update_uncommitted_diff_for_buffer(
19771                            cx.entity(),
19772                            project,
19773                            [buffer.clone()],
19774                            self.buffer.clone(),
19775                            cx,
19776                        )
19777                        .detach();
19778                    }
19779                }
19780                self.update_lsp_data(false, Some(buffer_id), window, cx);
19781                cx.emit(EditorEvent::ExcerptsAdded {
19782                    buffer: buffer.clone(),
19783                    predecessor: *predecessor,
19784                    excerpts: excerpts.clone(),
19785                });
19786                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19787            }
19788            multi_buffer::Event::ExcerptsRemoved {
19789                ids,
19790                removed_buffer_ids,
19791            } => {
19792                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19793                let buffer = self.buffer.read(cx);
19794                self.registered_buffers
19795                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19796                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19797                cx.emit(EditorEvent::ExcerptsRemoved {
19798                    ids: ids.clone(),
19799                    removed_buffer_ids: removed_buffer_ids.clone(),
19800                });
19801            }
19802            multi_buffer::Event::ExcerptsEdited {
19803                excerpt_ids,
19804                buffer_ids,
19805            } => {
19806                self.display_map.update(cx, |map, cx| {
19807                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19808                });
19809                cx.emit(EditorEvent::ExcerptsEdited {
19810                    ids: excerpt_ids.clone(),
19811                });
19812            }
19813            multi_buffer::Event::ExcerptsExpanded { ids } => {
19814                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19815                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19816            }
19817            multi_buffer::Event::Reparsed(buffer_id) => {
19818                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19819                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19820
19821                cx.emit(EditorEvent::Reparsed(*buffer_id));
19822            }
19823            multi_buffer::Event::DiffHunksToggled => {
19824                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19825            }
19826            multi_buffer::Event::LanguageChanged(buffer_id) => {
19827                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19828                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19829                cx.emit(EditorEvent::Reparsed(*buffer_id));
19830                cx.notify();
19831            }
19832            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19833            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19834            multi_buffer::Event::FileHandleChanged
19835            | multi_buffer::Event::Reloaded
19836            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19837            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19838            multi_buffer::Event::DiagnosticsUpdated => {
19839                self.update_diagnostics_state(window, cx);
19840            }
19841            _ => {}
19842        };
19843    }
19844
19845    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19846        if !self.diagnostics_enabled() {
19847            return;
19848        }
19849        self.refresh_active_diagnostics(cx);
19850        self.refresh_inline_diagnostics(true, window, cx);
19851        self.scrollbar_marker_state.dirty = true;
19852        cx.notify();
19853    }
19854
19855    pub fn start_temporary_diff_override(&mut self) {
19856        self.load_diff_task.take();
19857        self.temporary_diff_override = true;
19858    }
19859
19860    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19861        self.temporary_diff_override = false;
19862        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19863        self.buffer.update(cx, |buffer, cx| {
19864            buffer.set_all_diff_hunks_collapsed(cx);
19865        });
19866
19867        if let Some(project) = self.project.clone() {
19868            self.load_diff_task = Some(
19869                update_uncommitted_diff_for_buffer(
19870                    cx.entity(),
19871                    &project,
19872                    self.buffer.read(cx).all_buffers(),
19873                    self.buffer.clone(),
19874                    cx,
19875                )
19876                .shared(),
19877            );
19878        }
19879    }
19880
19881    fn on_display_map_changed(
19882        &mut self,
19883        _: Entity<DisplayMap>,
19884        _: &mut Window,
19885        cx: &mut Context<Self>,
19886    ) {
19887        cx.notify();
19888    }
19889
19890    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19891        let new_severity = if self.diagnostics_enabled() {
19892            EditorSettings::get_global(cx)
19893                .diagnostics_max_severity
19894                .unwrap_or(DiagnosticSeverity::Hint)
19895        } else {
19896            DiagnosticSeverity::Off
19897        };
19898        self.set_max_diagnostics_severity(new_severity, cx);
19899        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19900        self.update_edit_prediction_settings(cx);
19901        self.refresh_inline_completion(true, false, window, cx);
19902        self.refresh_inline_values(cx);
19903        self.refresh_inlay_hints(
19904            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19905                self.selections.newest_anchor().head(),
19906                &self.buffer.read(cx).snapshot(cx),
19907                cx,
19908            )),
19909            cx,
19910        );
19911
19912        let old_cursor_shape = self.cursor_shape;
19913
19914        {
19915            let editor_settings = EditorSettings::get_global(cx);
19916            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19917            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19918            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19919            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19920        }
19921
19922        if old_cursor_shape != self.cursor_shape {
19923            cx.emit(EditorEvent::CursorShapeChanged);
19924        }
19925
19926        let project_settings = ProjectSettings::get_global(cx);
19927        self.serialize_dirty_buffers =
19928            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19929
19930        if self.mode.is_full() {
19931            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19932            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19933            if self.show_inline_diagnostics != show_inline_diagnostics {
19934                self.show_inline_diagnostics = show_inline_diagnostics;
19935                self.refresh_inline_diagnostics(false, window, cx);
19936            }
19937
19938            if self.git_blame_inline_enabled != inline_blame_enabled {
19939                self.toggle_git_blame_inline_internal(false, window, cx);
19940            }
19941
19942            let minimap_settings = EditorSettings::get_global(cx).minimap;
19943            if self.minimap_visibility != MinimapVisibility::Disabled {
19944                if self.minimap_visibility.settings_visibility()
19945                    != minimap_settings.minimap_enabled()
19946                {
19947                    self.set_minimap_visibility(
19948                        MinimapVisibility::for_mode(self.mode(), cx),
19949                        window,
19950                        cx,
19951                    );
19952                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19953                    minimap_entity.update(cx, |minimap_editor, cx| {
19954                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19955                    })
19956                }
19957            }
19958        }
19959
19960        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19961            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19962        }) {
19963            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19964                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19965            }
19966            self.refresh_colors(false, None, window, cx);
19967        }
19968
19969        cx.notify();
19970    }
19971
19972    pub fn set_searchable(&mut self, searchable: bool) {
19973        self.searchable = searchable;
19974    }
19975
19976    pub fn searchable(&self) -> bool {
19977        self.searchable
19978    }
19979
19980    fn open_proposed_changes_editor(
19981        &mut self,
19982        _: &OpenProposedChangesEditor,
19983        window: &mut Window,
19984        cx: &mut Context<Self>,
19985    ) {
19986        let Some(workspace) = self.workspace() else {
19987            cx.propagate();
19988            return;
19989        };
19990
19991        let selections = self.selections.all::<usize>(cx);
19992        let multi_buffer = self.buffer.read(cx);
19993        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19994        let mut new_selections_by_buffer = HashMap::default();
19995        for selection in selections {
19996            for (buffer, range, _) in
19997                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19998            {
19999                let mut range = range.to_point(buffer);
20000                range.start.column = 0;
20001                range.end.column = buffer.line_len(range.end.row);
20002                new_selections_by_buffer
20003                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20004                    .or_insert(Vec::new())
20005                    .push(range)
20006            }
20007        }
20008
20009        let proposed_changes_buffers = new_selections_by_buffer
20010            .into_iter()
20011            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20012            .collect::<Vec<_>>();
20013        let proposed_changes_editor = cx.new(|cx| {
20014            ProposedChangesEditor::new(
20015                "Proposed changes",
20016                proposed_changes_buffers,
20017                self.project.clone(),
20018                window,
20019                cx,
20020            )
20021        });
20022
20023        window.defer(cx, move |window, cx| {
20024            workspace.update(cx, |workspace, cx| {
20025                workspace.active_pane().update(cx, |pane, cx| {
20026                    pane.add_item(
20027                        Box::new(proposed_changes_editor),
20028                        true,
20029                        true,
20030                        None,
20031                        window,
20032                        cx,
20033                    );
20034                });
20035            });
20036        });
20037    }
20038
20039    pub fn open_excerpts_in_split(
20040        &mut self,
20041        _: &OpenExcerptsSplit,
20042        window: &mut Window,
20043        cx: &mut Context<Self>,
20044    ) {
20045        self.open_excerpts_common(None, true, window, cx)
20046    }
20047
20048    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20049        self.open_excerpts_common(None, false, window, cx)
20050    }
20051
20052    fn open_excerpts_common(
20053        &mut self,
20054        jump_data: Option<JumpData>,
20055        split: bool,
20056        window: &mut Window,
20057        cx: &mut Context<Self>,
20058    ) {
20059        let Some(workspace) = self.workspace() else {
20060            cx.propagate();
20061            return;
20062        };
20063
20064        if self.buffer.read(cx).is_singleton() {
20065            cx.propagate();
20066            return;
20067        }
20068
20069        let mut new_selections_by_buffer = HashMap::default();
20070        match &jump_data {
20071            Some(JumpData::MultiBufferPoint {
20072                excerpt_id,
20073                position,
20074                anchor,
20075                line_offset_from_top,
20076            }) => {
20077                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20078                if let Some(buffer) = multi_buffer_snapshot
20079                    .buffer_id_for_excerpt(*excerpt_id)
20080                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20081                {
20082                    let buffer_snapshot = buffer.read(cx).snapshot();
20083                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20084                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20085                    } else {
20086                        buffer_snapshot.clip_point(*position, Bias::Left)
20087                    };
20088                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20089                    new_selections_by_buffer.insert(
20090                        buffer,
20091                        (
20092                            vec![jump_to_offset..jump_to_offset],
20093                            Some(*line_offset_from_top),
20094                        ),
20095                    );
20096                }
20097            }
20098            Some(JumpData::MultiBufferRow {
20099                row,
20100                line_offset_from_top,
20101            }) => {
20102                let point = MultiBufferPoint::new(row.0, 0);
20103                if let Some((buffer, buffer_point, _)) =
20104                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20105                {
20106                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20107                    new_selections_by_buffer
20108                        .entry(buffer)
20109                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20110                        .0
20111                        .push(buffer_offset..buffer_offset)
20112                }
20113            }
20114            None => {
20115                let selections = self.selections.all::<usize>(cx);
20116                let multi_buffer = self.buffer.read(cx);
20117                for selection in selections {
20118                    for (snapshot, range, _, anchor) in multi_buffer
20119                        .snapshot(cx)
20120                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20121                    {
20122                        if let Some(anchor) = anchor {
20123                            // selection is in a deleted hunk
20124                            let Some(buffer_id) = anchor.buffer_id else {
20125                                continue;
20126                            };
20127                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20128                                continue;
20129                            };
20130                            let offset = text::ToOffset::to_offset(
20131                                &anchor.text_anchor,
20132                                &buffer_handle.read(cx).snapshot(),
20133                            );
20134                            let range = offset..offset;
20135                            new_selections_by_buffer
20136                                .entry(buffer_handle)
20137                                .or_insert((Vec::new(), None))
20138                                .0
20139                                .push(range)
20140                        } else {
20141                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20142                            else {
20143                                continue;
20144                            };
20145                            new_selections_by_buffer
20146                                .entry(buffer_handle)
20147                                .or_insert((Vec::new(), None))
20148                                .0
20149                                .push(range)
20150                        }
20151                    }
20152                }
20153            }
20154        }
20155
20156        new_selections_by_buffer
20157            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20158
20159        if new_selections_by_buffer.is_empty() {
20160            return;
20161        }
20162
20163        // We defer the pane interaction because we ourselves are a workspace item
20164        // and activating a new item causes the pane to call a method on us reentrantly,
20165        // which panics if we're on the stack.
20166        window.defer(cx, move |window, cx| {
20167            workspace.update(cx, |workspace, cx| {
20168                let pane = if split {
20169                    workspace.adjacent_pane(window, cx)
20170                } else {
20171                    workspace.active_pane().clone()
20172                };
20173
20174                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20175                    let editor = buffer
20176                        .read(cx)
20177                        .file()
20178                        .is_none()
20179                        .then(|| {
20180                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20181                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20182                            // Instead, we try to activate the existing editor in the pane first.
20183                            let (editor, pane_item_index) =
20184                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20185                                    let editor = item.downcast::<Editor>()?;
20186                                    let singleton_buffer =
20187                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20188                                    if singleton_buffer == buffer {
20189                                        Some((editor, i))
20190                                    } else {
20191                                        None
20192                                    }
20193                                })?;
20194                            pane.update(cx, |pane, cx| {
20195                                pane.activate_item(pane_item_index, true, true, window, cx)
20196                            });
20197                            Some(editor)
20198                        })
20199                        .flatten()
20200                        .unwrap_or_else(|| {
20201                            workspace.open_project_item::<Self>(
20202                                pane.clone(),
20203                                buffer,
20204                                true,
20205                                true,
20206                                window,
20207                                cx,
20208                            )
20209                        });
20210
20211                    editor.update(cx, |editor, cx| {
20212                        let autoscroll = match scroll_offset {
20213                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20214                            None => Autoscroll::newest(),
20215                        };
20216                        let nav_history = editor.nav_history.take();
20217                        editor.change_selections(
20218                            SelectionEffects::scroll(autoscroll),
20219                            window,
20220                            cx,
20221                            |s| {
20222                                s.select_ranges(ranges);
20223                            },
20224                        );
20225                        editor.nav_history = nav_history;
20226                    });
20227                }
20228            })
20229        });
20230    }
20231
20232    // For now, don't allow opening excerpts in buffers that aren't backed by
20233    // regular project files.
20234    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20235        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20236    }
20237
20238    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20239        let snapshot = self.buffer.read(cx).read(cx);
20240        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20241        Some(
20242            ranges
20243                .iter()
20244                .map(move |range| {
20245                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20246                })
20247                .collect(),
20248        )
20249    }
20250
20251    fn selection_replacement_ranges(
20252        &self,
20253        range: Range<OffsetUtf16>,
20254        cx: &mut App,
20255    ) -> Vec<Range<OffsetUtf16>> {
20256        let selections = self.selections.all::<OffsetUtf16>(cx);
20257        let newest_selection = selections
20258            .iter()
20259            .max_by_key(|selection| selection.id)
20260            .unwrap();
20261        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20262        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20263        let snapshot = self.buffer.read(cx).read(cx);
20264        selections
20265            .into_iter()
20266            .map(|mut selection| {
20267                selection.start.0 =
20268                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20269                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20270                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20271                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20272            })
20273            .collect()
20274    }
20275
20276    fn report_editor_event(
20277        &self,
20278        event_type: &'static str,
20279        file_extension: Option<String>,
20280        cx: &App,
20281    ) {
20282        if cfg!(any(test, feature = "test-support")) {
20283            return;
20284        }
20285
20286        let Some(project) = &self.project else { return };
20287
20288        // If None, we are in a file without an extension
20289        let file = self
20290            .buffer
20291            .read(cx)
20292            .as_singleton()
20293            .and_then(|b| b.read(cx).file());
20294        let file_extension = file_extension.or(file
20295            .as_ref()
20296            .and_then(|file| Path::new(file.file_name(cx)).extension())
20297            .and_then(|e| e.to_str())
20298            .map(|a| a.to_string()));
20299
20300        let vim_mode = vim_enabled(cx);
20301
20302        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20303        let copilot_enabled = edit_predictions_provider
20304            == language::language_settings::EditPredictionProvider::Copilot;
20305        let copilot_enabled_for_language = self
20306            .buffer
20307            .read(cx)
20308            .language_settings(cx)
20309            .show_edit_predictions;
20310
20311        let project = project.read(cx);
20312        telemetry::event!(
20313            event_type,
20314            file_extension,
20315            vim_mode,
20316            copilot_enabled,
20317            copilot_enabled_for_language,
20318            edit_predictions_provider,
20319            is_via_ssh = project.is_via_ssh(),
20320        );
20321    }
20322
20323    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20324    /// with each line being an array of {text, highlight} objects.
20325    fn copy_highlight_json(
20326        &mut self,
20327        _: &CopyHighlightJson,
20328        window: &mut Window,
20329        cx: &mut Context<Self>,
20330    ) {
20331        #[derive(Serialize)]
20332        struct Chunk<'a> {
20333            text: String,
20334            highlight: Option<&'a str>,
20335        }
20336
20337        let snapshot = self.buffer.read(cx).snapshot(cx);
20338        let range = self
20339            .selected_text_range(false, window, cx)
20340            .and_then(|selection| {
20341                if selection.range.is_empty() {
20342                    None
20343                } else {
20344                    Some(selection.range)
20345                }
20346            })
20347            .unwrap_or_else(|| 0..snapshot.len());
20348
20349        let chunks = snapshot.chunks(range, true);
20350        let mut lines = Vec::new();
20351        let mut line: VecDeque<Chunk> = VecDeque::new();
20352
20353        let Some(style) = self.style.as_ref() else {
20354            return;
20355        };
20356
20357        for chunk in chunks {
20358            let highlight = chunk
20359                .syntax_highlight_id
20360                .and_then(|id| id.name(&style.syntax));
20361            let mut chunk_lines = chunk.text.split('\n').peekable();
20362            while let Some(text) = chunk_lines.next() {
20363                let mut merged_with_last_token = false;
20364                if let Some(last_token) = line.back_mut() {
20365                    if last_token.highlight == highlight {
20366                        last_token.text.push_str(text);
20367                        merged_with_last_token = true;
20368                    }
20369                }
20370
20371                if !merged_with_last_token {
20372                    line.push_back(Chunk {
20373                        text: text.into(),
20374                        highlight,
20375                    });
20376                }
20377
20378                if chunk_lines.peek().is_some() {
20379                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20380                        line.pop_front();
20381                    }
20382                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20383                        line.pop_back();
20384                    }
20385
20386                    lines.push(mem::take(&mut line));
20387                }
20388            }
20389        }
20390
20391        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20392            return;
20393        };
20394        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20395    }
20396
20397    pub fn open_context_menu(
20398        &mut self,
20399        _: &OpenContextMenu,
20400        window: &mut Window,
20401        cx: &mut Context<Self>,
20402    ) {
20403        self.request_autoscroll(Autoscroll::newest(), cx);
20404        let position = self.selections.newest_display(cx).start;
20405        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20406    }
20407
20408    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20409        &self.inlay_hint_cache
20410    }
20411
20412    pub fn replay_insert_event(
20413        &mut self,
20414        text: &str,
20415        relative_utf16_range: Option<Range<isize>>,
20416        window: &mut Window,
20417        cx: &mut Context<Self>,
20418    ) {
20419        if !self.input_enabled {
20420            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20421            return;
20422        }
20423        if let Some(relative_utf16_range) = relative_utf16_range {
20424            let selections = self.selections.all::<OffsetUtf16>(cx);
20425            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20426                let new_ranges = selections.into_iter().map(|range| {
20427                    let start = OffsetUtf16(
20428                        range
20429                            .head()
20430                            .0
20431                            .saturating_add_signed(relative_utf16_range.start),
20432                    );
20433                    let end = OffsetUtf16(
20434                        range
20435                            .head()
20436                            .0
20437                            .saturating_add_signed(relative_utf16_range.end),
20438                    );
20439                    start..end
20440                });
20441                s.select_ranges(new_ranges);
20442            });
20443        }
20444
20445        self.handle_input(text, window, cx);
20446    }
20447
20448    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20449        let Some(provider) = self.semantics_provider.as_ref() else {
20450            return false;
20451        };
20452
20453        let mut supports = false;
20454        self.buffer().update(cx, |this, cx| {
20455            this.for_each_buffer(|buffer| {
20456                supports |= provider.supports_inlay_hints(buffer, cx);
20457            });
20458        });
20459
20460        supports
20461    }
20462
20463    pub fn is_focused(&self, window: &Window) -> bool {
20464        self.focus_handle.is_focused(window)
20465    }
20466
20467    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20468        cx.emit(EditorEvent::Focused);
20469
20470        if let Some(descendant) = self
20471            .last_focused_descendant
20472            .take()
20473            .and_then(|descendant| descendant.upgrade())
20474        {
20475            window.focus(&descendant);
20476        } else {
20477            if let Some(blame) = self.blame.as_ref() {
20478                blame.update(cx, GitBlame::focus)
20479            }
20480
20481            self.blink_manager.update(cx, BlinkManager::enable);
20482            self.show_cursor_names(window, cx);
20483            self.buffer.update(cx, |buffer, cx| {
20484                buffer.finalize_last_transaction(cx);
20485                if self.leader_id.is_none() {
20486                    buffer.set_active_selections(
20487                        &self.selections.disjoint_anchors(),
20488                        self.selections.line_mode,
20489                        self.cursor_shape,
20490                        cx,
20491                    );
20492                }
20493            });
20494        }
20495    }
20496
20497    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20498        cx.emit(EditorEvent::FocusedIn)
20499    }
20500
20501    fn handle_focus_out(
20502        &mut self,
20503        event: FocusOutEvent,
20504        _window: &mut Window,
20505        cx: &mut Context<Self>,
20506    ) {
20507        if event.blurred != self.focus_handle {
20508            self.last_focused_descendant = Some(event.blurred);
20509        }
20510        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20511    }
20512
20513    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20514        self.blink_manager.update(cx, BlinkManager::disable);
20515        self.buffer
20516            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20517
20518        if let Some(blame) = self.blame.as_ref() {
20519            blame.update(cx, GitBlame::blur)
20520        }
20521        if !self.hover_state.focused(window, cx) {
20522            hide_hover(self, cx);
20523        }
20524        if !self
20525            .context_menu
20526            .borrow()
20527            .as_ref()
20528            .is_some_and(|context_menu| context_menu.focused(window, cx))
20529        {
20530            self.hide_context_menu(window, cx);
20531        }
20532        self.discard_inline_completion(false, cx);
20533        cx.emit(EditorEvent::Blurred);
20534        cx.notify();
20535    }
20536
20537    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20538        let mut pending: String = window
20539            .pending_input_keystrokes()
20540            .into_iter()
20541            .flatten()
20542            .filter_map(|keystroke| {
20543                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20544                    keystroke.key_char.clone()
20545                } else {
20546                    None
20547                }
20548            })
20549            .collect();
20550
20551        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20552            pending = "".to_string();
20553        }
20554
20555        let existing_pending = self
20556            .text_highlights::<PendingInput>(cx)
20557            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20558        if existing_pending.is_none() && pending.is_empty() {
20559            return;
20560        }
20561        let transaction =
20562            self.transact(window, cx, |this, window, cx| {
20563                let selections = this.selections.all::<usize>(cx);
20564                let edits = selections
20565                    .iter()
20566                    .map(|selection| (selection.end..selection.end, pending.clone()));
20567                this.edit(edits, cx);
20568                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20569                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20570                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20571                    }));
20572                });
20573                if let Some(existing_ranges) = existing_pending {
20574                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20575                    this.edit(edits, cx);
20576                }
20577            });
20578
20579        let snapshot = self.snapshot(window, cx);
20580        let ranges = self
20581            .selections
20582            .all::<usize>(cx)
20583            .into_iter()
20584            .map(|selection| {
20585                snapshot.buffer_snapshot.anchor_after(selection.end)
20586                    ..snapshot
20587                        .buffer_snapshot
20588                        .anchor_before(selection.end + pending.len())
20589            })
20590            .collect();
20591
20592        if pending.is_empty() {
20593            self.clear_highlights::<PendingInput>(cx);
20594        } else {
20595            self.highlight_text::<PendingInput>(
20596                ranges,
20597                HighlightStyle {
20598                    underline: Some(UnderlineStyle {
20599                        thickness: px(1.),
20600                        color: None,
20601                        wavy: false,
20602                    }),
20603                    ..Default::default()
20604                },
20605                cx,
20606            );
20607        }
20608
20609        self.ime_transaction = self.ime_transaction.or(transaction);
20610        if let Some(transaction) = self.ime_transaction {
20611            self.buffer.update(cx, |buffer, cx| {
20612                buffer.group_until_transaction(transaction, cx);
20613            });
20614        }
20615
20616        if self.text_highlights::<PendingInput>(cx).is_none() {
20617            self.ime_transaction.take();
20618        }
20619    }
20620
20621    pub fn register_action_renderer(
20622        &mut self,
20623        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20624    ) -> Subscription {
20625        let id = self.next_editor_action_id.post_inc();
20626        self.editor_actions
20627            .borrow_mut()
20628            .insert(id, Box::new(listener));
20629
20630        let editor_actions = self.editor_actions.clone();
20631        Subscription::new(move || {
20632            editor_actions.borrow_mut().remove(&id);
20633        })
20634    }
20635
20636    pub fn register_action<A: Action>(
20637        &mut self,
20638        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20639    ) -> Subscription {
20640        let id = self.next_editor_action_id.post_inc();
20641        let listener = Arc::new(listener);
20642        self.editor_actions.borrow_mut().insert(
20643            id,
20644            Box::new(move |_, window, _| {
20645                let listener = listener.clone();
20646                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20647                    let action = action.downcast_ref().unwrap();
20648                    if phase == DispatchPhase::Bubble {
20649                        listener(action, window, cx)
20650                    }
20651                })
20652            }),
20653        );
20654
20655        let editor_actions = self.editor_actions.clone();
20656        Subscription::new(move || {
20657            editor_actions.borrow_mut().remove(&id);
20658        })
20659    }
20660
20661    pub fn file_header_size(&self) -> u32 {
20662        FILE_HEADER_HEIGHT
20663    }
20664
20665    pub fn restore(
20666        &mut self,
20667        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20668        window: &mut Window,
20669        cx: &mut Context<Self>,
20670    ) {
20671        let workspace = self.workspace();
20672        let project = self.project.as_ref();
20673        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20674            let mut tasks = Vec::new();
20675            for (buffer_id, changes) in revert_changes {
20676                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20677                    buffer.update(cx, |buffer, cx| {
20678                        buffer.edit(
20679                            changes
20680                                .into_iter()
20681                                .map(|(range, text)| (range, text.to_string())),
20682                            None,
20683                            cx,
20684                        );
20685                    });
20686
20687                    if let Some(project) =
20688                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20689                    {
20690                        project.update(cx, |project, cx| {
20691                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20692                        })
20693                    }
20694                }
20695            }
20696            tasks
20697        });
20698        cx.spawn_in(window, async move |_, cx| {
20699            for (buffer, task) in save_tasks {
20700                let result = task.await;
20701                if result.is_err() {
20702                    let Some(path) = buffer
20703                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20704                        .ok()
20705                    else {
20706                        continue;
20707                    };
20708                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20709                        let Some(task) = cx
20710                            .update_window_entity(&workspace, |workspace, window, cx| {
20711                                workspace
20712                                    .open_path_preview(path, None, false, false, false, window, cx)
20713                            })
20714                            .ok()
20715                        else {
20716                            continue;
20717                        };
20718                        task.await.log_err();
20719                    }
20720                }
20721            }
20722        })
20723        .detach();
20724        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20725            selections.refresh()
20726        });
20727    }
20728
20729    pub fn to_pixel_point(
20730        &self,
20731        source: multi_buffer::Anchor,
20732        editor_snapshot: &EditorSnapshot,
20733        window: &mut Window,
20734    ) -> Option<gpui::Point<Pixels>> {
20735        let source_point = source.to_display_point(editor_snapshot);
20736        self.display_to_pixel_point(source_point, editor_snapshot, window)
20737    }
20738
20739    pub fn display_to_pixel_point(
20740        &self,
20741        source: DisplayPoint,
20742        editor_snapshot: &EditorSnapshot,
20743        window: &mut Window,
20744    ) -> Option<gpui::Point<Pixels>> {
20745        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20746        let text_layout_details = self.text_layout_details(window);
20747        let scroll_top = text_layout_details
20748            .scroll_anchor
20749            .scroll_position(editor_snapshot)
20750            .y;
20751
20752        if source.row().as_f32() < scroll_top.floor() {
20753            return None;
20754        }
20755        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20756        let source_y = line_height * (source.row().as_f32() - scroll_top);
20757        Some(gpui::Point::new(source_x, source_y))
20758    }
20759
20760    pub fn has_visible_completions_menu(&self) -> bool {
20761        !self.edit_prediction_preview_is_active()
20762            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20763                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20764            })
20765    }
20766
20767    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20768        if self.mode.is_minimap() {
20769            return;
20770        }
20771        self.addons
20772            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20773    }
20774
20775    pub fn unregister_addon<T: Addon>(&mut self) {
20776        self.addons.remove(&std::any::TypeId::of::<T>());
20777    }
20778
20779    pub fn addon<T: Addon>(&self) -> Option<&T> {
20780        let type_id = std::any::TypeId::of::<T>();
20781        self.addons
20782            .get(&type_id)
20783            .and_then(|item| item.to_any().downcast_ref::<T>())
20784    }
20785
20786    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20787        let type_id = std::any::TypeId::of::<T>();
20788        self.addons
20789            .get_mut(&type_id)
20790            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20791    }
20792
20793    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20794        let text_layout_details = self.text_layout_details(window);
20795        let style = &text_layout_details.editor_style;
20796        let font_id = window.text_system().resolve_font(&style.text.font());
20797        let font_size = style.text.font_size.to_pixels(window.rem_size());
20798        let line_height = style.text.line_height_in_pixels(window.rem_size());
20799        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20800        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20801
20802        CharacterDimensions {
20803            em_width,
20804            em_advance,
20805            line_height,
20806        }
20807    }
20808
20809    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20810        self.load_diff_task.clone()
20811    }
20812
20813    fn read_metadata_from_db(
20814        &mut self,
20815        item_id: u64,
20816        workspace_id: WorkspaceId,
20817        window: &mut Window,
20818        cx: &mut Context<Editor>,
20819    ) {
20820        if self.is_singleton(cx)
20821            && !self.mode.is_minimap()
20822            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20823        {
20824            let buffer_snapshot = OnceCell::new();
20825
20826            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20827                if !folds.is_empty() {
20828                    let snapshot =
20829                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20830                    self.fold_ranges(
20831                        folds
20832                            .into_iter()
20833                            .map(|(start, end)| {
20834                                snapshot.clip_offset(start, Bias::Left)
20835                                    ..snapshot.clip_offset(end, Bias::Right)
20836                            })
20837                            .collect(),
20838                        false,
20839                        window,
20840                        cx,
20841                    );
20842                }
20843            }
20844
20845            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20846                if !selections.is_empty() {
20847                    let snapshot =
20848                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20849                    // skip adding the initial selection to selection history
20850                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20851                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20852                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20853                            snapshot.clip_offset(start, Bias::Left)
20854                                ..snapshot.clip_offset(end, Bias::Right)
20855                        }));
20856                    });
20857                    self.selection_history.mode = SelectionHistoryMode::Normal;
20858                }
20859            };
20860        }
20861
20862        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20863    }
20864
20865    fn update_lsp_data(
20866        &mut self,
20867        ignore_cache: bool,
20868        for_buffer: Option<BufferId>,
20869        window: &mut Window,
20870        cx: &mut Context<'_, Self>,
20871    ) {
20872        self.pull_diagnostics(for_buffer, window, cx);
20873        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20874    }
20875}
20876
20877fn vim_enabled(cx: &App) -> bool {
20878    cx.global::<SettingsStore>()
20879        .raw_user_settings()
20880        .get("vim_mode")
20881        == Some(&serde_json::Value::Bool(true))
20882}
20883
20884fn process_completion_for_edit(
20885    completion: &Completion,
20886    intent: CompletionIntent,
20887    buffer: &Entity<Buffer>,
20888    cursor_position: &text::Anchor,
20889    cx: &mut Context<Editor>,
20890) -> CompletionEdit {
20891    let buffer = buffer.read(cx);
20892    let buffer_snapshot = buffer.snapshot();
20893    let (snippet, new_text) = if completion.is_snippet() {
20894        // Workaround for typescript language server issues so that methods don't expand within
20895        // strings and functions with type expressions. The previous point is used because the query
20896        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20897        let mut snippet_source = completion.new_text.clone();
20898        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20899        previous_point.column = previous_point.column.saturating_sub(1);
20900        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20901            if scope.prefers_label_for_snippet_in_completion() {
20902                if let Some(label) = completion.label() {
20903                    if matches!(
20904                        completion.kind(),
20905                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20906                    ) {
20907                        snippet_source = label;
20908                    }
20909                }
20910            }
20911        }
20912        match Snippet::parse(&snippet_source).log_err() {
20913            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20914            None => (None, completion.new_text.clone()),
20915        }
20916    } else {
20917        (None, completion.new_text.clone())
20918    };
20919
20920    let mut range_to_replace = {
20921        let replace_range = &completion.replace_range;
20922        if let CompletionSource::Lsp {
20923            insert_range: Some(insert_range),
20924            ..
20925        } = &completion.source
20926        {
20927            debug_assert_eq!(
20928                insert_range.start, replace_range.start,
20929                "insert_range and replace_range should start at the same position"
20930            );
20931            debug_assert!(
20932                insert_range
20933                    .start
20934                    .cmp(&cursor_position, &buffer_snapshot)
20935                    .is_le(),
20936                "insert_range should start before or at cursor position"
20937            );
20938            debug_assert!(
20939                replace_range
20940                    .start
20941                    .cmp(&cursor_position, &buffer_snapshot)
20942                    .is_le(),
20943                "replace_range should start before or at cursor position"
20944            );
20945            debug_assert!(
20946                insert_range
20947                    .end
20948                    .cmp(&cursor_position, &buffer_snapshot)
20949                    .is_le(),
20950                "insert_range should end before or at cursor position"
20951            );
20952
20953            let should_replace = match intent {
20954                CompletionIntent::CompleteWithInsert => false,
20955                CompletionIntent::CompleteWithReplace => true,
20956                CompletionIntent::Complete | CompletionIntent::Compose => {
20957                    let insert_mode =
20958                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20959                            .completions
20960                            .lsp_insert_mode;
20961                    match insert_mode {
20962                        LspInsertMode::Insert => false,
20963                        LspInsertMode::Replace => true,
20964                        LspInsertMode::ReplaceSubsequence => {
20965                            let mut text_to_replace = buffer.chars_for_range(
20966                                buffer.anchor_before(replace_range.start)
20967                                    ..buffer.anchor_after(replace_range.end),
20968                            );
20969                            let mut current_needle = text_to_replace.next();
20970                            for haystack_ch in completion.label.text.chars() {
20971                                if let Some(needle_ch) = current_needle {
20972                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20973                                        current_needle = text_to_replace.next();
20974                                    }
20975                                }
20976                            }
20977                            current_needle.is_none()
20978                        }
20979                        LspInsertMode::ReplaceSuffix => {
20980                            if replace_range
20981                                .end
20982                                .cmp(&cursor_position, &buffer_snapshot)
20983                                .is_gt()
20984                            {
20985                                let range_after_cursor = *cursor_position..replace_range.end;
20986                                let text_after_cursor = buffer
20987                                    .text_for_range(
20988                                        buffer.anchor_before(range_after_cursor.start)
20989                                            ..buffer.anchor_after(range_after_cursor.end),
20990                                    )
20991                                    .collect::<String>()
20992                                    .to_ascii_lowercase();
20993                                completion
20994                                    .label
20995                                    .text
20996                                    .to_ascii_lowercase()
20997                                    .ends_with(&text_after_cursor)
20998                            } else {
20999                                true
21000                            }
21001                        }
21002                    }
21003                }
21004            };
21005
21006            if should_replace {
21007                replace_range.clone()
21008            } else {
21009                insert_range.clone()
21010            }
21011        } else {
21012            replace_range.clone()
21013        }
21014    };
21015
21016    if range_to_replace
21017        .end
21018        .cmp(&cursor_position, &buffer_snapshot)
21019        .is_lt()
21020    {
21021        range_to_replace.end = *cursor_position;
21022    }
21023
21024    CompletionEdit {
21025        new_text,
21026        replace_range: range_to_replace.to_offset(&buffer),
21027        snippet,
21028    }
21029}
21030
21031struct CompletionEdit {
21032    new_text: String,
21033    replace_range: Range<usize>,
21034    snippet: Option<Snippet>,
21035}
21036
21037fn insert_extra_newline_brackets(
21038    buffer: &MultiBufferSnapshot,
21039    range: Range<usize>,
21040    language: &language::LanguageScope,
21041) -> bool {
21042    let leading_whitespace_len = buffer
21043        .reversed_chars_at(range.start)
21044        .take_while(|c| c.is_whitespace() && *c != '\n')
21045        .map(|c| c.len_utf8())
21046        .sum::<usize>();
21047    let trailing_whitespace_len = buffer
21048        .chars_at(range.end)
21049        .take_while(|c| c.is_whitespace() && *c != '\n')
21050        .map(|c| c.len_utf8())
21051        .sum::<usize>();
21052    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21053
21054    language.brackets().any(|(pair, enabled)| {
21055        let pair_start = pair.start.trim_end();
21056        let pair_end = pair.end.trim_start();
21057
21058        enabled
21059            && pair.newline
21060            && buffer.contains_str_at(range.end, pair_end)
21061            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21062    })
21063}
21064
21065fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21066    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21067        [(buffer, range, _)] => (*buffer, range.clone()),
21068        _ => return false,
21069    };
21070    let pair = {
21071        let mut result: Option<BracketMatch> = None;
21072
21073        for pair in buffer
21074            .all_bracket_ranges(range.clone())
21075            .filter(move |pair| {
21076                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21077            })
21078        {
21079            let len = pair.close_range.end - pair.open_range.start;
21080
21081            if let Some(existing) = &result {
21082                let existing_len = existing.close_range.end - existing.open_range.start;
21083                if len > existing_len {
21084                    continue;
21085                }
21086            }
21087
21088            result = Some(pair);
21089        }
21090
21091        result
21092    };
21093    let Some(pair) = pair else {
21094        return false;
21095    };
21096    pair.newline_only
21097        && buffer
21098            .chars_for_range(pair.open_range.end..range.start)
21099            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21100            .all(|c| c.is_whitespace() && c != '\n')
21101}
21102
21103fn update_uncommitted_diff_for_buffer(
21104    editor: Entity<Editor>,
21105    project: &Entity<Project>,
21106    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21107    buffer: Entity<MultiBuffer>,
21108    cx: &mut App,
21109) -> Task<()> {
21110    let mut tasks = Vec::new();
21111    project.update(cx, |project, cx| {
21112        for buffer in buffers {
21113            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21114                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21115            }
21116        }
21117    });
21118    cx.spawn(async move |cx| {
21119        let diffs = future::join_all(tasks).await;
21120        if editor
21121            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21122            .unwrap_or(false)
21123        {
21124            return;
21125        }
21126
21127        buffer
21128            .update(cx, |buffer, cx| {
21129                for diff in diffs.into_iter().flatten() {
21130                    buffer.add_diff(diff, cx);
21131                }
21132            })
21133            .ok();
21134    })
21135}
21136
21137fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21138    let tab_size = tab_size.get() as usize;
21139    let mut width = offset;
21140
21141    for ch in text.chars() {
21142        width += if ch == '\t' {
21143            tab_size - (width % tab_size)
21144        } else {
21145            1
21146        };
21147    }
21148
21149    width - offset
21150}
21151
21152#[cfg(test)]
21153mod tests {
21154    use super::*;
21155
21156    #[test]
21157    fn test_string_size_with_expanded_tabs() {
21158        let nz = |val| NonZeroU32::new(val).unwrap();
21159        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21160        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21161        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21162        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21163        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21164        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21165        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21166        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21167    }
21168}
21169
21170/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21171struct WordBreakingTokenizer<'a> {
21172    input: &'a str,
21173}
21174
21175impl<'a> WordBreakingTokenizer<'a> {
21176    fn new(input: &'a str) -> Self {
21177        Self { input }
21178    }
21179}
21180
21181fn is_char_ideographic(ch: char) -> bool {
21182    use unicode_script::Script::*;
21183    use unicode_script::UnicodeScript;
21184    matches!(ch.script(), Han | Tangut | Yi)
21185}
21186
21187fn is_grapheme_ideographic(text: &str) -> bool {
21188    text.chars().any(is_char_ideographic)
21189}
21190
21191fn is_grapheme_whitespace(text: &str) -> bool {
21192    text.chars().any(|x| x.is_whitespace())
21193}
21194
21195fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21196    text.chars().next().map_or(false, |ch| {
21197        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21198    })
21199}
21200
21201#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21202enum WordBreakToken<'a> {
21203    Word { token: &'a str, grapheme_len: usize },
21204    InlineWhitespace { token: &'a str, grapheme_len: usize },
21205    Newline,
21206}
21207
21208impl<'a> Iterator for WordBreakingTokenizer<'a> {
21209    /// Yields a span, the count of graphemes in the token, and whether it was
21210    /// whitespace. Note that it also breaks at word boundaries.
21211    type Item = WordBreakToken<'a>;
21212
21213    fn next(&mut self) -> Option<Self::Item> {
21214        use unicode_segmentation::UnicodeSegmentation;
21215        if self.input.is_empty() {
21216            return None;
21217        }
21218
21219        let mut iter = self.input.graphemes(true).peekable();
21220        let mut offset = 0;
21221        let mut grapheme_len = 0;
21222        if let Some(first_grapheme) = iter.next() {
21223            let is_newline = first_grapheme == "\n";
21224            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21225            offset += first_grapheme.len();
21226            grapheme_len += 1;
21227            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21228                if let Some(grapheme) = iter.peek().copied() {
21229                    if should_stay_with_preceding_ideograph(grapheme) {
21230                        offset += grapheme.len();
21231                        grapheme_len += 1;
21232                    }
21233                }
21234            } else {
21235                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21236                let mut next_word_bound = words.peek().copied();
21237                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21238                    next_word_bound = words.next();
21239                }
21240                while let Some(grapheme) = iter.peek().copied() {
21241                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21242                        break;
21243                    };
21244                    if is_grapheme_whitespace(grapheme) != is_whitespace
21245                        || (grapheme == "\n") != is_newline
21246                    {
21247                        break;
21248                    };
21249                    offset += grapheme.len();
21250                    grapheme_len += 1;
21251                    iter.next();
21252                }
21253            }
21254            let token = &self.input[..offset];
21255            self.input = &self.input[offset..];
21256            if token == "\n" {
21257                Some(WordBreakToken::Newline)
21258            } else if is_whitespace {
21259                Some(WordBreakToken::InlineWhitespace {
21260                    token,
21261                    grapheme_len,
21262                })
21263            } else {
21264                Some(WordBreakToken::Word {
21265                    token,
21266                    grapheme_len,
21267                })
21268            }
21269        } else {
21270            None
21271        }
21272    }
21273}
21274
21275#[test]
21276fn test_word_breaking_tokenizer() {
21277    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21278        ("", &[]),
21279        ("  ", &[whitespace("  ", 2)]),
21280        ("Ʒ", &[word("Ʒ", 1)]),
21281        ("Ǽ", &[word("Ǽ", 1)]),
21282        ("", &[word("", 1)]),
21283        ("⋑⋑", &[word("⋑⋑", 2)]),
21284        (
21285            "原理,进而",
21286            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21287        ),
21288        (
21289            "hello world",
21290            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21291        ),
21292        (
21293            "hello, world",
21294            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21295        ),
21296        (
21297            "  hello world",
21298            &[
21299                whitespace("  ", 2),
21300                word("hello", 5),
21301                whitespace(" ", 1),
21302                word("world", 5),
21303            ],
21304        ),
21305        (
21306            "这是什么 \n 钢笔",
21307            &[
21308                word("", 1),
21309                word("", 1),
21310                word("", 1),
21311                word("", 1),
21312                whitespace(" ", 1),
21313                newline(),
21314                whitespace(" ", 1),
21315                word("", 1),
21316                word("", 1),
21317            ],
21318        ),
21319        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21320    ];
21321
21322    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21323        WordBreakToken::Word {
21324            token,
21325            grapheme_len,
21326        }
21327    }
21328
21329    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21330        WordBreakToken::InlineWhitespace {
21331            token,
21332            grapheme_len,
21333        }
21334    }
21335
21336    fn newline() -> WordBreakToken<'static> {
21337        WordBreakToken::Newline
21338    }
21339
21340    for (input, result) in tests {
21341        assert_eq!(
21342            WordBreakingTokenizer::new(input)
21343                .collect::<Vec<_>>()
21344                .as_slice(),
21345            *result,
21346        );
21347    }
21348}
21349
21350fn wrap_with_prefix(
21351    first_line_prefix: String,
21352    subsequent_lines_prefix: String,
21353    unwrapped_text: String,
21354    wrap_column: usize,
21355    tab_size: NonZeroU32,
21356    preserve_existing_whitespace: bool,
21357) -> String {
21358    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21359    let subsequent_lines_prefix_len =
21360        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21361    let mut wrapped_text = String::new();
21362    let mut current_line = first_line_prefix.clone();
21363    let mut is_first_line = true;
21364
21365    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21366    let mut current_line_len = first_line_prefix_len;
21367    let mut in_whitespace = false;
21368    for token in tokenizer {
21369        let have_preceding_whitespace = in_whitespace;
21370        match token {
21371            WordBreakToken::Word {
21372                token,
21373                grapheme_len,
21374            } => {
21375                in_whitespace = false;
21376                let current_prefix_len = if is_first_line {
21377                    first_line_prefix_len
21378                } else {
21379                    subsequent_lines_prefix_len
21380                };
21381                if current_line_len + grapheme_len > wrap_column
21382                    && current_line_len != current_prefix_len
21383                {
21384                    wrapped_text.push_str(current_line.trim_end());
21385                    wrapped_text.push('\n');
21386                    is_first_line = false;
21387                    current_line = subsequent_lines_prefix.clone();
21388                    current_line_len = subsequent_lines_prefix_len;
21389                }
21390                current_line.push_str(token);
21391                current_line_len += grapheme_len;
21392            }
21393            WordBreakToken::InlineWhitespace {
21394                mut token,
21395                mut grapheme_len,
21396            } => {
21397                in_whitespace = true;
21398                if have_preceding_whitespace && !preserve_existing_whitespace {
21399                    continue;
21400                }
21401                if !preserve_existing_whitespace {
21402                    token = " ";
21403                    grapheme_len = 1;
21404                }
21405                let current_prefix_len = if is_first_line {
21406                    first_line_prefix_len
21407                } else {
21408                    subsequent_lines_prefix_len
21409                };
21410                if current_line_len + grapheme_len > wrap_column {
21411                    wrapped_text.push_str(current_line.trim_end());
21412                    wrapped_text.push('\n');
21413                    is_first_line = false;
21414                    current_line = subsequent_lines_prefix.clone();
21415                    current_line_len = subsequent_lines_prefix_len;
21416                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21417                    current_line.push_str(token);
21418                    current_line_len += grapheme_len;
21419                }
21420            }
21421            WordBreakToken::Newline => {
21422                in_whitespace = true;
21423                let current_prefix_len = if is_first_line {
21424                    first_line_prefix_len
21425                } else {
21426                    subsequent_lines_prefix_len
21427                };
21428                if preserve_existing_whitespace {
21429                    wrapped_text.push_str(current_line.trim_end());
21430                    wrapped_text.push('\n');
21431                    is_first_line = false;
21432                    current_line = subsequent_lines_prefix.clone();
21433                    current_line_len = subsequent_lines_prefix_len;
21434                } else if have_preceding_whitespace {
21435                    continue;
21436                } else if current_line_len + 1 > wrap_column
21437                    && current_line_len != current_prefix_len
21438                {
21439                    wrapped_text.push_str(current_line.trim_end());
21440                    wrapped_text.push('\n');
21441                    is_first_line = false;
21442                    current_line = subsequent_lines_prefix.clone();
21443                    current_line_len = subsequent_lines_prefix_len;
21444                } else if current_line_len != current_prefix_len {
21445                    current_line.push(' ');
21446                    current_line_len += 1;
21447                }
21448            }
21449        }
21450    }
21451
21452    if !current_line.is_empty() {
21453        wrapped_text.push_str(&current_line);
21454    }
21455    wrapped_text
21456}
21457
21458#[test]
21459fn test_wrap_with_prefix() {
21460    assert_eq!(
21461        wrap_with_prefix(
21462            "# ".to_string(),
21463            "# ".to_string(),
21464            "abcdefg".to_string(),
21465            4,
21466            NonZeroU32::new(4).unwrap(),
21467            false,
21468        ),
21469        "# abcdefg"
21470    );
21471    assert_eq!(
21472        wrap_with_prefix(
21473            "".to_string(),
21474            "".to_string(),
21475            "\thello world".to_string(),
21476            8,
21477            NonZeroU32::new(4).unwrap(),
21478            false,
21479        ),
21480        "hello\nworld"
21481    );
21482    assert_eq!(
21483        wrap_with_prefix(
21484            "// ".to_string(),
21485            "// ".to_string(),
21486            "xx \nyy zz aa bb cc".to_string(),
21487            12,
21488            NonZeroU32::new(4).unwrap(),
21489            false,
21490        ),
21491        "// xx yy zz\n// aa bb cc"
21492    );
21493    assert_eq!(
21494        wrap_with_prefix(
21495            String::new(),
21496            String::new(),
21497            "这是什么 \n 钢笔".to_string(),
21498            3,
21499            NonZeroU32::new(4).unwrap(),
21500            false,
21501        ),
21502        "这是什\n么 钢\n"
21503    );
21504}
21505
21506pub trait CollaborationHub {
21507    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21508    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21509    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21510}
21511
21512impl CollaborationHub for Entity<Project> {
21513    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21514        self.read(cx).collaborators()
21515    }
21516
21517    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21518        self.read(cx).user_store().read(cx).participant_indices()
21519    }
21520
21521    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21522        let this = self.read(cx);
21523        let user_ids = this.collaborators().values().map(|c| c.user_id);
21524        this.user_store().read(cx).participant_names(user_ids, cx)
21525    }
21526}
21527
21528pub trait SemanticsProvider {
21529    fn hover(
21530        &self,
21531        buffer: &Entity<Buffer>,
21532        position: text::Anchor,
21533        cx: &mut App,
21534    ) -> Option<Task<Vec<project::Hover>>>;
21535
21536    fn inline_values(
21537        &self,
21538        buffer_handle: Entity<Buffer>,
21539        range: Range<text::Anchor>,
21540        cx: &mut App,
21541    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21542
21543    fn inlay_hints(
21544        &self,
21545        buffer_handle: Entity<Buffer>,
21546        range: Range<text::Anchor>,
21547        cx: &mut App,
21548    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21549
21550    fn resolve_inlay_hint(
21551        &self,
21552        hint: InlayHint,
21553        buffer_handle: Entity<Buffer>,
21554        server_id: LanguageServerId,
21555        cx: &mut App,
21556    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21557
21558    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21559
21560    fn document_highlights(
21561        &self,
21562        buffer: &Entity<Buffer>,
21563        position: text::Anchor,
21564        cx: &mut App,
21565    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21566
21567    fn definitions(
21568        &self,
21569        buffer: &Entity<Buffer>,
21570        position: text::Anchor,
21571        kind: GotoDefinitionKind,
21572        cx: &mut App,
21573    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21574
21575    fn range_for_rename(
21576        &self,
21577        buffer: &Entity<Buffer>,
21578        position: text::Anchor,
21579        cx: &mut App,
21580    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21581
21582    fn perform_rename(
21583        &self,
21584        buffer: &Entity<Buffer>,
21585        position: text::Anchor,
21586        new_name: String,
21587        cx: &mut App,
21588    ) -> Option<Task<Result<ProjectTransaction>>>;
21589}
21590
21591pub trait CompletionProvider {
21592    fn completions(
21593        &self,
21594        excerpt_id: ExcerptId,
21595        buffer: &Entity<Buffer>,
21596        buffer_position: text::Anchor,
21597        trigger: CompletionContext,
21598        window: &mut Window,
21599        cx: &mut Context<Editor>,
21600    ) -> Task<Result<Vec<CompletionResponse>>>;
21601
21602    fn resolve_completions(
21603        &self,
21604        _buffer: Entity<Buffer>,
21605        _completion_indices: Vec<usize>,
21606        _completions: Rc<RefCell<Box<[Completion]>>>,
21607        _cx: &mut Context<Editor>,
21608    ) -> Task<Result<bool>> {
21609        Task::ready(Ok(false))
21610    }
21611
21612    fn apply_additional_edits_for_completion(
21613        &self,
21614        _buffer: Entity<Buffer>,
21615        _completions: Rc<RefCell<Box<[Completion]>>>,
21616        _completion_index: usize,
21617        _push_to_history: bool,
21618        _cx: &mut Context<Editor>,
21619    ) -> Task<Result<Option<language::Transaction>>> {
21620        Task::ready(Ok(None))
21621    }
21622
21623    fn is_completion_trigger(
21624        &self,
21625        buffer: &Entity<Buffer>,
21626        position: language::Anchor,
21627        text: &str,
21628        trigger_in_words: bool,
21629        menu_is_open: bool,
21630        cx: &mut Context<Editor>,
21631    ) -> bool;
21632
21633    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21634
21635    fn sort_completions(&self) -> bool {
21636        true
21637    }
21638
21639    fn filter_completions(&self) -> bool {
21640        true
21641    }
21642}
21643
21644pub trait CodeActionProvider {
21645    fn id(&self) -> Arc<str>;
21646
21647    fn code_actions(
21648        &self,
21649        buffer: &Entity<Buffer>,
21650        range: Range<text::Anchor>,
21651        window: &mut Window,
21652        cx: &mut App,
21653    ) -> Task<Result<Vec<CodeAction>>>;
21654
21655    fn apply_code_action(
21656        &self,
21657        buffer_handle: Entity<Buffer>,
21658        action: CodeAction,
21659        excerpt_id: ExcerptId,
21660        push_to_history: bool,
21661        window: &mut Window,
21662        cx: &mut App,
21663    ) -> Task<Result<ProjectTransaction>>;
21664}
21665
21666impl CodeActionProvider for Entity<Project> {
21667    fn id(&self) -> Arc<str> {
21668        "project".into()
21669    }
21670
21671    fn code_actions(
21672        &self,
21673        buffer: &Entity<Buffer>,
21674        range: Range<text::Anchor>,
21675        _window: &mut Window,
21676        cx: &mut App,
21677    ) -> Task<Result<Vec<CodeAction>>> {
21678        self.update(cx, |project, cx| {
21679            let code_lens = project.code_lens(buffer, range.clone(), cx);
21680            let code_actions = project.code_actions(buffer, range, None, cx);
21681            cx.background_spawn(async move {
21682                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21683                Ok(code_lens
21684                    .context("code lens fetch")?
21685                    .into_iter()
21686                    .chain(code_actions.context("code action fetch")?)
21687                    .collect())
21688            })
21689        })
21690    }
21691
21692    fn apply_code_action(
21693        &self,
21694        buffer_handle: Entity<Buffer>,
21695        action: CodeAction,
21696        _excerpt_id: ExcerptId,
21697        push_to_history: bool,
21698        _window: &mut Window,
21699        cx: &mut App,
21700    ) -> Task<Result<ProjectTransaction>> {
21701        self.update(cx, |project, cx| {
21702            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21703        })
21704    }
21705}
21706
21707fn snippet_completions(
21708    project: &Project,
21709    buffer: &Entity<Buffer>,
21710    buffer_position: text::Anchor,
21711    cx: &mut App,
21712) -> Task<Result<CompletionResponse>> {
21713    let languages = buffer.read(cx).languages_at(buffer_position);
21714    let snippet_store = project.snippets().read(cx);
21715
21716    let scopes: Vec<_> = languages
21717        .iter()
21718        .filter_map(|language| {
21719            let language_name = language.lsp_id();
21720            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21721
21722            if snippets.is_empty() {
21723                None
21724            } else {
21725                Some((language.default_scope(), snippets))
21726            }
21727        })
21728        .collect();
21729
21730    if scopes.is_empty() {
21731        return Task::ready(Ok(CompletionResponse {
21732            completions: vec![],
21733            is_incomplete: false,
21734        }));
21735    }
21736
21737    let snapshot = buffer.read(cx).text_snapshot();
21738    let chars: String = snapshot
21739        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21740        .collect();
21741    let executor = cx.background_executor().clone();
21742
21743    cx.background_spawn(async move {
21744        let mut is_incomplete = false;
21745        let mut completions: Vec<Completion> = Vec::new();
21746        for (scope, snippets) in scopes.into_iter() {
21747            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21748            let mut last_word = chars
21749                .chars()
21750                .take_while(|c| classifier.is_word(*c))
21751                .collect::<String>();
21752            last_word = last_word.chars().rev().collect();
21753
21754            if last_word.is_empty() {
21755                return Ok(CompletionResponse {
21756                    completions: vec![],
21757                    is_incomplete: true,
21758                });
21759            }
21760
21761            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21762            let to_lsp = |point: &text::Anchor| {
21763                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21764                point_to_lsp(end)
21765            };
21766            let lsp_end = to_lsp(&buffer_position);
21767
21768            let candidates = snippets
21769                .iter()
21770                .enumerate()
21771                .flat_map(|(ix, snippet)| {
21772                    snippet
21773                        .prefix
21774                        .iter()
21775                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21776                })
21777                .collect::<Vec<StringMatchCandidate>>();
21778
21779            const MAX_RESULTS: usize = 100;
21780            let mut matches = fuzzy::match_strings(
21781                &candidates,
21782                &last_word,
21783                last_word.chars().any(|c| c.is_uppercase()),
21784                true,
21785                MAX_RESULTS,
21786                &Default::default(),
21787                executor.clone(),
21788            )
21789            .await;
21790
21791            if matches.len() >= MAX_RESULTS {
21792                is_incomplete = true;
21793            }
21794
21795            // Remove all candidates where the query's start does not match the start of any word in the candidate
21796            if let Some(query_start) = last_word.chars().next() {
21797                matches.retain(|string_match| {
21798                    split_words(&string_match.string).any(|word| {
21799                        // Check that the first codepoint of the word as lowercase matches the first
21800                        // codepoint of the query as lowercase
21801                        word.chars()
21802                            .flat_map(|codepoint| codepoint.to_lowercase())
21803                            .zip(query_start.to_lowercase())
21804                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21805                    })
21806                });
21807            }
21808
21809            let matched_strings = matches
21810                .into_iter()
21811                .map(|m| m.string)
21812                .collect::<HashSet<_>>();
21813
21814            completions.extend(snippets.iter().filter_map(|snippet| {
21815                let matching_prefix = snippet
21816                    .prefix
21817                    .iter()
21818                    .find(|prefix| matched_strings.contains(*prefix))?;
21819                let start = as_offset - last_word.len();
21820                let start = snapshot.anchor_before(start);
21821                let range = start..buffer_position;
21822                let lsp_start = to_lsp(&start);
21823                let lsp_range = lsp::Range {
21824                    start: lsp_start,
21825                    end: lsp_end,
21826                };
21827                Some(Completion {
21828                    replace_range: range,
21829                    new_text: snippet.body.clone(),
21830                    source: CompletionSource::Lsp {
21831                        insert_range: None,
21832                        server_id: LanguageServerId(usize::MAX),
21833                        resolved: true,
21834                        lsp_completion: Box::new(lsp::CompletionItem {
21835                            label: snippet.prefix.first().unwrap().clone(),
21836                            kind: Some(CompletionItemKind::SNIPPET),
21837                            label_details: snippet.description.as_ref().map(|description| {
21838                                lsp::CompletionItemLabelDetails {
21839                                    detail: Some(description.clone()),
21840                                    description: None,
21841                                }
21842                            }),
21843                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21844                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21845                                lsp::InsertReplaceEdit {
21846                                    new_text: snippet.body.clone(),
21847                                    insert: lsp_range,
21848                                    replace: lsp_range,
21849                                },
21850                            )),
21851                            filter_text: Some(snippet.body.clone()),
21852                            sort_text: Some(char::MAX.to_string()),
21853                            ..lsp::CompletionItem::default()
21854                        }),
21855                        lsp_defaults: None,
21856                    },
21857                    label: CodeLabel {
21858                        text: matching_prefix.clone(),
21859                        runs: Vec::new(),
21860                        filter_range: 0..matching_prefix.len(),
21861                    },
21862                    icon_path: None,
21863                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21864                        single_line: snippet.name.clone().into(),
21865                        plain_text: snippet
21866                            .description
21867                            .clone()
21868                            .map(|description| description.into()),
21869                    }),
21870                    insert_text_mode: None,
21871                    confirm: None,
21872                })
21873            }))
21874        }
21875
21876        Ok(CompletionResponse {
21877            completions,
21878            is_incomplete,
21879        })
21880    })
21881}
21882
21883impl CompletionProvider for Entity<Project> {
21884    fn completions(
21885        &self,
21886        _excerpt_id: ExcerptId,
21887        buffer: &Entity<Buffer>,
21888        buffer_position: text::Anchor,
21889        options: CompletionContext,
21890        _window: &mut Window,
21891        cx: &mut Context<Editor>,
21892    ) -> Task<Result<Vec<CompletionResponse>>> {
21893        self.update(cx, |project, cx| {
21894            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21895            let project_completions = project.completions(buffer, buffer_position, options, cx);
21896            cx.background_spawn(async move {
21897                let mut responses = project_completions.await?;
21898                let snippets = snippets.await?;
21899                if !snippets.completions.is_empty() {
21900                    responses.push(snippets);
21901                }
21902                Ok(responses)
21903            })
21904        })
21905    }
21906
21907    fn resolve_completions(
21908        &self,
21909        buffer: Entity<Buffer>,
21910        completion_indices: Vec<usize>,
21911        completions: Rc<RefCell<Box<[Completion]>>>,
21912        cx: &mut Context<Editor>,
21913    ) -> Task<Result<bool>> {
21914        self.update(cx, |project, cx| {
21915            project.lsp_store().update(cx, |lsp_store, cx| {
21916                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21917            })
21918        })
21919    }
21920
21921    fn apply_additional_edits_for_completion(
21922        &self,
21923        buffer: Entity<Buffer>,
21924        completions: Rc<RefCell<Box<[Completion]>>>,
21925        completion_index: usize,
21926        push_to_history: bool,
21927        cx: &mut Context<Editor>,
21928    ) -> Task<Result<Option<language::Transaction>>> {
21929        self.update(cx, |project, cx| {
21930            project.lsp_store().update(cx, |lsp_store, cx| {
21931                lsp_store.apply_additional_edits_for_completion(
21932                    buffer,
21933                    completions,
21934                    completion_index,
21935                    push_to_history,
21936                    cx,
21937                )
21938            })
21939        })
21940    }
21941
21942    fn is_completion_trigger(
21943        &self,
21944        buffer: &Entity<Buffer>,
21945        position: language::Anchor,
21946        text: &str,
21947        trigger_in_words: bool,
21948        menu_is_open: bool,
21949        cx: &mut Context<Editor>,
21950    ) -> bool {
21951        let mut chars = text.chars();
21952        let char = if let Some(char) = chars.next() {
21953            char
21954        } else {
21955            return false;
21956        };
21957        if chars.next().is_some() {
21958            return false;
21959        }
21960
21961        let buffer = buffer.read(cx);
21962        let snapshot = buffer.snapshot();
21963        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21964            return false;
21965        }
21966        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21967        if trigger_in_words && classifier.is_word(char) {
21968            return true;
21969        }
21970
21971        buffer.completion_triggers().contains(text)
21972    }
21973}
21974
21975impl SemanticsProvider for Entity<Project> {
21976    fn hover(
21977        &self,
21978        buffer: &Entity<Buffer>,
21979        position: text::Anchor,
21980        cx: &mut App,
21981    ) -> Option<Task<Vec<project::Hover>>> {
21982        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21983    }
21984
21985    fn document_highlights(
21986        &self,
21987        buffer: &Entity<Buffer>,
21988        position: text::Anchor,
21989        cx: &mut App,
21990    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21991        Some(self.update(cx, |project, cx| {
21992            project.document_highlights(buffer, position, cx)
21993        }))
21994    }
21995
21996    fn definitions(
21997        &self,
21998        buffer: &Entity<Buffer>,
21999        position: text::Anchor,
22000        kind: GotoDefinitionKind,
22001        cx: &mut App,
22002    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22003        Some(self.update(cx, |project, cx| match kind {
22004            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22005            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22006            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22007            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22008        }))
22009    }
22010
22011    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22012        // TODO: make this work for remote projects
22013        self.update(cx, |project, cx| {
22014            if project
22015                .active_debug_session(cx)
22016                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22017            {
22018                return true;
22019            }
22020
22021            buffer.update(cx, |buffer, cx| {
22022                project.any_language_server_supports_inlay_hints(buffer, cx)
22023            })
22024        })
22025    }
22026
22027    fn inline_values(
22028        &self,
22029        buffer_handle: Entity<Buffer>,
22030        range: Range<text::Anchor>,
22031        cx: &mut App,
22032    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22033        self.update(cx, |project, cx| {
22034            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22035
22036            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22037        })
22038    }
22039
22040    fn inlay_hints(
22041        &self,
22042        buffer_handle: Entity<Buffer>,
22043        range: Range<text::Anchor>,
22044        cx: &mut App,
22045    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22046        Some(self.update(cx, |project, cx| {
22047            project.inlay_hints(buffer_handle, range, cx)
22048        }))
22049    }
22050
22051    fn resolve_inlay_hint(
22052        &self,
22053        hint: InlayHint,
22054        buffer_handle: Entity<Buffer>,
22055        server_id: LanguageServerId,
22056        cx: &mut App,
22057    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22058        Some(self.update(cx, |project, cx| {
22059            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22060        }))
22061    }
22062
22063    fn range_for_rename(
22064        &self,
22065        buffer: &Entity<Buffer>,
22066        position: text::Anchor,
22067        cx: &mut App,
22068    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22069        Some(self.update(cx, |project, cx| {
22070            let buffer = buffer.clone();
22071            let task = project.prepare_rename(buffer.clone(), position, cx);
22072            cx.spawn(async move |_, cx| {
22073                Ok(match task.await? {
22074                    PrepareRenameResponse::Success(range) => Some(range),
22075                    PrepareRenameResponse::InvalidPosition => None,
22076                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22077                        // Fallback on using TreeSitter info to determine identifier range
22078                        buffer.read_with(cx, |buffer, _| {
22079                            let snapshot = buffer.snapshot();
22080                            let (range, kind) = snapshot.surrounding_word(position);
22081                            if kind != Some(CharKind::Word) {
22082                                return None;
22083                            }
22084                            Some(
22085                                snapshot.anchor_before(range.start)
22086                                    ..snapshot.anchor_after(range.end),
22087                            )
22088                        })?
22089                    }
22090                })
22091            })
22092        }))
22093    }
22094
22095    fn perform_rename(
22096        &self,
22097        buffer: &Entity<Buffer>,
22098        position: text::Anchor,
22099        new_name: String,
22100        cx: &mut App,
22101    ) -> Option<Task<Result<ProjectTransaction>>> {
22102        Some(self.update(cx, |project, cx| {
22103            project.perform_rename(buffer.clone(), position, new_name, cx)
22104        }))
22105    }
22106}
22107
22108fn inlay_hint_settings(
22109    location: Anchor,
22110    snapshot: &MultiBufferSnapshot,
22111    cx: &mut Context<Editor>,
22112) -> InlayHintSettings {
22113    let file = snapshot.file_at(location);
22114    let language = snapshot.language_at(location).map(|l| l.name());
22115    language_settings(language, file, cx).inlay_hints
22116}
22117
22118fn consume_contiguous_rows(
22119    contiguous_row_selections: &mut Vec<Selection<Point>>,
22120    selection: &Selection<Point>,
22121    display_map: &DisplaySnapshot,
22122    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22123) -> (MultiBufferRow, MultiBufferRow) {
22124    contiguous_row_selections.push(selection.clone());
22125    let start_row = MultiBufferRow(selection.start.row);
22126    let mut end_row = ending_row(selection, display_map);
22127
22128    while let Some(next_selection) = selections.peek() {
22129        if next_selection.start.row <= end_row.0 {
22130            end_row = ending_row(next_selection, display_map);
22131            contiguous_row_selections.push(selections.next().unwrap().clone());
22132        } else {
22133            break;
22134        }
22135    }
22136    (start_row, end_row)
22137}
22138
22139fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22140    if next_selection.end.column > 0 || next_selection.is_empty() {
22141        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22142    } else {
22143        MultiBufferRow(next_selection.end.row)
22144    }
22145}
22146
22147impl EditorSnapshot {
22148    pub fn remote_selections_in_range<'a>(
22149        &'a self,
22150        range: &'a Range<Anchor>,
22151        collaboration_hub: &dyn CollaborationHub,
22152        cx: &'a App,
22153    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22154        let participant_names = collaboration_hub.user_names(cx);
22155        let participant_indices = collaboration_hub.user_participant_indices(cx);
22156        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22157        let collaborators_by_replica_id = collaborators_by_peer_id
22158            .values()
22159            .map(|collaborator| (collaborator.replica_id, collaborator))
22160            .collect::<HashMap<_, _>>();
22161        self.buffer_snapshot
22162            .selections_in_range(range, false)
22163            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22164                if replica_id == AGENT_REPLICA_ID {
22165                    Some(RemoteSelection {
22166                        replica_id,
22167                        selection,
22168                        cursor_shape,
22169                        line_mode,
22170                        collaborator_id: CollaboratorId::Agent,
22171                        user_name: Some("Agent".into()),
22172                        color: cx.theme().players().agent(),
22173                    })
22174                } else {
22175                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22176                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22177                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22178                    Some(RemoteSelection {
22179                        replica_id,
22180                        selection,
22181                        cursor_shape,
22182                        line_mode,
22183                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22184                        user_name,
22185                        color: if let Some(index) = participant_index {
22186                            cx.theme().players().color_for_participant(index.0)
22187                        } else {
22188                            cx.theme().players().absent()
22189                        },
22190                    })
22191                }
22192            })
22193    }
22194
22195    pub fn hunks_for_ranges(
22196        &self,
22197        ranges: impl IntoIterator<Item = Range<Point>>,
22198    ) -> Vec<MultiBufferDiffHunk> {
22199        let mut hunks = Vec::new();
22200        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22201            HashMap::default();
22202        for query_range in ranges {
22203            let query_rows =
22204                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22205            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22206                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22207            ) {
22208                // Include deleted hunks that are adjacent to the query range, because
22209                // otherwise they would be missed.
22210                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22211                if hunk.status().is_deleted() {
22212                    intersects_range |= hunk.row_range.start == query_rows.end;
22213                    intersects_range |= hunk.row_range.end == query_rows.start;
22214                }
22215                if intersects_range {
22216                    if !processed_buffer_rows
22217                        .entry(hunk.buffer_id)
22218                        .or_default()
22219                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22220                    {
22221                        continue;
22222                    }
22223                    hunks.push(hunk);
22224                }
22225            }
22226        }
22227
22228        hunks
22229    }
22230
22231    fn display_diff_hunks_for_rows<'a>(
22232        &'a self,
22233        display_rows: Range<DisplayRow>,
22234        folded_buffers: &'a HashSet<BufferId>,
22235    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22236        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22237        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22238
22239        self.buffer_snapshot
22240            .diff_hunks_in_range(buffer_start..buffer_end)
22241            .filter_map(|hunk| {
22242                if folded_buffers.contains(&hunk.buffer_id) {
22243                    return None;
22244                }
22245
22246                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22247                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22248
22249                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22250                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22251
22252                let display_hunk = if hunk_display_start.column() != 0 {
22253                    DisplayDiffHunk::Folded {
22254                        display_row: hunk_display_start.row(),
22255                    }
22256                } else {
22257                    let mut end_row = hunk_display_end.row();
22258                    if hunk_display_end.column() > 0 {
22259                        end_row.0 += 1;
22260                    }
22261                    let is_created_file = hunk.is_created_file();
22262                    DisplayDiffHunk::Unfolded {
22263                        status: hunk.status(),
22264                        diff_base_byte_range: hunk.diff_base_byte_range,
22265                        display_row_range: hunk_display_start.row()..end_row,
22266                        multi_buffer_range: Anchor::range_in_buffer(
22267                            hunk.excerpt_id,
22268                            hunk.buffer_id,
22269                            hunk.buffer_range,
22270                        ),
22271                        is_created_file,
22272                    }
22273                };
22274
22275                Some(display_hunk)
22276            })
22277    }
22278
22279    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22280        self.display_snapshot.buffer_snapshot.language_at(position)
22281    }
22282
22283    pub fn is_focused(&self) -> bool {
22284        self.is_focused
22285    }
22286
22287    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22288        self.placeholder_text.as_ref()
22289    }
22290
22291    pub fn scroll_position(&self) -> gpui::Point<f32> {
22292        self.scroll_anchor.scroll_position(&self.display_snapshot)
22293    }
22294
22295    fn gutter_dimensions(
22296        &self,
22297        font_id: FontId,
22298        font_size: Pixels,
22299        max_line_number_width: Pixels,
22300        cx: &App,
22301    ) -> Option<GutterDimensions> {
22302        if !self.show_gutter {
22303            return None;
22304        }
22305
22306        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22307        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22308
22309        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22310            matches!(
22311                ProjectSettings::get_global(cx).git.git_gutter,
22312                Some(GitGutterSetting::TrackedFiles)
22313            )
22314        });
22315        let gutter_settings = EditorSettings::get_global(cx).gutter;
22316        let show_line_numbers = self
22317            .show_line_numbers
22318            .unwrap_or(gutter_settings.line_numbers);
22319        let line_gutter_width = if show_line_numbers {
22320            // Avoid flicker-like gutter resizes when the line number gains another digit by
22321            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22322            let min_width_for_number_on_gutter =
22323                ch_advance * gutter_settings.min_line_number_digits as f32;
22324            max_line_number_width.max(min_width_for_number_on_gutter)
22325        } else {
22326            0.0.into()
22327        };
22328
22329        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22330        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22331
22332        let git_blame_entries_width =
22333            self.git_blame_gutter_max_author_length
22334                .map(|max_author_length| {
22335                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22336                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22337
22338                    /// The number of characters to dedicate to gaps and margins.
22339                    const SPACING_WIDTH: usize = 4;
22340
22341                    let max_char_count = max_author_length.min(renderer.max_author_length())
22342                        + ::git::SHORT_SHA_LENGTH
22343                        + MAX_RELATIVE_TIMESTAMP.len()
22344                        + SPACING_WIDTH;
22345
22346                    ch_advance * max_char_count
22347                });
22348
22349        let is_singleton = self.buffer_snapshot.is_singleton();
22350
22351        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22352        left_padding += if !is_singleton {
22353            ch_width * 4.0
22354        } else if show_runnables || show_breakpoints {
22355            ch_width * 3.0
22356        } else if show_git_gutter && show_line_numbers {
22357            ch_width * 2.0
22358        } else if show_git_gutter || show_line_numbers {
22359            ch_width
22360        } else {
22361            px(0.)
22362        };
22363
22364        let shows_folds = is_singleton && gutter_settings.folds;
22365
22366        let right_padding = if shows_folds && show_line_numbers {
22367            ch_width * 4.0
22368        } else if shows_folds || (!is_singleton && show_line_numbers) {
22369            ch_width * 3.0
22370        } else if show_line_numbers {
22371            ch_width
22372        } else {
22373            px(0.)
22374        };
22375
22376        Some(GutterDimensions {
22377            left_padding,
22378            right_padding,
22379            width: line_gutter_width + left_padding + right_padding,
22380            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22381            git_blame_entries_width,
22382        })
22383    }
22384
22385    pub fn render_crease_toggle(
22386        &self,
22387        buffer_row: MultiBufferRow,
22388        row_contains_cursor: bool,
22389        editor: Entity<Editor>,
22390        window: &mut Window,
22391        cx: &mut App,
22392    ) -> Option<AnyElement> {
22393        let folded = self.is_line_folded(buffer_row);
22394        let mut is_foldable = false;
22395
22396        if let Some(crease) = self
22397            .crease_snapshot
22398            .query_row(buffer_row, &self.buffer_snapshot)
22399        {
22400            is_foldable = true;
22401            match crease {
22402                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22403                    if let Some(render_toggle) = render_toggle {
22404                        let toggle_callback =
22405                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22406                                if folded {
22407                                    editor.update(cx, |editor, cx| {
22408                                        editor.fold_at(buffer_row, window, cx)
22409                                    });
22410                                } else {
22411                                    editor.update(cx, |editor, cx| {
22412                                        editor.unfold_at(buffer_row, window, cx)
22413                                    });
22414                                }
22415                            });
22416                        return Some((render_toggle)(
22417                            buffer_row,
22418                            folded,
22419                            toggle_callback,
22420                            window,
22421                            cx,
22422                        ));
22423                    }
22424                }
22425            }
22426        }
22427
22428        is_foldable |= self.starts_indent(buffer_row);
22429
22430        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22431            Some(
22432                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22433                    .toggle_state(folded)
22434                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22435                        if folded {
22436                            this.unfold_at(buffer_row, window, cx);
22437                        } else {
22438                            this.fold_at(buffer_row, window, cx);
22439                        }
22440                    }))
22441                    .into_any_element(),
22442            )
22443        } else {
22444            None
22445        }
22446    }
22447
22448    pub fn render_crease_trailer(
22449        &self,
22450        buffer_row: MultiBufferRow,
22451        window: &mut Window,
22452        cx: &mut App,
22453    ) -> Option<AnyElement> {
22454        let folded = self.is_line_folded(buffer_row);
22455        if let Crease::Inline { render_trailer, .. } = self
22456            .crease_snapshot
22457            .query_row(buffer_row, &self.buffer_snapshot)?
22458        {
22459            let render_trailer = render_trailer.as_ref()?;
22460            Some(render_trailer(buffer_row, folded, window, cx))
22461        } else {
22462            None
22463        }
22464    }
22465}
22466
22467impl Deref for EditorSnapshot {
22468    type Target = DisplaySnapshot;
22469
22470    fn deref(&self) -> &Self::Target {
22471        &self.display_snapshot
22472    }
22473}
22474
22475#[derive(Clone, Debug, PartialEq, Eq)]
22476pub enum EditorEvent {
22477    InputIgnored {
22478        text: Arc<str>,
22479    },
22480    InputHandled {
22481        utf16_range_to_replace: Option<Range<isize>>,
22482        text: Arc<str>,
22483    },
22484    ExcerptsAdded {
22485        buffer: Entity<Buffer>,
22486        predecessor: ExcerptId,
22487        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22488    },
22489    ExcerptsRemoved {
22490        ids: Vec<ExcerptId>,
22491        removed_buffer_ids: Vec<BufferId>,
22492    },
22493    BufferFoldToggled {
22494        ids: Vec<ExcerptId>,
22495        folded: bool,
22496    },
22497    ExcerptsEdited {
22498        ids: Vec<ExcerptId>,
22499    },
22500    ExcerptsExpanded {
22501        ids: Vec<ExcerptId>,
22502    },
22503    BufferEdited,
22504    Edited {
22505        transaction_id: clock::Lamport,
22506    },
22507    Reparsed(BufferId),
22508    Focused,
22509    FocusedIn,
22510    Blurred,
22511    DirtyChanged,
22512    Saved,
22513    TitleChanged,
22514    DiffBaseChanged,
22515    SelectionsChanged {
22516        local: bool,
22517    },
22518    ScrollPositionChanged {
22519        local: bool,
22520        autoscroll: bool,
22521    },
22522    Closed,
22523    TransactionUndone {
22524        transaction_id: clock::Lamport,
22525    },
22526    TransactionBegun {
22527        transaction_id: clock::Lamport,
22528    },
22529    Reloaded,
22530    CursorShapeChanged,
22531    PushedToNavHistory {
22532        anchor: Anchor,
22533        is_deactivate: bool,
22534    },
22535}
22536
22537impl EventEmitter<EditorEvent> for Editor {}
22538
22539impl Focusable for Editor {
22540    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22541        self.focus_handle.clone()
22542    }
22543}
22544
22545impl Render for Editor {
22546    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22547        let settings = ThemeSettings::get_global(cx);
22548
22549        let mut text_style = match self.mode {
22550            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22551                color: cx.theme().colors().editor_foreground,
22552                font_family: settings.ui_font.family.clone(),
22553                font_features: settings.ui_font.features.clone(),
22554                font_fallbacks: settings.ui_font.fallbacks.clone(),
22555                font_size: rems(0.875).into(),
22556                font_weight: settings.ui_font.weight,
22557                line_height: relative(settings.buffer_line_height.value()),
22558                ..Default::default()
22559            },
22560            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22561                color: cx.theme().colors().editor_foreground,
22562                font_family: settings.buffer_font.family.clone(),
22563                font_features: settings.buffer_font.features.clone(),
22564                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22565                font_size: settings.buffer_font_size(cx).into(),
22566                font_weight: settings.buffer_font.weight,
22567                line_height: relative(settings.buffer_line_height.value()),
22568                ..Default::default()
22569            },
22570        };
22571        if let Some(text_style_refinement) = &self.text_style_refinement {
22572            text_style.refine(text_style_refinement)
22573        }
22574
22575        let background = match self.mode {
22576            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22577            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22578            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22579            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22580        };
22581
22582        EditorElement::new(
22583            &cx.entity(),
22584            EditorStyle {
22585                background,
22586                border: cx.theme().colors().border,
22587                local_player: cx.theme().players().local(),
22588                text: text_style,
22589                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22590                syntax: cx.theme().syntax().clone(),
22591                status: cx.theme().status().clone(),
22592                inlay_hints_style: make_inlay_hints_style(cx),
22593                inline_completion_styles: make_suggestion_styles(cx),
22594                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22595                show_underlines: self.diagnostics_enabled(),
22596            },
22597        )
22598    }
22599}
22600
22601impl EntityInputHandler for Editor {
22602    fn text_for_range(
22603        &mut self,
22604        range_utf16: Range<usize>,
22605        adjusted_range: &mut Option<Range<usize>>,
22606        _: &mut Window,
22607        cx: &mut Context<Self>,
22608    ) -> Option<String> {
22609        let snapshot = self.buffer.read(cx).read(cx);
22610        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22611        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22612        if (start.0..end.0) != range_utf16 {
22613            adjusted_range.replace(start.0..end.0);
22614        }
22615        Some(snapshot.text_for_range(start..end).collect())
22616    }
22617
22618    fn selected_text_range(
22619        &mut self,
22620        ignore_disabled_input: bool,
22621        _: &mut Window,
22622        cx: &mut Context<Self>,
22623    ) -> Option<UTF16Selection> {
22624        // Prevent the IME menu from appearing when holding down an alphabetic key
22625        // while input is disabled.
22626        if !ignore_disabled_input && !self.input_enabled {
22627            return None;
22628        }
22629
22630        let selection = self.selections.newest::<OffsetUtf16>(cx);
22631        let range = selection.range();
22632
22633        Some(UTF16Selection {
22634            range: range.start.0..range.end.0,
22635            reversed: selection.reversed,
22636        })
22637    }
22638
22639    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22640        let snapshot = self.buffer.read(cx).read(cx);
22641        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22642        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22643    }
22644
22645    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22646        self.clear_highlights::<InputComposition>(cx);
22647        self.ime_transaction.take();
22648    }
22649
22650    fn replace_text_in_range(
22651        &mut self,
22652        range_utf16: Option<Range<usize>>,
22653        text: &str,
22654        window: &mut Window,
22655        cx: &mut Context<Self>,
22656    ) {
22657        if !self.input_enabled {
22658            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22659            return;
22660        }
22661
22662        self.transact(window, cx, |this, window, cx| {
22663            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22664                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22665                Some(this.selection_replacement_ranges(range_utf16, cx))
22666            } else {
22667                this.marked_text_ranges(cx)
22668            };
22669
22670            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22671                let newest_selection_id = this.selections.newest_anchor().id;
22672                this.selections
22673                    .all::<OffsetUtf16>(cx)
22674                    .iter()
22675                    .zip(ranges_to_replace.iter())
22676                    .find_map(|(selection, range)| {
22677                        if selection.id == newest_selection_id {
22678                            Some(
22679                                (range.start.0 as isize - selection.head().0 as isize)
22680                                    ..(range.end.0 as isize - selection.head().0 as isize),
22681                            )
22682                        } else {
22683                            None
22684                        }
22685                    })
22686            });
22687
22688            cx.emit(EditorEvent::InputHandled {
22689                utf16_range_to_replace: range_to_replace,
22690                text: text.into(),
22691            });
22692
22693            if let Some(new_selected_ranges) = new_selected_ranges {
22694                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22695                    selections.select_ranges(new_selected_ranges)
22696                });
22697                this.backspace(&Default::default(), window, cx);
22698            }
22699
22700            this.handle_input(text, window, cx);
22701        });
22702
22703        if let Some(transaction) = self.ime_transaction {
22704            self.buffer.update(cx, |buffer, cx| {
22705                buffer.group_until_transaction(transaction, cx);
22706            });
22707        }
22708
22709        self.unmark_text(window, cx);
22710    }
22711
22712    fn replace_and_mark_text_in_range(
22713        &mut self,
22714        range_utf16: Option<Range<usize>>,
22715        text: &str,
22716        new_selected_range_utf16: Option<Range<usize>>,
22717        window: &mut Window,
22718        cx: &mut Context<Self>,
22719    ) {
22720        if !self.input_enabled {
22721            return;
22722        }
22723
22724        let transaction = self.transact(window, cx, |this, window, cx| {
22725            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22726                let snapshot = this.buffer.read(cx).read(cx);
22727                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22728                    for marked_range in &mut marked_ranges {
22729                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22730                        marked_range.start.0 += relative_range_utf16.start;
22731                        marked_range.start =
22732                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22733                        marked_range.end =
22734                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22735                    }
22736                }
22737                Some(marked_ranges)
22738            } else if let Some(range_utf16) = range_utf16 {
22739                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22740                Some(this.selection_replacement_ranges(range_utf16, cx))
22741            } else {
22742                None
22743            };
22744
22745            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22746                let newest_selection_id = this.selections.newest_anchor().id;
22747                this.selections
22748                    .all::<OffsetUtf16>(cx)
22749                    .iter()
22750                    .zip(ranges_to_replace.iter())
22751                    .find_map(|(selection, range)| {
22752                        if selection.id == newest_selection_id {
22753                            Some(
22754                                (range.start.0 as isize - selection.head().0 as isize)
22755                                    ..(range.end.0 as isize - selection.head().0 as isize),
22756                            )
22757                        } else {
22758                            None
22759                        }
22760                    })
22761            });
22762
22763            cx.emit(EditorEvent::InputHandled {
22764                utf16_range_to_replace: range_to_replace,
22765                text: text.into(),
22766            });
22767
22768            if let Some(ranges) = ranges_to_replace {
22769                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22770                    s.select_ranges(ranges)
22771                });
22772            }
22773
22774            let marked_ranges = {
22775                let snapshot = this.buffer.read(cx).read(cx);
22776                this.selections
22777                    .disjoint_anchors()
22778                    .iter()
22779                    .map(|selection| {
22780                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22781                    })
22782                    .collect::<Vec<_>>()
22783            };
22784
22785            if text.is_empty() {
22786                this.unmark_text(window, cx);
22787            } else {
22788                this.highlight_text::<InputComposition>(
22789                    marked_ranges.clone(),
22790                    HighlightStyle {
22791                        underline: Some(UnderlineStyle {
22792                            thickness: px(1.),
22793                            color: None,
22794                            wavy: false,
22795                        }),
22796                        ..Default::default()
22797                    },
22798                    cx,
22799                );
22800            }
22801
22802            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22803            let use_autoclose = this.use_autoclose;
22804            let use_auto_surround = this.use_auto_surround;
22805            this.set_use_autoclose(false);
22806            this.set_use_auto_surround(false);
22807            this.handle_input(text, window, cx);
22808            this.set_use_autoclose(use_autoclose);
22809            this.set_use_auto_surround(use_auto_surround);
22810
22811            if let Some(new_selected_range) = new_selected_range_utf16 {
22812                let snapshot = this.buffer.read(cx).read(cx);
22813                let new_selected_ranges = marked_ranges
22814                    .into_iter()
22815                    .map(|marked_range| {
22816                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22817                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22818                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22819                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22820                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22821                    })
22822                    .collect::<Vec<_>>();
22823
22824                drop(snapshot);
22825                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22826                    selections.select_ranges(new_selected_ranges)
22827                });
22828            }
22829        });
22830
22831        self.ime_transaction = self.ime_transaction.or(transaction);
22832        if let Some(transaction) = self.ime_transaction {
22833            self.buffer.update(cx, |buffer, cx| {
22834                buffer.group_until_transaction(transaction, cx);
22835            });
22836        }
22837
22838        if self.text_highlights::<InputComposition>(cx).is_none() {
22839            self.ime_transaction.take();
22840        }
22841    }
22842
22843    fn bounds_for_range(
22844        &mut self,
22845        range_utf16: Range<usize>,
22846        element_bounds: gpui::Bounds<Pixels>,
22847        window: &mut Window,
22848        cx: &mut Context<Self>,
22849    ) -> Option<gpui::Bounds<Pixels>> {
22850        let text_layout_details = self.text_layout_details(window);
22851        let CharacterDimensions {
22852            em_width,
22853            em_advance,
22854            line_height,
22855        } = self.character_dimensions(window);
22856
22857        let snapshot = self.snapshot(window, cx);
22858        let scroll_position = snapshot.scroll_position();
22859        let scroll_left = scroll_position.x * em_advance;
22860
22861        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22862        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22863            + self.gutter_dimensions.full_width();
22864        let y = line_height * (start.row().as_f32() - scroll_position.y);
22865
22866        Some(Bounds {
22867            origin: element_bounds.origin + point(x, y),
22868            size: size(em_width, line_height),
22869        })
22870    }
22871
22872    fn character_index_for_point(
22873        &mut self,
22874        point: gpui::Point<Pixels>,
22875        _window: &mut Window,
22876        _cx: &mut Context<Self>,
22877    ) -> Option<usize> {
22878        let position_map = self.last_position_map.as_ref()?;
22879        if !position_map.text_hitbox.contains(&point) {
22880            return None;
22881        }
22882        let display_point = position_map.point_for_position(point).previous_valid;
22883        let anchor = position_map
22884            .snapshot
22885            .display_point_to_anchor(display_point, Bias::Left);
22886        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22887        Some(utf16_offset.0)
22888    }
22889}
22890
22891trait SelectionExt {
22892    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22893    fn spanned_rows(
22894        &self,
22895        include_end_if_at_line_start: bool,
22896        map: &DisplaySnapshot,
22897    ) -> Range<MultiBufferRow>;
22898}
22899
22900impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22901    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22902        let start = self
22903            .start
22904            .to_point(&map.buffer_snapshot)
22905            .to_display_point(map);
22906        let end = self
22907            .end
22908            .to_point(&map.buffer_snapshot)
22909            .to_display_point(map);
22910        if self.reversed {
22911            end..start
22912        } else {
22913            start..end
22914        }
22915    }
22916
22917    fn spanned_rows(
22918        &self,
22919        include_end_if_at_line_start: bool,
22920        map: &DisplaySnapshot,
22921    ) -> Range<MultiBufferRow> {
22922        let start = self.start.to_point(&map.buffer_snapshot);
22923        let mut end = self.end.to_point(&map.buffer_snapshot);
22924        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22925            end.row -= 1;
22926        }
22927
22928        let buffer_start = map.prev_line_boundary(start).0;
22929        let buffer_end = map.next_line_boundary(end).0;
22930        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22931    }
22932}
22933
22934impl<T: InvalidationRegion> InvalidationStack<T> {
22935    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22936    where
22937        S: Clone + ToOffset,
22938    {
22939        while let Some(region) = self.last() {
22940            let all_selections_inside_invalidation_ranges =
22941                if selections.len() == region.ranges().len() {
22942                    selections
22943                        .iter()
22944                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22945                        .all(|(selection, invalidation_range)| {
22946                            let head = selection.head().to_offset(buffer);
22947                            invalidation_range.start <= head && invalidation_range.end >= head
22948                        })
22949                } else {
22950                    false
22951                };
22952
22953            if all_selections_inside_invalidation_ranges {
22954                break;
22955            } else {
22956                self.pop();
22957            }
22958        }
22959    }
22960}
22961
22962impl<T> Default for InvalidationStack<T> {
22963    fn default() -> Self {
22964        Self(Default::default())
22965    }
22966}
22967
22968impl<T> Deref for InvalidationStack<T> {
22969    type Target = Vec<T>;
22970
22971    fn deref(&self) -> &Self::Target {
22972        &self.0
22973    }
22974}
22975
22976impl<T> DerefMut for InvalidationStack<T> {
22977    fn deref_mut(&mut self) -> &mut Self::Target {
22978        &mut self.0
22979    }
22980}
22981
22982impl InvalidationRegion for SnippetState {
22983    fn ranges(&self) -> &[Range<Anchor>] {
22984        &self.ranges[self.active_index]
22985    }
22986}
22987
22988fn inline_completion_edit_text(
22989    current_snapshot: &BufferSnapshot,
22990    edits: &[(Range<Anchor>, String)],
22991    edit_preview: &EditPreview,
22992    include_deletions: bool,
22993    cx: &App,
22994) -> HighlightedText {
22995    let edits = edits
22996        .iter()
22997        .map(|(anchor, text)| {
22998            (
22999                anchor.start.text_anchor..anchor.end.text_anchor,
23000                text.clone(),
23001            )
23002        })
23003        .collect::<Vec<_>>();
23004
23005    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23006}
23007
23008pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23009    match severity {
23010        lsp::DiagnosticSeverity::ERROR => colors.error,
23011        lsp::DiagnosticSeverity::WARNING => colors.warning,
23012        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23013        lsp::DiagnosticSeverity::HINT => colors.info,
23014        _ => colors.ignored,
23015    }
23016}
23017
23018pub fn styled_runs_for_code_label<'a>(
23019    label: &'a CodeLabel,
23020    syntax_theme: &'a theme::SyntaxTheme,
23021) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23022    let fade_out = HighlightStyle {
23023        fade_out: Some(0.35),
23024        ..Default::default()
23025    };
23026
23027    let mut prev_end = label.filter_range.end;
23028    label
23029        .runs
23030        .iter()
23031        .enumerate()
23032        .flat_map(move |(ix, (range, highlight_id))| {
23033            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23034                style
23035            } else {
23036                return Default::default();
23037            };
23038            let mut muted_style = style;
23039            muted_style.highlight(fade_out);
23040
23041            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23042            if range.start >= label.filter_range.end {
23043                if range.start > prev_end {
23044                    runs.push((prev_end..range.start, fade_out));
23045                }
23046                runs.push((range.clone(), muted_style));
23047            } else if range.end <= label.filter_range.end {
23048                runs.push((range.clone(), style));
23049            } else {
23050                runs.push((range.start..label.filter_range.end, style));
23051                runs.push((label.filter_range.end..range.end, muted_style));
23052            }
23053            prev_end = cmp::max(prev_end, range.end);
23054
23055            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23056                runs.push((prev_end..label.text.len(), fade_out));
23057            }
23058
23059            runs
23060        })
23061}
23062
23063pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23064    let mut prev_index = 0;
23065    let mut prev_codepoint: Option<char> = None;
23066    text.char_indices()
23067        .chain([(text.len(), '\0')])
23068        .filter_map(move |(index, codepoint)| {
23069            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23070            let is_boundary = index == text.len()
23071                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23072                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23073            if is_boundary {
23074                let chunk = &text[prev_index..index];
23075                prev_index = index;
23076                Some(chunk)
23077            } else {
23078                None
23079            }
23080        })
23081}
23082
23083pub trait RangeToAnchorExt: Sized {
23084    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23085
23086    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23087        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23088        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23089    }
23090}
23091
23092impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23093    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23094        let start_offset = self.start.to_offset(snapshot);
23095        let end_offset = self.end.to_offset(snapshot);
23096        if start_offset == end_offset {
23097            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23098        } else {
23099            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23100        }
23101    }
23102}
23103
23104pub trait RowExt {
23105    fn as_f32(&self) -> f32;
23106
23107    fn next_row(&self) -> Self;
23108
23109    fn previous_row(&self) -> Self;
23110
23111    fn minus(&self, other: Self) -> u32;
23112}
23113
23114impl RowExt for DisplayRow {
23115    fn as_f32(&self) -> f32 {
23116        self.0 as f32
23117    }
23118
23119    fn next_row(&self) -> Self {
23120        Self(self.0 + 1)
23121    }
23122
23123    fn previous_row(&self) -> Self {
23124        Self(self.0.saturating_sub(1))
23125    }
23126
23127    fn minus(&self, other: Self) -> u32 {
23128        self.0 - other.0
23129    }
23130}
23131
23132impl RowExt for MultiBufferRow {
23133    fn as_f32(&self) -> f32 {
23134        self.0 as f32
23135    }
23136
23137    fn next_row(&self) -> Self {
23138        Self(self.0 + 1)
23139    }
23140
23141    fn previous_row(&self) -> Self {
23142        Self(self.0.saturating_sub(1))
23143    }
23144
23145    fn minus(&self, other: Self) -> u32 {
23146        self.0 - other.0
23147    }
23148}
23149
23150trait RowRangeExt {
23151    type Row;
23152
23153    fn len(&self) -> usize;
23154
23155    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23156}
23157
23158impl RowRangeExt for Range<MultiBufferRow> {
23159    type Row = MultiBufferRow;
23160
23161    fn len(&self) -> usize {
23162        (self.end.0 - self.start.0) as usize
23163    }
23164
23165    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23166        (self.start.0..self.end.0).map(MultiBufferRow)
23167    }
23168}
23169
23170impl RowRangeExt for Range<DisplayRow> {
23171    type Row = DisplayRow;
23172
23173    fn len(&self) -> usize {
23174        (self.end.0 - self.start.0) as usize
23175    }
23176
23177    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23178        (self.start.0..self.end.0).map(DisplayRow)
23179    }
23180}
23181
23182/// If select range has more than one line, we
23183/// just point the cursor to range.start.
23184fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23185    if range.start.row == range.end.row {
23186        range
23187    } else {
23188        range.start..range.start
23189    }
23190}
23191pub struct KillRing(ClipboardItem);
23192impl Global for KillRing {}
23193
23194const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23195
23196enum BreakpointPromptEditAction {
23197    Log,
23198    Condition,
23199    HitCondition,
23200}
23201
23202struct BreakpointPromptEditor {
23203    pub(crate) prompt: Entity<Editor>,
23204    editor: WeakEntity<Editor>,
23205    breakpoint_anchor: Anchor,
23206    breakpoint: Breakpoint,
23207    edit_action: BreakpointPromptEditAction,
23208    block_ids: HashSet<CustomBlockId>,
23209    editor_margins: Arc<Mutex<EditorMargins>>,
23210    _subscriptions: Vec<Subscription>,
23211}
23212
23213impl BreakpointPromptEditor {
23214    const MAX_LINES: u8 = 4;
23215
23216    fn new(
23217        editor: WeakEntity<Editor>,
23218        breakpoint_anchor: Anchor,
23219        breakpoint: Breakpoint,
23220        edit_action: BreakpointPromptEditAction,
23221        window: &mut Window,
23222        cx: &mut Context<Self>,
23223    ) -> Self {
23224        let base_text = match edit_action {
23225            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23226            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23227            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23228        }
23229        .map(|msg| msg.to_string())
23230        .unwrap_or_default();
23231
23232        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23233        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23234
23235        let prompt = cx.new(|cx| {
23236            let mut prompt = Editor::new(
23237                EditorMode::AutoHeight {
23238                    min_lines: 1,
23239                    max_lines: Some(Self::MAX_LINES as usize),
23240                },
23241                buffer,
23242                None,
23243                window,
23244                cx,
23245            );
23246            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23247            prompt.set_show_cursor_when_unfocused(false, cx);
23248            prompt.set_placeholder_text(
23249                match edit_action {
23250                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23251                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23252                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23253                },
23254                cx,
23255            );
23256
23257            prompt
23258        });
23259
23260        Self {
23261            prompt,
23262            editor,
23263            breakpoint_anchor,
23264            breakpoint,
23265            edit_action,
23266            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23267            block_ids: Default::default(),
23268            _subscriptions: vec![],
23269        }
23270    }
23271
23272    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23273        self.block_ids.extend(block_ids)
23274    }
23275
23276    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23277        if let Some(editor) = self.editor.upgrade() {
23278            let message = self
23279                .prompt
23280                .read(cx)
23281                .buffer
23282                .read(cx)
23283                .as_singleton()
23284                .expect("A multi buffer in breakpoint prompt isn't possible")
23285                .read(cx)
23286                .as_rope()
23287                .to_string();
23288
23289            editor.update(cx, |editor, cx| {
23290                editor.edit_breakpoint_at_anchor(
23291                    self.breakpoint_anchor,
23292                    self.breakpoint.clone(),
23293                    match self.edit_action {
23294                        BreakpointPromptEditAction::Log => {
23295                            BreakpointEditAction::EditLogMessage(message.into())
23296                        }
23297                        BreakpointPromptEditAction::Condition => {
23298                            BreakpointEditAction::EditCondition(message.into())
23299                        }
23300                        BreakpointPromptEditAction::HitCondition => {
23301                            BreakpointEditAction::EditHitCondition(message.into())
23302                        }
23303                    },
23304                    cx,
23305                );
23306
23307                editor.remove_blocks(self.block_ids.clone(), None, cx);
23308                cx.focus_self(window);
23309            });
23310        }
23311    }
23312
23313    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23314        self.editor
23315            .update(cx, |editor, cx| {
23316                editor.remove_blocks(self.block_ids.clone(), None, cx);
23317                window.focus(&editor.focus_handle);
23318            })
23319            .log_err();
23320    }
23321
23322    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23323        let settings = ThemeSettings::get_global(cx);
23324        let text_style = TextStyle {
23325            color: if self.prompt.read(cx).read_only(cx) {
23326                cx.theme().colors().text_disabled
23327            } else {
23328                cx.theme().colors().text
23329            },
23330            font_family: settings.buffer_font.family.clone(),
23331            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23332            font_size: settings.buffer_font_size(cx).into(),
23333            font_weight: settings.buffer_font.weight,
23334            line_height: relative(settings.buffer_line_height.value()),
23335            ..Default::default()
23336        };
23337        EditorElement::new(
23338            &self.prompt,
23339            EditorStyle {
23340                background: cx.theme().colors().editor_background,
23341                local_player: cx.theme().players().local(),
23342                text: text_style,
23343                ..Default::default()
23344            },
23345        )
23346    }
23347}
23348
23349impl Render for BreakpointPromptEditor {
23350    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23351        let editor_margins = *self.editor_margins.lock();
23352        let gutter_dimensions = editor_margins.gutter;
23353        h_flex()
23354            .key_context("Editor")
23355            .bg(cx.theme().colors().editor_background)
23356            .border_y_1()
23357            .border_color(cx.theme().status().info_border)
23358            .size_full()
23359            .py(window.line_height() / 2.5)
23360            .on_action(cx.listener(Self::confirm))
23361            .on_action(cx.listener(Self::cancel))
23362            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23363            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23364    }
23365}
23366
23367impl Focusable for BreakpointPromptEditor {
23368    fn focus_handle(&self, cx: &App) -> FocusHandle {
23369        self.prompt.focus_handle(cx)
23370    }
23371}
23372
23373fn all_edits_insertions_or_deletions(
23374    edits: &Vec<(Range<Anchor>, String)>,
23375    snapshot: &MultiBufferSnapshot,
23376) -> bool {
23377    let mut all_insertions = true;
23378    let mut all_deletions = true;
23379
23380    for (range, new_text) in edits.iter() {
23381        let range_is_empty = range.to_offset(&snapshot).is_empty();
23382        let text_is_empty = new_text.is_empty();
23383
23384        if range_is_empty != text_is_empty {
23385            if range_is_empty {
23386                all_deletions = false;
23387            } else {
23388                all_insertions = false;
23389            }
23390        } else {
23391            return false;
23392        }
23393
23394        if !all_insertions && !all_deletions {
23395            return false;
23396        }
23397    }
23398    all_insertions || all_deletions
23399}
23400
23401struct MissingEditPredictionKeybindingTooltip;
23402
23403impl Render for MissingEditPredictionKeybindingTooltip {
23404    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23405        ui::tooltip_container(window, cx, |container, _, cx| {
23406            container
23407                .flex_shrink_0()
23408                .max_w_80()
23409                .min_h(rems_from_px(124.))
23410                .justify_between()
23411                .child(
23412                    v_flex()
23413                        .flex_1()
23414                        .text_ui_sm(cx)
23415                        .child(Label::new("Conflict with Accept Keybinding"))
23416                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23417                )
23418                .child(
23419                    h_flex()
23420                        .pb_1()
23421                        .gap_1()
23422                        .items_end()
23423                        .w_full()
23424                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23425                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23426                        }))
23427                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23428                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23429                        })),
23430                )
23431        })
23432    }
23433}
23434
23435#[derive(Debug, Clone, Copy, PartialEq)]
23436pub struct LineHighlight {
23437    pub background: Background,
23438    pub border: Option<gpui::Hsla>,
23439    pub include_gutter: bool,
23440    pub type_id: Option<TypeId>,
23441}
23442
23443struct LineManipulationResult {
23444    pub new_text: String,
23445    pub line_count_before: usize,
23446    pub line_count_after: usize,
23447}
23448
23449fn render_diff_hunk_controls(
23450    row: u32,
23451    status: &DiffHunkStatus,
23452    hunk_range: Range<Anchor>,
23453    is_created_file: bool,
23454    line_height: Pixels,
23455    editor: &Entity<Editor>,
23456    _window: &mut Window,
23457    cx: &mut App,
23458) -> AnyElement {
23459    h_flex()
23460        .h(line_height)
23461        .mr_1()
23462        .gap_1()
23463        .px_0p5()
23464        .pb_1()
23465        .border_x_1()
23466        .border_b_1()
23467        .border_color(cx.theme().colors().border_variant)
23468        .rounded_b_lg()
23469        .bg(cx.theme().colors().editor_background)
23470        .gap_1()
23471        .block_mouse_except_scroll()
23472        .shadow_md()
23473        .child(if status.has_secondary_hunk() {
23474            Button::new(("stage", row as u64), "Stage")
23475                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23476                .tooltip({
23477                    let focus_handle = editor.focus_handle(cx);
23478                    move |window, cx| {
23479                        Tooltip::for_action_in(
23480                            "Stage Hunk",
23481                            &::git::ToggleStaged,
23482                            &focus_handle,
23483                            window,
23484                            cx,
23485                        )
23486                    }
23487                })
23488                .on_click({
23489                    let editor = editor.clone();
23490                    move |_event, _window, cx| {
23491                        editor.update(cx, |editor, cx| {
23492                            editor.stage_or_unstage_diff_hunks(
23493                                true,
23494                                vec![hunk_range.start..hunk_range.start],
23495                                cx,
23496                            );
23497                        });
23498                    }
23499                })
23500        } else {
23501            Button::new(("unstage", row as u64), "Unstage")
23502                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23503                .tooltip({
23504                    let focus_handle = editor.focus_handle(cx);
23505                    move |window, cx| {
23506                        Tooltip::for_action_in(
23507                            "Unstage Hunk",
23508                            &::git::ToggleStaged,
23509                            &focus_handle,
23510                            window,
23511                            cx,
23512                        )
23513                    }
23514                })
23515                .on_click({
23516                    let editor = editor.clone();
23517                    move |_event, _window, cx| {
23518                        editor.update(cx, |editor, cx| {
23519                            editor.stage_or_unstage_diff_hunks(
23520                                false,
23521                                vec![hunk_range.start..hunk_range.start],
23522                                cx,
23523                            );
23524                        });
23525                    }
23526                })
23527        })
23528        .child(
23529            Button::new(("restore", row as u64), "Restore")
23530                .tooltip({
23531                    let focus_handle = editor.focus_handle(cx);
23532                    move |window, cx| {
23533                        Tooltip::for_action_in(
23534                            "Restore Hunk",
23535                            &::git::Restore,
23536                            &focus_handle,
23537                            window,
23538                            cx,
23539                        )
23540                    }
23541                })
23542                .on_click({
23543                    let editor = editor.clone();
23544                    move |_event, window, cx| {
23545                        editor.update(cx, |editor, cx| {
23546                            let snapshot = editor.snapshot(window, cx);
23547                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23548                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23549                        });
23550                    }
23551                })
23552                .disabled(is_created_file),
23553        )
23554        .when(
23555            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23556            |el| {
23557                el.child(
23558                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23559                        .shape(IconButtonShape::Square)
23560                        .icon_size(IconSize::Small)
23561                        // .disabled(!has_multiple_hunks)
23562                        .tooltip({
23563                            let focus_handle = editor.focus_handle(cx);
23564                            move |window, cx| {
23565                                Tooltip::for_action_in(
23566                                    "Next Hunk",
23567                                    &GoToHunk,
23568                                    &focus_handle,
23569                                    window,
23570                                    cx,
23571                                )
23572                            }
23573                        })
23574                        .on_click({
23575                            let editor = editor.clone();
23576                            move |_event, window, cx| {
23577                                editor.update(cx, |editor, cx| {
23578                                    let snapshot = editor.snapshot(window, cx);
23579                                    let position =
23580                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23581                                    editor.go_to_hunk_before_or_after_position(
23582                                        &snapshot,
23583                                        position,
23584                                        Direction::Next,
23585                                        window,
23586                                        cx,
23587                                    );
23588                                    editor.expand_selected_diff_hunks(cx);
23589                                });
23590                            }
23591                        }),
23592                )
23593                .child(
23594                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23595                        .shape(IconButtonShape::Square)
23596                        .icon_size(IconSize::Small)
23597                        // .disabled(!has_multiple_hunks)
23598                        .tooltip({
23599                            let focus_handle = editor.focus_handle(cx);
23600                            move |window, cx| {
23601                                Tooltip::for_action_in(
23602                                    "Previous Hunk",
23603                                    &GoToPreviousHunk,
23604                                    &focus_handle,
23605                                    window,
23606                                    cx,
23607                                )
23608                            }
23609                        })
23610                        .on_click({
23611                            let editor = editor.clone();
23612                            move |_event, window, cx| {
23613                                editor.update(cx, |editor, cx| {
23614                                    let snapshot = editor.snapshot(window, cx);
23615                                    let point =
23616                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23617                                    editor.go_to_hunk_before_or_after_position(
23618                                        &snapshot,
23619                                        point,
23620                                        Direction::Prev,
23621                                        window,
23622                                        cx,
23623                                    );
23624                                    editor.expand_selected_diff_hunks(cx);
23625                                });
23626                            }
23627                        }),
23628                )
23629            },
23630        )
23631        .into_any_element()
23632}