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, impl_actions, 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: 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    pub fn is_full(&self) -> bool {
  515        matches!(self, Self::Full { .. })
  516    }
  517
  518    fn is_minimap(&self) -> bool {
  519        matches!(self, Self::Minimap { .. })
  520    }
  521}
  522
  523#[derive(Copy, Clone, Debug)]
  524pub enum SoftWrap {
  525    /// Prefer not to wrap at all.
  526    ///
  527    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  528    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  529    GitDiff,
  530    /// Prefer a single line generally, unless an overly long line is encountered.
  531    None,
  532    /// Soft wrap lines that exceed the editor width.
  533    EditorWidth,
  534    /// Soft wrap lines at the preferred line length.
  535    Column(u32),
  536    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  537    Bounded(u32),
  538}
  539
  540#[derive(Clone)]
  541pub struct EditorStyle {
  542    pub background: Hsla,
  543    pub local_player: PlayerColor,
  544    pub text: TextStyle,
  545    pub scrollbar_width: Pixels,
  546    pub syntax: Arc<SyntaxTheme>,
  547    pub status: StatusColors,
  548    pub inlay_hints_style: HighlightStyle,
  549    pub inline_completion_styles: InlineCompletionStyles,
  550    pub unnecessary_code_fade: f32,
  551    pub show_underlines: bool,
  552}
  553
  554impl Default for EditorStyle {
  555    fn default() -> Self {
  556        Self {
  557            background: Hsla::default(),
  558            local_player: PlayerColor::default(),
  559            text: TextStyle::default(),
  560            scrollbar_width: Pixels::default(),
  561            syntax: Default::default(),
  562            // HACK: Status colors don't have a real default.
  563            // We should look into removing the status colors from the editor
  564            // style and retrieve them directly from the theme.
  565            status: StatusColors::dark(),
  566            inlay_hints_style: HighlightStyle::default(),
  567            inline_completion_styles: InlineCompletionStyles {
  568                insertion: HighlightStyle::default(),
  569                whitespace: HighlightStyle::default(),
  570            },
  571            unnecessary_code_fade: Default::default(),
  572            show_underlines: true,
  573        }
  574    }
  575}
  576
  577pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  578    let show_background = language_settings::language_settings(None, None, cx)
  579        .inlay_hints
  580        .show_background;
  581
  582    HighlightStyle {
  583        color: Some(cx.theme().status().hint),
  584        background_color: show_background.then(|| cx.theme().status().hint_background),
  585        ..HighlightStyle::default()
  586    }
  587}
  588
  589pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  590    InlineCompletionStyles {
  591        insertion: HighlightStyle {
  592            color: Some(cx.theme().status().predictive),
  593            ..HighlightStyle::default()
  594        },
  595        whitespace: HighlightStyle {
  596            background_color: Some(cx.theme().status().created_background),
  597            ..HighlightStyle::default()
  598        },
  599    }
  600}
  601
  602type CompletionId = usize;
  603
  604pub(crate) enum EditDisplayMode {
  605    TabAccept,
  606    DiffPopover,
  607    Inline,
  608}
  609
  610enum InlineCompletion {
  611    Edit {
  612        edits: Vec<(Range<Anchor>, String)>,
  613        edit_preview: Option<EditPreview>,
  614        display_mode: EditDisplayMode,
  615        snapshot: BufferSnapshot,
  616    },
  617    Move {
  618        target: Anchor,
  619        snapshot: BufferSnapshot,
  620    },
  621}
  622
  623struct InlineCompletionState {
  624    inlay_ids: Vec<InlayId>,
  625    completion: InlineCompletion,
  626    completion_id: Option<SharedString>,
  627    invalidation_range: Range<Anchor>,
  628}
  629
  630enum EditPredictionSettings {
  631    Disabled,
  632    Enabled {
  633        show_in_menu: bool,
  634        preview_requires_modifier: bool,
  635    },
  636}
  637
  638enum InlineCompletionHighlight {}
  639
  640#[derive(Debug, Clone)]
  641struct InlineDiagnostic {
  642    message: SharedString,
  643    group_id: usize,
  644    is_primary: bool,
  645    start: Point,
  646    severity: lsp::DiagnosticSeverity,
  647}
  648
  649pub enum MenuInlineCompletionsPolicy {
  650    Never,
  651    ByProvider,
  652}
  653
  654pub enum EditPredictionPreview {
  655    /// Modifier is not pressed
  656    Inactive { released_too_fast: bool },
  657    /// Modifier pressed
  658    Active {
  659        since: Instant,
  660        previous_scroll_position: Option<ScrollAnchor>,
  661    },
  662}
  663
  664impl EditPredictionPreview {
  665    pub fn released_too_fast(&self) -> bool {
  666        match self {
  667            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  668            EditPredictionPreview::Active { .. } => false,
  669        }
  670    }
  671
  672    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  673        if let EditPredictionPreview::Active {
  674            previous_scroll_position,
  675            ..
  676        } = self
  677        {
  678            *previous_scroll_position = scroll_position;
  679        }
  680    }
  681}
  682
  683pub struct ContextMenuOptions {
  684    pub min_entries_visible: usize,
  685    pub max_entries_visible: usize,
  686    pub placement: Option<ContextMenuPlacement>,
  687}
  688
  689#[derive(Debug, Clone, PartialEq, Eq)]
  690pub enum ContextMenuPlacement {
  691    Above,
  692    Below,
  693}
  694
  695#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  696struct EditorActionId(usize);
  697
  698impl EditorActionId {
  699    pub fn post_inc(&mut self) -> Self {
  700        let answer = self.0;
  701
  702        *self = Self(answer + 1);
  703
  704        Self(answer)
  705    }
  706}
  707
  708// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  709// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  710
  711type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  712type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  713
  714#[derive(Default)]
  715struct ScrollbarMarkerState {
  716    scrollbar_size: Size<Pixels>,
  717    dirty: bool,
  718    markers: Arc<[PaintQuad]>,
  719    pending_refresh: Option<Task<Result<()>>>,
  720}
  721
  722impl ScrollbarMarkerState {
  723    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  724        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  725    }
  726}
  727
  728#[derive(Clone, Copy, PartialEq, Eq)]
  729pub enum MinimapVisibility {
  730    Disabled,
  731    Enabled {
  732        /// The configuration currently present in the users settings.
  733        setting_configuration: bool,
  734        /// Whether to override the currently set visibility from the users setting.
  735        toggle_override: bool,
  736    },
  737}
  738
  739impl MinimapVisibility {
  740    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  741        if mode.is_full() {
  742            Self::Enabled {
  743                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  744                toggle_override: false,
  745            }
  746        } else {
  747            Self::Disabled
  748        }
  749    }
  750
  751    fn hidden(&self) -> Self {
  752        match *self {
  753            Self::Enabled {
  754                setting_configuration,
  755                ..
  756            } => Self::Enabled {
  757                setting_configuration,
  758                toggle_override: setting_configuration,
  759            },
  760            Self::Disabled => Self::Disabled,
  761        }
  762    }
  763
  764    fn disabled(&self) -> bool {
  765        match *self {
  766            Self::Disabled => true,
  767            _ => false,
  768        }
  769    }
  770
  771    fn settings_visibility(&self) -> bool {
  772        match *self {
  773            Self::Enabled {
  774                setting_configuration,
  775                ..
  776            } => setting_configuration,
  777            _ => false,
  778        }
  779    }
  780
  781    fn visible(&self) -> bool {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                toggle_override,
  786            } => setting_configuration ^ toggle_override,
  787            _ => false,
  788        }
  789    }
  790
  791    fn toggle_visibility(&self) -> Self {
  792        match *self {
  793            Self::Enabled {
  794                toggle_override,
  795                setting_configuration,
  796            } => Self::Enabled {
  797                setting_configuration,
  798                toggle_override: !toggle_override,
  799            },
  800            Self::Disabled => Self::Disabled,
  801        }
  802    }
  803}
  804
  805#[derive(Clone, Debug)]
  806struct RunnableTasks {
  807    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  808    offset: multi_buffer::Anchor,
  809    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  810    column: u32,
  811    // Values of all named captures, including those starting with '_'
  812    extra_variables: HashMap<String, String>,
  813    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  814    context_range: Range<BufferOffset>,
  815}
  816
  817impl RunnableTasks {
  818    fn resolve<'a>(
  819        &'a self,
  820        cx: &'a task::TaskContext,
  821    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  822        self.templates.iter().filter_map(|(kind, template)| {
  823            template
  824                .resolve_task(&kind.to_id_base(), cx)
  825                .map(|task| (kind.clone(), task))
  826        })
  827    }
  828}
  829
  830#[derive(Clone)]
  831pub struct ResolvedTasks {
  832    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  833    position: Anchor,
  834}
  835
  836#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  837struct BufferOffset(usize);
  838
  839// Addons allow storing per-editor state in other crates (e.g. Vim)
  840pub trait Addon: 'static {
  841    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  842
  843    fn render_buffer_header_controls(
  844        &self,
  845        _: &ExcerptInfo,
  846        _: &Window,
  847        _: &App,
  848    ) -> Option<AnyElement> {
  849        None
  850    }
  851
  852    fn to_any(&self) -> &dyn std::any::Any;
  853
  854    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  855        None
  856    }
  857}
  858
  859/// A set of caret positions, registered when the editor was edited.
  860pub struct ChangeList {
  861    changes: Vec<Vec<Anchor>>,
  862    /// Currently "selected" change.
  863    position: Option<usize>,
  864}
  865
  866impl ChangeList {
  867    pub fn new() -> Self {
  868        Self {
  869            changes: Vec::new(),
  870            position: None,
  871        }
  872    }
  873
  874    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  875    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  876    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  877        if self.changes.is_empty() {
  878            return None;
  879        }
  880
  881        let prev = self.position.unwrap_or(self.changes.len());
  882        let next = if direction == Direction::Prev {
  883            prev.saturating_sub(count)
  884        } else {
  885            (prev + count).min(self.changes.len() - 1)
  886        };
  887        self.position = Some(next);
  888        self.changes.get(next).map(|anchors| anchors.as_slice())
  889    }
  890
  891    /// Adds a new change to the list, resetting the change list position.
  892    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  893        self.position.take();
  894        if pop_state {
  895            self.changes.pop();
  896        }
  897        self.changes.push(new_positions.clone());
  898    }
  899
  900    pub fn last(&self) -> Option<&[Anchor]> {
  901        self.changes.last().map(|anchors| anchors.as_slice())
  902    }
  903}
  904
  905#[derive(Clone)]
  906struct InlineBlamePopoverState {
  907    scroll_handle: ScrollHandle,
  908    commit_message: Option<ParsedCommitMessage>,
  909    markdown: Entity<Markdown>,
  910}
  911
  912struct InlineBlamePopover {
  913    position: gpui::Point<Pixels>,
  914    hide_task: Option<Task<()>>,
  915    popover_bounds: Option<Bounds<Pixels>>,
  916    popover_state: InlineBlamePopoverState,
  917}
  918
  919enum SelectionDragState {
  920    /// State when no drag related activity is detected.
  921    None,
  922    /// State when the mouse is down on a selection that is about to be dragged.
  923    ReadyToDrag {
  924        selection: Selection<Anchor>,
  925        click_position: gpui::Point<Pixels>,
  926        mouse_down_time: Instant,
  927    },
  928    /// State when the mouse is dragging the selection in the editor.
  929    Dragging {
  930        selection: Selection<Anchor>,
  931        drop_cursor: Selection<Anchor>,
  932        hide_drop_cursor: bool,
  933    },
  934}
  935
  936enum ColumnarSelectionState {
  937    FromMouse {
  938        selection_tail: Anchor,
  939        display_point: Option<DisplayPoint>,
  940    },
  941    FromSelection {
  942        selection_tail: Anchor,
  943    },
  944}
  945
  946/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  947/// a breakpoint on them.
  948#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  949struct PhantomBreakpointIndicator {
  950    display_row: DisplayRow,
  951    /// There's a small debounce between hovering over the line and showing the indicator.
  952    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  953    is_active: bool,
  954    collides_with_existing_breakpoint: bool,
  955}
  956
  957/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  958///
  959/// See the [module level documentation](self) for more information.
  960pub struct Editor {
  961    focus_handle: FocusHandle,
  962    last_focused_descendant: Option<WeakFocusHandle>,
  963    /// The text buffer being edited
  964    buffer: Entity<MultiBuffer>,
  965    /// Map of how text in the buffer should be displayed.
  966    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  967    pub display_map: Entity<DisplayMap>,
  968    pub selections: SelectionsCollection,
  969    pub scroll_manager: ScrollManager,
  970    /// When inline assist editors are linked, they all render cursors because
  971    /// typing enters text into each of them, even the ones that aren't focused.
  972    pub(crate) show_cursor_when_unfocused: bool,
  973    columnar_selection_state: Option<ColumnarSelectionState>,
  974    add_selections_state: Option<AddSelectionsState>,
  975    select_next_state: Option<SelectNextState>,
  976    select_prev_state: Option<SelectNextState>,
  977    selection_history: SelectionHistory,
  978    defer_selection_effects: bool,
  979    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  980    autoclose_regions: Vec<AutocloseRegion>,
  981    snippet_stack: InvalidationStack<SnippetState>,
  982    select_syntax_node_history: SelectSyntaxNodeHistory,
  983    ime_transaction: Option<TransactionId>,
  984    pub diagnostics_max_severity: DiagnosticSeverity,
  985    active_diagnostics: ActiveDiagnostic,
  986    show_inline_diagnostics: bool,
  987    inline_diagnostics_update: Task<()>,
  988    inline_diagnostics_enabled: bool,
  989    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  990    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  991    hard_wrap: Option<usize>,
  992
  993    // TODO: make this a access method
  994    pub project: Option<Entity<Project>>,
  995    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  996    completion_provider: Option<Rc<dyn CompletionProvider>>,
  997    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  998    blink_manager: Entity<BlinkManager>,
  999    show_cursor_names: bool,
 1000    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1001    pub show_local_selections: bool,
 1002    mode: EditorMode,
 1003    show_breadcrumbs: bool,
 1004    show_gutter: bool,
 1005    show_scrollbars: ScrollbarAxes,
 1006    minimap_visibility: MinimapVisibility,
 1007    offset_content: bool,
 1008    disable_expand_excerpt_buttons: bool,
 1009    show_line_numbers: Option<bool>,
 1010    use_relative_line_numbers: Option<bool>,
 1011    show_git_diff_gutter: Option<bool>,
 1012    show_code_actions: Option<bool>,
 1013    show_runnables: Option<bool>,
 1014    show_breakpoints: Option<bool>,
 1015    show_wrap_guides: Option<bool>,
 1016    show_indent_guides: Option<bool>,
 1017    placeholder_text: Option<Arc<str>>,
 1018    highlight_order: usize,
 1019    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1020    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1021    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1022    scrollbar_marker_state: ScrollbarMarkerState,
 1023    active_indent_guides_state: ActiveIndentGuidesState,
 1024    nav_history: Option<ItemNavHistory>,
 1025    context_menu: RefCell<Option<CodeContextMenu>>,
 1026    context_menu_options: Option<ContextMenuOptions>,
 1027    mouse_context_menu: Option<MouseContextMenu>,
 1028    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1029    inline_blame_popover: Option<InlineBlamePopover>,
 1030    inline_blame_popover_show_task: Option<Task<()>>,
 1031    signature_help_state: SignatureHelpState,
 1032    auto_signature_help: Option<bool>,
 1033    find_all_references_task_sources: Vec<Anchor>,
 1034    next_completion_id: CompletionId,
 1035    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1036    code_actions_task: Option<Task<Result<()>>>,
 1037    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1038    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1039    document_highlights_task: Option<Task<()>>,
 1040    linked_editing_range_task: Option<Task<Option<()>>>,
 1041    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1042    pending_rename: Option<RenameState>,
 1043    searchable: bool,
 1044    cursor_shape: CursorShape,
 1045    current_line_highlight: Option<CurrentLineHighlight>,
 1046    collapse_matches: bool,
 1047    autoindent_mode: Option<AutoindentMode>,
 1048    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1049    input_enabled: bool,
 1050    use_modal_editing: bool,
 1051    read_only: bool,
 1052    leader_id: Option<CollaboratorId>,
 1053    remote_id: Option<ViewId>,
 1054    pub hover_state: HoverState,
 1055    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1056    gutter_hovered: bool,
 1057    hovered_link_state: Option<HoveredLinkState>,
 1058    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1059    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1060    active_inline_completion: Option<InlineCompletionState>,
 1061    /// Used to prevent flickering as the user types while the menu is open
 1062    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1063    edit_prediction_settings: EditPredictionSettings,
 1064    inline_completions_hidden_for_vim_mode: bool,
 1065    show_inline_completions_override: Option<bool>,
 1066    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1067    edit_prediction_preview: EditPredictionPreview,
 1068    edit_prediction_indent_conflict: bool,
 1069    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1070    inlay_hint_cache: InlayHintCache,
 1071    next_inlay_id: usize,
 1072    _subscriptions: Vec<Subscription>,
 1073    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1074    gutter_dimensions: GutterDimensions,
 1075    style: Option<EditorStyle>,
 1076    text_style_refinement: Option<TextStyleRefinement>,
 1077    next_editor_action_id: EditorActionId,
 1078    editor_actions: Rc<
 1079        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1080    >,
 1081    use_autoclose: bool,
 1082    use_auto_surround: bool,
 1083    auto_replace_emoji_shortcode: bool,
 1084    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1085    show_git_blame_gutter: bool,
 1086    show_git_blame_inline: bool,
 1087    show_git_blame_inline_delay_task: Option<Task<()>>,
 1088    git_blame_inline_enabled: bool,
 1089    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1090    serialize_dirty_buffers: bool,
 1091    show_selection_menu: Option<bool>,
 1092    blame: Option<Entity<GitBlame>>,
 1093    blame_subscription: Option<Subscription>,
 1094    custom_context_menu: Option<
 1095        Box<
 1096            dyn 'static
 1097                + Fn(
 1098                    &mut Self,
 1099                    DisplayPoint,
 1100                    &mut Window,
 1101                    &mut Context<Self>,
 1102                ) -> Option<Entity<ui::ContextMenu>>,
 1103        >,
 1104    >,
 1105    last_bounds: Option<Bounds<Pixels>>,
 1106    last_position_map: Option<Rc<PositionMap>>,
 1107    expect_bounds_change: Option<Bounds<Pixels>>,
 1108    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1109    tasks_update_task: Option<Task<()>>,
 1110    breakpoint_store: Option<Entity<BreakpointStore>>,
 1111    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1112    hovered_diff_hunk_row: Option<DisplayRow>,
 1113    pull_diagnostics_task: Task<()>,
 1114    in_project_search: bool,
 1115    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1116    breadcrumb_header: Option<String>,
 1117    focused_block: Option<FocusedBlock>,
 1118    next_scroll_position: NextScrollCursorCenterTopBottom,
 1119    addons: HashMap<TypeId, Box<dyn Addon>>,
 1120    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1121    load_diff_task: Option<Shared<Task<()>>>,
 1122    /// Whether we are temporarily displaying a diff other than git's
 1123    temporary_diff_override: bool,
 1124    selection_mark_mode: bool,
 1125    toggle_fold_multiple_buffers: Task<()>,
 1126    _scroll_cursor_center_top_bottom_task: Task<()>,
 1127    serialize_selections: Task<()>,
 1128    serialize_folds: Task<()>,
 1129    mouse_cursor_hidden: bool,
 1130    minimap: Option<Entity<Self>>,
 1131    hide_mouse_mode: HideMouseMode,
 1132    pub change_list: ChangeList,
 1133    inline_value_cache: InlineValueCache,
 1134    selection_drag_state: SelectionDragState,
 1135    drag_and_drop_selection_enabled: bool,
 1136    next_color_inlay_id: usize,
 1137    colors: Option<LspColorData>,
 1138}
 1139
 1140#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1141enum NextScrollCursorCenterTopBottom {
 1142    #[default]
 1143    Center,
 1144    Top,
 1145    Bottom,
 1146}
 1147
 1148impl NextScrollCursorCenterTopBottom {
 1149    fn next(&self) -> Self {
 1150        match self {
 1151            Self::Center => Self::Top,
 1152            Self::Top => Self::Bottom,
 1153            Self::Bottom => Self::Center,
 1154        }
 1155    }
 1156}
 1157
 1158#[derive(Clone)]
 1159pub struct EditorSnapshot {
 1160    pub mode: EditorMode,
 1161    show_gutter: bool,
 1162    show_line_numbers: Option<bool>,
 1163    show_git_diff_gutter: Option<bool>,
 1164    show_code_actions: Option<bool>,
 1165    show_runnables: Option<bool>,
 1166    show_breakpoints: Option<bool>,
 1167    git_blame_gutter_max_author_length: Option<usize>,
 1168    pub display_snapshot: DisplaySnapshot,
 1169    pub placeholder_text: Option<Arc<str>>,
 1170    is_focused: bool,
 1171    scroll_anchor: ScrollAnchor,
 1172    ongoing_scroll: OngoingScroll,
 1173    current_line_highlight: CurrentLineHighlight,
 1174    gutter_hovered: bool,
 1175}
 1176
 1177#[derive(Default, Debug, Clone, Copy)]
 1178pub struct GutterDimensions {
 1179    pub left_padding: Pixels,
 1180    pub right_padding: Pixels,
 1181    pub width: Pixels,
 1182    pub margin: Pixels,
 1183    pub git_blame_entries_width: Option<Pixels>,
 1184}
 1185
 1186impl GutterDimensions {
 1187    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1188        Self {
 1189            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1190            ..Default::default()
 1191        }
 1192    }
 1193
 1194    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1195        -cx.text_system().descent(font_id, font_size)
 1196    }
 1197    /// The full width of the space taken up by the gutter.
 1198    pub fn full_width(&self) -> Pixels {
 1199        self.margin + self.width
 1200    }
 1201
 1202    /// The width of the space reserved for the fold indicators,
 1203    /// use alongside 'justify_end' and `gutter_width` to
 1204    /// right align content with the line numbers
 1205    pub fn fold_area_width(&self) -> Pixels {
 1206        self.margin + self.right_padding
 1207    }
 1208}
 1209
 1210#[derive(Debug)]
 1211pub struct RemoteSelection {
 1212    pub replica_id: ReplicaId,
 1213    pub selection: Selection<Anchor>,
 1214    pub cursor_shape: CursorShape,
 1215    pub collaborator_id: CollaboratorId,
 1216    pub line_mode: bool,
 1217    pub user_name: Option<SharedString>,
 1218    pub color: PlayerColor,
 1219}
 1220
 1221#[derive(Clone, Debug)]
 1222struct SelectionHistoryEntry {
 1223    selections: Arc<[Selection<Anchor>]>,
 1224    select_next_state: Option<SelectNextState>,
 1225    select_prev_state: Option<SelectNextState>,
 1226    add_selections_state: Option<AddSelectionsState>,
 1227}
 1228
 1229#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1230enum SelectionHistoryMode {
 1231    Normal,
 1232    Undoing,
 1233    Redoing,
 1234    Skipping,
 1235}
 1236
 1237#[derive(Clone, PartialEq, Eq, Hash)]
 1238struct HoveredCursor {
 1239    replica_id: u16,
 1240    selection_id: usize,
 1241}
 1242
 1243impl Default for SelectionHistoryMode {
 1244    fn default() -> Self {
 1245        Self::Normal
 1246    }
 1247}
 1248
 1249#[derive(Debug)]
 1250pub struct SelectionEffects {
 1251    nav_history: bool,
 1252    completions: bool,
 1253    scroll: Option<Autoscroll>,
 1254}
 1255
 1256impl Default for SelectionEffects {
 1257    fn default() -> Self {
 1258        Self {
 1259            nav_history: true,
 1260            completions: true,
 1261            scroll: Some(Autoscroll::fit()),
 1262        }
 1263    }
 1264}
 1265impl SelectionEffects {
 1266    pub fn scroll(scroll: Autoscroll) -> Self {
 1267        Self {
 1268            scroll: Some(scroll),
 1269            ..Default::default()
 1270        }
 1271    }
 1272
 1273    pub fn no_scroll() -> Self {
 1274        Self {
 1275            scroll: None,
 1276            ..Default::default()
 1277        }
 1278    }
 1279
 1280    pub fn completions(self, completions: bool) -> Self {
 1281        Self {
 1282            completions,
 1283            ..self
 1284        }
 1285    }
 1286
 1287    pub fn nav_history(self, nav_history: bool) -> Self {
 1288        Self {
 1289            nav_history,
 1290            ..self
 1291        }
 1292    }
 1293}
 1294
 1295struct DeferredSelectionEffectsState {
 1296    changed: bool,
 1297    effects: SelectionEffects,
 1298    old_cursor_position: Anchor,
 1299    history_entry: SelectionHistoryEntry,
 1300}
 1301
 1302#[derive(Default)]
 1303struct SelectionHistory {
 1304    #[allow(clippy::type_complexity)]
 1305    selections_by_transaction:
 1306        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1307    mode: SelectionHistoryMode,
 1308    undo_stack: VecDeque<SelectionHistoryEntry>,
 1309    redo_stack: VecDeque<SelectionHistoryEntry>,
 1310}
 1311
 1312impl SelectionHistory {
 1313    #[track_caller]
 1314    fn insert_transaction(
 1315        &mut self,
 1316        transaction_id: TransactionId,
 1317        selections: Arc<[Selection<Anchor>]>,
 1318    ) {
 1319        if selections.is_empty() {
 1320            log::error!(
 1321                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1322                std::panic::Location::caller()
 1323            );
 1324            return;
 1325        }
 1326        self.selections_by_transaction
 1327            .insert(transaction_id, (selections, None));
 1328    }
 1329
 1330    #[allow(clippy::type_complexity)]
 1331    fn transaction(
 1332        &self,
 1333        transaction_id: TransactionId,
 1334    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1335        self.selections_by_transaction.get(&transaction_id)
 1336    }
 1337
 1338    #[allow(clippy::type_complexity)]
 1339    fn transaction_mut(
 1340        &mut self,
 1341        transaction_id: TransactionId,
 1342    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1343        self.selections_by_transaction.get_mut(&transaction_id)
 1344    }
 1345
 1346    fn push(&mut self, entry: SelectionHistoryEntry) {
 1347        if !entry.selections.is_empty() {
 1348            match self.mode {
 1349                SelectionHistoryMode::Normal => {
 1350                    self.push_undo(entry);
 1351                    self.redo_stack.clear();
 1352                }
 1353                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1354                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1355                SelectionHistoryMode::Skipping => {}
 1356            }
 1357        }
 1358    }
 1359
 1360    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1361        if self
 1362            .undo_stack
 1363            .back()
 1364            .map_or(true, |e| e.selections != entry.selections)
 1365        {
 1366            self.undo_stack.push_back(entry);
 1367            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1368                self.undo_stack.pop_front();
 1369            }
 1370        }
 1371    }
 1372
 1373    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1374        if self
 1375            .redo_stack
 1376            .back()
 1377            .map_or(true, |e| e.selections != entry.selections)
 1378        {
 1379            self.redo_stack.push_back(entry);
 1380            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1381                self.redo_stack.pop_front();
 1382            }
 1383        }
 1384    }
 1385}
 1386
 1387#[derive(Clone, Copy)]
 1388pub struct RowHighlightOptions {
 1389    pub autoscroll: bool,
 1390    pub include_gutter: bool,
 1391}
 1392
 1393impl Default for RowHighlightOptions {
 1394    fn default() -> Self {
 1395        Self {
 1396            autoscroll: Default::default(),
 1397            include_gutter: true,
 1398        }
 1399    }
 1400}
 1401
 1402struct RowHighlight {
 1403    index: usize,
 1404    range: Range<Anchor>,
 1405    color: Hsla,
 1406    options: RowHighlightOptions,
 1407    type_id: TypeId,
 1408}
 1409
 1410#[derive(Clone, Debug)]
 1411struct AddSelectionsState {
 1412    groups: Vec<AddSelectionsGroup>,
 1413}
 1414
 1415#[derive(Clone, Debug)]
 1416struct AddSelectionsGroup {
 1417    above: bool,
 1418    stack: Vec<usize>,
 1419}
 1420
 1421#[derive(Clone)]
 1422struct SelectNextState {
 1423    query: AhoCorasick,
 1424    wordwise: bool,
 1425    done: bool,
 1426}
 1427
 1428impl std::fmt::Debug for SelectNextState {
 1429    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1430        f.debug_struct(std::any::type_name::<Self>())
 1431            .field("wordwise", &self.wordwise)
 1432            .field("done", &self.done)
 1433            .finish()
 1434    }
 1435}
 1436
 1437#[derive(Debug)]
 1438struct AutocloseRegion {
 1439    selection_id: usize,
 1440    range: Range<Anchor>,
 1441    pair: BracketPair,
 1442}
 1443
 1444#[derive(Debug)]
 1445struct SnippetState {
 1446    ranges: Vec<Vec<Range<Anchor>>>,
 1447    active_index: usize,
 1448    choices: Vec<Option<Vec<String>>>,
 1449}
 1450
 1451#[doc(hidden)]
 1452pub struct RenameState {
 1453    pub range: Range<Anchor>,
 1454    pub old_name: Arc<str>,
 1455    pub editor: Entity<Editor>,
 1456    block_id: CustomBlockId,
 1457}
 1458
 1459struct InvalidationStack<T>(Vec<T>);
 1460
 1461struct RegisteredInlineCompletionProvider {
 1462    provider: Arc<dyn InlineCompletionProviderHandle>,
 1463    _subscription: Subscription,
 1464}
 1465
 1466#[derive(Debug, PartialEq, Eq)]
 1467pub struct ActiveDiagnosticGroup {
 1468    pub active_range: Range<Anchor>,
 1469    pub active_message: String,
 1470    pub group_id: usize,
 1471    pub blocks: HashSet<CustomBlockId>,
 1472}
 1473
 1474#[derive(Debug, PartialEq, Eq)]
 1475
 1476pub(crate) enum ActiveDiagnostic {
 1477    None,
 1478    All,
 1479    Group(ActiveDiagnosticGroup),
 1480}
 1481
 1482#[derive(Serialize, Deserialize, Clone, Debug)]
 1483pub struct ClipboardSelection {
 1484    /// The number of bytes in this selection.
 1485    pub len: usize,
 1486    /// Whether this was a full-line selection.
 1487    pub is_entire_line: bool,
 1488    /// The indentation of the first line when this content was originally copied.
 1489    pub first_line_indent: u32,
 1490}
 1491
 1492// selections, scroll behavior, was newest selection reversed
 1493type SelectSyntaxNodeHistoryState = (
 1494    Box<[Selection<usize>]>,
 1495    SelectSyntaxNodeScrollBehavior,
 1496    bool,
 1497);
 1498
 1499#[derive(Default)]
 1500struct SelectSyntaxNodeHistory {
 1501    stack: Vec<SelectSyntaxNodeHistoryState>,
 1502    // disable temporarily to allow changing selections without losing the stack
 1503    pub disable_clearing: bool,
 1504}
 1505
 1506impl SelectSyntaxNodeHistory {
 1507    pub fn try_clear(&mut self) {
 1508        if !self.disable_clearing {
 1509            self.stack.clear();
 1510        }
 1511    }
 1512
 1513    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1514        self.stack.push(selection);
 1515    }
 1516
 1517    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1518        self.stack.pop()
 1519    }
 1520}
 1521
 1522enum SelectSyntaxNodeScrollBehavior {
 1523    CursorTop,
 1524    FitSelection,
 1525    CursorBottom,
 1526}
 1527
 1528#[derive(Debug)]
 1529pub(crate) struct NavigationData {
 1530    cursor_anchor: Anchor,
 1531    cursor_position: Point,
 1532    scroll_anchor: ScrollAnchor,
 1533    scroll_top_row: u32,
 1534}
 1535
 1536#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1537pub enum GotoDefinitionKind {
 1538    Symbol,
 1539    Declaration,
 1540    Type,
 1541    Implementation,
 1542}
 1543
 1544#[derive(Debug, Clone)]
 1545enum InlayHintRefreshReason {
 1546    ModifiersChanged(bool),
 1547    Toggle(bool),
 1548    SettingsChange(InlayHintSettings),
 1549    NewLinesShown,
 1550    BufferEdited(HashSet<Arc<Language>>),
 1551    RefreshRequested,
 1552    ExcerptsRemoved(Vec<ExcerptId>),
 1553}
 1554
 1555impl InlayHintRefreshReason {
 1556    fn description(&self) -> &'static str {
 1557        match self {
 1558            Self::ModifiersChanged(_) => "modifiers changed",
 1559            Self::Toggle(_) => "toggle",
 1560            Self::SettingsChange(_) => "settings change",
 1561            Self::NewLinesShown => "new lines shown",
 1562            Self::BufferEdited(_) => "buffer edited",
 1563            Self::RefreshRequested => "refresh requested",
 1564            Self::ExcerptsRemoved(_) => "excerpts removed",
 1565        }
 1566    }
 1567}
 1568
 1569pub enum FormatTarget {
 1570    Buffers(HashSet<Entity<Buffer>>),
 1571    Ranges(Vec<Range<MultiBufferPoint>>),
 1572}
 1573
 1574pub(crate) struct FocusedBlock {
 1575    id: BlockId,
 1576    focus_handle: WeakFocusHandle,
 1577}
 1578
 1579#[derive(Clone)]
 1580enum JumpData {
 1581    MultiBufferRow {
 1582        row: MultiBufferRow,
 1583        line_offset_from_top: u32,
 1584    },
 1585    MultiBufferPoint {
 1586        excerpt_id: ExcerptId,
 1587        position: Point,
 1588        anchor: text::Anchor,
 1589        line_offset_from_top: u32,
 1590    },
 1591}
 1592
 1593pub enum MultibufferSelectionMode {
 1594    First,
 1595    All,
 1596}
 1597
 1598#[derive(Clone, Copy, Debug, Default)]
 1599pub struct RewrapOptions {
 1600    pub override_language_settings: bool,
 1601    pub preserve_existing_whitespace: bool,
 1602}
 1603
 1604impl Editor {
 1605    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1606        let buffer = cx.new(|cx| Buffer::local("", cx));
 1607        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1608        Self::new(
 1609            EditorMode::SingleLine { auto_width: false },
 1610            buffer,
 1611            None,
 1612            window,
 1613            cx,
 1614        )
 1615    }
 1616
 1617    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1618        let buffer = cx.new(|cx| Buffer::local("", cx));
 1619        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1620        Self::new(EditorMode::full(), buffer, None, window, cx)
 1621    }
 1622
 1623    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1624        let buffer = cx.new(|cx| Buffer::local("", cx));
 1625        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1626        Self::new(
 1627            EditorMode::SingleLine { auto_width: true },
 1628            buffer,
 1629            None,
 1630            window,
 1631            cx,
 1632        )
 1633    }
 1634
 1635    pub fn auto_height(
 1636        min_lines: usize,
 1637        max_lines: usize,
 1638        window: &mut Window,
 1639        cx: &mut Context<Self>,
 1640    ) -> Self {
 1641        let buffer = cx.new(|cx| Buffer::local("", cx));
 1642        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1643        Self::new(
 1644            EditorMode::AutoHeight {
 1645                min_lines,
 1646                max_lines,
 1647            },
 1648            buffer,
 1649            None,
 1650            window,
 1651            cx,
 1652        )
 1653    }
 1654
 1655    pub fn for_buffer(
 1656        buffer: Entity<Buffer>,
 1657        project: Option<Entity<Project>>,
 1658        window: &mut Window,
 1659        cx: &mut Context<Self>,
 1660    ) -> Self {
 1661        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1662        Self::new(EditorMode::full(), buffer, project, window, cx)
 1663    }
 1664
 1665    pub fn for_multibuffer(
 1666        buffer: Entity<MultiBuffer>,
 1667        project: Option<Entity<Project>>,
 1668        window: &mut Window,
 1669        cx: &mut Context<Self>,
 1670    ) -> Self {
 1671        Self::new(EditorMode::full(), buffer, project, window, cx)
 1672    }
 1673
 1674    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1675        let mut clone = Self::new(
 1676            self.mode.clone(),
 1677            self.buffer.clone(),
 1678            self.project.clone(),
 1679            window,
 1680            cx,
 1681        );
 1682        self.display_map.update(cx, |display_map, cx| {
 1683            let snapshot = display_map.snapshot(cx);
 1684            clone.display_map.update(cx, |display_map, cx| {
 1685                display_map.set_state(&snapshot, cx);
 1686            });
 1687        });
 1688        clone.folds_did_change(cx);
 1689        clone.selections.clone_state(&self.selections);
 1690        clone.scroll_manager.clone_state(&self.scroll_manager);
 1691        clone.searchable = self.searchable;
 1692        clone.read_only = self.read_only;
 1693        clone
 1694    }
 1695
 1696    pub fn new(
 1697        mode: EditorMode,
 1698        buffer: Entity<MultiBuffer>,
 1699        project: Option<Entity<Project>>,
 1700        window: &mut Window,
 1701        cx: &mut Context<Self>,
 1702    ) -> Self {
 1703        Editor::new_internal(mode, buffer, project, None, window, cx)
 1704    }
 1705
 1706    fn new_internal(
 1707        mode: EditorMode,
 1708        buffer: Entity<MultiBuffer>,
 1709        project: Option<Entity<Project>>,
 1710        display_map: Option<Entity<DisplayMap>>,
 1711        window: &mut Window,
 1712        cx: &mut Context<Self>,
 1713    ) -> Self {
 1714        debug_assert!(
 1715            display_map.is_none() || mode.is_minimap(),
 1716            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1717        );
 1718
 1719        let full_mode = mode.is_full();
 1720        let diagnostics_max_severity = if full_mode {
 1721            EditorSettings::get_global(cx)
 1722                .diagnostics_max_severity
 1723                .unwrap_or(DiagnosticSeverity::Hint)
 1724        } else {
 1725            DiagnosticSeverity::Off
 1726        };
 1727        let style = window.text_style();
 1728        let font_size = style.font_size.to_pixels(window.rem_size());
 1729        let editor = cx.entity().downgrade();
 1730        let fold_placeholder = FoldPlaceholder {
 1731            constrain_width: true,
 1732            render: Arc::new(move |fold_id, fold_range, cx| {
 1733                let editor = editor.clone();
 1734                div()
 1735                    .id(fold_id)
 1736                    .bg(cx.theme().colors().ghost_element_background)
 1737                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1738                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1739                    .rounded_xs()
 1740                    .size_full()
 1741                    .cursor_pointer()
 1742                    .child("")
 1743                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1744                    .on_click(move |_, _window, cx| {
 1745                        editor
 1746                            .update(cx, |editor, cx| {
 1747                                editor.unfold_ranges(
 1748                                    &[fold_range.start..fold_range.end],
 1749                                    true,
 1750                                    false,
 1751                                    cx,
 1752                                );
 1753                                cx.stop_propagation();
 1754                            })
 1755                            .ok();
 1756                    })
 1757                    .into_any()
 1758            }),
 1759            merge_adjacent: true,
 1760            ..FoldPlaceholder::default()
 1761        };
 1762        let display_map = display_map.unwrap_or_else(|| {
 1763            cx.new(|cx| {
 1764                DisplayMap::new(
 1765                    buffer.clone(),
 1766                    style.font(),
 1767                    font_size,
 1768                    None,
 1769                    FILE_HEADER_HEIGHT,
 1770                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1771                    fold_placeholder,
 1772                    diagnostics_max_severity,
 1773                    cx,
 1774                )
 1775            })
 1776        });
 1777
 1778        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1779
 1780        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1781
 1782        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1783            .then(|| language_settings::SoftWrap::None);
 1784
 1785        let mut project_subscriptions = Vec::new();
 1786        if mode.is_full() {
 1787            if let Some(project) = project.as_ref() {
 1788                project_subscriptions.push(cx.subscribe_in(
 1789                    project,
 1790                    window,
 1791                    |editor, _, event, window, cx| match event {
 1792                        project::Event::RefreshCodeLens => {
 1793                            // we always query lens with actions, without storing them, always refreshing them
 1794                        }
 1795                        project::Event::RefreshInlayHints => {
 1796                            editor
 1797                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1798                        }
 1799                        project::Event::LanguageServerAdded(server_id, ..)
 1800                        | project::Event::LanguageServerRemoved(server_id) => {
 1801                            if editor.tasks_update_task.is_none() {
 1802                                editor.tasks_update_task =
 1803                                    Some(editor.refresh_runnables(window, cx));
 1804                            }
 1805                            editor.update_lsp_data(false, Some(*server_id), None, window, cx);
 1806                        }
 1807                        project::Event::SnippetEdit(id, snippet_edits) => {
 1808                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1809                                let focus_handle = editor.focus_handle(cx);
 1810                                if focus_handle.is_focused(window) {
 1811                                    let snapshot = buffer.read(cx).snapshot();
 1812                                    for (range, snippet) in snippet_edits {
 1813                                        let editor_range =
 1814                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1815                                        editor
 1816                                            .insert_snippet(
 1817                                                &[editor_range],
 1818                                                snippet.clone(),
 1819                                                window,
 1820                                                cx,
 1821                                            )
 1822                                            .ok();
 1823                                    }
 1824                                }
 1825                            }
 1826                        }
 1827                        _ => {}
 1828                    },
 1829                ));
 1830                if let Some(task_inventory) = project
 1831                    .read(cx)
 1832                    .task_store()
 1833                    .read(cx)
 1834                    .task_inventory()
 1835                    .cloned()
 1836                {
 1837                    project_subscriptions.push(cx.observe_in(
 1838                        &task_inventory,
 1839                        window,
 1840                        |editor, _, window, cx| {
 1841                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1842                        },
 1843                    ));
 1844                };
 1845
 1846                project_subscriptions.push(cx.subscribe_in(
 1847                    &project.read(cx).breakpoint_store(),
 1848                    window,
 1849                    |editor, _, event, window, cx| match event {
 1850                        BreakpointStoreEvent::ClearDebugLines => {
 1851                            editor.clear_row_highlights::<ActiveDebugLine>();
 1852                            editor.refresh_inline_values(cx);
 1853                        }
 1854                        BreakpointStoreEvent::SetDebugLine => {
 1855                            if editor.go_to_active_debug_line(window, cx) {
 1856                                cx.stop_propagation();
 1857                            }
 1858
 1859                            editor.refresh_inline_values(cx);
 1860                        }
 1861                        _ => {}
 1862                    },
 1863                ));
 1864                let git_store = project.read(cx).git_store().clone();
 1865                let project = project.clone();
 1866                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1867                    match event {
 1868                        GitStoreEvent::RepositoryUpdated(
 1869                            _,
 1870                            RepositoryEvent::Updated {
 1871                                new_instance: true, ..
 1872                            },
 1873                            _,
 1874                        ) => {
 1875                            this.load_diff_task = Some(
 1876                                update_uncommitted_diff_for_buffer(
 1877                                    cx.entity(),
 1878                                    &project,
 1879                                    this.buffer.read(cx).all_buffers(),
 1880                                    this.buffer.clone(),
 1881                                    cx,
 1882                                )
 1883                                .shared(),
 1884                            );
 1885                        }
 1886                        _ => {}
 1887                    }
 1888                }));
 1889            }
 1890        }
 1891
 1892        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1893
 1894        let inlay_hint_settings =
 1895            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1896        let focus_handle = cx.focus_handle();
 1897        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1898            .detach();
 1899        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1900            .detach();
 1901        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1902            .detach();
 1903        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1904            .detach();
 1905        cx.observe_pending_input(window, Self::observe_pending_input)
 1906            .detach();
 1907
 1908        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1909            Some(false)
 1910        } else {
 1911            None
 1912        };
 1913
 1914        let breakpoint_store = match (&mode, project.as_ref()) {
 1915            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1916            _ => None,
 1917        };
 1918
 1919        let mut code_action_providers = Vec::new();
 1920        let mut load_uncommitted_diff = None;
 1921        if let Some(project) = project.clone() {
 1922            load_uncommitted_diff = Some(
 1923                update_uncommitted_diff_for_buffer(
 1924                    cx.entity(),
 1925                    &project,
 1926                    buffer.read(cx).all_buffers(),
 1927                    buffer.clone(),
 1928                    cx,
 1929                )
 1930                .shared(),
 1931            );
 1932            code_action_providers.push(Rc::new(project) as Rc<_>);
 1933        }
 1934
 1935        let mut editor = Self {
 1936            focus_handle,
 1937            show_cursor_when_unfocused: false,
 1938            last_focused_descendant: None,
 1939            buffer: buffer.clone(),
 1940            display_map: display_map.clone(),
 1941            selections,
 1942            scroll_manager: ScrollManager::new(cx),
 1943            columnar_selection_state: None,
 1944            add_selections_state: None,
 1945            select_next_state: None,
 1946            select_prev_state: None,
 1947            selection_history: SelectionHistory::default(),
 1948            defer_selection_effects: false,
 1949            deferred_selection_effects_state: None,
 1950            autoclose_regions: Vec::new(),
 1951            snippet_stack: InvalidationStack::default(),
 1952            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1953            ime_transaction: None,
 1954            active_diagnostics: ActiveDiagnostic::None,
 1955            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1956            inline_diagnostics_update: Task::ready(()),
 1957            inline_diagnostics: Vec::new(),
 1958            soft_wrap_mode_override,
 1959            diagnostics_max_severity,
 1960            hard_wrap: None,
 1961            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1962            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1963            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1964            project,
 1965            blink_manager: blink_manager.clone(),
 1966            show_local_selections: true,
 1967            show_scrollbars: ScrollbarAxes {
 1968                horizontal: full_mode,
 1969                vertical: full_mode,
 1970            },
 1971            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1972            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1973            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1974            show_gutter: mode.is_full(),
 1975            show_line_numbers: None,
 1976            use_relative_line_numbers: None,
 1977            disable_expand_excerpt_buttons: false,
 1978            show_git_diff_gutter: None,
 1979            show_code_actions: None,
 1980            show_runnables: None,
 1981            show_breakpoints: None,
 1982            show_wrap_guides: None,
 1983            show_indent_guides,
 1984            placeholder_text: None,
 1985            highlight_order: 0,
 1986            highlighted_rows: HashMap::default(),
 1987            background_highlights: TreeMap::default(),
 1988            gutter_highlights: TreeMap::default(),
 1989            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1990            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1991            nav_history: None,
 1992            context_menu: RefCell::new(None),
 1993            context_menu_options: None,
 1994            mouse_context_menu: None,
 1995            completion_tasks: Vec::new(),
 1996            inline_blame_popover: None,
 1997            inline_blame_popover_show_task: None,
 1998            signature_help_state: SignatureHelpState::default(),
 1999            auto_signature_help: None,
 2000            find_all_references_task_sources: Vec::new(),
 2001            next_completion_id: 0,
 2002            next_inlay_id: 0,
 2003            code_action_providers,
 2004            available_code_actions: None,
 2005            code_actions_task: None,
 2006            quick_selection_highlight_task: None,
 2007            debounced_selection_highlight_task: None,
 2008            document_highlights_task: None,
 2009            linked_editing_range_task: None,
 2010            pending_rename: None,
 2011            searchable: true,
 2012            cursor_shape: EditorSettings::get_global(cx)
 2013                .cursor_shape
 2014                .unwrap_or_default(),
 2015            current_line_highlight: None,
 2016            autoindent_mode: Some(AutoindentMode::EachLine),
 2017            collapse_matches: false,
 2018            workspace: None,
 2019            input_enabled: true,
 2020            use_modal_editing: mode.is_full(),
 2021            read_only: mode.is_minimap(),
 2022            use_autoclose: true,
 2023            use_auto_surround: true,
 2024            auto_replace_emoji_shortcode: false,
 2025            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2026            leader_id: None,
 2027            remote_id: None,
 2028            hover_state: HoverState::default(),
 2029            pending_mouse_down: None,
 2030            hovered_link_state: None,
 2031            edit_prediction_provider: None,
 2032            active_inline_completion: None,
 2033            stale_inline_completion_in_menu: None,
 2034            edit_prediction_preview: EditPredictionPreview::Inactive {
 2035                released_too_fast: false,
 2036            },
 2037            inline_diagnostics_enabled: mode.is_full(),
 2038            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2039            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2040
 2041            gutter_hovered: false,
 2042            pixel_position_of_newest_cursor: None,
 2043            last_bounds: None,
 2044            last_position_map: None,
 2045            expect_bounds_change: None,
 2046            gutter_dimensions: GutterDimensions::default(),
 2047            style: None,
 2048            show_cursor_names: false,
 2049            hovered_cursors: HashMap::default(),
 2050            next_editor_action_id: EditorActionId::default(),
 2051            editor_actions: Rc::default(),
 2052            inline_completions_hidden_for_vim_mode: false,
 2053            show_inline_completions_override: None,
 2054            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2055            edit_prediction_settings: EditPredictionSettings::Disabled,
 2056            edit_prediction_indent_conflict: false,
 2057            edit_prediction_requires_modifier_in_indent_conflict: true,
 2058            custom_context_menu: None,
 2059            show_git_blame_gutter: false,
 2060            show_git_blame_inline: false,
 2061            show_selection_menu: None,
 2062            show_git_blame_inline_delay_task: None,
 2063            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2064            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2065            serialize_dirty_buffers: !mode.is_minimap()
 2066                && ProjectSettings::get_global(cx)
 2067                    .session
 2068                    .restore_unsaved_buffers,
 2069            blame: None,
 2070            blame_subscription: None,
 2071            tasks: BTreeMap::default(),
 2072
 2073            breakpoint_store,
 2074            gutter_breakpoint_indicator: (None, None),
 2075            hovered_diff_hunk_row: None,
 2076            _subscriptions: vec![
 2077                cx.observe(&buffer, Self::on_buffer_changed),
 2078                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2079                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2080                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2081                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2082                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2083                cx.observe_window_activation(window, |editor, window, cx| {
 2084                    let active = window.is_window_active();
 2085                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2086                        if active {
 2087                            blink_manager.enable(cx);
 2088                        } else {
 2089                            blink_manager.disable(cx);
 2090                        }
 2091                    });
 2092                    if active {
 2093                        editor.show_mouse_cursor(cx);
 2094                    }
 2095                }),
 2096            ],
 2097            tasks_update_task: None,
 2098            pull_diagnostics_task: Task::ready(()),
 2099            colors: None,
 2100            next_color_inlay_id: 0,
 2101            linked_edit_ranges: Default::default(),
 2102            in_project_search: false,
 2103            previous_search_ranges: None,
 2104            breadcrumb_header: None,
 2105            focused_block: None,
 2106            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2107            addons: HashMap::default(),
 2108            registered_buffers: HashMap::default(),
 2109            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2110            selection_mark_mode: false,
 2111            toggle_fold_multiple_buffers: Task::ready(()),
 2112            serialize_selections: Task::ready(()),
 2113            serialize_folds: Task::ready(()),
 2114            text_style_refinement: None,
 2115            load_diff_task: load_uncommitted_diff,
 2116            temporary_diff_override: false,
 2117            mouse_cursor_hidden: false,
 2118            minimap: None,
 2119            hide_mouse_mode: EditorSettings::get_global(cx)
 2120                .hide_mouse
 2121                .unwrap_or_default(),
 2122            change_list: ChangeList::new(),
 2123            mode,
 2124            selection_drag_state: SelectionDragState::None,
 2125            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2126        };
 2127        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2128            editor
 2129                ._subscriptions
 2130                .push(cx.observe(breakpoints, |_, _, cx| {
 2131                    cx.notify();
 2132                }));
 2133        }
 2134        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2135        editor._subscriptions.extend(project_subscriptions);
 2136
 2137        editor._subscriptions.push(cx.subscribe_in(
 2138            &cx.entity(),
 2139            window,
 2140            |editor, _, e: &EditorEvent, window, cx| match e {
 2141                EditorEvent::ScrollPositionChanged { local, .. } => {
 2142                    if *local {
 2143                        let new_anchor = editor.scroll_manager.anchor();
 2144                        let snapshot = editor.snapshot(window, cx);
 2145                        editor.update_restoration_data(cx, move |data| {
 2146                            data.scroll_position = (
 2147                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2148                                new_anchor.offset,
 2149                            );
 2150                        });
 2151                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2152                        editor.inline_blame_popover.take();
 2153                    }
 2154                }
 2155                EditorEvent::Edited { .. } => {
 2156                    if !vim_enabled(cx) {
 2157                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2158                        let pop_state = editor
 2159                            .change_list
 2160                            .last()
 2161                            .map(|previous| {
 2162                                previous.len() == selections.len()
 2163                                    && previous.iter().enumerate().all(|(ix, p)| {
 2164                                        p.to_display_point(&map).row()
 2165                                            == selections[ix].head().row()
 2166                                    })
 2167                            })
 2168                            .unwrap_or(false);
 2169                        let new_positions = selections
 2170                            .into_iter()
 2171                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2172                            .collect();
 2173                        editor
 2174                            .change_list
 2175                            .push_to_change_list(pop_state, new_positions);
 2176                    }
 2177                }
 2178                _ => (),
 2179            },
 2180        ));
 2181
 2182        if let Some(dap_store) = editor
 2183            .project
 2184            .as_ref()
 2185            .map(|project| project.read(cx).dap_store())
 2186        {
 2187            let weak_editor = cx.weak_entity();
 2188
 2189            editor
 2190                ._subscriptions
 2191                .push(
 2192                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2193                        let session_entity = cx.entity();
 2194                        weak_editor
 2195                            .update(cx, |editor, cx| {
 2196                                editor._subscriptions.push(
 2197                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2198                                );
 2199                            })
 2200                            .ok();
 2201                    }),
 2202                );
 2203
 2204            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2205                editor
 2206                    ._subscriptions
 2207                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2208            }
 2209        }
 2210
 2211        // skip adding the initial selection to selection history
 2212        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2213        editor.end_selection(window, cx);
 2214        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2215
 2216        editor.scroll_manager.show_scrollbars(window, cx);
 2217        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2218
 2219        if full_mode {
 2220            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2221            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2222
 2223            if editor.git_blame_inline_enabled {
 2224                editor.start_git_blame_inline(false, window, cx);
 2225            }
 2226
 2227            editor.go_to_active_debug_line(window, cx);
 2228
 2229            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2230                if let Some(project) = editor.project.as_ref() {
 2231                    let handle = project.update(cx, |project, cx| {
 2232                        project.register_buffer_with_language_servers(&buffer, cx)
 2233                    });
 2234                    editor
 2235                        .registered_buffers
 2236                        .insert(buffer.read(cx).remote_id(), handle);
 2237                }
 2238            }
 2239
 2240            editor.minimap =
 2241                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2242            editor.colors = Some(LspColorData::new(cx));
 2243            editor.update_lsp_data(false, None, None, window, cx);
 2244        }
 2245
 2246        editor.report_editor_event("Editor Opened", None, cx);
 2247        editor
 2248    }
 2249
 2250    pub fn deploy_mouse_context_menu(
 2251        &mut self,
 2252        position: gpui::Point<Pixels>,
 2253        context_menu: Entity<ContextMenu>,
 2254        window: &mut Window,
 2255        cx: &mut Context<Self>,
 2256    ) {
 2257        self.mouse_context_menu = Some(MouseContextMenu::new(
 2258            self,
 2259            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2260            context_menu,
 2261            window,
 2262            cx,
 2263        ));
 2264    }
 2265
 2266    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2267        self.mouse_context_menu
 2268            .as_ref()
 2269            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2270    }
 2271
 2272    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2273        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2274    }
 2275
 2276    fn key_context_internal(
 2277        &self,
 2278        has_active_edit_prediction: bool,
 2279        window: &Window,
 2280        cx: &App,
 2281    ) -> KeyContext {
 2282        let mut key_context = KeyContext::new_with_defaults();
 2283        key_context.add("Editor");
 2284        let mode = match self.mode {
 2285            EditorMode::SingleLine { .. } => "single_line",
 2286            EditorMode::AutoHeight { .. } => "auto_height",
 2287            EditorMode::Minimap { .. } => "minimap",
 2288            EditorMode::Full { .. } => "full",
 2289        };
 2290
 2291        if EditorSettings::jupyter_enabled(cx) {
 2292            key_context.add("jupyter");
 2293        }
 2294
 2295        key_context.set("mode", mode);
 2296        if self.pending_rename.is_some() {
 2297            key_context.add("renaming");
 2298        }
 2299
 2300        match self.context_menu.borrow().as_ref() {
 2301            Some(CodeContextMenu::Completions(_)) => {
 2302                key_context.add("menu");
 2303                key_context.add("showing_completions");
 2304            }
 2305            Some(CodeContextMenu::CodeActions(_)) => {
 2306                key_context.add("menu");
 2307                key_context.add("showing_code_actions")
 2308            }
 2309            None => {}
 2310        }
 2311
 2312        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2313        if !self.focus_handle(cx).contains_focused(window, cx)
 2314            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2315        {
 2316            for addon in self.addons.values() {
 2317                addon.extend_key_context(&mut key_context, cx)
 2318            }
 2319        }
 2320
 2321        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2322            if let Some(extension) = singleton_buffer
 2323                .read(cx)
 2324                .file()
 2325                .and_then(|file| file.path().extension()?.to_str())
 2326            {
 2327                key_context.set("extension", extension.to_string());
 2328            }
 2329        } else {
 2330            key_context.add("multibuffer");
 2331        }
 2332
 2333        if has_active_edit_prediction {
 2334            if self.edit_prediction_in_conflict() {
 2335                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2336            } else {
 2337                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2338                key_context.add("copilot_suggestion");
 2339            }
 2340        }
 2341
 2342        if self.selection_mark_mode {
 2343            key_context.add("selection_mode");
 2344        }
 2345
 2346        key_context
 2347    }
 2348
 2349    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2350        if self.mouse_cursor_hidden {
 2351            self.mouse_cursor_hidden = false;
 2352            cx.notify();
 2353        }
 2354    }
 2355
 2356    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2357        let hide_mouse_cursor = match origin {
 2358            HideMouseCursorOrigin::TypingAction => {
 2359                matches!(
 2360                    self.hide_mouse_mode,
 2361                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2362                )
 2363            }
 2364            HideMouseCursorOrigin::MovementAction => {
 2365                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2366            }
 2367        };
 2368        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2369            self.mouse_cursor_hidden = hide_mouse_cursor;
 2370            cx.notify();
 2371        }
 2372    }
 2373
 2374    pub fn edit_prediction_in_conflict(&self) -> bool {
 2375        if !self.show_edit_predictions_in_menu() {
 2376            return false;
 2377        }
 2378
 2379        let showing_completions = self
 2380            .context_menu
 2381            .borrow()
 2382            .as_ref()
 2383            .map_or(false, |context| {
 2384                matches!(context, CodeContextMenu::Completions(_))
 2385            });
 2386
 2387        showing_completions
 2388            || self.edit_prediction_requires_modifier()
 2389            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2390            // bindings to insert tab characters.
 2391            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2392    }
 2393
 2394    pub fn accept_edit_prediction_keybind(
 2395        &self,
 2396        accept_partial: bool,
 2397        window: &Window,
 2398        cx: &App,
 2399    ) -> AcceptEditPredictionBinding {
 2400        let key_context = self.key_context_internal(true, window, cx);
 2401        let in_conflict = self.edit_prediction_in_conflict();
 2402
 2403        let bindings = if accept_partial {
 2404            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2405        } else {
 2406            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2407        };
 2408
 2409        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2410        // just the first one.
 2411        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2412            !in_conflict
 2413                || binding
 2414                    .keystrokes()
 2415                    .first()
 2416                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2417        }))
 2418    }
 2419
 2420    pub fn new_file(
 2421        workspace: &mut Workspace,
 2422        _: &workspace::NewFile,
 2423        window: &mut Window,
 2424        cx: &mut Context<Workspace>,
 2425    ) {
 2426        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2427            "Failed to create buffer",
 2428            window,
 2429            cx,
 2430            |e, _, _| match e.error_code() {
 2431                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2432                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2433                e.error_tag("required").unwrap_or("the latest version")
 2434            )),
 2435                _ => None,
 2436            },
 2437        );
 2438    }
 2439
 2440    pub fn new_in_workspace(
 2441        workspace: &mut Workspace,
 2442        window: &mut Window,
 2443        cx: &mut Context<Workspace>,
 2444    ) -> Task<Result<Entity<Editor>>> {
 2445        let project = workspace.project().clone();
 2446        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2447
 2448        cx.spawn_in(window, async move |workspace, cx| {
 2449            let buffer = create.await?;
 2450            workspace.update_in(cx, |workspace, window, cx| {
 2451                let editor =
 2452                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2453                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2454                editor
 2455            })
 2456        })
 2457    }
 2458
 2459    fn new_file_vertical(
 2460        workspace: &mut Workspace,
 2461        _: &workspace::NewFileSplitVertical,
 2462        window: &mut Window,
 2463        cx: &mut Context<Workspace>,
 2464    ) {
 2465        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2466    }
 2467
 2468    fn new_file_horizontal(
 2469        workspace: &mut Workspace,
 2470        _: &workspace::NewFileSplitHorizontal,
 2471        window: &mut Window,
 2472        cx: &mut Context<Workspace>,
 2473    ) {
 2474        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2475    }
 2476
 2477    fn new_file_in_direction(
 2478        workspace: &mut Workspace,
 2479        direction: SplitDirection,
 2480        window: &mut Window,
 2481        cx: &mut Context<Workspace>,
 2482    ) {
 2483        let project = workspace.project().clone();
 2484        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2485
 2486        cx.spawn_in(window, async move |workspace, cx| {
 2487            let buffer = create.await?;
 2488            workspace.update_in(cx, move |workspace, window, cx| {
 2489                workspace.split_item(
 2490                    direction,
 2491                    Box::new(
 2492                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2493                    ),
 2494                    window,
 2495                    cx,
 2496                )
 2497            })?;
 2498            anyhow::Ok(())
 2499        })
 2500        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2501            match e.error_code() {
 2502                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2503                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2504                e.error_tag("required").unwrap_or("the latest version")
 2505            )),
 2506                _ => None,
 2507            }
 2508        });
 2509    }
 2510
 2511    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2512        self.leader_id
 2513    }
 2514
 2515    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2516        &self.buffer
 2517    }
 2518
 2519    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2520        self.workspace.as_ref()?.0.upgrade()
 2521    }
 2522
 2523    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2524        self.buffer().read(cx).title(cx)
 2525    }
 2526
 2527    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2528        let git_blame_gutter_max_author_length = self
 2529            .render_git_blame_gutter(cx)
 2530            .then(|| {
 2531                if let Some(blame) = self.blame.as_ref() {
 2532                    let max_author_length =
 2533                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2534                    Some(max_author_length)
 2535                } else {
 2536                    None
 2537                }
 2538            })
 2539            .flatten();
 2540
 2541        EditorSnapshot {
 2542            mode: self.mode.clone(),
 2543            show_gutter: self.show_gutter,
 2544            show_line_numbers: self.show_line_numbers,
 2545            show_git_diff_gutter: self.show_git_diff_gutter,
 2546            show_code_actions: self.show_code_actions,
 2547            show_runnables: self.show_runnables,
 2548            show_breakpoints: self.show_breakpoints,
 2549            git_blame_gutter_max_author_length,
 2550            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2551            scroll_anchor: self.scroll_manager.anchor(),
 2552            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2553            placeholder_text: self.placeholder_text.clone(),
 2554            is_focused: self.focus_handle.is_focused(window),
 2555            current_line_highlight: self
 2556                .current_line_highlight
 2557                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2558            gutter_hovered: self.gutter_hovered,
 2559        }
 2560    }
 2561
 2562    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2563        self.buffer.read(cx).language_at(point, cx)
 2564    }
 2565
 2566    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2567        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2568    }
 2569
 2570    pub fn active_excerpt(
 2571        &self,
 2572        cx: &App,
 2573    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2574        self.buffer
 2575            .read(cx)
 2576            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2577    }
 2578
 2579    pub fn mode(&self) -> &EditorMode {
 2580        &self.mode
 2581    }
 2582
 2583    pub fn set_mode(&mut self, mode: EditorMode) {
 2584        self.mode = mode;
 2585    }
 2586
 2587    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2588        self.collaboration_hub.as_deref()
 2589    }
 2590
 2591    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2592        self.collaboration_hub = Some(hub);
 2593    }
 2594
 2595    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2596        self.in_project_search = in_project_search;
 2597    }
 2598
 2599    pub fn set_custom_context_menu(
 2600        &mut self,
 2601        f: impl 'static
 2602        + Fn(
 2603            &mut Self,
 2604            DisplayPoint,
 2605            &mut Window,
 2606            &mut Context<Self>,
 2607        ) -> Option<Entity<ui::ContextMenu>>,
 2608    ) {
 2609        self.custom_context_menu = Some(Box::new(f))
 2610    }
 2611
 2612    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2613        self.completion_provider = provider;
 2614    }
 2615
 2616    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2617        self.semantics_provider.clone()
 2618    }
 2619
 2620    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2621        self.semantics_provider = provider;
 2622    }
 2623
 2624    pub fn set_edit_prediction_provider<T>(
 2625        &mut self,
 2626        provider: Option<Entity<T>>,
 2627        window: &mut Window,
 2628        cx: &mut Context<Self>,
 2629    ) where
 2630        T: EditPredictionProvider,
 2631    {
 2632        self.edit_prediction_provider =
 2633            provider.map(|provider| RegisteredInlineCompletionProvider {
 2634                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2635                    if this.focus_handle.is_focused(window) {
 2636                        this.update_visible_inline_completion(window, cx);
 2637                    }
 2638                }),
 2639                provider: Arc::new(provider),
 2640            });
 2641        self.update_edit_prediction_settings(cx);
 2642        self.refresh_inline_completion(false, false, window, cx);
 2643    }
 2644
 2645    pub fn placeholder_text(&self) -> Option<&str> {
 2646        self.placeholder_text.as_deref()
 2647    }
 2648
 2649    pub fn set_placeholder_text(
 2650        &mut self,
 2651        placeholder_text: impl Into<Arc<str>>,
 2652        cx: &mut Context<Self>,
 2653    ) {
 2654        let placeholder_text = Some(placeholder_text.into());
 2655        if self.placeholder_text != placeholder_text {
 2656            self.placeholder_text = placeholder_text;
 2657            cx.notify();
 2658        }
 2659    }
 2660
 2661    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2662        self.cursor_shape = cursor_shape;
 2663
 2664        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2665        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2666
 2667        cx.notify();
 2668    }
 2669
 2670    pub fn set_current_line_highlight(
 2671        &mut self,
 2672        current_line_highlight: Option<CurrentLineHighlight>,
 2673    ) {
 2674        self.current_line_highlight = current_line_highlight;
 2675    }
 2676
 2677    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2678        self.collapse_matches = collapse_matches;
 2679    }
 2680
 2681    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2682        let buffers = self.buffer.read(cx).all_buffers();
 2683        let Some(project) = self.project.as_ref() else {
 2684            return;
 2685        };
 2686        project.update(cx, |project, cx| {
 2687            for buffer in buffers {
 2688                self.registered_buffers
 2689                    .entry(buffer.read(cx).remote_id())
 2690                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2691            }
 2692        })
 2693    }
 2694
 2695    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2696        if self.collapse_matches {
 2697            return range.start..range.start;
 2698        }
 2699        range.clone()
 2700    }
 2701
 2702    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2703        if self.display_map.read(cx).clip_at_line_ends != clip {
 2704            self.display_map
 2705                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2706        }
 2707    }
 2708
 2709    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2710        self.input_enabled = input_enabled;
 2711    }
 2712
 2713    pub fn set_inline_completions_hidden_for_vim_mode(
 2714        &mut self,
 2715        hidden: bool,
 2716        window: &mut Window,
 2717        cx: &mut Context<Self>,
 2718    ) {
 2719        if hidden != self.inline_completions_hidden_for_vim_mode {
 2720            self.inline_completions_hidden_for_vim_mode = hidden;
 2721            if hidden {
 2722                self.update_visible_inline_completion(window, cx);
 2723            } else {
 2724                self.refresh_inline_completion(true, false, window, cx);
 2725            }
 2726        }
 2727    }
 2728
 2729    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2730        self.menu_inline_completions_policy = value;
 2731    }
 2732
 2733    pub fn set_autoindent(&mut self, autoindent: bool) {
 2734        if autoindent {
 2735            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2736        } else {
 2737            self.autoindent_mode = None;
 2738        }
 2739    }
 2740
 2741    pub fn read_only(&self, cx: &App) -> bool {
 2742        self.read_only || self.buffer.read(cx).read_only()
 2743    }
 2744
 2745    pub fn set_read_only(&mut self, read_only: bool) {
 2746        self.read_only = read_only;
 2747    }
 2748
 2749    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2750        self.use_autoclose = autoclose;
 2751    }
 2752
 2753    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2754        self.use_auto_surround = auto_surround;
 2755    }
 2756
 2757    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2758        self.auto_replace_emoji_shortcode = auto_replace;
 2759    }
 2760
 2761    pub fn toggle_edit_predictions(
 2762        &mut self,
 2763        _: &ToggleEditPrediction,
 2764        window: &mut Window,
 2765        cx: &mut Context<Self>,
 2766    ) {
 2767        if self.show_inline_completions_override.is_some() {
 2768            self.set_show_edit_predictions(None, window, cx);
 2769        } else {
 2770            let show_edit_predictions = !self.edit_predictions_enabled();
 2771            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2772        }
 2773    }
 2774
 2775    pub fn set_show_edit_predictions(
 2776        &mut self,
 2777        show_edit_predictions: Option<bool>,
 2778        window: &mut Window,
 2779        cx: &mut Context<Self>,
 2780    ) {
 2781        self.show_inline_completions_override = show_edit_predictions;
 2782        self.update_edit_prediction_settings(cx);
 2783
 2784        if let Some(false) = show_edit_predictions {
 2785            self.discard_inline_completion(false, cx);
 2786        } else {
 2787            self.refresh_inline_completion(false, true, window, cx);
 2788        }
 2789    }
 2790
 2791    fn inline_completions_disabled_in_scope(
 2792        &self,
 2793        buffer: &Entity<Buffer>,
 2794        buffer_position: language::Anchor,
 2795        cx: &App,
 2796    ) -> bool {
 2797        let snapshot = buffer.read(cx).snapshot();
 2798        let settings = snapshot.settings_at(buffer_position, cx);
 2799
 2800        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2801            return false;
 2802        };
 2803
 2804        scope.override_name().map_or(false, |scope_name| {
 2805            settings
 2806                .edit_predictions_disabled_in
 2807                .iter()
 2808                .any(|s| s == scope_name)
 2809        })
 2810    }
 2811
 2812    pub fn set_use_modal_editing(&mut self, to: bool) {
 2813        self.use_modal_editing = to;
 2814    }
 2815
 2816    pub fn use_modal_editing(&self) -> bool {
 2817        self.use_modal_editing
 2818    }
 2819
 2820    fn selections_did_change(
 2821        &mut self,
 2822        local: bool,
 2823        old_cursor_position: &Anchor,
 2824        effects: SelectionEffects,
 2825        window: &mut Window,
 2826        cx: &mut Context<Self>,
 2827    ) {
 2828        window.invalidate_character_coordinates();
 2829
 2830        // Copy selections to primary selection buffer
 2831        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2832        if local {
 2833            let selections = self.selections.all::<usize>(cx);
 2834            let buffer_handle = self.buffer.read(cx).read(cx);
 2835
 2836            let mut text = String::new();
 2837            for (index, selection) in selections.iter().enumerate() {
 2838                let text_for_selection = buffer_handle
 2839                    .text_for_range(selection.start..selection.end)
 2840                    .collect::<String>();
 2841
 2842                text.push_str(&text_for_selection);
 2843                if index != selections.len() - 1 {
 2844                    text.push('\n');
 2845                }
 2846            }
 2847
 2848            if !text.is_empty() {
 2849                cx.write_to_primary(ClipboardItem::new_string(text));
 2850            }
 2851        }
 2852
 2853        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2854            self.buffer.update(cx, |buffer, cx| {
 2855                buffer.set_active_selections(
 2856                    &self.selections.disjoint_anchors(),
 2857                    self.selections.line_mode,
 2858                    self.cursor_shape,
 2859                    cx,
 2860                )
 2861            });
 2862        }
 2863        let display_map = self
 2864            .display_map
 2865            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2866        let buffer = &display_map.buffer_snapshot;
 2867        if self.selections.count() == 1 {
 2868            self.add_selections_state = None;
 2869        }
 2870        self.select_next_state = None;
 2871        self.select_prev_state = None;
 2872        self.select_syntax_node_history.try_clear();
 2873        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2874        self.snippet_stack
 2875            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2876        self.take_rename(false, window, cx);
 2877
 2878        let newest_selection = self.selections.newest_anchor();
 2879        let new_cursor_position = newest_selection.head();
 2880        let selection_start = newest_selection.start;
 2881
 2882        if effects.nav_history {
 2883            self.push_to_nav_history(
 2884                *old_cursor_position,
 2885                Some(new_cursor_position.to_point(buffer)),
 2886                false,
 2887                cx,
 2888            );
 2889        }
 2890
 2891        if local {
 2892            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2893                if !self.registered_buffers.contains_key(&buffer_id) {
 2894                    if let Some(project) = self.project.as_ref() {
 2895                        project.update(cx, |project, cx| {
 2896                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2897                                return;
 2898                            };
 2899                            self.registered_buffers.insert(
 2900                                buffer_id,
 2901                                project.register_buffer_with_language_servers(&buffer, cx),
 2902                            );
 2903                        })
 2904                    }
 2905                }
 2906            }
 2907
 2908            let mut context_menu = self.context_menu.borrow_mut();
 2909            let completion_menu = match context_menu.as_ref() {
 2910                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2911                Some(CodeContextMenu::CodeActions(_)) => {
 2912                    *context_menu = None;
 2913                    None
 2914                }
 2915                None => None,
 2916            };
 2917            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2918            drop(context_menu);
 2919
 2920            if effects.completions {
 2921                if let Some(completion_position) = completion_position {
 2922                    let start_offset = selection_start.to_offset(buffer);
 2923                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2924                    let continue_showing = if position_matches {
 2925                        if self.snippet_stack.is_empty() {
 2926                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2927                        } else {
 2928                            // Snippet choices can be shown even when the cursor is in whitespace.
 2929                            // Dismissing the menu with actions like backspace is handled by
 2930                            // invalidation regions.
 2931                            true
 2932                        }
 2933                    } else {
 2934                        false
 2935                    };
 2936
 2937                    if continue_showing {
 2938                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2939                    } else {
 2940                        self.hide_context_menu(window, cx);
 2941                    }
 2942                }
 2943            }
 2944
 2945            hide_hover(self, cx);
 2946
 2947            if old_cursor_position.to_display_point(&display_map).row()
 2948                != new_cursor_position.to_display_point(&display_map).row()
 2949            {
 2950                self.available_code_actions.take();
 2951            }
 2952            self.refresh_code_actions(window, cx);
 2953            self.refresh_document_highlights(cx);
 2954            self.refresh_selected_text_highlights(false, window, cx);
 2955            refresh_matching_bracket_highlights(self, window, cx);
 2956            self.update_visible_inline_completion(window, cx);
 2957            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2958            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2959            self.inline_blame_popover.take();
 2960            if self.git_blame_inline_enabled {
 2961                self.start_inline_blame_timer(window, cx);
 2962            }
 2963        }
 2964
 2965        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2966        cx.emit(EditorEvent::SelectionsChanged { local });
 2967
 2968        let selections = &self.selections.disjoint;
 2969        if selections.len() == 1 {
 2970            cx.emit(SearchEvent::ActiveMatchChanged)
 2971        }
 2972        if local {
 2973            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2974                let inmemory_selections = selections
 2975                    .iter()
 2976                    .map(|s| {
 2977                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2978                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2979                    })
 2980                    .collect();
 2981                self.update_restoration_data(cx, |data| {
 2982                    data.selections = inmemory_selections;
 2983                });
 2984
 2985                if WorkspaceSettings::get(None, cx).restore_on_startup
 2986                    != RestoreOnStartupBehavior::None
 2987                {
 2988                    if let Some(workspace_id) =
 2989                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2990                    {
 2991                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2992                        let selections = selections.clone();
 2993                        let background_executor = cx.background_executor().clone();
 2994                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2995                        self.serialize_selections = cx.background_spawn(async move {
 2996                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2997                            let db_selections = selections
 2998                                .iter()
 2999                                .map(|selection| {
 3000                                    (
 3001                                        selection.start.to_offset(&snapshot),
 3002                                        selection.end.to_offset(&snapshot),
 3003                                    )
 3004                                })
 3005                                .collect();
 3006
 3007                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3008                                .await
 3009                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3010                                .log_err();
 3011                        });
 3012                    }
 3013                }
 3014            }
 3015        }
 3016
 3017        cx.notify();
 3018    }
 3019
 3020    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3021        use text::ToOffset as _;
 3022        use text::ToPoint as _;
 3023
 3024        if self.mode.is_minimap()
 3025            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3026        {
 3027            return;
 3028        }
 3029
 3030        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3031            return;
 3032        };
 3033
 3034        let snapshot = singleton.read(cx).snapshot();
 3035        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3036            let display_snapshot = display_map.snapshot(cx);
 3037
 3038            display_snapshot
 3039                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3040                .map(|fold| {
 3041                    fold.range.start.text_anchor.to_point(&snapshot)
 3042                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3043                })
 3044                .collect()
 3045        });
 3046        self.update_restoration_data(cx, |data| {
 3047            data.folds = inmemory_folds;
 3048        });
 3049
 3050        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3051            return;
 3052        };
 3053        let background_executor = cx.background_executor().clone();
 3054        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3055        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3056            display_map
 3057                .snapshot(cx)
 3058                .folds_in_range(0..snapshot.len())
 3059                .map(|fold| {
 3060                    (
 3061                        fold.range.start.text_anchor.to_offset(&snapshot),
 3062                        fold.range.end.text_anchor.to_offset(&snapshot),
 3063                    )
 3064                })
 3065                .collect()
 3066        });
 3067        self.serialize_folds = cx.background_spawn(async move {
 3068            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3069            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3070                .await
 3071                .with_context(|| {
 3072                    format!(
 3073                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3074                    )
 3075                })
 3076                .log_err();
 3077        });
 3078    }
 3079
 3080    pub fn sync_selections(
 3081        &mut self,
 3082        other: Entity<Editor>,
 3083        cx: &mut Context<Self>,
 3084    ) -> gpui::Subscription {
 3085        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3086        self.selections.change_with(cx, |selections| {
 3087            selections.select_anchors(other_selections);
 3088        });
 3089
 3090        let other_subscription =
 3091            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3092                EditorEvent::SelectionsChanged { local: true } => {
 3093                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3094                    if other_selections.is_empty() {
 3095                        return;
 3096                    }
 3097                    this.selections.change_with(cx, |selections| {
 3098                        selections.select_anchors(other_selections);
 3099                    });
 3100                }
 3101                _ => {}
 3102            });
 3103
 3104        let this_subscription =
 3105            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3106                EditorEvent::SelectionsChanged { local: true } => {
 3107                    let these_selections = this.selections.disjoint.to_vec();
 3108                    if these_selections.is_empty() {
 3109                        return;
 3110                    }
 3111                    other.update(cx, |other_editor, cx| {
 3112                        other_editor.selections.change_with(cx, |selections| {
 3113                            selections.select_anchors(these_selections);
 3114                        })
 3115                    });
 3116                }
 3117                _ => {}
 3118            });
 3119
 3120        Subscription::join(other_subscription, this_subscription)
 3121    }
 3122
 3123    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3124    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3125    /// effects of selection change occur at the end of the transaction.
 3126    pub fn change_selections<R>(
 3127        &mut self,
 3128        effects: impl Into<SelectionEffects>,
 3129        window: &mut Window,
 3130        cx: &mut Context<Self>,
 3131        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3132    ) -> R {
 3133        let effects = effects.into();
 3134        if let Some(state) = &mut self.deferred_selection_effects_state {
 3135            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3136            state.effects.completions = effects.completions;
 3137            state.effects.nav_history |= effects.nav_history;
 3138            let (changed, result) = self.selections.change_with(cx, change);
 3139            state.changed |= changed;
 3140            return result;
 3141        }
 3142        let mut state = DeferredSelectionEffectsState {
 3143            changed: false,
 3144            effects,
 3145            old_cursor_position: self.selections.newest_anchor().head(),
 3146            history_entry: SelectionHistoryEntry {
 3147                selections: self.selections.disjoint_anchors(),
 3148                select_next_state: self.select_next_state.clone(),
 3149                select_prev_state: self.select_prev_state.clone(),
 3150                add_selections_state: self.add_selections_state.clone(),
 3151            },
 3152        };
 3153        let (changed, result) = self.selections.change_with(cx, change);
 3154        state.changed = state.changed || changed;
 3155        if self.defer_selection_effects {
 3156            self.deferred_selection_effects_state = Some(state);
 3157        } else {
 3158            self.apply_selection_effects(state, window, cx);
 3159        }
 3160        result
 3161    }
 3162
 3163    /// Defers the effects of selection change, so that the effects of multiple calls to
 3164    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3165    /// to selection history and the state of popovers based on selection position aren't
 3166    /// erroneously updated.
 3167    pub fn with_selection_effects_deferred<R>(
 3168        &mut self,
 3169        window: &mut Window,
 3170        cx: &mut Context<Self>,
 3171        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3172    ) -> R {
 3173        let already_deferred = self.defer_selection_effects;
 3174        self.defer_selection_effects = true;
 3175        let result = update(self, window, cx);
 3176        if !already_deferred {
 3177            self.defer_selection_effects = false;
 3178            if let Some(state) = self.deferred_selection_effects_state.take() {
 3179                self.apply_selection_effects(state, window, cx);
 3180            }
 3181        }
 3182        result
 3183    }
 3184
 3185    fn apply_selection_effects(
 3186        &mut self,
 3187        state: DeferredSelectionEffectsState,
 3188        window: &mut Window,
 3189        cx: &mut Context<Self>,
 3190    ) {
 3191        if state.changed {
 3192            self.selection_history.push(state.history_entry);
 3193
 3194            if let Some(autoscroll) = state.effects.scroll {
 3195                self.request_autoscroll(autoscroll, cx);
 3196            }
 3197
 3198            let old_cursor_position = &state.old_cursor_position;
 3199
 3200            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3201
 3202            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3203                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3204            }
 3205        }
 3206    }
 3207
 3208    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3209    where
 3210        I: IntoIterator<Item = (Range<S>, T)>,
 3211        S: ToOffset,
 3212        T: Into<Arc<str>>,
 3213    {
 3214        if self.read_only(cx) {
 3215            return;
 3216        }
 3217
 3218        self.buffer
 3219            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3220    }
 3221
 3222    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3223    where
 3224        I: IntoIterator<Item = (Range<S>, T)>,
 3225        S: ToOffset,
 3226        T: Into<Arc<str>>,
 3227    {
 3228        if self.read_only(cx) {
 3229            return;
 3230        }
 3231
 3232        self.buffer.update(cx, |buffer, cx| {
 3233            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3234        });
 3235    }
 3236
 3237    pub fn edit_with_block_indent<I, S, T>(
 3238        &mut self,
 3239        edits: I,
 3240        original_indent_columns: Vec<Option<u32>>,
 3241        cx: &mut Context<Self>,
 3242    ) where
 3243        I: IntoIterator<Item = (Range<S>, T)>,
 3244        S: ToOffset,
 3245        T: Into<Arc<str>>,
 3246    {
 3247        if self.read_only(cx) {
 3248            return;
 3249        }
 3250
 3251        self.buffer.update(cx, |buffer, cx| {
 3252            buffer.edit(
 3253                edits,
 3254                Some(AutoindentMode::Block {
 3255                    original_indent_columns,
 3256                }),
 3257                cx,
 3258            )
 3259        });
 3260    }
 3261
 3262    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3263        self.hide_context_menu(window, cx);
 3264
 3265        match phase {
 3266            SelectPhase::Begin {
 3267                position,
 3268                add,
 3269                click_count,
 3270            } => self.begin_selection(position, add, click_count, window, cx),
 3271            SelectPhase::BeginColumnar {
 3272                position,
 3273                goal_column,
 3274                reset,
 3275                mode,
 3276            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3277            SelectPhase::Extend {
 3278                position,
 3279                click_count,
 3280            } => self.extend_selection(position, click_count, window, cx),
 3281            SelectPhase::Update {
 3282                position,
 3283                goal_column,
 3284                scroll_delta,
 3285            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3286            SelectPhase::End => self.end_selection(window, cx),
 3287        }
 3288    }
 3289
 3290    fn extend_selection(
 3291        &mut self,
 3292        position: DisplayPoint,
 3293        click_count: usize,
 3294        window: &mut Window,
 3295        cx: &mut Context<Self>,
 3296    ) {
 3297        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3298        let tail = self.selections.newest::<usize>(cx).tail();
 3299        self.begin_selection(position, false, click_count, window, cx);
 3300
 3301        let position = position.to_offset(&display_map, Bias::Left);
 3302        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3303
 3304        let mut pending_selection = self
 3305            .selections
 3306            .pending_anchor()
 3307            .expect("extend_selection not called with pending selection");
 3308        if position >= tail {
 3309            pending_selection.start = tail_anchor;
 3310        } else {
 3311            pending_selection.end = tail_anchor;
 3312            pending_selection.reversed = true;
 3313        }
 3314
 3315        let mut pending_mode = self.selections.pending_mode().unwrap();
 3316        match &mut pending_mode {
 3317            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3318            _ => {}
 3319        }
 3320
 3321        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3322            SelectionEffects::scroll(Autoscroll::fit())
 3323        } else {
 3324            SelectionEffects::no_scroll()
 3325        };
 3326
 3327        self.change_selections(effects, window, cx, |s| {
 3328            s.set_pending(pending_selection, pending_mode)
 3329        });
 3330    }
 3331
 3332    fn begin_selection(
 3333        &mut self,
 3334        position: DisplayPoint,
 3335        add: bool,
 3336        click_count: usize,
 3337        window: &mut Window,
 3338        cx: &mut Context<Self>,
 3339    ) {
 3340        if !self.focus_handle.is_focused(window) {
 3341            self.last_focused_descendant = None;
 3342            window.focus(&self.focus_handle);
 3343        }
 3344
 3345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3346        let buffer = &display_map.buffer_snapshot;
 3347        let position = display_map.clip_point(position, Bias::Left);
 3348
 3349        let start;
 3350        let end;
 3351        let mode;
 3352        let mut auto_scroll;
 3353        match click_count {
 3354            1 => {
 3355                start = buffer.anchor_before(position.to_point(&display_map));
 3356                end = start;
 3357                mode = SelectMode::Character;
 3358                auto_scroll = true;
 3359            }
 3360            2 => {
 3361                let range = movement::surrounding_word(&display_map, position);
 3362                start = buffer.anchor_before(range.start.to_point(&display_map));
 3363                end = buffer.anchor_before(range.end.to_point(&display_map));
 3364                mode = SelectMode::Word(start..end);
 3365                auto_scroll = true;
 3366            }
 3367            3 => {
 3368                let position = display_map
 3369                    .clip_point(position, Bias::Left)
 3370                    .to_point(&display_map);
 3371                let line_start = display_map.prev_line_boundary(position).0;
 3372                let next_line_start = buffer.clip_point(
 3373                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3374                    Bias::Left,
 3375                );
 3376                start = buffer.anchor_before(line_start);
 3377                end = buffer.anchor_before(next_line_start);
 3378                mode = SelectMode::Line(start..end);
 3379                auto_scroll = true;
 3380            }
 3381            _ => {
 3382                start = buffer.anchor_before(0);
 3383                end = buffer.anchor_before(buffer.len());
 3384                mode = SelectMode::All;
 3385                auto_scroll = false;
 3386            }
 3387        }
 3388        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3389
 3390        let point_to_delete: Option<usize> = {
 3391            let selected_points: Vec<Selection<Point>> =
 3392                self.selections.disjoint_in_range(start..end, cx);
 3393
 3394            if !add || click_count > 1 {
 3395                None
 3396            } else if !selected_points.is_empty() {
 3397                Some(selected_points[0].id)
 3398            } else {
 3399                let clicked_point_already_selected =
 3400                    self.selections.disjoint.iter().find(|selection| {
 3401                        selection.start.to_point(buffer) == start.to_point(buffer)
 3402                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3403                    });
 3404
 3405                clicked_point_already_selected.map(|selection| selection.id)
 3406            }
 3407        };
 3408
 3409        let selections_count = self.selections.count();
 3410
 3411        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3412            if let Some(point_to_delete) = point_to_delete {
 3413                s.delete(point_to_delete);
 3414
 3415                if selections_count == 1 {
 3416                    s.set_pending_anchor_range(start..end, mode);
 3417                }
 3418            } else {
 3419                if !add {
 3420                    s.clear_disjoint();
 3421                }
 3422
 3423                s.set_pending_anchor_range(start..end, mode);
 3424            }
 3425        });
 3426    }
 3427
 3428    fn begin_columnar_selection(
 3429        &mut self,
 3430        position: DisplayPoint,
 3431        goal_column: u32,
 3432        reset: bool,
 3433        mode: ColumnarMode,
 3434        window: &mut Window,
 3435        cx: &mut Context<Self>,
 3436    ) {
 3437        if !self.focus_handle.is_focused(window) {
 3438            self.last_focused_descendant = None;
 3439            window.focus(&self.focus_handle);
 3440        }
 3441
 3442        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3443
 3444        if reset {
 3445            let pointer_position = display_map
 3446                .buffer_snapshot
 3447                .anchor_before(position.to_point(&display_map));
 3448
 3449            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3450                s.clear_disjoint();
 3451                s.set_pending_anchor_range(
 3452                    pointer_position..pointer_position,
 3453                    SelectMode::Character,
 3454                );
 3455            });
 3456        };
 3457
 3458        let tail = self.selections.newest::<Point>(cx).tail();
 3459        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3460        self.columnar_selection_state = match mode {
 3461            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3462                selection_tail: selection_anchor,
 3463                display_point: if reset {
 3464                    if position.column() != goal_column {
 3465                        Some(DisplayPoint::new(position.row(), goal_column))
 3466                    } else {
 3467                        None
 3468                    }
 3469                } else {
 3470                    None
 3471                },
 3472            }),
 3473            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3474                selection_tail: selection_anchor,
 3475            }),
 3476        };
 3477
 3478        if !reset {
 3479            self.select_columns(position, goal_column, &display_map, window, cx);
 3480        }
 3481    }
 3482
 3483    fn update_selection(
 3484        &mut self,
 3485        position: DisplayPoint,
 3486        goal_column: u32,
 3487        scroll_delta: gpui::Point<f32>,
 3488        window: &mut Window,
 3489        cx: &mut Context<Self>,
 3490    ) {
 3491        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3492
 3493        if self.columnar_selection_state.is_some() {
 3494            self.select_columns(position, goal_column, &display_map, window, cx);
 3495        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3496            let buffer = self.buffer.read(cx).snapshot(cx);
 3497            let head;
 3498            let tail;
 3499            let mode = self.selections.pending_mode().unwrap();
 3500            match &mode {
 3501                SelectMode::Character => {
 3502                    head = position.to_point(&display_map);
 3503                    tail = pending.tail().to_point(&buffer);
 3504                }
 3505                SelectMode::Word(original_range) => {
 3506                    let original_display_range = original_range.start.to_display_point(&display_map)
 3507                        ..original_range.end.to_display_point(&display_map);
 3508                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3509                        ..original_display_range.end.to_point(&display_map);
 3510                    if movement::is_inside_word(&display_map, position)
 3511                        || original_display_range.contains(&position)
 3512                    {
 3513                        let word_range = movement::surrounding_word(&display_map, position);
 3514                        if word_range.start < original_display_range.start {
 3515                            head = word_range.start.to_point(&display_map);
 3516                        } else {
 3517                            head = word_range.end.to_point(&display_map);
 3518                        }
 3519                    } else {
 3520                        head = position.to_point(&display_map);
 3521                    }
 3522
 3523                    if head <= original_buffer_range.start {
 3524                        tail = original_buffer_range.end;
 3525                    } else {
 3526                        tail = original_buffer_range.start;
 3527                    }
 3528                }
 3529                SelectMode::Line(original_range) => {
 3530                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3531
 3532                    let position = display_map
 3533                        .clip_point(position, Bias::Left)
 3534                        .to_point(&display_map);
 3535                    let line_start = display_map.prev_line_boundary(position).0;
 3536                    let next_line_start = buffer.clip_point(
 3537                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3538                        Bias::Left,
 3539                    );
 3540
 3541                    if line_start < original_range.start {
 3542                        head = line_start
 3543                    } else {
 3544                        head = next_line_start
 3545                    }
 3546
 3547                    if head <= original_range.start {
 3548                        tail = original_range.end;
 3549                    } else {
 3550                        tail = original_range.start;
 3551                    }
 3552                }
 3553                SelectMode::All => {
 3554                    return;
 3555                }
 3556            };
 3557
 3558            if head < tail {
 3559                pending.start = buffer.anchor_before(head);
 3560                pending.end = buffer.anchor_before(tail);
 3561                pending.reversed = true;
 3562            } else {
 3563                pending.start = buffer.anchor_before(tail);
 3564                pending.end = buffer.anchor_before(head);
 3565                pending.reversed = false;
 3566            }
 3567
 3568            self.change_selections(None, window, cx, |s| {
 3569                s.set_pending(pending, mode);
 3570            });
 3571        } else {
 3572            log::error!("update_selection dispatched with no pending selection");
 3573            return;
 3574        }
 3575
 3576        self.apply_scroll_delta(scroll_delta, window, cx);
 3577        cx.notify();
 3578    }
 3579
 3580    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3581        self.columnar_selection_state.take();
 3582        if self.selections.pending_anchor().is_some() {
 3583            let selections = self.selections.all::<usize>(cx);
 3584            self.change_selections(None, window, cx, |s| {
 3585                s.select(selections);
 3586                s.clear_pending();
 3587            });
 3588        }
 3589    }
 3590
 3591    fn select_columns(
 3592        &mut self,
 3593        head: DisplayPoint,
 3594        goal_column: u32,
 3595        display_map: &DisplaySnapshot,
 3596        window: &mut Window,
 3597        cx: &mut Context<Self>,
 3598    ) {
 3599        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3600            return;
 3601        };
 3602
 3603        let tail = match columnar_state {
 3604            ColumnarSelectionState::FromMouse {
 3605                selection_tail,
 3606                display_point,
 3607            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3608            ColumnarSelectionState::FromSelection { selection_tail } => {
 3609                selection_tail.to_display_point(&display_map)
 3610            }
 3611        };
 3612
 3613        let start_row = cmp::min(tail.row(), head.row());
 3614        let end_row = cmp::max(tail.row(), head.row());
 3615        let start_column = cmp::min(tail.column(), goal_column);
 3616        let end_column = cmp::max(tail.column(), goal_column);
 3617        let reversed = start_column < tail.column();
 3618
 3619        let selection_ranges = (start_row.0..=end_row.0)
 3620            .map(DisplayRow)
 3621            .filter_map(|row| {
 3622                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3623                    || start_column <= display_map.line_len(row))
 3624                    && !display_map.is_block_line(row)
 3625                {
 3626                    let start = display_map
 3627                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3628                        .to_point(display_map);
 3629                    let end = display_map
 3630                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3631                        .to_point(display_map);
 3632                    if reversed {
 3633                        Some(end..start)
 3634                    } else {
 3635                        Some(start..end)
 3636                    }
 3637                } else {
 3638                    None
 3639                }
 3640            })
 3641            .collect::<Vec<_>>();
 3642
 3643        let ranges = match columnar_state {
 3644            ColumnarSelectionState::FromMouse { .. } => {
 3645                let mut non_empty_ranges = selection_ranges
 3646                    .iter()
 3647                    .filter(|selection_range| selection_range.start != selection_range.end)
 3648                    .peekable();
 3649                if non_empty_ranges.peek().is_some() {
 3650                    non_empty_ranges.cloned().collect()
 3651                } else {
 3652                    selection_ranges
 3653                }
 3654            }
 3655            _ => selection_ranges,
 3656        };
 3657
 3658        self.change_selections(None, window, cx, |s| {
 3659            s.select_ranges(ranges);
 3660        });
 3661        cx.notify();
 3662    }
 3663
 3664    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3665        self.selections
 3666            .all_adjusted(cx)
 3667            .iter()
 3668            .any(|selection| !selection.is_empty())
 3669    }
 3670
 3671    pub fn has_pending_nonempty_selection(&self) -> bool {
 3672        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3673            Some(Selection { start, end, .. }) => start != end,
 3674            None => false,
 3675        };
 3676
 3677        pending_nonempty_selection
 3678            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3679    }
 3680
 3681    pub fn has_pending_selection(&self) -> bool {
 3682        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3683    }
 3684
 3685    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3686        self.selection_mark_mode = false;
 3687        self.selection_drag_state = SelectionDragState::None;
 3688
 3689        if self.clear_expanded_diff_hunks(cx) {
 3690            cx.notify();
 3691            return;
 3692        }
 3693        if self.dismiss_menus_and_popups(true, window, cx) {
 3694            return;
 3695        }
 3696
 3697        if self.mode.is_full()
 3698            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3699        {
 3700            return;
 3701        }
 3702
 3703        cx.propagate();
 3704    }
 3705
 3706    pub fn dismiss_menus_and_popups(
 3707        &mut self,
 3708        is_user_requested: bool,
 3709        window: &mut Window,
 3710        cx: &mut Context<Self>,
 3711    ) -> bool {
 3712        if self.take_rename(false, window, cx).is_some() {
 3713            return true;
 3714        }
 3715
 3716        if hide_hover(self, cx) {
 3717            return true;
 3718        }
 3719
 3720        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3721            return true;
 3722        }
 3723
 3724        if self.hide_context_menu(window, cx).is_some() {
 3725            return true;
 3726        }
 3727
 3728        if self.mouse_context_menu.take().is_some() {
 3729            return true;
 3730        }
 3731
 3732        if is_user_requested && self.discard_inline_completion(true, cx) {
 3733            return true;
 3734        }
 3735
 3736        if self.snippet_stack.pop().is_some() {
 3737            return true;
 3738        }
 3739
 3740        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3741            self.dismiss_diagnostics(cx);
 3742            return true;
 3743        }
 3744
 3745        false
 3746    }
 3747
 3748    fn linked_editing_ranges_for(
 3749        &self,
 3750        selection: Range<text::Anchor>,
 3751        cx: &App,
 3752    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3753        if self.linked_edit_ranges.is_empty() {
 3754            return None;
 3755        }
 3756        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3757            selection.end.buffer_id.and_then(|end_buffer_id| {
 3758                if selection.start.buffer_id != Some(end_buffer_id) {
 3759                    return None;
 3760                }
 3761                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3762                let snapshot = buffer.read(cx).snapshot();
 3763                self.linked_edit_ranges
 3764                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3765                    .map(|ranges| (ranges, snapshot, buffer))
 3766            })?;
 3767        use text::ToOffset as TO;
 3768        // find offset from the start of current range to current cursor position
 3769        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3770
 3771        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3772        let start_difference = start_offset - start_byte_offset;
 3773        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3774        let end_difference = end_offset - start_byte_offset;
 3775        // Current range has associated linked ranges.
 3776        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3777        for range in linked_ranges.iter() {
 3778            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3779            let end_offset = start_offset + end_difference;
 3780            let start_offset = start_offset + start_difference;
 3781            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3782                continue;
 3783            }
 3784            if self.selections.disjoint_anchor_ranges().any(|s| {
 3785                if s.start.buffer_id != selection.start.buffer_id
 3786                    || s.end.buffer_id != selection.end.buffer_id
 3787                {
 3788                    return false;
 3789                }
 3790                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3791                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3792            }) {
 3793                continue;
 3794            }
 3795            let start = buffer_snapshot.anchor_after(start_offset);
 3796            let end = buffer_snapshot.anchor_after(end_offset);
 3797            linked_edits
 3798                .entry(buffer.clone())
 3799                .or_default()
 3800                .push(start..end);
 3801        }
 3802        Some(linked_edits)
 3803    }
 3804
 3805    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3806        let text: Arc<str> = text.into();
 3807
 3808        if self.read_only(cx) {
 3809            return;
 3810        }
 3811
 3812        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3813
 3814        let selections = self.selections.all_adjusted(cx);
 3815        let mut bracket_inserted = false;
 3816        let mut edits = Vec::new();
 3817        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3818        let mut new_selections = Vec::with_capacity(selections.len());
 3819        let mut new_autoclose_regions = Vec::new();
 3820        let snapshot = self.buffer.read(cx).read(cx);
 3821        let mut clear_linked_edit_ranges = false;
 3822
 3823        for (selection, autoclose_region) in
 3824            self.selections_with_autoclose_regions(selections, &snapshot)
 3825        {
 3826            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3827                // Determine if the inserted text matches the opening or closing
 3828                // bracket of any of this language's bracket pairs.
 3829                let mut bracket_pair = None;
 3830                let mut is_bracket_pair_start = false;
 3831                let mut is_bracket_pair_end = false;
 3832                if !text.is_empty() {
 3833                    let mut bracket_pair_matching_end = None;
 3834                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3835                    //  and they are removing the character that triggered IME popup.
 3836                    for (pair, enabled) in scope.brackets() {
 3837                        if !pair.close && !pair.surround {
 3838                            continue;
 3839                        }
 3840
 3841                        if enabled && pair.start.ends_with(text.as_ref()) {
 3842                            let prefix_len = pair.start.len() - text.len();
 3843                            let preceding_text_matches_prefix = prefix_len == 0
 3844                                || (selection.start.column >= (prefix_len as u32)
 3845                                    && snapshot.contains_str_at(
 3846                                        Point::new(
 3847                                            selection.start.row,
 3848                                            selection.start.column - (prefix_len as u32),
 3849                                        ),
 3850                                        &pair.start[..prefix_len],
 3851                                    ));
 3852                            if preceding_text_matches_prefix {
 3853                                bracket_pair = Some(pair.clone());
 3854                                is_bracket_pair_start = true;
 3855                                break;
 3856                            }
 3857                        }
 3858                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3859                        {
 3860                            // take first bracket pair matching end, but don't break in case a later bracket
 3861                            // pair matches start
 3862                            bracket_pair_matching_end = Some(pair.clone());
 3863                        }
 3864                    }
 3865                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3866                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3867                        is_bracket_pair_end = true;
 3868                    }
 3869                }
 3870
 3871                if let Some(bracket_pair) = bracket_pair {
 3872                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3873                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3874                    let auto_surround =
 3875                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3876                    if selection.is_empty() {
 3877                        if is_bracket_pair_start {
 3878                            // If the inserted text is a suffix of an opening bracket and the
 3879                            // selection is preceded by the rest of the opening bracket, then
 3880                            // insert the closing bracket.
 3881                            let following_text_allows_autoclose = snapshot
 3882                                .chars_at(selection.start)
 3883                                .next()
 3884                                .map_or(true, |c| scope.should_autoclose_before(c));
 3885
 3886                            let preceding_text_allows_autoclose = selection.start.column == 0
 3887                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3888                                    true,
 3889                                    |c| {
 3890                                        bracket_pair.start != bracket_pair.end
 3891                                            || !snapshot
 3892                                                .char_classifier_at(selection.start)
 3893                                                .is_word(c)
 3894                                    },
 3895                                );
 3896
 3897                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3898                                && bracket_pair.start.len() == 1
 3899                            {
 3900                                let target = bracket_pair.start.chars().next().unwrap();
 3901                                let current_line_count = snapshot
 3902                                    .reversed_chars_at(selection.start)
 3903                                    .take_while(|&c| c != '\n')
 3904                                    .filter(|&c| c == target)
 3905                                    .count();
 3906                                current_line_count % 2 == 1
 3907                            } else {
 3908                                false
 3909                            };
 3910
 3911                            if autoclose
 3912                                && bracket_pair.close
 3913                                && following_text_allows_autoclose
 3914                                && preceding_text_allows_autoclose
 3915                                && !is_closing_quote
 3916                            {
 3917                                let anchor = snapshot.anchor_before(selection.end);
 3918                                new_selections.push((selection.map(|_| anchor), text.len()));
 3919                                new_autoclose_regions.push((
 3920                                    anchor,
 3921                                    text.len(),
 3922                                    selection.id,
 3923                                    bracket_pair.clone(),
 3924                                ));
 3925                                edits.push((
 3926                                    selection.range(),
 3927                                    format!("{}{}", text, bracket_pair.end).into(),
 3928                                ));
 3929                                bracket_inserted = true;
 3930                                continue;
 3931                            }
 3932                        }
 3933
 3934                        if let Some(region) = autoclose_region {
 3935                            // If the selection is followed by an auto-inserted closing bracket,
 3936                            // then don't insert that closing bracket again; just move the selection
 3937                            // past the closing bracket.
 3938                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3939                                && text.as_ref() == region.pair.end.as_str();
 3940                            if should_skip {
 3941                                let anchor = snapshot.anchor_after(selection.end);
 3942                                new_selections
 3943                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3944                                continue;
 3945                            }
 3946                        }
 3947
 3948                        let always_treat_brackets_as_autoclosed = snapshot
 3949                            .language_settings_at(selection.start, cx)
 3950                            .always_treat_brackets_as_autoclosed;
 3951                        if always_treat_brackets_as_autoclosed
 3952                            && is_bracket_pair_end
 3953                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3954                        {
 3955                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3956                            // and the inserted text is a closing bracket and the selection is followed
 3957                            // by the closing bracket then move the selection past the closing bracket.
 3958                            let anchor = snapshot.anchor_after(selection.end);
 3959                            new_selections.push((selection.map(|_| anchor), text.len()));
 3960                            continue;
 3961                        }
 3962                    }
 3963                    // If an opening bracket is 1 character long and is typed while
 3964                    // text is selected, then surround that text with the bracket pair.
 3965                    else if auto_surround
 3966                        && bracket_pair.surround
 3967                        && is_bracket_pair_start
 3968                        && bracket_pair.start.chars().count() == 1
 3969                    {
 3970                        edits.push((selection.start..selection.start, text.clone()));
 3971                        edits.push((
 3972                            selection.end..selection.end,
 3973                            bracket_pair.end.as_str().into(),
 3974                        ));
 3975                        bracket_inserted = true;
 3976                        new_selections.push((
 3977                            Selection {
 3978                                id: selection.id,
 3979                                start: snapshot.anchor_after(selection.start),
 3980                                end: snapshot.anchor_before(selection.end),
 3981                                reversed: selection.reversed,
 3982                                goal: selection.goal,
 3983                            },
 3984                            0,
 3985                        ));
 3986                        continue;
 3987                    }
 3988                }
 3989            }
 3990
 3991            if self.auto_replace_emoji_shortcode
 3992                && selection.is_empty()
 3993                && text.as_ref().ends_with(':')
 3994            {
 3995                if let Some(possible_emoji_short_code) =
 3996                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3997                {
 3998                    if !possible_emoji_short_code.is_empty() {
 3999                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4000                            let emoji_shortcode_start = Point::new(
 4001                                selection.start.row,
 4002                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4003                            );
 4004
 4005                            // Remove shortcode from buffer
 4006                            edits.push((
 4007                                emoji_shortcode_start..selection.start,
 4008                                "".to_string().into(),
 4009                            ));
 4010                            new_selections.push((
 4011                                Selection {
 4012                                    id: selection.id,
 4013                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4014                                    end: snapshot.anchor_before(selection.start),
 4015                                    reversed: selection.reversed,
 4016                                    goal: selection.goal,
 4017                                },
 4018                                0,
 4019                            ));
 4020
 4021                            // Insert emoji
 4022                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4023                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4024                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4025
 4026                            continue;
 4027                        }
 4028                    }
 4029                }
 4030            }
 4031
 4032            // If not handling any auto-close operation, then just replace the selected
 4033            // text with the given input and move the selection to the end of the
 4034            // newly inserted text.
 4035            let anchor = snapshot.anchor_after(selection.end);
 4036            if !self.linked_edit_ranges.is_empty() {
 4037                let start_anchor = snapshot.anchor_before(selection.start);
 4038
 4039                let is_word_char = text.chars().next().map_or(true, |char| {
 4040                    let classifier = snapshot
 4041                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4042                        .ignore_punctuation(true);
 4043                    classifier.is_word(char)
 4044                });
 4045
 4046                if is_word_char {
 4047                    if let Some(ranges) = self
 4048                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4049                    {
 4050                        for (buffer, edits) in ranges {
 4051                            linked_edits
 4052                                .entry(buffer.clone())
 4053                                .or_default()
 4054                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4055                        }
 4056                    }
 4057                } else {
 4058                    clear_linked_edit_ranges = true;
 4059                }
 4060            }
 4061
 4062            new_selections.push((selection.map(|_| anchor), 0));
 4063            edits.push((selection.start..selection.end, text.clone()));
 4064        }
 4065
 4066        drop(snapshot);
 4067
 4068        self.transact(window, cx, |this, window, cx| {
 4069            if clear_linked_edit_ranges {
 4070                this.linked_edit_ranges.clear();
 4071            }
 4072            let initial_buffer_versions =
 4073                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4074
 4075            this.buffer.update(cx, |buffer, cx| {
 4076                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4077            });
 4078            for (buffer, edits) in linked_edits {
 4079                buffer.update(cx, |buffer, cx| {
 4080                    let snapshot = buffer.snapshot();
 4081                    let edits = edits
 4082                        .into_iter()
 4083                        .map(|(range, text)| {
 4084                            use text::ToPoint as TP;
 4085                            let end_point = TP::to_point(&range.end, &snapshot);
 4086                            let start_point = TP::to_point(&range.start, &snapshot);
 4087                            (start_point..end_point, text)
 4088                        })
 4089                        .sorted_by_key(|(range, _)| range.start);
 4090                    buffer.edit(edits, None, cx);
 4091                })
 4092            }
 4093            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4094            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4095            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4096            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4097                .zip(new_selection_deltas)
 4098                .map(|(selection, delta)| Selection {
 4099                    id: selection.id,
 4100                    start: selection.start + delta,
 4101                    end: selection.end + delta,
 4102                    reversed: selection.reversed,
 4103                    goal: SelectionGoal::None,
 4104                })
 4105                .collect::<Vec<_>>();
 4106
 4107            let mut i = 0;
 4108            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4109                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4110                let start = map.buffer_snapshot.anchor_before(position);
 4111                let end = map.buffer_snapshot.anchor_after(position);
 4112                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4113                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4114                        Ordering::Less => i += 1,
 4115                        Ordering::Greater => break,
 4116                        Ordering::Equal => {
 4117                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4118                                Ordering::Less => i += 1,
 4119                                Ordering::Equal => break,
 4120                                Ordering::Greater => break,
 4121                            }
 4122                        }
 4123                    }
 4124                }
 4125                this.autoclose_regions.insert(
 4126                    i,
 4127                    AutocloseRegion {
 4128                        selection_id,
 4129                        range: start..end,
 4130                        pair,
 4131                    },
 4132                );
 4133            }
 4134
 4135            let had_active_inline_completion = this.has_active_inline_completion();
 4136            this.change_selections(
 4137                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4138                window,
 4139                cx,
 4140                |s| s.select(new_selections),
 4141            );
 4142
 4143            if !bracket_inserted {
 4144                if let Some(on_type_format_task) =
 4145                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4146                {
 4147                    on_type_format_task.detach_and_log_err(cx);
 4148                }
 4149            }
 4150
 4151            let editor_settings = EditorSettings::get_global(cx);
 4152            if bracket_inserted
 4153                && (editor_settings.auto_signature_help
 4154                    || editor_settings.show_signature_help_after_edits)
 4155            {
 4156                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4157            }
 4158
 4159            let trigger_in_words =
 4160                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4161            if this.hard_wrap.is_some() {
 4162                let latest: Range<Point> = this.selections.newest(cx).range();
 4163                if latest.is_empty()
 4164                    && this
 4165                        .buffer()
 4166                        .read(cx)
 4167                        .snapshot(cx)
 4168                        .line_len(MultiBufferRow(latest.start.row))
 4169                        == latest.start.column
 4170                {
 4171                    this.rewrap_impl(
 4172                        RewrapOptions {
 4173                            override_language_settings: true,
 4174                            preserve_existing_whitespace: true,
 4175                        },
 4176                        cx,
 4177                    )
 4178                }
 4179            }
 4180            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4181            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4182            this.refresh_inline_completion(true, false, window, cx);
 4183            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4184        });
 4185    }
 4186
 4187    fn find_possible_emoji_shortcode_at_position(
 4188        snapshot: &MultiBufferSnapshot,
 4189        position: Point,
 4190    ) -> Option<String> {
 4191        let mut chars = Vec::new();
 4192        let mut found_colon = false;
 4193        for char in snapshot.reversed_chars_at(position).take(100) {
 4194            // Found a possible emoji shortcode in the middle of the buffer
 4195            if found_colon {
 4196                if char.is_whitespace() {
 4197                    chars.reverse();
 4198                    return Some(chars.iter().collect());
 4199                }
 4200                // If the previous character is not a whitespace, we are in the middle of a word
 4201                // and we only want to complete the shortcode if the word is made up of other emojis
 4202                let mut containing_word = String::new();
 4203                for ch in snapshot
 4204                    .reversed_chars_at(position)
 4205                    .skip(chars.len() + 1)
 4206                    .take(100)
 4207                {
 4208                    if ch.is_whitespace() {
 4209                        break;
 4210                    }
 4211                    containing_word.push(ch);
 4212                }
 4213                let containing_word = containing_word.chars().rev().collect::<String>();
 4214                if util::word_consists_of_emojis(containing_word.as_str()) {
 4215                    chars.reverse();
 4216                    return Some(chars.iter().collect());
 4217                }
 4218            }
 4219
 4220            if char.is_whitespace() || !char.is_ascii() {
 4221                return None;
 4222            }
 4223            if char == ':' {
 4224                found_colon = true;
 4225            } else {
 4226                chars.push(char);
 4227            }
 4228        }
 4229        // Found a possible emoji shortcode at the beginning of the buffer
 4230        chars.reverse();
 4231        Some(chars.iter().collect())
 4232    }
 4233
 4234    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4235        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4236        self.transact(window, cx, |this, window, cx| {
 4237            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4238                let selections = this.selections.all::<usize>(cx);
 4239                let multi_buffer = this.buffer.read(cx);
 4240                let buffer = multi_buffer.snapshot(cx);
 4241                selections
 4242                    .iter()
 4243                    .map(|selection| {
 4244                        let start_point = selection.start.to_point(&buffer);
 4245                        let mut existing_indent =
 4246                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4247                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4248                        let start = selection.start;
 4249                        let end = selection.end;
 4250                        let selection_is_empty = start == end;
 4251                        let language_scope = buffer.language_scope_at(start);
 4252                        let (
 4253                            comment_delimiter,
 4254                            doc_delimiter,
 4255                            insert_extra_newline,
 4256                            indent_on_newline,
 4257                            indent_on_extra_newline,
 4258                        ) = if let Some(language) = &language_scope {
 4259                            let mut insert_extra_newline =
 4260                                insert_extra_newline_brackets(&buffer, start..end, language)
 4261                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4262
 4263                            // Comment extension on newline is allowed only for cursor selections
 4264                            let comment_delimiter = maybe!({
 4265                                if !selection_is_empty {
 4266                                    return None;
 4267                                }
 4268
 4269                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4270                                    return None;
 4271                                }
 4272
 4273                                let delimiters = language.line_comment_prefixes();
 4274                                let max_len_of_delimiter =
 4275                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4276                                let (snapshot, range) =
 4277                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4278
 4279                                let num_of_whitespaces = snapshot
 4280                                    .chars_for_range(range.clone())
 4281                                    .take_while(|c| c.is_whitespace())
 4282                                    .count();
 4283                                let comment_candidate = snapshot
 4284                                    .chars_for_range(range)
 4285                                    .skip(num_of_whitespaces)
 4286                                    .take(max_len_of_delimiter)
 4287                                    .collect::<String>();
 4288                                let (delimiter, trimmed_len) = delimiters
 4289                                    .iter()
 4290                                    .filter_map(|delimiter| {
 4291                                        let prefix = delimiter.trim_end();
 4292                                        if comment_candidate.starts_with(prefix) {
 4293                                            Some((delimiter, prefix.len()))
 4294                                        } else {
 4295                                            None
 4296                                        }
 4297                                    })
 4298                                    .max_by_key(|(_, len)| *len)?;
 4299
 4300                                let cursor_is_placed_after_comment_marker =
 4301                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4302                                if cursor_is_placed_after_comment_marker {
 4303                                    Some(delimiter.clone())
 4304                                } else {
 4305                                    None
 4306                                }
 4307                            });
 4308
 4309                            let mut indent_on_newline = IndentSize::spaces(0);
 4310                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4311
 4312                            let doc_delimiter = maybe!({
 4313                                if !selection_is_empty {
 4314                                    return None;
 4315                                }
 4316
 4317                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4318                                    return None;
 4319                                }
 4320
 4321                                let DocumentationConfig {
 4322                                    start: start_tag,
 4323                                    end: end_tag,
 4324                                    prefix: delimiter,
 4325                                    tab_size: len,
 4326                                } = language.documentation()?;
 4327
 4328                                let is_within_block_comment = buffer
 4329                                    .language_scope_at(start_point)
 4330                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4331                                if !is_within_block_comment {
 4332                                    return None;
 4333                                }
 4334
 4335                                let (snapshot, range) =
 4336                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4337
 4338                                let num_of_whitespaces = snapshot
 4339                                    .chars_for_range(range.clone())
 4340                                    .take_while(|c| c.is_whitespace())
 4341                                    .count();
 4342
 4343                                // 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.
 4344                                let column = start_point.column;
 4345                                let cursor_is_after_start_tag = {
 4346                                    let start_tag_len = start_tag.len();
 4347                                    let start_tag_line = snapshot
 4348                                        .chars_for_range(range.clone())
 4349                                        .skip(num_of_whitespaces)
 4350                                        .take(start_tag_len)
 4351                                        .collect::<String>();
 4352                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4353                                        num_of_whitespaces + start_tag_len <= column as usize
 4354                                    } else {
 4355                                        false
 4356                                    }
 4357                                };
 4358
 4359                                let cursor_is_after_delimiter = {
 4360                                    let delimiter_trim = delimiter.trim_end();
 4361                                    let delimiter_line = snapshot
 4362                                        .chars_for_range(range.clone())
 4363                                        .skip(num_of_whitespaces)
 4364                                        .take(delimiter_trim.len())
 4365                                        .collect::<String>();
 4366                                    if delimiter_line.starts_with(delimiter_trim) {
 4367                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4368                                    } else {
 4369                                        false
 4370                                    }
 4371                                };
 4372
 4373                                let cursor_is_before_end_tag_if_exists = {
 4374                                    let mut char_position = 0u32;
 4375                                    let mut end_tag_offset = None;
 4376
 4377                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4378                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4379                                            let chars_before_match =
 4380                                                chunk[..byte_pos].chars().count() as u32;
 4381                                            end_tag_offset =
 4382                                                Some(char_position + chars_before_match);
 4383                                            break 'outer;
 4384                                        }
 4385                                        char_position += chunk.chars().count() as u32;
 4386                                    }
 4387
 4388                                    if let Some(end_tag_offset) = end_tag_offset {
 4389                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4390                                        if cursor_is_after_start_tag {
 4391                                            if cursor_is_before_end_tag {
 4392                                                insert_extra_newline = true;
 4393                                            }
 4394                                            let cursor_is_at_start_of_end_tag =
 4395                                                column == end_tag_offset;
 4396                                            if cursor_is_at_start_of_end_tag {
 4397                                                indent_on_extra_newline.len = (*len).into();
 4398                                            }
 4399                                        }
 4400                                        cursor_is_before_end_tag
 4401                                    } else {
 4402                                        true
 4403                                    }
 4404                                };
 4405
 4406                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4407                                    && cursor_is_before_end_tag_if_exists
 4408                                {
 4409                                    if cursor_is_after_start_tag {
 4410                                        indent_on_newline.len = (*len).into();
 4411                                    }
 4412                                    Some(delimiter.clone())
 4413                                } else {
 4414                                    None
 4415                                }
 4416                            });
 4417
 4418                            (
 4419                                comment_delimiter,
 4420                                doc_delimiter,
 4421                                insert_extra_newline,
 4422                                indent_on_newline,
 4423                                indent_on_extra_newline,
 4424                            )
 4425                        } else {
 4426                            (
 4427                                None,
 4428                                None,
 4429                                false,
 4430                                IndentSize::default(),
 4431                                IndentSize::default(),
 4432                            )
 4433                        };
 4434
 4435                        let prevent_auto_indent = doc_delimiter.is_some();
 4436                        let delimiter = comment_delimiter.or(doc_delimiter);
 4437
 4438                        let capacity_for_delimiter =
 4439                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4440                        let mut new_text = String::with_capacity(
 4441                            1 + capacity_for_delimiter
 4442                                + existing_indent.len as usize
 4443                                + indent_on_newline.len as usize
 4444                                + indent_on_extra_newline.len as usize,
 4445                        );
 4446                        new_text.push('\n');
 4447                        new_text.extend(existing_indent.chars());
 4448                        new_text.extend(indent_on_newline.chars());
 4449
 4450                        if let Some(delimiter) = &delimiter {
 4451                            new_text.push_str(delimiter);
 4452                        }
 4453
 4454                        if insert_extra_newline {
 4455                            new_text.push('\n');
 4456                            new_text.extend(existing_indent.chars());
 4457                            new_text.extend(indent_on_extra_newline.chars());
 4458                        }
 4459
 4460                        let anchor = buffer.anchor_after(end);
 4461                        let new_selection = selection.map(|_| anchor);
 4462                        (
 4463                            ((start..end, new_text), prevent_auto_indent),
 4464                            (insert_extra_newline, new_selection),
 4465                        )
 4466                    })
 4467                    .unzip()
 4468            };
 4469
 4470            let mut auto_indent_edits = Vec::new();
 4471            let mut edits = Vec::new();
 4472            for (edit, prevent_auto_indent) in edits_with_flags {
 4473                if prevent_auto_indent {
 4474                    edits.push(edit);
 4475                } else {
 4476                    auto_indent_edits.push(edit);
 4477                }
 4478            }
 4479            if !edits.is_empty() {
 4480                this.edit(edits, cx);
 4481            }
 4482            if !auto_indent_edits.is_empty() {
 4483                this.edit_with_autoindent(auto_indent_edits, cx);
 4484            }
 4485
 4486            let buffer = this.buffer.read(cx).snapshot(cx);
 4487            let new_selections = selection_info
 4488                .into_iter()
 4489                .map(|(extra_newline_inserted, new_selection)| {
 4490                    let mut cursor = new_selection.end.to_point(&buffer);
 4491                    if extra_newline_inserted {
 4492                        cursor.row -= 1;
 4493                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4494                    }
 4495                    new_selection.map(|_| cursor)
 4496                })
 4497                .collect();
 4498
 4499            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4500                s.select(new_selections)
 4501            });
 4502            this.refresh_inline_completion(true, false, window, cx);
 4503        });
 4504    }
 4505
 4506    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4507        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4508
 4509        let buffer = self.buffer.read(cx);
 4510        let snapshot = buffer.snapshot(cx);
 4511
 4512        let mut edits = Vec::new();
 4513        let mut rows = Vec::new();
 4514
 4515        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4516            let cursor = selection.head();
 4517            let row = cursor.row;
 4518
 4519            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4520
 4521            let newline = "\n".to_string();
 4522            edits.push((start_of_line..start_of_line, newline));
 4523
 4524            rows.push(row + rows_inserted as u32);
 4525        }
 4526
 4527        self.transact(window, cx, |editor, window, cx| {
 4528            editor.edit(edits, cx);
 4529
 4530            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4531                let mut index = 0;
 4532                s.move_cursors_with(|map, _, _| {
 4533                    let row = rows[index];
 4534                    index += 1;
 4535
 4536                    let point = Point::new(row, 0);
 4537                    let boundary = map.next_line_boundary(point).1;
 4538                    let clipped = map.clip_point(boundary, Bias::Left);
 4539
 4540                    (clipped, SelectionGoal::None)
 4541                });
 4542            });
 4543
 4544            let mut indent_edits = Vec::new();
 4545            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4546            for row in rows {
 4547                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4548                for (row, indent) in indents {
 4549                    if indent.len == 0 {
 4550                        continue;
 4551                    }
 4552
 4553                    let text = match indent.kind {
 4554                        IndentKind::Space => " ".repeat(indent.len as usize),
 4555                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4556                    };
 4557                    let point = Point::new(row.0, 0);
 4558                    indent_edits.push((point..point, text));
 4559                }
 4560            }
 4561            editor.edit(indent_edits, cx);
 4562        });
 4563    }
 4564
 4565    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4566        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4567
 4568        let buffer = self.buffer.read(cx);
 4569        let snapshot = buffer.snapshot(cx);
 4570
 4571        let mut edits = Vec::new();
 4572        let mut rows = Vec::new();
 4573        let mut rows_inserted = 0;
 4574
 4575        for selection in self.selections.all_adjusted(cx) {
 4576            let cursor = selection.head();
 4577            let row = cursor.row;
 4578
 4579            let point = Point::new(row + 1, 0);
 4580            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4581
 4582            let newline = "\n".to_string();
 4583            edits.push((start_of_line..start_of_line, newline));
 4584
 4585            rows_inserted += 1;
 4586            rows.push(row + rows_inserted);
 4587        }
 4588
 4589        self.transact(window, cx, |editor, window, cx| {
 4590            editor.edit(edits, cx);
 4591
 4592            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4593                let mut index = 0;
 4594                s.move_cursors_with(|map, _, _| {
 4595                    let row = rows[index];
 4596                    index += 1;
 4597
 4598                    let point = Point::new(row, 0);
 4599                    let boundary = map.next_line_boundary(point).1;
 4600                    let clipped = map.clip_point(boundary, Bias::Left);
 4601
 4602                    (clipped, SelectionGoal::None)
 4603                });
 4604            });
 4605
 4606            let mut indent_edits = Vec::new();
 4607            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4608            for row in rows {
 4609                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4610                for (row, indent) in indents {
 4611                    if indent.len == 0 {
 4612                        continue;
 4613                    }
 4614
 4615                    let text = match indent.kind {
 4616                        IndentKind::Space => " ".repeat(indent.len as usize),
 4617                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4618                    };
 4619                    let point = Point::new(row.0, 0);
 4620                    indent_edits.push((point..point, text));
 4621                }
 4622            }
 4623            editor.edit(indent_edits, cx);
 4624        });
 4625    }
 4626
 4627    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4628        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4629            original_indent_columns: Vec::new(),
 4630        });
 4631        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4632    }
 4633
 4634    fn insert_with_autoindent_mode(
 4635        &mut self,
 4636        text: &str,
 4637        autoindent_mode: Option<AutoindentMode>,
 4638        window: &mut Window,
 4639        cx: &mut Context<Self>,
 4640    ) {
 4641        if self.read_only(cx) {
 4642            return;
 4643        }
 4644
 4645        let text: Arc<str> = text.into();
 4646        self.transact(window, cx, |this, window, cx| {
 4647            let old_selections = this.selections.all_adjusted(cx);
 4648            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4649                let anchors = {
 4650                    let snapshot = buffer.read(cx);
 4651                    old_selections
 4652                        .iter()
 4653                        .map(|s| {
 4654                            let anchor = snapshot.anchor_after(s.head());
 4655                            s.map(|_| anchor)
 4656                        })
 4657                        .collect::<Vec<_>>()
 4658                };
 4659                buffer.edit(
 4660                    old_selections
 4661                        .iter()
 4662                        .map(|s| (s.start..s.end, text.clone())),
 4663                    autoindent_mode,
 4664                    cx,
 4665                );
 4666                anchors
 4667            });
 4668
 4669            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4670                s.select_anchors(selection_anchors);
 4671            });
 4672
 4673            cx.notify();
 4674        });
 4675    }
 4676
 4677    fn trigger_completion_on_input(
 4678        &mut self,
 4679        text: &str,
 4680        trigger_in_words: bool,
 4681        window: &mut Window,
 4682        cx: &mut Context<Self>,
 4683    ) {
 4684        let completions_source = self
 4685            .context_menu
 4686            .borrow()
 4687            .as_ref()
 4688            .and_then(|menu| match menu {
 4689                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4690                CodeContextMenu::CodeActions(_) => None,
 4691            });
 4692
 4693        match completions_source {
 4694            Some(CompletionsMenuSource::Words) => {
 4695                self.show_word_completions(&ShowWordCompletions, window, cx)
 4696            }
 4697            Some(CompletionsMenuSource::Normal)
 4698            | Some(CompletionsMenuSource::SnippetChoices)
 4699            | None
 4700                if self.is_completion_trigger(
 4701                    text,
 4702                    trigger_in_words,
 4703                    completions_source.is_some(),
 4704                    cx,
 4705                ) =>
 4706            {
 4707                self.show_completions(
 4708                    &ShowCompletions {
 4709                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4710                    },
 4711                    window,
 4712                    cx,
 4713                )
 4714            }
 4715            _ => {
 4716                self.hide_context_menu(window, cx);
 4717            }
 4718        }
 4719    }
 4720
 4721    fn is_completion_trigger(
 4722        &self,
 4723        text: &str,
 4724        trigger_in_words: bool,
 4725        menu_is_open: bool,
 4726        cx: &mut Context<Self>,
 4727    ) -> bool {
 4728        let position = self.selections.newest_anchor().head();
 4729        let multibuffer = self.buffer.read(cx);
 4730        let Some(buffer) = position
 4731            .buffer_id
 4732            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4733        else {
 4734            return false;
 4735        };
 4736
 4737        if let Some(completion_provider) = &self.completion_provider {
 4738            completion_provider.is_completion_trigger(
 4739                &buffer,
 4740                position.text_anchor,
 4741                text,
 4742                trigger_in_words,
 4743                menu_is_open,
 4744                cx,
 4745            )
 4746        } else {
 4747            false
 4748        }
 4749    }
 4750
 4751    /// If any empty selections is touching the start of its innermost containing autoclose
 4752    /// region, expand it to select the brackets.
 4753    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4754        let selections = self.selections.all::<usize>(cx);
 4755        let buffer = self.buffer.read(cx).read(cx);
 4756        let new_selections = self
 4757            .selections_with_autoclose_regions(selections, &buffer)
 4758            .map(|(mut selection, region)| {
 4759                if !selection.is_empty() {
 4760                    return selection;
 4761                }
 4762
 4763                if let Some(region) = region {
 4764                    let mut range = region.range.to_offset(&buffer);
 4765                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4766                        range.start -= region.pair.start.len();
 4767                        if buffer.contains_str_at(range.start, &region.pair.start)
 4768                            && buffer.contains_str_at(range.end, &region.pair.end)
 4769                        {
 4770                            range.end += region.pair.end.len();
 4771                            selection.start = range.start;
 4772                            selection.end = range.end;
 4773
 4774                            return selection;
 4775                        }
 4776                    }
 4777                }
 4778
 4779                let always_treat_brackets_as_autoclosed = buffer
 4780                    .language_settings_at(selection.start, cx)
 4781                    .always_treat_brackets_as_autoclosed;
 4782
 4783                if !always_treat_brackets_as_autoclosed {
 4784                    return selection;
 4785                }
 4786
 4787                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4788                    for (pair, enabled) in scope.brackets() {
 4789                        if !enabled || !pair.close {
 4790                            continue;
 4791                        }
 4792
 4793                        if buffer.contains_str_at(selection.start, &pair.end) {
 4794                            let pair_start_len = pair.start.len();
 4795                            if buffer.contains_str_at(
 4796                                selection.start.saturating_sub(pair_start_len),
 4797                                &pair.start,
 4798                            ) {
 4799                                selection.start -= pair_start_len;
 4800                                selection.end += pair.end.len();
 4801
 4802                                return selection;
 4803                            }
 4804                        }
 4805                    }
 4806                }
 4807
 4808                selection
 4809            })
 4810            .collect();
 4811
 4812        drop(buffer);
 4813        self.change_selections(None, window, cx, |selections| {
 4814            selections.select(new_selections)
 4815        });
 4816    }
 4817
 4818    /// Iterate the given selections, and for each one, find the smallest surrounding
 4819    /// autoclose region. This uses the ordering of the selections and the autoclose
 4820    /// regions to avoid repeated comparisons.
 4821    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4822        &'a self,
 4823        selections: impl IntoIterator<Item = Selection<D>>,
 4824        buffer: &'a MultiBufferSnapshot,
 4825    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4826        let mut i = 0;
 4827        let mut regions = self.autoclose_regions.as_slice();
 4828        selections.into_iter().map(move |selection| {
 4829            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4830
 4831            let mut enclosing = None;
 4832            while let Some(pair_state) = regions.get(i) {
 4833                if pair_state.range.end.to_offset(buffer) < range.start {
 4834                    regions = &regions[i + 1..];
 4835                    i = 0;
 4836                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4837                    break;
 4838                } else {
 4839                    if pair_state.selection_id == selection.id {
 4840                        enclosing = Some(pair_state);
 4841                    }
 4842                    i += 1;
 4843                }
 4844            }
 4845
 4846            (selection, enclosing)
 4847        })
 4848    }
 4849
 4850    /// Remove any autoclose regions that no longer contain their selection.
 4851    fn invalidate_autoclose_regions(
 4852        &mut self,
 4853        mut selections: &[Selection<Anchor>],
 4854        buffer: &MultiBufferSnapshot,
 4855    ) {
 4856        self.autoclose_regions.retain(|state| {
 4857            let mut i = 0;
 4858            while let Some(selection) = selections.get(i) {
 4859                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4860                    selections = &selections[1..];
 4861                    continue;
 4862                }
 4863                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4864                    break;
 4865                }
 4866                if selection.id == state.selection_id {
 4867                    return true;
 4868                } else {
 4869                    i += 1;
 4870                }
 4871            }
 4872            false
 4873        });
 4874    }
 4875
 4876    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4877        let offset = position.to_offset(buffer);
 4878        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4879        if offset > word_range.start && kind == Some(CharKind::Word) {
 4880            Some(
 4881                buffer
 4882                    .text_for_range(word_range.start..offset)
 4883                    .collect::<String>(),
 4884            )
 4885        } else {
 4886            None
 4887        }
 4888    }
 4889
 4890    pub fn toggle_inline_values(
 4891        &mut self,
 4892        _: &ToggleInlineValues,
 4893        _: &mut Window,
 4894        cx: &mut Context<Self>,
 4895    ) {
 4896        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4897
 4898        self.refresh_inline_values(cx);
 4899    }
 4900
 4901    pub fn toggle_inlay_hints(
 4902        &mut self,
 4903        _: &ToggleInlayHints,
 4904        _: &mut Window,
 4905        cx: &mut Context<Self>,
 4906    ) {
 4907        self.refresh_inlay_hints(
 4908            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4909            cx,
 4910        );
 4911    }
 4912
 4913    pub fn inlay_hints_enabled(&self) -> bool {
 4914        self.inlay_hint_cache.enabled
 4915    }
 4916
 4917    pub fn inline_values_enabled(&self) -> bool {
 4918        self.inline_value_cache.enabled
 4919    }
 4920
 4921    #[cfg(any(test, feature = "test-support"))]
 4922    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4923        self.display_map
 4924            .read(cx)
 4925            .current_inlays()
 4926            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4927            .cloned()
 4928            .collect()
 4929    }
 4930
 4931    #[cfg(any(test, feature = "test-support"))]
 4932    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 4933        self.display_map
 4934            .read(cx)
 4935            .current_inlays()
 4936            .cloned()
 4937            .collect()
 4938    }
 4939
 4940    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4941        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4942            return;
 4943        }
 4944
 4945        let reason_description = reason.description();
 4946        let ignore_debounce = matches!(
 4947            reason,
 4948            InlayHintRefreshReason::SettingsChange(_)
 4949                | InlayHintRefreshReason::Toggle(_)
 4950                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4951                | InlayHintRefreshReason::ModifiersChanged(_)
 4952        );
 4953        let (invalidate_cache, required_languages) = match reason {
 4954            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4955                match self.inlay_hint_cache.modifiers_override(enabled) {
 4956                    Some(enabled) => {
 4957                        if enabled {
 4958                            (InvalidationStrategy::RefreshRequested, None)
 4959                        } else {
 4960                            self.splice_inlays(
 4961                                &self
 4962                                    .visible_inlay_hints(cx)
 4963                                    .iter()
 4964                                    .map(|inlay| inlay.id)
 4965                                    .collect::<Vec<InlayId>>(),
 4966                                Vec::new(),
 4967                                cx,
 4968                            );
 4969                            return;
 4970                        }
 4971                    }
 4972                    None => return,
 4973                }
 4974            }
 4975            InlayHintRefreshReason::Toggle(enabled) => {
 4976                if self.inlay_hint_cache.toggle(enabled) {
 4977                    if enabled {
 4978                        (InvalidationStrategy::RefreshRequested, None)
 4979                    } else {
 4980                        self.splice_inlays(
 4981                            &self
 4982                                .visible_inlay_hints(cx)
 4983                                .iter()
 4984                                .map(|inlay| inlay.id)
 4985                                .collect::<Vec<InlayId>>(),
 4986                            Vec::new(),
 4987                            cx,
 4988                        );
 4989                        return;
 4990                    }
 4991                } else {
 4992                    return;
 4993                }
 4994            }
 4995            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4996                match self.inlay_hint_cache.update_settings(
 4997                    &self.buffer,
 4998                    new_settings,
 4999                    self.visible_inlay_hints(cx),
 5000                    cx,
 5001                ) {
 5002                    ControlFlow::Break(Some(InlaySplice {
 5003                        to_remove,
 5004                        to_insert,
 5005                    })) => {
 5006                        self.splice_inlays(&to_remove, to_insert, cx);
 5007                        return;
 5008                    }
 5009                    ControlFlow::Break(None) => return,
 5010                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5011                }
 5012            }
 5013            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5014                if let Some(InlaySplice {
 5015                    to_remove,
 5016                    to_insert,
 5017                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5018                {
 5019                    self.splice_inlays(&to_remove, to_insert, cx);
 5020                }
 5021                self.display_map.update(cx, |display_map, _| {
 5022                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5023                });
 5024                return;
 5025            }
 5026            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5027            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5028                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5029            }
 5030            InlayHintRefreshReason::RefreshRequested => {
 5031                (InvalidationStrategy::RefreshRequested, None)
 5032            }
 5033        };
 5034
 5035        if let Some(InlaySplice {
 5036            to_remove,
 5037            to_insert,
 5038        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5039            reason_description,
 5040            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 5041            invalidate_cache,
 5042            ignore_debounce,
 5043            cx,
 5044        ) {
 5045            self.splice_inlays(&to_remove, to_insert, cx);
 5046        }
 5047    }
 5048
 5049    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5050        self.display_map
 5051            .read(cx)
 5052            .current_inlays()
 5053            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5054            .cloned()
 5055            .collect()
 5056    }
 5057
 5058    pub fn excerpts_for_inlay_hints_query(
 5059        &self,
 5060        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5061        cx: &mut Context<Editor>,
 5062    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5063        let Some(project) = self.project.as_ref() else {
 5064            return HashMap::default();
 5065        };
 5066        let project = project.read(cx);
 5067        let multi_buffer = self.buffer().read(cx);
 5068        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5069        let multi_buffer_visible_start = self
 5070            .scroll_manager
 5071            .anchor()
 5072            .anchor
 5073            .to_point(&multi_buffer_snapshot);
 5074        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5075            multi_buffer_visible_start
 5076                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5077            Bias::Left,
 5078        );
 5079        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5080        multi_buffer_snapshot
 5081            .range_to_buffer_ranges(multi_buffer_visible_range)
 5082            .into_iter()
 5083            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5084            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5085                let buffer_file = project::File::from_dyn(buffer.file())?;
 5086                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5087                let worktree_entry = buffer_worktree
 5088                    .read(cx)
 5089                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5090                if worktree_entry.is_ignored {
 5091                    return None;
 5092                }
 5093
 5094                let language = buffer.language()?;
 5095                if let Some(restrict_to_languages) = restrict_to_languages {
 5096                    if !restrict_to_languages.contains(language) {
 5097                        return None;
 5098                    }
 5099                }
 5100                Some((
 5101                    excerpt_id,
 5102                    (
 5103                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5104                        buffer.version().clone(),
 5105                        excerpt_visible_range,
 5106                    ),
 5107                ))
 5108            })
 5109            .collect()
 5110    }
 5111
 5112    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5113        TextLayoutDetails {
 5114            text_system: window.text_system().clone(),
 5115            editor_style: self.style.clone().unwrap(),
 5116            rem_size: window.rem_size(),
 5117            scroll_anchor: self.scroll_manager.anchor(),
 5118            visible_rows: self.visible_line_count(),
 5119            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5120        }
 5121    }
 5122
 5123    pub fn splice_inlays(
 5124        &self,
 5125        to_remove: &[InlayId],
 5126        to_insert: Vec<Inlay>,
 5127        cx: &mut Context<Self>,
 5128    ) {
 5129        self.display_map.update(cx, |display_map, cx| {
 5130            display_map.splice_inlays(to_remove, to_insert, cx)
 5131        });
 5132        cx.notify();
 5133    }
 5134
 5135    fn trigger_on_type_formatting(
 5136        &self,
 5137        input: String,
 5138        window: &mut Window,
 5139        cx: &mut Context<Self>,
 5140    ) -> Option<Task<Result<()>>> {
 5141        if input.len() != 1 {
 5142            return None;
 5143        }
 5144
 5145        let project = self.project.as_ref()?;
 5146        let position = self.selections.newest_anchor().head();
 5147        let (buffer, buffer_position) = self
 5148            .buffer
 5149            .read(cx)
 5150            .text_anchor_for_position(position, cx)?;
 5151
 5152        let settings = language_settings::language_settings(
 5153            buffer
 5154                .read(cx)
 5155                .language_at(buffer_position)
 5156                .map(|l| l.name()),
 5157            buffer.read(cx).file(),
 5158            cx,
 5159        );
 5160        if !settings.use_on_type_format {
 5161            return None;
 5162        }
 5163
 5164        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5165        // hence we do LSP request & edit on host side only — add formats to host's history.
 5166        let push_to_lsp_host_history = true;
 5167        // If this is not the host, append its history with new edits.
 5168        let push_to_client_history = project.read(cx).is_via_collab();
 5169
 5170        let on_type_formatting = project.update(cx, |project, cx| {
 5171            project.on_type_format(
 5172                buffer.clone(),
 5173                buffer_position,
 5174                input,
 5175                push_to_lsp_host_history,
 5176                cx,
 5177            )
 5178        });
 5179        Some(cx.spawn_in(window, async move |editor, cx| {
 5180            if let Some(transaction) = on_type_formatting.await? {
 5181                if push_to_client_history {
 5182                    buffer
 5183                        .update(cx, |buffer, _| {
 5184                            buffer.push_transaction(transaction, Instant::now());
 5185                            buffer.finalize_last_transaction();
 5186                        })
 5187                        .ok();
 5188                }
 5189                editor.update(cx, |editor, cx| {
 5190                    editor.refresh_document_highlights(cx);
 5191                })?;
 5192            }
 5193            Ok(())
 5194        }))
 5195    }
 5196
 5197    pub fn show_word_completions(
 5198        &mut self,
 5199        _: &ShowWordCompletions,
 5200        window: &mut Window,
 5201        cx: &mut Context<Self>,
 5202    ) {
 5203        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5204    }
 5205
 5206    pub fn show_completions(
 5207        &mut self,
 5208        options: &ShowCompletions,
 5209        window: &mut Window,
 5210        cx: &mut Context<Self>,
 5211    ) {
 5212        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5213    }
 5214
 5215    fn open_or_update_completions_menu(
 5216        &mut self,
 5217        requested_source: Option<CompletionsMenuSource>,
 5218        trigger: Option<&str>,
 5219        window: &mut Window,
 5220        cx: &mut Context<Self>,
 5221    ) {
 5222        if self.pending_rename.is_some() {
 5223            return;
 5224        }
 5225
 5226        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5227
 5228        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5229        // inserted and selected. To handle that case, the start of the selection is used so that
 5230        // the menu starts with all choices.
 5231        let position = self
 5232            .selections
 5233            .newest_anchor()
 5234            .start
 5235            .bias_right(&multibuffer_snapshot);
 5236        if position.diff_base_anchor.is_some() {
 5237            return;
 5238        }
 5239        let (buffer, buffer_position) =
 5240            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5241                output
 5242            } else {
 5243                return;
 5244            };
 5245        let buffer_snapshot = buffer.read(cx).snapshot();
 5246
 5247        let query: Option<Arc<String>> =
 5248            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5249
 5250        drop(multibuffer_snapshot);
 5251
 5252        let provider = match requested_source {
 5253            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5254            Some(CompletionsMenuSource::Words) => None,
 5255            Some(CompletionsMenuSource::SnippetChoices) => {
 5256                log::error!("bug: SnippetChoices requested_source is not handled");
 5257                None
 5258            }
 5259        };
 5260
 5261        let sort_completions = provider
 5262            .as_ref()
 5263            .map_or(false, |provider| provider.sort_completions());
 5264
 5265        let filter_completions = provider
 5266            .as_ref()
 5267            .map_or(true, |provider| provider.filter_completions());
 5268
 5269        let trigger_kind = match trigger {
 5270            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5271                CompletionTriggerKind::TRIGGER_CHARACTER
 5272            }
 5273            _ => CompletionTriggerKind::INVOKED,
 5274        };
 5275        let completion_context = CompletionContext {
 5276            trigger_character: trigger.and_then(|trigger| {
 5277                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5278                    Some(String::from(trigger))
 5279                } else {
 5280                    None
 5281                }
 5282            }),
 5283            trigger_kind,
 5284        };
 5285
 5286        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5287        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5288        // involve trigger chars, so this is skipped in that case.
 5289        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5290        {
 5291            let menu_is_open = matches!(
 5292                self.context_menu.borrow().as_ref(),
 5293                Some(CodeContextMenu::Completions(_))
 5294            );
 5295            if menu_is_open {
 5296                self.hide_context_menu(window, cx);
 5297            }
 5298        }
 5299
 5300        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5301            if filter_completions {
 5302                menu.filter(query.clone(), provider.clone(), window, cx);
 5303            }
 5304            // When `is_incomplete` is false, no need to re-query completions when the current query
 5305            // is a suffix of the initial query.
 5306            if !menu.is_incomplete {
 5307                // If the new query is a suffix of the old query (typing more characters) and
 5308                // the previous result was complete, the existing completions can be filtered.
 5309                //
 5310                // Note that this is always true for snippet completions.
 5311                let query_matches = match (&menu.initial_query, &query) {
 5312                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5313                    (None, _) => true,
 5314                    _ => false,
 5315                };
 5316                if query_matches {
 5317                    let position_matches = if menu.initial_position == position {
 5318                        true
 5319                    } else {
 5320                        let snapshot = self.buffer.read(cx).read(cx);
 5321                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5322                    };
 5323                    if position_matches {
 5324                        return;
 5325                    }
 5326                }
 5327            }
 5328        };
 5329
 5330        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5331            buffer_snapshot.surrounding_word(buffer_position)
 5332        {
 5333            let word_to_exclude = buffer_snapshot
 5334                .text_for_range(word_range.clone())
 5335                .collect::<String>();
 5336            (
 5337                buffer_snapshot.anchor_before(word_range.start)
 5338                    ..buffer_snapshot.anchor_after(buffer_position),
 5339                Some(word_to_exclude),
 5340            )
 5341        } else {
 5342            (buffer_position..buffer_position, None)
 5343        };
 5344
 5345        let language = buffer_snapshot
 5346            .language_at(buffer_position)
 5347            .map(|language| language.name());
 5348
 5349        let completion_settings =
 5350            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5351
 5352        let show_completion_documentation = buffer_snapshot
 5353            .settings_at(buffer_position, cx)
 5354            .show_completion_documentation;
 5355
 5356        // The document can be large, so stay in reasonable bounds when searching for words,
 5357        // otherwise completion pop-up might be slow to appear.
 5358        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5359        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5360        let min_word_search = buffer_snapshot.clip_point(
 5361            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5362            Bias::Left,
 5363        );
 5364        let max_word_search = buffer_snapshot.clip_point(
 5365            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5366            Bias::Right,
 5367        );
 5368        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5369            ..buffer_snapshot.point_to_offset(max_word_search);
 5370
 5371        let skip_digits = query
 5372            .as_ref()
 5373            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5374
 5375        let (mut words, provider_responses) = match &provider {
 5376            Some(provider) => {
 5377                let provider_responses = provider.completions(
 5378                    position.excerpt_id,
 5379                    &buffer,
 5380                    buffer_position,
 5381                    completion_context,
 5382                    window,
 5383                    cx,
 5384                );
 5385
 5386                let words = match completion_settings.words {
 5387                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5388                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5389                        .background_spawn(async move {
 5390                            buffer_snapshot.words_in_range(WordsQuery {
 5391                                fuzzy_contents: None,
 5392                                range: word_search_range,
 5393                                skip_digits,
 5394                            })
 5395                        }),
 5396                };
 5397
 5398                (words, provider_responses)
 5399            }
 5400            None => (
 5401                cx.background_spawn(async move {
 5402                    buffer_snapshot.words_in_range(WordsQuery {
 5403                        fuzzy_contents: None,
 5404                        range: word_search_range,
 5405                        skip_digits,
 5406                    })
 5407                }),
 5408                Task::ready(Ok(Vec::new())),
 5409            ),
 5410        };
 5411
 5412        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5413
 5414        let id = post_inc(&mut self.next_completion_id);
 5415        let task = cx.spawn_in(window, async move |editor, cx| {
 5416            let Ok(()) = editor.update(cx, |this, _| {
 5417                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5418            }) else {
 5419                return;
 5420            };
 5421
 5422            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5423            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5424            let mut completions = Vec::new();
 5425            let mut is_incomplete = false;
 5426            if let Some(provider_responses) = provider_responses.await.log_err() {
 5427                if !provider_responses.is_empty() {
 5428                    for response in provider_responses {
 5429                        completions.extend(response.completions);
 5430                        is_incomplete = is_incomplete || response.is_incomplete;
 5431                    }
 5432                    if completion_settings.words == WordsCompletionMode::Fallback {
 5433                        words = Task::ready(BTreeMap::default());
 5434                    }
 5435                }
 5436            }
 5437
 5438            let mut words = words.await;
 5439            if let Some(word_to_exclude) = &word_to_exclude {
 5440                words.remove(word_to_exclude);
 5441            }
 5442            for lsp_completion in &completions {
 5443                words.remove(&lsp_completion.new_text);
 5444            }
 5445            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5446                replace_range: word_replace_range.clone(),
 5447                new_text: word.clone(),
 5448                label: CodeLabel::plain(word, None),
 5449                icon_path: None,
 5450                documentation: None,
 5451                source: CompletionSource::BufferWord {
 5452                    word_range,
 5453                    resolved: false,
 5454                },
 5455                insert_text_mode: Some(InsertTextMode::AS_IS),
 5456                confirm: None,
 5457            }));
 5458
 5459            let menu = if completions.is_empty() {
 5460                None
 5461            } else {
 5462                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5463                    let languages = editor
 5464                        .workspace
 5465                        .as_ref()
 5466                        .and_then(|(workspace, _)| workspace.upgrade())
 5467                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5468                    let menu = CompletionsMenu::new(
 5469                        id,
 5470                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5471                        sort_completions,
 5472                        show_completion_documentation,
 5473                        position,
 5474                        query.clone(),
 5475                        is_incomplete,
 5476                        buffer.clone(),
 5477                        completions.into(),
 5478                        snippet_sort_order,
 5479                        languages,
 5480                        language,
 5481                        cx,
 5482                    );
 5483
 5484                    let query = if filter_completions { query } else { None };
 5485                    let matches_task = if let Some(query) = query {
 5486                        menu.do_async_filtering(query, cx)
 5487                    } else {
 5488                        Task::ready(menu.unfiltered_matches())
 5489                    };
 5490                    (menu, matches_task)
 5491                }) else {
 5492                    return;
 5493                };
 5494
 5495                let matches = matches_task.await;
 5496
 5497                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5498                    // Newer menu already set, so exit.
 5499                    match editor.context_menu.borrow().as_ref() {
 5500                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5501                            if prev_menu.id > id {
 5502                                return;
 5503                            }
 5504                        }
 5505                        _ => {}
 5506                    };
 5507
 5508                    // Only valid to take prev_menu because it the new menu is immediately set
 5509                    // below, or the menu is hidden.
 5510                    match editor.context_menu.borrow_mut().take() {
 5511                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5512                            let position_matches =
 5513                                if prev_menu.initial_position == menu.initial_position {
 5514                                    true
 5515                                } else {
 5516                                    let snapshot = editor.buffer.read(cx).read(cx);
 5517                                    prev_menu.initial_position.to_offset(&snapshot)
 5518                                        == menu.initial_position.to_offset(&snapshot)
 5519                                };
 5520                            if position_matches {
 5521                                // Preserve markdown cache before `set_filter_results` because it will
 5522                                // try to populate the documentation cache.
 5523                                menu.preserve_markdown_cache(prev_menu);
 5524                            }
 5525                        }
 5526                        _ => {}
 5527                    };
 5528
 5529                    menu.set_filter_results(matches, provider, window, cx);
 5530                }) else {
 5531                    return;
 5532                };
 5533
 5534                menu.visible().then_some(menu)
 5535            };
 5536
 5537            editor
 5538                .update_in(cx, |editor, window, cx| {
 5539                    if editor.focus_handle.is_focused(window) {
 5540                        if let Some(menu) = menu {
 5541                            *editor.context_menu.borrow_mut() =
 5542                                Some(CodeContextMenu::Completions(menu));
 5543
 5544                            crate::hover_popover::hide_hover(editor, cx);
 5545                            if editor.show_edit_predictions_in_menu() {
 5546                                editor.update_visible_inline_completion(window, cx);
 5547                            } else {
 5548                                editor.discard_inline_completion(false, cx);
 5549                            }
 5550
 5551                            cx.notify();
 5552                            return;
 5553                        }
 5554                    }
 5555
 5556                    if editor.completion_tasks.len() <= 1 {
 5557                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5558                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5559                        // If it was already hidden and we don't show inline completions in the menu, we should
 5560                        // also show the inline-completion when available.
 5561                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5562                            editor.update_visible_inline_completion(window, cx);
 5563                        }
 5564                    }
 5565                })
 5566                .ok();
 5567        });
 5568
 5569        self.completion_tasks.push((id, task));
 5570    }
 5571
 5572    #[cfg(feature = "test-support")]
 5573    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5574        let menu = self.context_menu.borrow();
 5575        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5576            let completions = menu.completions.borrow();
 5577            Some(completions.to_vec())
 5578        } else {
 5579            None
 5580        }
 5581    }
 5582
 5583    pub fn with_completions_menu_matching_id<R>(
 5584        &self,
 5585        id: CompletionId,
 5586        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5587    ) -> R {
 5588        let mut context_menu = self.context_menu.borrow_mut();
 5589        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5590            return f(None);
 5591        };
 5592        if completions_menu.id != id {
 5593            return f(None);
 5594        }
 5595        f(Some(completions_menu))
 5596    }
 5597
 5598    pub fn confirm_completion(
 5599        &mut self,
 5600        action: &ConfirmCompletion,
 5601        window: &mut Window,
 5602        cx: &mut Context<Self>,
 5603    ) -> Option<Task<Result<()>>> {
 5604        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5605        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5606    }
 5607
 5608    pub fn confirm_completion_insert(
 5609        &mut self,
 5610        _: &ConfirmCompletionInsert,
 5611        window: &mut Window,
 5612        cx: &mut Context<Self>,
 5613    ) -> Option<Task<Result<()>>> {
 5614        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5615        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5616    }
 5617
 5618    pub fn confirm_completion_replace(
 5619        &mut self,
 5620        _: &ConfirmCompletionReplace,
 5621        window: &mut Window,
 5622        cx: &mut Context<Self>,
 5623    ) -> Option<Task<Result<()>>> {
 5624        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5625        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5626    }
 5627
 5628    pub fn compose_completion(
 5629        &mut self,
 5630        action: &ComposeCompletion,
 5631        window: &mut Window,
 5632        cx: &mut Context<Self>,
 5633    ) -> Option<Task<Result<()>>> {
 5634        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5635        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5636    }
 5637
 5638    fn do_completion(
 5639        &mut self,
 5640        item_ix: Option<usize>,
 5641        intent: CompletionIntent,
 5642        window: &mut Window,
 5643        cx: &mut Context<Editor>,
 5644    ) -> Option<Task<Result<()>>> {
 5645        use language::ToOffset as _;
 5646
 5647        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5648        else {
 5649            return None;
 5650        };
 5651
 5652        let candidate_id = {
 5653            let entries = completions_menu.entries.borrow();
 5654            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5655            if self.show_edit_predictions_in_menu() {
 5656                self.discard_inline_completion(true, cx);
 5657            }
 5658            mat.candidate_id
 5659        };
 5660
 5661        let completion = completions_menu
 5662            .completions
 5663            .borrow()
 5664            .get(candidate_id)?
 5665            .clone();
 5666        cx.stop_propagation();
 5667
 5668        let buffer_handle = completions_menu.buffer.clone();
 5669
 5670        let CompletionEdit {
 5671            new_text,
 5672            snippet,
 5673            replace_range,
 5674        } = process_completion_for_edit(
 5675            &completion,
 5676            intent,
 5677            &buffer_handle,
 5678            &completions_menu.initial_position.text_anchor,
 5679            cx,
 5680        );
 5681
 5682        let buffer = buffer_handle.read(cx);
 5683        let snapshot = self.buffer.read(cx).snapshot(cx);
 5684        let newest_anchor = self.selections.newest_anchor();
 5685        let replace_range_multibuffer = {
 5686            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5687            let multibuffer_anchor = snapshot
 5688                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5689                .unwrap()
 5690                ..snapshot
 5691                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5692                    .unwrap();
 5693            multibuffer_anchor.start.to_offset(&snapshot)
 5694                ..multibuffer_anchor.end.to_offset(&snapshot)
 5695        };
 5696        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5697            return None;
 5698        }
 5699
 5700        let old_text = buffer
 5701            .text_for_range(replace_range.clone())
 5702            .collect::<String>();
 5703        let lookbehind = newest_anchor
 5704            .start
 5705            .text_anchor
 5706            .to_offset(buffer)
 5707            .saturating_sub(replace_range.start);
 5708        let lookahead = replace_range
 5709            .end
 5710            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5711        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5712        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5713
 5714        let selections = self.selections.all::<usize>(cx);
 5715        let mut ranges = Vec::new();
 5716        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5717
 5718        for selection in &selections {
 5719            let range = if selection.id == newest_anchor.id {
 5720                replace_range_multibuffer.clone()
 5721            } else {
 5722                let mut range = selection.range();
 5723
 5724                // if prefix is present, don't duplicate it
 5725                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5726                    range.start = range.start.saturating_sub(lookbehind);
 5727
 5728                    // if suffix is also present, mimic the newest cursor and replace it
 5729                    if selection.id != newest_anchor.id
 5730                        && snapshot.contains_str_at(range.end, suffix)
 5731                    {
 5732                        range.end += lookahead;
 5733                    }
 5734                }
 5735                range
 5736            };
 5737
 5738            ranges.push(range.clone());
 5739
 5740            if !self.linked_edit_ranges.is_empty() {
 5741                let start_anchor = snapshot.anchor_before(range.start);
 5742                let end_anchor = snapshot.anchor_after(range.end);
 5743                if let Some(ranges) = self
 5744                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5745                {
 5746                    for (buffer, edits) in ranges {
 5747                        linked_edits
 5748                            .entry(buffer.clone())
 5749                            .or_default()
 5750                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5751                    }
 5752                }
 5753            }
 5754        }
 5755
 5756        let common_prefix_len = old_text
 5757            .chars()
 5758            .zip(new_text.chars())
 5759            .take_while(|(a, b)| a == b)
 5760            .map(|(a, _)| a.len_utf8())
 5761            .sum::<usize>();
 5762
 5763        cx.emit(EditorEvent::InputHandled {
 5764            utf16_range_to_replace: None,
 5765            text: new_text[common_prefix_len..].into(),
 5766        });
 5767
 5768        self.transact(window, cx, |this, window, cx| {
 5769            if let Some(mut snippet) = snippet {
 5770                snippet.text = new_text.to_string();
 5771                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5772            } else {
 5773                this.buffer.update(cx, |buffer, cx| {
 5774                    let auto_indent = match completion.insert_text_mode {
 5775                        Some(InsertTextMode::AS_IS) => None,
 5776                        _ => this.autoindent_mode.clone(),
 5777                    };
 5778                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5779                    buffer.edit(edits, auto_indent, cx);
 5780                });
 5781            }
 5782            for (buffer, edits) in linked_edits {
 5783                buffer.update(cx, |buffer, cx| {
 5784                    let snapshot = buffer.snapshot();
 5785                    let edits = edits
 5786                        .into_iter()
 5787                        .map(|(range, text)| {
 5788                            use text::ToPoint as TP;
 5789                            let end_point = TP::to_point(&range.end, &snapshot);
 5790                            let start_point = TP::to_point(&range.start, &snapshot);
 5791                            (start_point..end_point, text)
 5792                        })
 5793                        .sorted_by_key(|(range, _)| range.start);
 5794                    buffer.edit(edits, None, cx);
 5795                })
 5796            }
 5797
 5798            this.refresh_inline_completion(true, false, window, cx);
 5799        });
 5800
 5801        let show_new_completions_on_confirm = completion
 5802            .confirm
 5803            .as_ref()
 5804            .map_or(false, |confirm| confirm(intent, window, cx));
 5805        if show_new_completions_on_confirm {
 5806            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5807        }
 5808
 5809        let provider = self.completion_provider.as_ref()?;
 5810        drop(completion);
 5811        let apply_edits = provider.apply_additional_edits_for_completion(
 5812            buffer_handle,
 5813            completions_menu.completions.clone(),
 5814            candidate_id,
 5815            true,
 5816            cx,
 5817        );
 5818
 5819        let editor_settings = EditorSettings::get_global(cx);
 5820        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5821            // After the code completion is finished, users often want to know what signatures are needed.
 5822            // so we should automatically call signature_help
 5823            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5824        }
 5825
 5826        Some(cx.foreground_executor().spawn(async move {
 5827            apply_edits.await?;
 5828            Ok(())
 5829        }))
 5830    }
 5831
 5832    pub fn toggle_code_actions(
 5833        &mut self,
 5834        action: &ToggleCodeActions,
 5835        window: &mut Window,
 5836        cx: &mut Context<Self>,
 5837    ) {
 5838        let quick_launch = action.quick_launch;
 5839        let mut context_menu = self.context_menu.borrow_mut();
 5840        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5841            if code_actions.deployed_from == action.deployed_from {
 5842                // Toggle if we're selecting the same one
 5843                *context_menu = None;
 5844                cx.notify();
 5845                return;
 5846            } else {
 5847                // Otherwise, clear it and start a new one
 5848                *context_menu = None;
 5849                cx.notify();
 5850            }
 5851        }
 5852        drop(context_menu);
 5853        let snapshot = self.snapshot(window, cx);
 5854        let deployed_from = action.deployed_from.clone();
 5855        let action = action.clone();
 5856        self.completion_tasks.clear();
 5857        self.discard_inline_completion(false, cx);
 5858
 5859        let multibuffer_point = match &action.deployed_from {
 5860            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5861                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5862            }
 5863            _ => self.selections.newest::<Point>(cx).head(),
 5864        };
 5865        let Some((buffer, buffer_row)) = snapshot
 5866            .buffer_snapshot
 5867            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5868            .and_then(|(buffer_snapshot, range)| {
 5869                self.buffer()
 5870                    .read(cx)
 5871                    .buffer(buffer_snapshot.remote_id())
 5872                    .map(|buffer| (buffer, range.start.row))
 5873            })
 5874        else {
 5875            return;
 5876        };
 5877        let buffer_id = buffer.read(cx).remote_id();
 5878        let tasks = self
 5879            .tasks
 5880            .get(&(buffer_id, buffer_row))
 5881            .map(|t| Arc::new(t.to_owned()));
 5882
 5883        if !self.focus_handle.is_focused(window) {
 5884            return;
 5885        }
 5886        let project = self.project.clone();
 5887
 5888        let code_actions_task = match deployed_from {
 5889            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5890            _ => self.code_actions(buffer_row, window, cx),
 5891        };
 5892
 5893        let runnable_task = match deployed_from {
 5894            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5895            _ => {
 5896                let mut task_context_task = Task::ready(None);
 5897                if let Some(tasks) = &tasks {
 5898                    if let Some(project) = project {
 5899                        task_context_task =
 5900                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5901                    }
 5902                }
 5903
 5904                cx.spawn_in(window, {
 5905                    let buffer = buffer.clone();
 5906                    async move |editor, cx| {
 5907                        let task_context = task_context_task.await;
 5908
 5909                        let resolved_tasks =
 5910                            tasks
 5911                                .zip(task_context.clone())
 5912                                .map(|(tasks, task_context)| ResolvedTasks {
 5913                                    templates: tasks.resolve(&task_context).collect(),
 5914                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5915                                        multibuffer_point.row,
 5916                                        tasks.column,
 5917                                    )),
 5918                                });
 5919                        let debug_scenarios = editor
 5920                            .update(cx, |editor, cx| {
 5921                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5922                            })?
 5923                            .await;
 5924                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5925                    }
 5926                })
 5927            }
 5928        };
 5929
 5930        cx.spawn_in(window, async move |editor, cx| {
 5931            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5932            let code_actions = code_actions_task.await;
 5933            let spawn_straight_away = quick_launch
 5934                && resolved_tasks
 5935                    .as_ref()
 5936                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5937                && code_actions
 5938                    .as_ref()
 5939                    .map_or(true, |actions| actions.is_empty())
 5940                && debug_scenarios.is_empty();
 5941
 5942            editor.update_in(cx, |editor, window, cx| {
 5943                crate::hover_popover::hide_hover(editor, cx);
 5944                *editor.context_menu.borrow_mut() =
 5945                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5946                        buffer,
 5947                        actions: CodeActionContents::new(
 5948                            resolved_tasks,
 5949                            code_actions,
 5950                            debug_scenarios,
 5951                            task_context.unwrap_or_default(),
 5952                        ),
 5953                        selected_item: Default::default(),
 5954                        scroll_handle: UniformListScrollHandle::default(),
 5955                        deployed_from,
 5956                    }));
 5957                cx.notify();
 5958                if spawn_straight_away {
 5959                    if let Some(task) = editor.confirm_code_action(
 5960                        &ConfirmCodeAction { item_ix: Some(0) },
 5961                        window,
 5962                        cx,
 5963                    ) {
 5964                        return task;
 5965                    }
 5966                }
 5967
 5968                Task::ready(Ok(()))
 5969            })
 5970        })
 5971        .detach_and_log_err(cx);
 5972    }
 5973
 5974    fn debug_scenarios(
 5975        &mut self,
 5976        resolved_tasks: &Option<ResolvedTasks>,
 5977        buffer: &Entity<Buffer>,
 5978        cx: &mut App,
 5979    ) -> Task<Vec<task::DebugScenario>> {
 5980        maybe!({
 5981            let project = self.project.as_ref()?;
 5982            let dap_store = project.read(cx).dap_store();
 5983            let mut scenarios = vec![];
 5984            let resolved_tasks = resolved_tasks.as_ref()?;
 5985            let buffer = buffer.read(cx);
 5986            let language = buffer.language()?;
 5987            let file = buffer.file();
 5988            let debug_adapter = language_settings(language.name().into(), file, cx)
 5989                .debuggers
 5990                .first()
 5991                .map(SharedString::from)
 5992                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5993
 5994            dap_store.update(cx, |dap_store, cx| {
 5995                for (_, task) in &resolved_tasks.templates {
 5996                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 5997                        task.original_task().clone(),
 5998                        debug_adapter.clone().into(),
 5999                        task.display_label().to_owned().into(),
 6000                        cx,
 6001                    );
 6002                    scenarios.push(maybe_scenario);
 6003                }
 6004            });
 6005            Some(cx.background_spawn(async move {
 6006                let scenarios = futures::future::join_all(scenarios)
 6007                    .await
 6008                    .into_iter()
 6009                    .flatten()
 6010                    .collect::<Vec<_>>();
 6011                scenarios
 6012            }))
 6013        })
 6014        .unwrap_or_else(|| Task::ready(vec![]))
 6015    }
 6016
 6017    fn code_actions(
 6018        &mut self,
 6019        buffer_row: u32,
 6020        window: &mut Window,
 6021        cx: &mut Context<Self>,
 6022    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6023        let mut task = self.code_actions_task.take();
 6024        cx.spawn_in(window, async move |editor, cx| {
 6025            while let Some(prev_task) = task {
 6026                prev_task.await.log_err();
 6027                task = editor
 6028                    .update(cx, |this, _| this.code_actions_task.take())
 6029                    .ok()?;
 6030            }
 6031
 6032            editor
 6033                .update(cx, |editor, cx| {
 6034                    editor
 6035                        .available_code_actions
 6036                        .clone()
 6037                        .and_then(|(location, code_actions)| {
 6038                            let snapshot = location.buffer.read(cx).snapshot();
 6039                            let point_range = location.range.to_point(&snapshot);
 6040                            let point_range = point_range.start.row..=point_range.end.row;
 6041                            if point_range.contains(&buffer_row) {
 6042                                Some(code_actions)
 6043                            } else {
 6044                                None
 6045                            }
 6046                        })
 6047                })
 6048                .ok()
 6049                .flatten()
 6050        })
 6051    }
 6052
 6053    pub fn confirm_code_action(
 6054        &mut self,
 6055        action: &ConfirmCodeAction,
 6056        window: &mut Window,
 6057        cx: &mut Context<Self>,
 6058    ) -> Option<Task<Result<()>>> {
 6059        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6060
 6061        let actions_menu =
 6062            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6063                menu
 6064            } else {
 6065                return None;
 6066            };
 6067
 6068        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6069        let action = actions_menu.actions.get(action_ix)?;
 6070        let title = action.label();
 6071        let buffer = actions_menu.buffer;
 6072        let workspace = self.workspace()?;
 6073
 6074        match action {
 6075            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6076                workspace.update(cx, |workspace, cx| {
 6077                    workspace.schedule_resolved_task(
 6078                        task_source_kind,
 6079                        resolved_task,
 6080                        false,
 6081                        window,
 6082                        cx,
 6083                    );
 6084
 6085                    Some(Task::ready(Ok(())))
 6086                })
 6087            }
 6088            CodeActionsItem::CodeAction {
 6089                excerpt_id,
 6090                action,
 6091                provider,
 6092            } => {
 6093                let apply_code_action =
 6094                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6095                let workspace = workspace.downgrade();
 6096                Some(cx.spawn_in(window, async move |editor, cx| {
 6097                    let project_transaction = apply_code_action.await?;
 6098                    Self::open_project_transaction(
 6099                        &editor,
 6100                        workspace,
 6101                        project_transaction,
 6102                        title,
 6103                        cx,
 6104                    )
 6105                    .await
 6106                }))
 6107            }
 6108            CodeActionsItem::DebugScenario(scenario) => {
 6109                let context = actions_menu.actions.context.clone();
 6110
 6111                workspace.update(cx, |workspace, cx| {
 6112                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6113                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6114                });
 6115                Some(Task::ready(Ok(())))
 6116            }
 6117        }
 6118    }
 6119
 6120    pub async fn open_project_transaction(
 6121        this: &WeakEntity<Editor>,
 6122        workspace: WeakEntity<Workspace>,
 6123        transaction: ProjectTransaction,
 6124        title: String,
 6125        cx: &mut AsyncWindowContext,
 6126    ) -> Result<()> {
 6127        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6128        cx.update(|_, cx| {
 6129            entries.sort_unstable_by_key(|(buffer, _)| {
 6130                buffer.read(cx).file().map(|f| f.path().clone())
 6131            });
 6132        })?;
 6133
 6134        // If the project transaction's edits are all contained within this editor, then
 6135        // avoid opening a new editor to display them.
 6136
 6137        if let Some((buffer, transaction)) = entries.first() {
 6138            if entries.len() == 1 {
 6139                let excerpt = this.update(cx, |editor, cx| {
 6140                    editor
 6141                        .buffer()
 6142                        .read(cx)
 6143                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6144                })?;
 6145                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6146                    if excerpted_buffer == *buffer {
 6147                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6148                            let excerpt_range = excerpt_range.to_offset(buffer);
 6149                            buffer
 6150                                .edited_ranges_for_transaction::<usize>(transaction)
 6151                                .all(|range| {
 6152                                    excerpt_range.start <= range.start
 6153                                        && excerpt_range.end >= range.end
 6154                                })
 6155                        })?;
 6156
 6157                        if all_edits_within_excerpt {
 6158                            return Ok(());
 6159                        }
 6160                    }
 6161                }
 6162            }
 6163        } else {
 6164            return Ok(());
 6165        }
 6166
 6167        let mut ranges_to_highlight = Vec::new();
 6168        let excerpt_buffer = cx.new(|cx| {
 6169            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6170            for (buffer_handle, transaction) in &entries {
 6171                let edited_ranges = buffer_handle
 6172                    .read(cx)
 6173                    .edited_ranges_for_transaction::<Point>(transaction)
 6174                    .collect::<Vec<_>>();
 6175                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6176                    PathKey::for_buffer(buffer_handle, cx),
 6177                    buffer_handle.clone(),
 6178                    edited_ranges,
 6179                    DEFAULT_MULTIBUFFER_CONTEXT,
 6180                    cx,
 6181                );
 6182
 6183                ranges_to_highlight.extend(ranges);
 6184            }
 6185            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6186            multibuffer
 6187        })?;
 6188
 6189        workspace.update_in(cx, |workspace, window, cx| {
 6190            let project = workspace.project().clone();
 6191            let editor =
 6192                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6193            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6194            editor.update(cx, |editor, cx| {
 6195                editor.highlight_background::<Self>(
 6196                    &ranges_to_highlight,
 6197                    |theme| theme.colors().editor_highlighted_line_background,
 6198                    cx,
 6199                );
 6200            });
 6201        })?;
 6202
 6203        Ok(())
 6204    }
 6205
 6206    pub fn clear_code_action_providers(&mut self) {
 6207        self.code_action_providers.clear();
 6208        self.available_code_actions.take();
 6209    }
 6210
 6211    pub fn add_code_action_provider(
 6212        &mut self,
 6213        provider: Rc<dyn CodeActionProvider>,
 6214        window: &mut Window,
 6215        cx: &mut Context<Self>,
 6216    ) {
 6217        if self
 6218            .code_action_providers
 6219            .iter()
 6220            .any(|existing_provider| existing_provider.id() == provider.id())
 6221        {
 6222            return;
 6223        }
 6224
 6225        self.code_action_providers.push(provider);
 6226        self.refresh_code_actions(window, cx);
 6227    }
 6228
 6229    pub fn remove_code_action_provider(
 6230        &mut self,
 6231        id: Arc<str>,
 6232        window: &mut Window,
 6233        cx: &mut Context<Self>,
 6234    ) {
 6235        self.code_action_providers
 6236            .retain(|provider| provider.id() != id);
 6237        self.refresh_code_actions(window, cx);
 6238    }
 6239
 6240    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6241        !self.code_action_providers.is_empty()
 6242            && EditorSettings::get_global(cx).toolbar.code_actions
 6243    }
 6244
 6245    pub fn has_available_code_actions(&self) -> bool {
 6246        self.available_code_actions
 6247            .as_ref()
 6248            .is_some_and(|(_, actions)| !actions.is_empty())
 6249    }
 6250
 6251    fn render_inline_code_actions(
 6252        &self,
 6253        icon_size: ui::IconSize,
 6254        display_row: DisplayRow,
 6255        is_active: bool,
 6256        cx: &mut Context<Self>,
 6257    ) -> AnyElement {
 6258        let show_tooltip = !self.context_menu_visible();
 6259        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6260            .icon_size(icon_size)
 6261            .shape(ui::IconButtonShape::Square)
 6262            .style(ButtonStyle::Transparent)
 6263            .icon_color(ui::Color::Hidden)
 6264            .toggle_state(is_active)
 6265            .when(show_tooltip, |this| {
 6266                this.tooltip({
 6267                    let focus_handle = self.focus_handle.clone();
 6268                    move |window, cx| {
 6269                        Tooltip::for_action_in(
 6270                            "Toggle Code Actions",
 6271                            &ToggleCodeActions {
 6272                                deployed_from: None,
 6273                                quick_launch: false,
 6274                            },
 6275                            &focus_handle,
 6276                            window,
 6277                            cx,
 6278                        )
 6279                    }
 6280                })
 6281            })
 6282            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6283                window.focus(&editor.focus_handle(cx));
 6284                editor.toggle_code_actions(
 6285                    &crate::actions::ToggleCodeActions {
 6286                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6287                            display_row,
 6288                        )),
 6289                        quick_launch: false,
 6290                    },
 6291                    window,
 6292                    cx,
 6293                );
 6294            }))
 6295            .into_any_element()
 6296    }
 6297
 6298    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6299        &self.context_menu
 6300    }
 6301
 6302    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6303        let newest_selection = self.selections.newest_anchor().clone();
 6304        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6305        let buffer = self.buffer.read(cx);
 6306        if newest_selection.head().diff_base_anchor.is_some() {
 6307            return None;
 6308        }
 6309        let (start_buffer, start) =
 6310            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6311        let (end_buffer, end) =
 6312            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6313        if start_buffer != end_buffer {
 6314            return None;
 6315        }
 6316
 6317        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6318            cx.background_executor()
 6319                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6320                .await;
 6321
 6322            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6323                let providers = this.code_action_providers.clone();
 6324                let tasks = this
 6325                    .code_action_providers
 6326                    .iter()
 6327                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6328                    .collect::<Vec<_>>();
 6329                (providers, tasks)
 6330            })?;
 6331
 6332            let mut actions = Vec::new();
 6333            for (provider, provider_actions) in
 6334                providers.into_iter().zip(future::join_all(tasks).await)
 6335            {
 6336                if let Some(provider_actions) = provider_actions.log_err() {
 6337                    actions.extend(provider_actions.into_iter().map(|action| {
 6338                        AvailableCodeAction {
 6339                            excerpt_id: newest_selection.start.excerpt_id,
 6340                            action,
 6341                            provider: provider.clone(),
 6342                        }
 6343                    }));
 6344                }
 6345            }
 6346
 6347            this.update(cx, |this, cx| {
 6348                this.available_code_actions = if actions.is_empty() {
 6349                    None
 6350                } else {
 6351                    Some((
 6352                        Location {
 6353                            buffer: start_buffer,
 6354                            range: start..end,
 6355                        },
 6356                        actions.into(),
 6357                    ))
 6358                };
 6359                cx.notify();
 6360            })
 6361        }));
 6362        None
 6363    }
 6364
 6365    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6366        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6367            self.show_git_blame_inline = false;
 6368
 6369            self.show_git_blame_inline_delay_task =
 6370                Some(cx.spawn_in(window, async move |this, cx| {
 6371                    cx.background_executor().timer(delay).await;
 6372
 6373                    this.update(cx, |this, cx| {
 6374                        this.show_git_blame_inline = true;
 6375                        cx.notify();
 6376                    })
 6377                    .log_err();
 6378                }));
 6379        }
 6380    }
 6381
 6382    fn show_blame_popover(
 6383        &mut self,
 6384        blame_entry: &BlameEntry,
 6385        position: gpui::Point<Pixels>,
 6386        cx: &mut Context<Self>,
 6387    ) {
 6388        if let Some(state) = &mut self.inline_blame_popover {
 6389            state.hide_task.take();
 6390        } else {
 6391            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6392            let blame_entry = blame_entry.clone();
 6393            let show_task = cx.spawn(async move |editor, cx| {
 6394                cx.background_executor()
 6395                    .timer(std::time::Duration::from_millis(delay))
 6396                    .await;
 6397                editor
 6398                    .update(cx, |editor, cx| {
 6399                        editor.inline_blame_popover_show_task.take();
 6400                        let Some(blame) = editor.blame.as_ref() else {
 6401                            return;
 6402                        };
 6403                        let blame = blame.read(cx);
 6404                        let details = blame.details_for_entry(&blame_entry);
 6405                        let markdown = cx.new(|cx| {
 6406                            Markdown::new(
 6407                                details
 6408                                    .as_ref()
 6409                                    .map(|message| message.message.clone())
 6410                                    .unwrap_or_default(),
 6411                                None,
 6412                                None,
 6413                                cx,
 6414                            )
 6415                        });
 6416                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6417                            position,
 6418                            hide_task: None,
 6419                            popover_bounds: None,
 6420                            popover_state: InlineBlamePopoverState {
 6421                                scroll_handle: ScrollHandle::new(),
 6422                                commit_message: details,
 6423                                markdown,
 6424                            },
 6425                        });
 6426                        cx.notify();
 6427                    })
 6428                    .ok();
 6429            });
 6430            self.inline_blame_popover_show_task = Some(show_task);
 6431        }
 6432    }
 6433
 6434    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6435        self.inline_blame_popover_show_task.take();
 6436        if let Some(state) = &mut self.inline_blame_popover {
 6437            let hide_task = cx.spawn(async move |editor, cx| {
 6438                cx.background_executor()
 6439                    .timer(std::time::Duration::from_millis(100))
 6440                    .await;
 6441                editor
 6442                    .update(cx, |editor, cx| {
 6443                        editor.inline_blame_popover.take();
 6444                        cx.notify();
 6445                    })
 6446                    .ok();
 6447            });
 6448            state.hide_task = Some(hide_task);
 6449        }
 6450    }
 6451
 6452    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6453        if self.pending_rename.is_some() {
 6454            return None;
 6455        }
 6456
 6457        let provider = self.semantics_provider.clone()?;
 6458        let buffer = self.buffer.read(cx);
 6459        let newest_selection = self.selections.newest_anchor().clone();
 6460        let cursor_position = newest_selection.head();
 6461        let (cursor_buffer, cursor_buffer_position) =
 6462            buffer.text_anchor_for_position(cursor_position, cx)?;
 6463        let (tail_buffer, tail_buffer_position) =
 6464            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6465        if cursor_buffer != tail_buffer {
 6466            return None;
 6467        }
 6468
 6469        let snapshot = cursor_buffer.read(cx).snapshot();
 6470        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6471        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6472        if start_word_range != end_word_range {
 6473            self.document_highlights_task.take();
 6474            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6475            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6476            return None;
 6477        }
 6478
 6479        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6480        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6481            cx.background_executor()
 6482                .timer(Duration::from_millis(debounce))
 6483                .await;
 6484
 6485            let highlights = if let Some(highlights) = cx
 6486                .update(|cx| {
 6487                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6488                })
 6489                .ok()
 6490                .flatten()
 6491            {
 6492                highlights.await.log_err()
 6493            } else {
 6494                None
 6495            };
 6496
 6497            if let Some(highlights) = highlights {
 6498                this.update(cx, |this, cx| {
 6499                    if this.pending_rename.is_some() {
 6500                        return;
 6501                    }
 6502
 6503                    let buffer_id = cursor_position.buffer_id;
 6504                    let buffer = this.buffer.read(cx);
 6505                    if !buffer
 6506                        .text_anchor_for_position(cursor_position, cx)
 6507                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6508                    {
 6509                        return;
 6510                    }
 6511
 6512                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6513                    let mut write_ranges = Vec::new();
 6514                    let mut read_ranges = Vec::new();
 6515                    for highlight in highlights {
 6516                        for (excerpt_id, excerpt_range) in
 6517                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6518                        {
 6519                            let start = highlight
 6520                                .range
 6521                                .start
 6522                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6523                            let end = highlight
 6524                                .range
 6525                                .end
 6526                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6527                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6528                                continue;
 6529                            }
 6530
 6531                            let range = Anchor {
 6532                                buffer_id,
 6533                                excerpt_id,
 6534                                text_anchor: start,
 6535                                diff_base_anchor: None,
 6536                            }..Anchor {
 6537                                buffer_id,
 6538                                excerpt_id,
 6539                                text_anchor: end,
 6540                                diff_base_anchor: None,
 6541                            };
 6542                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6543                                write_ranges.push(range);
 6544                            } else {
 6545                                read_ranges.push(range);
 6546                            }
 6547                        }
 6548                    }
 6549
 6550                    this.highlight_background::<DocumentHighlightRead>(
 6551                        &read_ranges,
 6552                        |theme| theme.colors().editor_document_highlight_read_background,
 6553                        cx,
 6554                    );
 6555                    this.highlight_background::<DocumentHighlightWrite>(
 6556                        &write_ranges,
 6557                        |theme| theme.colors().editor_document_highlight_write_background,
 6558                        cx,
 6559                    );
 6560                    cx.notify();
 6561                })
 6562                .log_err();
 6563            }
 6564        }));
 6565        None
 6566    }
 6567
 6568    fn prepare_highlight_query_from_selection(
 6569        &mut self,
 6570        cx: &mut Context<Editor>,
 6571    ) -> Option<(String, Range<Anchor>)> {
 6572        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6573            return None;
 6574        }
 6575        if !EditorSettings::get_global(cx).selection_highlight {
 6576            return None;
 6577        }
 6578        if self.selections.count() != 1 || self.selections.line_mode {
 6579            return None;
 6580        }
 6581        let selection = self.selections.newest::<Point>(cx);
 6582        if selection.is_empty() || selection.start.row != selection.end.row {
 6583            return None;
 6584        }
 6585        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6586        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6587        let query = multi_buffer_snapshot
 6588            .text_for_range(selection_anchor_range.clone())
 6589            .collect::<String>();
 6590        if query.trim().is_empty() {
 6591            return None;
 6592        }
 6593        Some((query, selection_anchor_range))
 6594    }
 6595
 6596    fn update_selection_occurrence_highlights(
 6597        &mut self,
 6598        query_text: String,
 6599        query_range: Range<Anchor>,
 6600        multi_buffer_range_to_query: Range<Point>,
 6601        use_debounce: bool,
 6602        window: &mut Window,
 6603        cx: &mut Context<Editor>,
 6604    ) -> Task<()> {
 6605        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6606        cx.spawn_in(window, async move |editor, cx| {
 6607            if use_debounce {
 6608                cx.background_executor()
 6609                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6610                    .await;
 6611            }
 6612            let match_task = cx.background_spawn(async move {
 6613                let buffer_ranges = multi_buffer_snapshot
 6614                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6615                    .into_iter()
 6616                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6617                let mut match_ranges = Vec::new();
 6618                let Ok(regex) = project::search::SearchQuery::text(
 6619                    query_text.clone(),
 6620                    false,
 6621                    false,
 6622                    false,
 6623                    Default::default(),
 6624                    Default::default(),
 6625                    false,
 6626                    None,
 6627                ) else {
 6628                    return Vec::default();
 6629                };
 6630                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6631                    match_ranges.extend(
 6632                        regex
 6633                            .search(&buffer_snapshot, Some(search_range.clone()))
 6634                            .await
 6635                            .into_iter()
 6636                            .filter_map(|match_range| {
 6637                                let match_start = buffer_snapshot
 6638                                    .anchor_after(search_range.start + match_range.start);
 6639                                let match_end = buffer_snapshot
 6640                                    .anchor_before(search_range.start + match_range.end);
 6641                                let match_anchor_range = Anchor::range_in_buffer(
 6642                                    excerpt_id,
 6643                                    buffer_snapshot.remote_id(),
 6644                                    match_start..match_end,
 6645                                );
 6646                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6647                            }),
 6648                    );
 6649                }
 6650                match_ranges
 6651            });
 6652            let match_ranges = match_task.await;
 6653            editor
 6654                .update_in(cx, |editor, _, cx| {
 6655                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6656                    if !match_ranges.is_empty() {
 6657                        editor.highlight_background::<SelectedTextHighlight>(
 6658                            &match_ranges,
 6659                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6660                            cx,
 6661                        )
 6662                    }
 6663                })
 6664                .log_err();
 6665        })
 6666    }
 6667
 6668    fn refresh_selected_text_highlights(
 6669        &mut self,
 6670        on_buffer_edit: bool,
 6671        window: &mut Window,
 6672        cx: &mut Context<Editor>,
 6673    ) {
 6674        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6675        else {
 6676            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6677            self.quick_selection_highlight_task.take();
 6678            self.debounced_selection_highlight_task.take();
 6679            return;
 6680        };
 6681        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6682        if on_buffer_edit
 6683            || self
 6684                .quick_selection_highlight_task
 6685                .as_ref()
 6686                .map_or(true, |(prev_anchor_range, _)| {
 6687                    prev_anchor_range != &query_range
 6688                })
 6689        {
 6690            let multi_buffer_visible_start = self
 6691                .scroll_manager
 6692                .anchor()
 6693                .anchor
 6694                .to_point(&multi_buffer_snapshot);
 6695            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6696                multi_buffer_visible_start
 6697                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6698                Bias::Left,
 6699            );
 6700            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6701            self.quick_selection_highlight_task = Some((
 6702                query_range.clone(),
 6703                self.update_selection_occurrence_highlights(
 6704                    query_text.clone(),
 6705                    query_range.clone(),
 6706                    multi_buffer_visible_range,
 6707                    false,
 6708                    window,
 6709                    cx,
 6710                ),
 6711            ));
 6712        }
 6713        if on_buffer_edit
 6714            || self
 6715                .debounced_selection_highlight_task
 6716                .as_ref()
 6717                .map_or(true, |(prev_anchor_range, _)| {
 6718                    prev_anchor_range != &query_range
 6719                })
 6720        {
 6721            let multi_buffer_start = multi_buffer_snapshot
 6722                .anchor_before(0)
 6723                .to_point(&multi_buffer_snapshot);
 6724            let multi_buffer_end = multi_buffer_snapshot
 6725                .anchor_after(multi_buffer_snapshot.len())
 6726                .to_point(&multi_buffer_snapshot);
 6727            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6728            self.debounced_selection_highlight_task = Some((
 6729                query_range.clone(),
 6730                self.update_selection_occurrence_highlights(
 6731                    query_text,
 6732                    query_range,
 6733                    multi_buffer_full_range,
 6734                    true,
 6735                    window,
 6736                    cx,
 6737                ),
 6738            ));
 6739        }
 6740    }
 6741
 6742    pub fn refresh_inline_completion(
 6743        &mut self,
 6744        debounce: bool,
 6745        user_requested: bool,
 6746        window: &mut Window,
 6747        cx: &mut Context<Self>,
 6748    ) -> Option<()> {
 6749        let provider = self.edit_prediction_provider()?;
 6750        let cursor = self.selections.newest_anchor().head();
 6751        let (buffer, cursor_buffer_position) =
 6752            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6753
 6754        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6755            self.discard_inline_completion(false, cx);
 6756            return None;
 6757        }
 6758
 6759        if !user_requested
 6760            && (!self.should_show_edit_predictions()
 6761                || !self.is_focused(window)
 6762                || buffer.read(cx).is_empty())
 6763        {
 6764            self.discard_inline_completion(false, cx);
 6765            return None;
 6766        }
 6767
 6768        self.update_visible_inline_completion(window, cx);
 6769        provider.refresh(
 6770            self.project.clone(),
 6771            buffer,
 6772            cursor_buffer_position,
 6773            debounce,
 6774            cx,
 6775        );
 6776        Some(())
 6777    }
 6778
 6779    fn show_edit_predictions_in_menu(&self) -> bool {
 6780        match self.edit_prediction_settings {
 6781            EditPredictionSettings::Disabled => false,
 6782            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6783        }
 6784    }
 6785
 6786    pub fn edit_predictions_enabled(&self) -> bool {
 6787        match self.edit_prediction_settings {
 6788            EditPredictionSettings::Disabled => false,
 6789            EditPredictionSettings::Enabled { .. } => true,
 6790        }
 6791    }
 6792
 6793    fn edit_prediction_requires_modifier(&self) -> bool {
 6794        match self.edit_prediction_settings {
 6795            EditPredictionSettings::Disabled => false,
 6796            EditPredictionSettings::Enabled {
 6797                preview_requires_modifier,
 6798                ..
 6799            } => preview_requires_modifier,
 6800        }
 6801    }
 6802
 6803    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6804        if self.edit_prediction_provider.is_none() {
 6805            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6806        } else {
 6807            let selection = self.selections.newest_anchor();
 6808            let cursor = selection.head();
 6809
 6810            if let Some((buffer, cursor_buffer_position)) =
 6811                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6812            {
 6813                self.edit_prediction_settings =
 6814                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6815            }
 6816        }
 6817    }
 6818
 6819    fn edit_prediction_settings_at_position(
 6820        &self,
 6821        buffer: &Entity<Buffer>,
 6822        buffer_position: language::Anchor,
 6823        cx: &App,
 6824    ) -> EditPredictionSettings {
 6825        if !self.mode.is_full()
 6826            || !self.show_inline_completions_override.unwrap_or(true)
 6827            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6828        {
 6829            return EditPredictionSettings::Disabled;
 6830        }
 6831
 6832        let buffer = buffer.read(cx);
 6833
 6834        let file = buffer.file();
 6835
 6836        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6837            return EditPredictionSettings::Disabled;
 6838        };
 6839
 6840        let by_provider = matches!(
 6841            self.menu_inline_completions_policy,
 6842            MenuInlineCompletionsPolicy::ByProvider
 6843        );
 6844
 6845        let show_in_menu = by_provider
 6846            && self
 6847                .edit_prediction_provider
 6848                .as_ref()
 6849                .map_or(false, |provider| {
 6850                    provider.provider.show_completions_in_menu()
 6851                });
 6852
 6853        let preview_requires_modifier =
 6854            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6855
 6856        EditPredictionSettings::Enabled {
 6857            show_in_menu,
 6858            preview_requires_modifier,
 6859        }
 6860    }
 6861
 6862    fn should_show_edit_predictions(&self) -> bool {
 6863        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6864    }
 6865
 6866    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6867        matches!(
 6868            self.edit_prediction_preview,
 6869            EditPredictionPreview::Active { .. }
 6870        )
 6871    }
 6872
 6873    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6874        let cursor = self.selections.newest_anchor().head();
 6875        if let Some((buffer, cursor_position)) =
 6876            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6877        {
 6878            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6879        } else {
 6880            false
 6881        }
 6882    }
 6883
 6884    pub fn supports_minimap(&self, cx: &App) -> bool {
 6885        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6886    }
 6887
 6888    fn edit_predictions_enabled_in_buffer(
 6889        &self,
 6890        buffer: &Entity<Buffer>,
 6891        buffer_position: language::Anchor,
 6892        cx: &App,
 6893    ) -> bool {
 6894        maybe!({
 6895            if self.read_only(cx) {
 6896                return Some(false);
 6897            }
 6898            let provider = self.edit_prediction_provider()?;
 6899            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6900                return Some(false);
 6901            }
 6902            let buffer = buffer.read(cx);
 6903            let Some(file) = buffer.file() else {
 6904                return Some(true);
 6905            };
 6906            let settings = all_language_settings(Some(file), cx);
 6907            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6908        })
 6909        .unwrap_or(false)
 6910    }
 6911
 6912    fn cycle_inline_completion(
 6913        &mut self,
 6914        direction: Direction,
 6915        window: &mut Window,
 6916        cx: &mut Context<Self>,
 6917    ) -> Option<()> {
 6918        let provider = self.edit_prediction_provider()?;
 6919        let cursor = self.selections.newest_anchor().head();
 6920        let (buffer, cursor_buffer_position) =
 6921            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6922        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6923            return None;
 6924        }
 6925
 6926        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6927        self.update_visible_inline_completion(window, cx);
 6928
 6929        Some(())
 6930    }
 6931
 6932    pub fn show_inline_completion(
 6933        &mut self,
 6934        _: &ShowEditPrediction,
 6935        window: &mut Window,
 6936        cx: &mut Context<Self>,
 6937    ) {
 6938        if !self.has_active_inline_completion() {
 6939            self.refresh_inline_completion(false, true, window, cx);
 6940            return;
 6941        }
 6942
 6943        self.update_visible_inline_completion(window, cx);
 6944    }
 6945
 6946    pub fn display_cursor_names(
 6947        &mut self,
 6948        _: &DisplayCursorNames,
 6949        window: &mut Window,
 6950        cx: &mut Context<Self>,
 6951    ) {
 6952        self.show_cursor_names(window, cx);
 6953    }
 6954
 6955    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6956        self.show_cursor_names = true;
 6957        cx.notify();
 6958        cx.spawn_in(window, async move |this, cx| {
 6959            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6960            this.update(cx, |this, cx| {
 6961                this.show_cursor_names = false;
 6962                cx.notify()
 6963            })
 6964            .ok()
 6965        })
 6966        .detach();
 6967    }
 6968
 6969    pub fn next_edit_prediction(
 6970        &mut self,
 6971        _: &NextEditPrediction,
 6972        window: &mut Window,
 6973        cx: &mut Context<Self>,
 6974    ) {
 6975        if self.has_active_inline_completion() {
 6976            self.cycle_inline_completion(Direction::Next, window, cx);
 6977        } else {
 6978            let is_copilot_disabled = self
 6979                .refresh_inline_completion(false, true, window, cx)
 6980                .is_none();
 6981            if is_copilot_disabled {
 6982                cx.propagate();
 6983            }
 6984        }
 6985    }
 6986
 6987    pub fn previous_edit_prediction(
 6988        &mut self,
 6989        _: &PreviousEditPrediction,
 6990        window: &mut Window,
 6991        cx: &mut Context<Self>,
 6992    ) {
 6993        if self.has_active_inline_completion() {
 6994            self.cycle_inline_completion(Direction::Prev, window, cx);
 6995        } else {
 6996            let is_copilot_disabled = self
 6997                .refresh_inline_completion(false, true, window, cx)
 6998                .is_none();
 6999            if is_copilot_disabled {
 7000                cx.propagate();
 7001            }
 7002        }
 7003    }
 7004
 7005    pub fn accept_edit_prediction(
 7006        &mut self,
 7007        _: &AcceptEditPrediction,
 7008        window: &mut Window,
 7009        cx: &mut Context<Self>,
 7010    ) {
 7011        if self.show_edit_predictions_in_menu() {
 7012            self.hide_context_menu(window, cx);
 7013        }
 7014
 7015        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7016            return;
 7017        };
 7018
 7019        self.report_inline_completion_event(
 7020            active_inline_completion.completion_id.clone(),
 7021            true,
 7022            cx,
 7023        );
 7024
 7025        match &active_inline_completion.completion {
 7026            InlineCompletion::Move { target, .. } => {
 7027                let target = *target;
 7028
 7029                if let Some(position_map) = &self.last_position_map {
 7030                    if position_map
 7031                        .visible_row_range
 7032                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7033                        || !self.edit_prediction_requires_modifier()
 7034                    {
 7035                        self.unfold_ranges(&[target..target], true, false, cx);
 7036                        // Note that this is also done in vim's handler of the Tab action.
 7037                        self.change_selections(
 7038                            Some(Autoscroll::newest()),
 7039                            window,
 7040                            cx,
 7041                            |selections| {
 7042                                selections.select_anchor_ranges([target..target]);
 7043                            },
 7044                        );
 7045                        self.clear_row_highlights::<EditPredictionPreview>();
 7046
 7047                        self.edit_prediction_preview
 7048                            .set_previous_scroll_position(None);
 7049                    } else {
 7050                        self.edit_prediction_preview
 7051                            .set_previous_scroll_position(Some(
 7052                                position_map.snapshot.scroll_anchor,
 7053                            ));
 7054
 7055                        self.highlight_rows::<EditPredictionPreview>(
 7056                            target..target,
 7057                            cx.theme().colors().editor_highlighted_line_background,
 7058                            RowHighlightOptions {
 7059                                autoscroll: true,
 7060                                ..Default::default()
 7061                            },
 7062                            cx,
 7063                        );
 7064                        self.request_autoscroll(Autoscroll::fit(), cx);
 7065                    }
 7066                }
 7067            }
 7068            InlineCompletion::Edit { edits, .. } => {
 7069                if let Some(provider) = self.edit_prediction_provider() {
 7070                    provider.accept(cx);
 7071                }
 7072
 7073                // Store the transaction ID and selections before applying the edit
 7074                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7075
 7076                let snapshot = self.buffer.read(cx).snapshot(cx);
 7077                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7078
 7079                self.buffer.update(cx, |buffer, cx| {
 7080                    buffer.edit(edits.iter().cloned(), None, cx)
 7081                });
 7082
 7083                self.change_selections(None, window, cx, |s| {
 7084                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7085                });
 7086
 7087                let selections = self.selections.disjoint_anchors();
 7088                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7089                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7090                    if has_new_transaction {
 7091                        self.selection_history
 7092                            .insert_transaction(transaction_id_now, selections);
 7093                    }
 7094                }
 7095
 7096                self.update_visible_inline_completion(window, cx);
 7097                if self.active_inline_completion.is_none() {
 7098                    self.refresh_inline_completion(true, true, window, cx);
 7099                }
 7100
 7101                cx.notify();
 7102            }
 7103        }
 7104
 7105        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7106    }
 7107
 7108    pub fn accept_partial_inline_completion(
 7109        &mut self,
 7110        _: &AcceptPartialEditPrediction,
 7111        window: &mut Window,
 7112        cx: &mut Context<Self>,
 7113    ) {
 7114        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7115            return;
 7116        };
 7117        if self.selections.count() != 1 {
 7118            return;
 7119        }
 7120
 7121        self.report_inline_completion_event(
 7122            active_inline_completion.completion_id.clone(),
 7123            true,
 7124            cx,
 7125        );
 7126
 7127        match &active_inline_completion.completion {
 7128            InlineCompletion::Move { target, .. } => {
 7129                let target = *target;
 7130                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7131                    selections.select_anchor_ranges([target..target]);
 7132                });
 7133            }
 7134            InlineCompletion::Edit { edits, .. } => {
 7135                // Find an insertion that starts at the cursor position.
 7136                let snapshot = self.buffer.read(cx).snapshot(cx);
 7137                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7138                let insertion = edits.iter().find_map(|(range, text)| {
 7139                    let range = range.to_offset(&snapshot);
 7140                    if range.is_empty() && range.start == cursor_offset {
 7141                        Some(text)
 7142                    } else {
 7143                        None
 7144                    }
 7145                });
 7146
 7147                if let Some(text) = insertion {
 7148                    let mut partial_completion = text
 7149                        .chars()
 7150                        .by_ref()
 7151                        .take_while(|c| c.is_alphabetic())
 7152                        .collect::<String>();
 7153                    if partial_completion.is_empty() {
 7154                        partial_completion = text
 7155                            .chars()
 7156                            .by_ref()
 7157                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7158                            .collect::<String>();
 7159                    }
 7160
 7161                    cx.emit(EditorEvent::InputHandled {
 7162                        utf16_range_to_replace: None,
 7163                        text: partial_completion.clone().into(),
 7164                    });
 7165
 7166                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7167
 7168                    self.refresh_inline_completion(true, true, window, cx);
 7169                    cx.notify();
 7170                } else {
 7171                    self.accept_edit_prediction(&Default::default(), window, cx);
 7172                }
 7173            }
 7174        }
 7175    }
 7176
 7177    fn discard_inline_completion(
 7178        &mut self,
 7179        should_report_inline_completion_event: bool,
 7180        cx: &mut Context<Self>,
 7181    ) -> bool {
 7182        if should_report_inline_completion_event {
 7183            let completion_id = self
 7184                .active_inline_completion
 7185                .as_ref()
 7186                .and_then(|active_completion| active_completion.completion_id.clone());
 7187
 7188            self.report_inline_completion_event(completion_id, false, cx);
 7189        }
 7190
 7191        if let Some(provider) = self.edit_prediction_provider() {
 7192            provider.discard(cx);
 7193        }
 7194
 7195        self.take_active_inline_completion(cx)
 7196    }
 7197
 7198    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7199        let Some(provider) = self.edit_prediction_provider() else {
 7200            return;
 7201        };
 7202
 7203        let Some((_, buffer, _)) = self
 7204            .buffer
 7205            .read(cx)
 7206            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7207        else {
 7208            return;
 7209        };
 7210
 7211        let extension = buffer
 7212            .read(cx)
 7213            .file()
 7214            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7215
 7216        let event_type = match accepted {
 7217            true => "Edit Prediction Accepted",
 7218            false => "Edit Prediction Discarded",
 7219        };
 7220        telemetry::event!(
 7221            event_type,
 7222            provider = provider.name(),
 7223            prediction_id = id,
 7224            suggestion_accepted = accepted,
 7225            file_extension = extension,
 7226        );
 7227    }
 7228
 7229    pub fn has_active_inline_completion(&self) -> bool {
 7230        self.active_inline_completion.is_some()
 7231    }
 7232
 7233    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7234        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7235            return false;
 7236        };
 7237
 7238        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7239        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7240        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7241        true
 7242    }
 7243
 7244    /// Returns true when we're displaying the edit prediction popover below the cursor
 7245    /// like we are not previewing and the LSP autocomplete menu is visible
 7246    /// or we are in `when_holding_modifier` mode.
 7247    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7248        if self.edit_prediction_preview_is_active()
 7249            || !self.show_edit_predictions_in_menu()
 7250            || !self.edit_predictions_enabled()
 7251        {
 7252            return false;
 7253        }
 7254
 7255        if self.has_visible_completions_menu() {
 7256            return true;
 7257        }
 7258
 7259        has_completion && self.edit_prediction_requires_modifier()
 7260    }
 7261
 7262    fn handle_modifiers_changed(
 7263        &mut self,
 7264        modifiers: Modifiers,
 7265        position_map: &PositionMap,
 7266        window: &mut Window,
 7267        cx: &mut Context<Self>,
 7268    ) {
 7269        if self.show_edit_predictions_in_menu() {
 7270            self.update_edit_prediction_preview(&modifiers, window, cx);
 7271        }
 7272
 7273        self.update_selection_mode(&modifiers, position_map, window, cx);
 7274
 7275        let mouse_position = window.mouse_position();
 7276        if !position_map.text_hitbox.is_hovered(window) {
 7277            return;
 7278        }
 7279
 7280        self.update_hovered_link(
 7281            position_map.point_for_position(mouse_position),
 7282            &position_map.snapshot,
 7283            modifiers,
 7284            window,
 7285            cx,
 7286        )
 7287    }
 7288
 7289    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7290        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7291        if invert {
 7292            match multi_cursor_setting {
 7293                MultiCursorModifier::Alt => modifiers.alt,
 7294                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7295            }
 7296        } else {
 7297            match multi_cursor_setting {
 7298                MultiCursorModifier::Alt => modifiers.secondary(),
 7299                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7300            }
 7301        }
 7302    }
 7303
 7304    fn columnar_selection_mode(
 7305        modifiers: &Modifiers,
 7306        cx: &mut Context<Self>,
 7307    ) -> Option<ColumnarMode> {
 7308        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7309            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7310                Some(ColumnarMode::FromMouse)
 7311            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7312                Some(ColumnarMode::FromSelection)
 7313            } else {
 7314                None
 7315            }
 7316        } else {
 7317            None
 7318        }
 7319    }
 7320
 7321    fn update_selection_mode(
 7322        &mut self,
 7323        modifiers: &Modifiers,
 7324        position_map: &PositionMap,
 7325        window: &mut Window,
 7326        cx: &mut Context<Self>,
 7327    ) {
 7328        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7329            return;
 7330        };
 7331        if self.selections.pending.is_none() {
 7332            return;
 7333        }
 7334
 7335        let mouse_position = window.mouse_position();
 7336        let point_for_position = position_map.point_for_position(mouse_position);
 7337        let position = point_for_position.previous_valid;
 7338
 7339        self.select(
 7340            SelectPhase::BeginColumnar {
 7341                position,
 7342                reset: false,
 7343                mode,
 7344                goal_column: point_for_position.exact_unclipped.column(),
 7345            },
 7346            window,
 7347            cx,
 7348        );
 7349    }
 7350
 7351    fn update_edit_prediction_preview(
 7352        &mut self,
 7353        modifiers: &Modifiers,
 7354        window: &mut Window,
 7355        cx: &mut Context<Self>,
 7356    ) {
 7357        let mut modifiers_held = false;
 7358        if let Some(accept_keystroke) = self
 7359            .accept_edit_prediction_keybind(false, window, cx)
 7360            .keystroke()
 7361        {
 7362            modifiers_held = modifiers_held
 7363                || (&accept_keystroke.modifiers == modifiers
 7364                    && accept_keystroke.modifiers.modified());
 7365        };
 7366        if let Some(accept_partial_keystroke) = self
 7367            .accept_edit_prediction_keybind(true, window, cx)
 7368            .keystroke()
 7369        {
 7370            modifiers_held = modifiers_held
 7371                || (&accept_partial_keystroke.modifiers == modifiers
 7372                    && accept_partial_keystroke.modifiers.modified());
 7373        }
 7374
 7375        if modifiers_held {
 7376            if matches!(
 7377                self.edit_prediction_preview,
 7378                EditPredictionPreview::Inactive { .. }
 7379            ) {
 7380                self.edit_prediction_preview = EditPredictionPreview::Active {
 7381                    previous_scroll_position: None,
 7382                    since: Instant::now(),
 7383                };
 7384
 7385                self.update_visible_inline_completion(window, cx);
 7386                cx.notify();
 7387            }
 7388        } else if let EditPredictionPreview::Active {
 7389            previous_scroll_position,
 7390            since,
 7391        } = self.edit_prediction_preview
 7392        {
 7393            if let (Some(previous_scroll_position), Some(position_map)) =
 7394                (previous_scroll_position, self.last_position_map.as_ref())
 7395            {
 7396                self.set_scroll_position(
 7397                    previous_scroll_position
 7398                        .scroll_position(&position_map.snapshot.display_snapshot),
 7399                    window,
 7400                    cx,
 7401                );
 7402            }
 7403
 7404            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7405                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7406            };
 7407            self.clear_row_highlights::<EditPredictionPreview>();
 7408            self.update_visible_inline_completion(window, cx);
 7409            cx.notify();
 7410        }
 7411    }
 7412
 7413    fn update_visible_inline_completion(
 7414        &mut self,
 7415        _window: &mut Window,
 7416        cx: &mut Context<Self>,
 7417    ) -> Option<()> {
 7418        let selection = self.selections.newest_anchor();
 7419        let cursor = selection.head();
 7420        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7421        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7422        let excerpt_id = cursor.excerpt_id;
 7423
 7424        let show_in_menu = self.show_edit_predictions_in_menu();
 7425        let completions_menu_has_precedence = !show_in_menu
 7426            && (self.context_menu.borrow().is_some()
 7427                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7428
 7429        if completions_menu_has_precedence
 7430            || !offset_selection.is_empty()
 7431            || self
 7432                .active_inline_completion
 7433                .as_ref()
 7434                .map_or(false, |completion| {
 7435                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7436                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7437                    !invalidation_range.contains(&offset_selection.head())
 7438                })
 7439        {
 7440            self.discard_inline_completion(false, cx);
 7441            return None;
 7442        }
 7443
 7444        self.take_active_inline_completion(cx);
 7445        let Some(provider) = self.edit_prediction_provider() else {
 7446            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7447            return None;
 7448        };
 7449
 7450        let (buffer, cursor_buffer_position) =
 7451            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7452
 7453        self.edit_prediction_settings =
 7454            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7455
 7456        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7457
 7458        if self.edit_prediction_indent_conflict {
 7459            let cursor_point = cursor.to_point(&multibuffer);
 7460
 7461            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7462
 7463            if let Some((_, indent)) = indents.iter().next() {
 7464                if indent.len == cursor_point.column {
 7465                    self.edit_prediction_indent_conflict = false;
 7466                }
 7467            }
 7468        }
 7469
 7470        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7471        let edits = inline_completion
 7472            .edits
 7473            .into_iter()
 7474            .flat_map(|(range, new_text)| {
 7475                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7476                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7477                Some((start..end, new_text))
 7478            })
 7479            .collect::<Vec<_>>();
 7480        if edits.is_empty() {
 7481            return None;
 7482        }
 7483
 7484        let first_edit_start = edits.first().unwrap().0.start;
 7485        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7486        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7487
 7488        let last_edit_end = edits.last().unwrap().0.end;
 7489        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7490        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7491
 7492        let cursor_row = cursor.to_point(&multibuffer).row;
 7493
 7494        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7495
 7496        let mut inlay_ids = Vec::new();
 7497        let invalidation_row_range;
 7498        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7499            Some(cursor_row..edit_end_row)
 7500        } else if cursor_row > edit_end_row {
 7501            Some(edit_start_row..cursor_row)
 7502        } else {
 7503            None
 7504        };
 7505        let is_move =
 7506            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7507        let completion = if is_move {
 7508            invalidation_row_range =
 7509                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7510            let target = first_edit_start;
 7511            InlineCompletion::Move { target, snapshot }
 7512        } else {
 7513            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7514                && !self.inline_completions_hidden_for_vim_mode;
 7515
 7516            if show_completions_in_buffer {
 7517                if edits
 7518                    .iter()
 7519                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7520                {
 7521                    let mut inlays = Vec::new();
 7522                    for (range, new_text) in &edits {
 7523                        let inlay = Inlay::inline_completion(
 7524                            post_inc(&mut self.next_inlay_id),
 7525                            range.start,
 7526                            new_text.as_str(),
 7527                        );
 7528                        inlay_ids.push(inlay.id);
 7529                        inlays.push(inlay);
 7530                    }
 7531
 7532                    self.splice_inlays(&[], inlays, cx);
 7533                } else {
 7534                    let background_color = cx.theme().status().deleted_background;
 7535                    self.highlight_text::<InlineCompletionHighlight>(
 7536                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7537                        HighlightStyle {
 7538                            background_color: Some(background_color),
 7539                            ..Default::default()
 7540                        },
 7541                        cx,
 7542                    );
 7543                }
 7544            }
 7545
 7546            invalidation_row_range = edit_start_row..edit_end_row;
 7547
 7548            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7549                if provider.show_tab_accept_marker() {
 7550                    EditDisplayMode::TabAccept
 7551                } else {
 7552                    EditDisplayMode::Inline
 7553                }
 7554            } else {
 7555                EditDisplayMode::DiffPopover
 7556            };
 7557
 7558            InlineCompletion::Edit {
 7559                edits,
 7560                edit_preview: inline_completion.edit_preview,
 7561                display_mode,
 7562                snapshot,
 7563            }
 7564        };
 7565
 7566        let invalidation_range = multibuffer
 7567            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7568            ..multibuffer.anchor_after(Point::new(
 7569                invalidation_row_range.end,
 7570                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7571            ));
 7572
 7573        self.stale_inline_completion_in_menu = None;
 7574        self.active_inline_completion = Some(InlineCompletionState {
 7575            inlay_ids,
 7576            completion,
 7577            completion_id: inline_completion.id,
 7578            invalidation_range,
 7579        });
 7580
 7581        cx.notify();
 7582
 7583        Some(())
 7584    }
 7585
 7586    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7587        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7588    }
 7589
 7590    fn clear_tasks(&mut self) {
 7591        self.tasks.clear()
 7592    }
 7593
 7594    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7595        if self.tasks.insert(key, value).is_some() {
 7596            // This case should hopefully be rare, but just in case...
 7597            log::error!(
 7598                "multiple different run targets found on a single line, only the last target will be rendered"
 7599            )
 7600        }
 7601    }
 7602
 7603    /// Get all display points of breakpoints that will be rendered within editor
 7604    ///
 7605    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7606    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7607    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7608    fn active_breakpoints(
 7609        &self,
 7610        range: Range<DisplayRow>,
 7611        window: &mut Window,
 7612        cx: &mut Context<Self>,
 7613    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7614        let mut breakpoint_display_points = HashMap::default();
 7615
 7616        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7617            return breakpoint_display_points;
 7618        };
 7619
 7620        let snapshot = self.snapshot(window, cx);
 7621
 7622        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7623        let Some(project) = self.project.as_ref() else {
 7624            return breakpoint_display_points;
 7625        };
 7626
 7627        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7628            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7629
 7630        for (buffer_snapshot, range, excerpt_id) in
 7631            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7632        {
 7633            let Some(buffer) = project
 7634                .read(cx)
 7635                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7636            else {
 7637                continue;
 7638            };
 7639            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7640                &buffer,
 7641                Some(
 7642                    buffer_snapshot.anchor_before(range.start)
 7643                        ..buffer_snapshot.anchor_after(range.end),
 7644                ),
 7645                buffer_snapshot,
 7646                cx,
 7647            );
 7648            for (breakpoint, state) in breakpoints {
 7649                let multi_buffer_anchor =
 7650                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7651                let position = multi_buffer_anchor
 7652                    .to_point(&multi_buffer_snapshot)
 7653                    .to_display_point(&snapshot);
 7654
 7655                breakpoint_display_points.insert(
 7656                    position.row(),
 7657                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7658                );
 7659            }
 7660        }
 7661
 7662        breakpoint_display_points
 7663    }
 7664
 7665    fn breakpoint_context_menu(
 7666        &self,
 7667        anchor: Anchor,
 7668        window: &mut Window,
 7669        cx: &mut Context<Self>,
 7670    ) -> Entity<ui::ContextMenu> {
 7671        let weak_editor = cx.weak_entity();
 7672        let focus_handle = self.focus_handle(cx);
 7673
 7674        let row = self
 7675            .buffer
 7676            .read(cx)
 7677            .snapshot(cx)
 7678            .summary_for_anchor::<Point>(&anchor)
 7679            .row;
 7680
 7681        let breakpoint = self
 7682            .breakpoint_at_row(row, window, cx)
 7683            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7684
 7685        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7686            "Edit Log Breakpoint"
 7687        } else {
 7688            "Set Log Breakpoint"
 7689        };
 7690
 7691        let condition_breakpoint_msg = if breakpoint
 7692            .as_ref()
 7693            .is_some_and(|bp| bp.1.condition.is_some())
 7694        {
 7695            "Edit Condition Breakpoint"
 7696        } else {
 7697            "Set Condition Breakpoint"
 7698        };
 7699
 7700        let hit_condition_breakpoint_msg = if breakpoint
 7701            .as_ref()
 7702            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7703        {
 7704            "Edit Hit Condition Breakpoint"
 7705        } else {
 7706            "Set Hit Condition Breakpoint"
 7707        };
 7708
 7709        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7710            "Unset Breakpoint"
 7711        } else {
 7712            "Set Breakpoint"
 7713        };
 7714
 7715        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7716
 7717        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7718            BreakpointState::Enabled => Some("Disable"),
 7719            BreakpointState::Disabled => Some("Enable"),
 7720        });
 7721
 7722        let (anchor, breakpoint) =
 7723            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7724
 7725        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7726            menu.on_blur_subscription(Subscription::new(|| {}))
 7727                .context(focus_handle)
 7728                .when(run_to_cursor, |this| {
 7729                    let weak_editor = weak_editor.clone();
 7730                    this.entry("Run to cursor", None, move |window, cx| {
 7731                        weak_editor
 7732                            .update(cx, |editor, cx| {
 7733                                editor.change_selections(None, window, cx, |s| {
 7734                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7735                                });
 7736                            })
 7737                            .ok();
 7738
 7739                        window.dispatch_action(Box::new(RunToCursor), cx);
 7740                    })
 7741                    .separator()
 7742                })
 7743                .when_some(toggle_state_msg, |this, msg| {
 7744                    this.entry(msg, None, {
 7745                        let weak_editor = weak_editor.clone();
 7746                        let breakpoint = breakpoint.clone();
 7747                        move |_window, cx| {
 7748                            weak_editor
 7749                                .update(cx, |this, cx| {
 7750                                    this.edit_breakpoint_at_anchor(
 7751                                        anchor,
 7752                                        breakpoint.as_ref().clone(),
 7753                                        BreakpointEditAction::InvertState,
 7754                                        cx,
 7755                                    );
 7756                                })
 7757                                .log_err();
 7758                        }
 7759                    })
 7760                })
 7761                .entry(set_breakpoint_msg, None, {
 7762                    let weak_editor = weak_editor.clone();
 7763                    let breakpoint = breakpoint.clone();
 7764                    move |_window, cx| {
 7765                        weak_editor
 7766                            .update(cx, |this, cx| {
 7767                                this.edit_breakpoint_at_anchor(
 7768                                    anchor,
 7769                                    breakpoint.as_ref().clone(),
 7770                                    BreakpointEditAction::Toggle,
 7771                                    cx,
 7772                                );
 7773                            })
 7774                            .log_err();
 7775                    }
 7776                })
 7777                .entry(log_breakpoint_msg, None, {
 7778                    let breakpoint = breakpoint.clone();
 7779                    let weak_editor = weak_editor.clone();
 7780                    move |window, cx| {
 7781                        weak_editor
 7782                            .update(cx, |this, cx| {
 7783                                this.add_edit_breakpoint_block(
 7784                                    anchor,
 7785                                    breakpoint.as_ref(),
 7786                                    BreakpointPromptEditAction::Log,
 7787                                    window,
 7788                                    cx,
 7789                                );
 7790                            })
 7791                            .log_err();
 7792                    }
 7793                })
 7794                .entry(condition_breakpoint_msg, None, {
 7795                    let breakpoint = breakpoint.clone();
 7796                    let weak_editor = weak_editor.clone();
 7797                    move |window, cx| {
 7798                        weak_editor
 7799                            .update(cx, |this, cx| {
 7800                                this.add_edit_breakpoint_block(
 7801                                    anchor,
 7802                                    breakpoint.as_ref(),
 7803                                    BreakpointPromptEditAction::Condition,
 7804                                    window,
 7805                                    cx,
 7806                                );
 7807                            })
 7808                            .log_err();
 7809                    }
 7810                })
 7811                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7812                    weak_editor
 7813                        .update(cx, |this, cx| {
 7814                            this.add_edit_breakpoint_block(
 7815                                anchor,
 7816                                breakpoint.as_ref(),
 7817                                BreakpointPromptEditAction::HitCondition,
 7818                                window,
 7819                                cx,
 7820                            );
 7821                        })
 7822                        .log_err();
 7823                })
 7824        })
 7825    }
 7826
 7827    fn render_breakpoint(
 7828        &self,
 7829        position: Anchor,
 7830        row: DisplayRow,
 7831        breakpoint: &Breakpoint,
 7832        state: Option<BreakpointSessionState>,
 7833        cx: &mut Context<Self>,
 7834    ) -> IconButton {
 7835        let is_rejected = state.is_some_and(|s| !s.verified);
 7836        // Is it a breakpoint that shows up when hovering over gutter?
 7837        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7838            (false, false),
 7839            |PhantomBreakpointIndicator {
 7840                 is_active,
 7841                 display_row,
 7842                 collides_with_existing_breakpoint,
 7843             }| {
 7844                (
 7845                    is_active && display_row == row,
 7846                    collides_with_existing_breakpoint,
 7847                )
 7848            },
 7849        );
 7850
 7851        let (color, icon) = {
 7852            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7853                (false, false) => ui::IconName::DebugBreakpoint,
 7854                (true, false) => ui::IconName::DebugLogBreakpoint,
 7855                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7856                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7857            };
 7858
 7859            let color = if is_phantom {
 7860                Color::Hint
 7861            } else if is_rejected {
 7862                Color::Disabled
 7863            } else {
 7864                Color::Debugger
 7865            };
 7866
 7867            (color, icon)
 7868        };
 7869
 7870        let breakpoint = Arc::from(breakpoint.clone());
 7871
 7872        let alt_as_text = gpui::Keystroke {
 7873            modifiers: Modifiers::secondary_key(),
 7874            ..Default::default()
 7875        };
 7876        let primary_action_text = if breakpoint.is_disabled() {
 7877            "Enable breakpoint"
 7878        } else if is_phantom && !collides_with_existing {
 7879            "Set breakpoint"
 7880        } else {
 7881            "Unset breakpoint"
 7882        };
 7883        let focus_handle = self.focus_handle.clone();
 7884
 7885        let meta = if is_rejected {
 7886            SharedString::from("No executable code is associated with this line.")
 7887        } else if collides_with_existing && !breakpoint.is_disabled() {
 7888            SharedString::from(format!(
 7889                "{alt_as_text}-click to disable,\nright-click for more options."
 7890            ))
 7891        } else {
 7892            SharedString::from("Right-click for more options.")
 7893        };
 7894        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7895            .icon_size(IconSize::XSmall)
 7896            .size(ui::ButtonSize::None)
 7897            .when(is_rejected, |this| {
 7898                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7899            })
 7900            .icon_color(color)
 7901            .style(ButtonStyle::Transparent)
 7902            .on_click(cx.listener({
 7903                let breakpoint = breakpoint.clone();
 7904
 7905                move |editor, event: &ClickEvent, window, cx| {
 7906                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7907                        BreakpointEditAction::InvertState
 7908                    } else {
 7909                        BreakpointEditAction::Toggle
 7910                    };
 7911
 7912                    window.focus(&editor.focus_handle(cx));
 7913                    editor.edit_breakpoint_at_anchor(
 7914                        position,
 7915                        breakpoint.as_ref().clone(),
 7916                        edit_action,
 7917                        cx,
 7918                    );
 7919                }
 7920            }))
 7921            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7922                editor.set_breakpoint_context_menu(
 7923                    row,
 7924                    Some(position),
 7925                    event.down.position,
 7926                    window,
 7927                    cx,
 7928                );
 7929            }))
 7930            .tooltip(move |window, cx| {
 7931                Tooltip::with_meta_in(
 7932                    primary_action_text,
 7933                    Some(&ToggleBreakpoint),
 7934                    meta.clone(),
 7935                    &focus_handle,
 7936                    window,
 7937                    cx,
 7938                )
 7939            })
 7940    }
 7941
 7942    fn build_tasks_context(
 7943        project: &Entity<Project>,
 7944        buffer: &Entity<Buffer>,
 7945        buffer_row: u32,
 7946        tasks: &Arc<RunnableTasks>,
 7947        cx: &mut Context<Self>,
 7948    ) -> Task<Option<task::TaskContext>> {
 7949        let position = Point::new(buffer_row, tasks.column);
 7950        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7951        let location = Location {
 7952            buffer: buffer.clone(),
 7953            range: range_start..range_start,
 7954        };
 7955        // Fill in the environmental variables from the tree-sitter captures
 7956        let mut captured_task_variables = TaskVariables::default();
 7957        for (capture_name, value) in tasks.extra_variables.clone() {
 7958            captured_task_variables.insert(
 7959                task::VariableName::Custom(capture_name.into()),
 7960                value.clone(),
 7961            );
 7962        }
 7963        project.update(cx, |project, cx| {
 7964            project.task_store().update(cx, |task_store, cx| {
 7965                task_store.task_context_for_location(captured_task_variables, location, cx)
 7966            })
 7967        })
 7968    }
 7969
 7970    pub fn spawn_nearest_task(
 7971        &mut self,
 7972        action: &SpawnNearestTask,
 7973        window: &mut Window,
 7974        cx: &mut Context<Self>,
 7975    ) {
 7976        let Some((workspace, _)) = self.workspace.clone() else {
 7977            return;
 7978        };
 7979        let Some(project) = self.project.clone() else {
 7980            return;
 7981        };
 7982
 7983        // Try to find a closest, enclosing node using tree-sitter that has a
 7984        // task
 7985        let Some((buffer, buffer_row, tasks)) = self
 7986            .find_enclosing_node_task(cx)
 7987            // Or find the task that's closest in row-distance.
 7988            .or_else(|| self.find_closest_task(cx))
 7989        else {
 7990            return;
 7991        };
 7992
 7993        let reveal_strategy = action.reveal;
 7994        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7995        cx.spawn_in(window, async move |_, cx| {
 7996            let context = task_context.await?;
 7997            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7998
 7999            let resolved = &mut resolved_task.resolved;
 8000            resolved.reveal = reveal_strategy;
 8001
 8002            workspace
 8003                .update_in(cx, |workspace, window, cx| {
 8004                    workspace.schedule_resolved_task(
 8005                        task_source_kind,
 8006                        resolved_task,
 8007                        false,
 8008                        window,
 8009                        cx,
 8010                    );
 8011                })
 8012                .ok()
 8013        })
 8014        .detach();
 8015    }
 8016
 8017    fn find_closest_task(
 8018        &mut self,
 8019        cx: &mut Context<Self>,
 8020    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8021        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8022
 8023        let ((buffer_id, row), tasks) = self
 8024            .tasks
 8025            .iter()
 8026            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8027
 8028        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8029        let tasks = Arc::new(tasks.to_owned());
 8030        Some((buffer, *row, tasks))
 8031    }
 8032
 8033    fn find_enclosing_node_task(
 8034        &mut self,
 8035        cx: &mut Context<Self>,
 8036    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8037        let snapshot = self.buffer.read(cx).snapshot(cx);
 8038        let offset = self.selections.newest::<usize>(cx).head();
 8039        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8040        let buffer_id = excerpt.buffer().remote_id();
 8041
 8042        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8043        let mut cursor = layer.node().walk();
 8044
 8045        while cursor.goto_first_child_for_byte(offset).is_some() {
 8046            if cursor.node().end_byte() == offset {
 8047                cursor.goto_next_sibling();
 8048            }
 8049        }
 8050
 8051        // Ascend to the smallest ancestor that contains the range and has a task.
 8052        loop {
 8053            let node = cursor.node();
 8054            let node_range = node.byte_range();
 8055            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8056
 8057            // Check if this node contains our offset
 8058            if node_range.start <= offset && node_range.end >= offset {
 8059                // If it contains offset, check for task
 8060                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8061                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8062                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8063                }
 8064            }
 8065
 8066            if !cursor.goto_parent() {
 8067                break;
 8068            }
 8069        }
 8070        None
 8071    }
 8072
 8073    fn render_run_indicator(
 8074        &self,
 8075        _style: &EditorStyle,
 8076        is_active: bool,
 8077        row: DisplayRow,
 8078        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8079        cx: &mut Context<Self>,
 8080    ) -> IconButton {
 8081        let color = Color::Muted;
 8082        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8083
 8084        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8085            .shape(ui::IconButtonShape::Square)
 8086            .icon_size(IconSize::XSmall)
 8087            .icon_color(color)
 8088            .toggle_state(is_active)
 8089            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8090                let quick_launch = e.down.button == MouseButton::Left;
 8091                window.focus(&editor.focus_handle(cx));
 8092                editor.toggle_code_actions(
 8093                    &ToggleCodeActions {
 8094                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8095                        quick_launch,
 8096                    },
 8097                    window,
 8098                    cx,
 8099                );
 8100            }))
 8101            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8102                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8103            }))
 8104    }
 8105
 8106    pub fn context_menu_visible(&self) -> bool {
 8107        !self.edit_prediction_preview_is_active()
 8108            && self
 8109                .context_menu
 8110                .borrow()
 8111                .as_ref()
 8112                .map_or(false, |menu| menu.visible())
 8113    }
 8114
 8115    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8116        self.context_menu
 8117            .borrow()
 8118            .as_ref()
 8119            .map(|menu| menu.origin())
 8120    }
 8121
 8122    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8123        self.context_menu_options = Some(options);
 8124    }
 8125
 8126    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8127    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8128
 8129    fn render_edit_prediction_popover(
 8130        &mut self,
 8131        text_bounds: &Bounds<Pixels>,
 8132        content_origin: gpui::Point<Pixels>,
 8133        right_margin: Pixels,
 8134        editor_snapshot: &EditorSnapshot,
 8135        visible_row_range: Range<DisplayRow>,
 8136        scroll_top: f32,
 8137        scroll_bottom: f32,
 8138        line_layouts: &[LineWithInvisibles],
 8139        line_height: Pixels,
 8140        scroll_pixel_position: gpui::Point<Pixels>,
 8141        newest_selection_head: Option<DisplayPoint>,
 8142        editor_width: Pixels,
 8143        style: &EditorStyle,
 8144        window: &mut Window,
 8145        cx: &mut App,
 8146    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8147        if self.mode().is_minimap() {
 8148            return None;
 8149        }
 8150        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8151
 8152        if self.edit_prediction_visible_in_cursor_popover(true) {
 8153            return None;
 8154        }
 8155
 8156        match &active_inline_completion.completion {
 8157            InlineCompletion::Move { target, .. } => {
 8158                let target_display_point = target.to_display_point(editor_snapshot);
 8159
 8160                if self.edit_prediction_requires_modifier() {
 8161                    if !self.edit_prediction_preview_is_active() {
 8162                        return None;
 8163                    }
 8164
 8165                    self.render_edit_prediction_modifier_jump_popover(
 8166                        text_bounds,
 8167                        content_origin,
 8168                        visible_row_range,
 8169                        line_layouts,
 8170                        line_height,
 8171                        scroll_pixel_position,
 8172                        newest_selection_head,
 8173                        target_display_point,
 8174                        window,
 8175                        cx,
 8176                    )
 8177                } else {
 8178                    self.render_edit_prediction_eager_jump_popover(
 8179                        text_bounds,
 8180                        content_origin,
 8181                        editor_snapshot,
 8182                        visible_row_range,
 8183                        scroll_top,
 8184                        scroll_bottom,
 8185                        line_height,
 8186                        scroll_pixel_position,
 8187                        target_display_point,
 8188                        editor_width,
 8189                        window,
 8190                        cx,
 8191                    )
 8192                }
 8193            }
 8194            InlineCompletion::Edit {
 8195                display_mode: EditDisplayMode::Inline,
 8196                ..
 8197            } => None,
 8198            InlineCompletion::Edit {
 8199                display_mode: EditDisplayMode::TabAccept,
 8200                edits,
 8201                ..
 8202            } => {
 8203                let range = &edits.first()?.0;
 8204                let target_display_point = range.end.to_display_point(editor_snapshot);
 8205
 8206                self.render_edit_prediction_end_of_line_popover(
 8207                    "Accept",
 8208                    editor_snapshot,
 8209                    visible_row_range,
 8210                    target_display_point,
 8211                    line_height,
 8212                    scroll_pixel_position,
 8213                    content_origin,
 8214                    editor_width,
 8215                    window,
 8216                    cx,
 8217                )
 8218            }
 8219            InlineCompletion::Edit {
 8220                edits,
 8221                edit_preview,
 8222                display_mode: EditDisplayMode::DiffPopover,
 8223                snapshot,
 8224            } => self.render_edit_prediction_diff_popover(
 8225                text_bounds,
 8226                content_origin,
 8227                right_margin,
 8228                editor_snapshot,
 8229                visible_row_range,
 8230                line_layouts,
 8231                line_height,
 8232                scroll_pixel_position,
 8233                newest_selection_head,
 8234                editor_width,
 8235                style,
 8236                edits,
 8237                edit_preview,
 8238                snapshot,
 8239                window,
 8240                cx,
 8241            ),
 8242        }
 8243    }
 8244
 8245    fn render_edit_prediction_modifier_jump_popover(
 8246        &mut self,
 8247        text_bounds: &Bounds<Pixels>,
 8248        content_origin: gpui::Point<Pixels>,
 8249        visible_row_range: Range<DisplayRow>,
 8250        line_layouts: &[LineWithInvisibles],
 8251        line_height: Pixels,
 8252        scroll_pixel_position: gpui::Point<Pixels>,
 8253        newest_selection_head: Option<DisplayPoint>,
 8254        target_display_point: DisplayPoint,
 8255        window: &mut Window,
 8256        cx: &mut App,
 8257    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8258        let scrolled_content_origin =
 8259            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8260
 8261        const SCROLL_PADDING_Y: Pixels = px(12.);
 8262
 8263        if target_display_point.row() < visible_row_range.start {
 8264            return self.render_edit_prediction_scroll_popover(
 8265                |_| SCROLL_PADDING_Y,
 8266                IconName::ArrowUp,
 8267                visible_row_range,
 8268                line_layouts,
 8269                newest_selection_head,
 8270                scrolled_content_origin,
 8271                window,
 8272                cx,
 8273            );
 8274        } else if target_display_point.row() >= visible_row_range.end {
 8275            return self.render_edit_prediction_scroll_popover(
 8276                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8277                IconName::ArrowDown,
 8278                visible_row_range,
 8279                line_layouts,
 8280                newest_selection_head,
 8281                scrolled_content_origin,
 8282                window,
 8283                cx,
 8284            );
 8285        }
 8286
 8287        const POLE_WIDTH: Pixels = px(2.);
 8288
 8289        let line_layout =
 8290            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8291        let target_column = target_display_point.column() as usize;
 8292
 8293        let target_x = line_layout.x_for_index(target_column);
 8294        let target_y =
 8295            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8296
 8297        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8298
 8299        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8300        border_color.l += 0.001;
 8301
 8302        let mut element = v_flex()
 8303            .items_end()
 8304            .when(flag_on_right, |el| el.items_start())
 8305            .child(if flag_on_right {
 8306                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8307                    .rounded_bl(px(0.))
 8308                    .rounded_tl(px(0.))
 8309                    .border_l_2()
 8310                    .border_color(border_color)
 8311            } else {
 8312                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8313                    .rounded_br(px(0.))
 8314                    .rounded_tr(px(0.))
 8315                    .border_r_2()
 8316                    .border_color(border_color)
 8317            })
 8318            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8319            .into_any();
 8320
 8321        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8322
 8323        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8324            - point(
 8325                if flag_on_right {
 8326                    POLE_WIDTH
 8327                } else {
 8328                    size.width - POLE_WIDTH
 8329                },
 8330                size.height - line_height,
 8331            );
 8332
 8333        origin.x = origin.x.max(content_origin.x);
 8334
 8335        element.prepaint_at(origin, window, cx);
 8336
 8337        Some((element, origin))
 8338    }
 8339
 8340    fn render_edit_prediction_scroll_popover(
 8341        &mut self,
 8342        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8343        scroll_icon: IconName,
 8344        visible_row_range: Range<DisplayRow>,
 8345        line_layouts: &[LineWithInvisibles],
 8346        newest_selection_head: Option<DisplayPoint>,
 8347        scrolled_content_origin: gpui::Point<Pixels>,
 8348        window: &mut Window,
 8349        cx: &mut App,
 8350    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8351        let mut element = self
 8352            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8353            .into_any();
 8354
 8355        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8356
 8357        let cursor = newest_selection_head?;
 8358        let cursor_row_layout =
 8359            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8360        let cursor_column = cursor.column() as usize;
 8361
 8362        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8363
 8364        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8365
 8366        element.prepaint_at(origin, window, cx);
 8367        Some((element, origin))
 8368    }
 8369
 8370    fn render_edit_prediction_eager_jump_popover(
 8371        &mut self,
 8372        text_bounds: &Bounds<Pixels>,
 8373        content_origin: gpui::Point<Pixels>,
 8374        editor_snapshot: &EditorSnapshot,
 8375        visible_row_range: Range<DisplayRow>,
 8376        scroll_top: f32,
 8377        scroll_bottom: f32,
 8378        line_height: Pixels,
 8379        scroll_pixel_position: gpui::Point<Pixels>,
 8380        target_display_point: DisplayPoint,
 8381        editor_width: Pixels,
 8382        window: &mut Window,
 8383        cx: &mut App,
 8384    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8385        if target_display_point.row().as_f32() < scroll_top {
 8386            let mut element = self
 8387                .render_edit_prediction_line_popover(
 8388                    "Jump to Edit",
 8389                    Some(IconName::ArrowUp),
 8390                    window,
 8391                    cx,
 8392                )?
 8393                .into_any();
 8394
 8395            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8396            let offset = point(
 8397                (text_bounds.size.width - size.width) / 2.,
 8398                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8399            );
 8400
 8401            let origin = text_bounds.origin + offset;
 8402            element.prepaint_at(origin, window, cx);
 8403            Some((element, origin))
 8404        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8405            let mut element = self
 8406                .render_edit_prediction_line_popover(
 8407                    "Jump to Edit",
 8408                    Some(IconName::ArrowDown),
 8409                    window,
 8410                    cx,
 8411                )?
 8412                .into_any();
 8413
 8414            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8415            let offset = point(
 8416                (text_bounds.size.width - size.width) / 2.,
 8417                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8418            );
 8419
 8420            let origin = text_bounds.origin + offset;
 8421            element.prepaint_at(origin, window, cx);
 8422            Some((element, origin))
 8423        } else {
 8424            self.render_edit_prediction_end_of_line_popover(
 8425                "Jump to Edit",
 8426                editor_snapshot,
 8427                visible_row_range,
 8428                target_display_point,
 8429                line_height,
 8430                scroll_pixel_position,
 8431                content_origin,
 8432                editor_width,
 8433                window,
 8434                cx,
 8435            )
 8436        }
 8437    }
 8438
 8439    fn render_edit_prediction_end_of_line_popover(
 8440        self: &mut Editor,
 8441        label: &'static str,
 8442        editor_snapshot: &EditorSnapshot,
 8443        visible_row_range: Range<DisplayRow>,
 8444        target_display_point: DisplayPoint,
 8445        line_height: Pixels,
 8446        scroll_pixel_position: gpui::Point<Pixels>,
 8447        content_origin: gpui::Point<Pixels>,
 8448        editor_width: Pixels,
 8449        window: &mut Window,
 8450        cx: &mut App,
 8451    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8452        let target_line_end = DisplayPoint::new(
 8453            target_display_point.row(),
 8454            editor_snapshot.line_len(target_display_point.row()),
 8455        );
 8456
 8457        let mut element = self
 8458            .render_edit_prediction_line_popover(label, None, window, cx)?
 8459            .into_any();
 8460
 8461        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8462
 8463        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8464
 8465        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8466        let mut origin = start_point
 8467            + line_origin
 8468            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8469        origin.x = origin.x.max(content_origin.x);
 8470
 8471        let max_x = content_origin.x + editor_width - size.width;
 8472
 8473        if origin.x > max_x {
 8474            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8475
 8476            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8477                origin.y += offset;
 8478                IconName::ArrowUp
 8479            } else {
 8480                origin.y -= offset;
 8481                IconName::ArrowDown
 8482            };
 8483
 8484            element = self
 8485                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8486                .into_any();
 8487
 8488            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8489
 8490            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8491        }
 8492
 8493        element.prepaint_at(origin, window, cx);
 8494        Some((element, origin))
 8495    }
 8496
 8497    fn render_edit_prediction_diff_popover(
 8498        self: &Editor,
 8499        text_bounds: &Bounds<Pixels>,
 8500        content_origin: gpui::Point<Pixels>,
 8501        right_margin: Pixels,
 8502        editor_snapshot: &EditorSnapshot,
 8503        visible_row_range: Range<DisplayRow>,
 8504        line_layouts: &[LineWithInvisibles],
 8505        line_height: Pixels,
 8506        scroll_pixel_position: gpui::Point<Pixels>,
 8507        newest_selection_head: Option<DisplayPoint>,
 8508        editor_width: Pixels,
 8509        style: &EditorStyle,
 8510        edits: &Vec<(Range<Anchor>, String)>,
 8511        edit_preview: &Option<language::EditPreview>,
 8512        snapshot: &language::BufferSnapshot,
 8513        window: &mut Window,
 8514        cx: &mut App,
 8515    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8516        let edit_start = edits
 8517            .first()
 8518            .unwrap()
 8519            .0
 8520            .start
 8521            .to_display_point(editor_snapshot);
 8522        let edit_end = edits
 8523            .last()
 8524            .unwrap()
 8525            .0
 8526            .end
 8527            .to_display_point(editor_snapshot);
 8528
 8529        let is_visible = visible_row_range.contains(&edit_start.row())
 8530            || visible_row_range.contains(&edit_end.row());
 8531        if !is_visible {
 8532            return None;
 8533        }
 8534
 8535        let highlighted_edits =
 8536            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8537
 8538        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8539        let line_count = highlighted_edits.text.lines().count();
 8540
 8541        const BORDER_WIDTH: Pixels = px(1.);
 8542
 8543        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8544        let has_keybind = keybind.is_some();
 8545
 8546        let mut element = h_flex()
 8547            .items_start()
 8548            .child(
 8549                h_flex()
 8550                    .bg(cx.theme().colors().editor_background)
 8551                    .border(BORDER_WIDTH)
 8552                    .shadow_sm()
 8553                    .border_color(cx.theme().colors().border)
 8554                    .rounded_l_lg()
 8555                    .when(line_count > 1, |el| el.rounded_br_lg())
 8556                    .pr_1()
 8557                    .child(styled_text),
 8558            )
 8559            .child(
 8560                h_flex()
 8561                    .h(line_height + BORDER_WIDTH * 2.)
 8562                    .px_1p5()
 8563                    .gap_1()
 8564                    // Workaround: For some reason, there's a gap if we don't do this
 8565                    .ml(-BORDER_WIDTH)
 8566                    .shadow(vec![gpui::BoxShadow {
 8567                        color: gpui::black().opacity(0.05),
 8568                        offset: point(px(1.), px(1.)),
 8569                        blur_radius: px(2.),
 8570                        spread_radius: px(0.),
 8571                    }])
 8572                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8573                    .border(BORDER_WIDTH)
 8574                    .border_color(cx.theme().colors().border)
 8575                    .rounded_r_lg()
 8576                    .id("edit_prediction_diff_popover_keybind")
 8577                    .when(!has_keybind, |el| {
 8578                        let status_colors = cx.theme().status();
 8579
 8580                        el.bg(status_colors.error_background)
 8581                            .border_color(status_colors.error.opacity(0.6))
 8582                            .child(Icon::new(IconName::Info).color(Color::Error))
 8583                            .cursor_default()
 8584                            .hoverable_tooltip(move |_window, cx| {
 8585                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8586                            })
 8587                    })
 8588                    .children(keybind),
 8589            )
 8590            .into_any();
 8591
 8592        let longest_row =
 8593            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8594        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8595            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8596        } else {
 8597            layout_line(
 8598                longest_row,
 8599                editor_snapshot,
 8600                style,
 8601                editor_width,
 8602                |_| false,
 8603                window,
 8604                cx,
 8605            )
 8606            .width
 8607        };
 8608
 8609        let viewport_bounds =
 8610            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8611                right: -right_margin,
 8612                ..Default::default()
 8613            });
 8614
 8615        let x_after_longest =
 8616            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8617                - scroll_pixel_position.x;
 8618
 8619        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8620
 8621        // Fully visible if it can be displayed within the window (allow overlapping other
 8622        // panes). However, this is only allowed if the popover starts within text_bounds.
 8623        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8624            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8625
 8626        let mut origin = if can_position_to_the_right {
 8627            point(
 8628                x_after_longest,
 8629                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8630                    - scroll_pixel_position.y,
 8631            )
 8632        } else {
 8633            let cursor_row = newest_selection_head.map(|head| head.row());
 8634            let above_edit = edit_start
 8635                .row()
 8636                .0
 8637                .checked_sub(line_count as u32)
 8638                .map(DisplayRow);
 8639            let below_edit = Some(edit_end.row() + 1);
 8640            let above_cursor =
 8641                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8642            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8643
 8644            // Place the edit popover adjacent to the edit if there is a location
 8645            // available that is onscreen and does not obscure the cursor. Otherwise,
 8646            // place it adjacent to the cursor.
 8647            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8648                .into_iter()
 8649                .flatten()
 8650                .find(|&start_row| {
 8651                    let end_row = start_row + line_count as u32;
 8652                    visible_row_range.contains(&start_row)
 8653                        && visible_row_range.contains(&end_row)
 8654                        && cursor_row.map_or(true, |cursor_row| {
 8655                            !((start_row..end_row).contains(&cursor_row))
 8656                        })
 8657                })?;
 8658
 8659            content_origin
 8660                + point(
 8661                    -scroll_pixel_position.x,
 8662                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8663                )
 8664        };
 8665
 8666        origin.x -= BORDER_WIDTH;
 8667
 8668        window.defer_draw(element, origin, 1);
 8669
 8670        // Do not return an element, since it will already be drawn due to defer_draw.
 8671        None
 8672    }
 8673
 8674    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8675        px(30.)
 8676    }
 8677
 8678    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8679        if self.read_only(cx) {
 8680            cx.theme().players().read_only()
 8681        } else {
 8682            self.style.as_ref().unwrap().local_player
 8683        }
 8684    }
 8685
 8686    fn render_edit_prediction_accept_keybind(
 8687        &self,
 8688        window: &mut Window,
 8689        cx: &App,
 8690    ) -> Option<AnyElement> {
 8691        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8692        let accept_keystroke = accept_binding.keystroke()?;
 8693
 8694        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8695
 8696        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8697            Color::Accent
 8698        } else {
 8699            Color::Muted
 8700        };
 8701
 8702        h_flex()
 8703            .px_0p5()
 8704            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8705            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8706            .text_size(TextSize::XSmall.rems(cx))
 8707            .child(h_flex().children(ui::render_modifiers(
 8708                &accept_keystroke.modifiers,
 8709                PlatformStyle::platform(),
 8710                Some(modifiers_color),
 8711                Some(IconSize::XSmall.rems().into()),
 8712                true,
 8713            )))
 8714            .when(is_platform_style_mac, |parent| {
 8715                parent.child(accept_keystroke.key.clone())
 8716            })
 8717            .when(!is_platform_style_mac, |parent| {
 8718                parent.child(
 8719                    Key::new(
 8720                        util::capitalize(&accept_keystroke.key),
 8721                        Some(Color::Default),
 8722                    )
 8723                    .size(Some(IconSize::XSmall.rems().into())),
 8724                )
 8725            })
 8726            .into_any()
 8727            .into()
 8728    }
 8729
 8730    fn render_edit_prediction_line_popover(
 8731        &self,
 8732        label: impl Into<SharedString>,
 8733        icon: Option<IconName>,
 8734        window: &mut Window,
 8735        cx: &App,
 8736    ) -> Option<Stateful<Div>> {
 8737        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8738
 8739        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8740        let has_keybind = keybind.is_some();
 8741
 8742        let result = h_flex()
 8743            .id("ep-line-popover")
 8744            .py_0p5()
 8745            .pl_1()
 8746            .pr(padding_right)
 8747            .gap_1()
 8748            .rounded_md()
 8749            .border_1()
 8750            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8751            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8752            .shadow_sm()
 8753            .when(!has_keybind, |el| {
 8754                let status_colors = cx.theme().status();
 8755
 8756                el.bg(status_colors.error_background)
 8757                    .border_color(status_colors.error.opacity(0.6))
 8758                    .pl_2()
 8759                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8760                    .cursor_default()
 8761                    .hoverable_tooltip(move |_window, cx| {
 8762                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8763                    })
 8764            })
 8765            .children(keybind)
 8766            .child(
 8767                Label::new(label)
 8768                    .size(LabelSize::Small)
 8769                    .when(!has_keybind, |el| {
 8770                        el.color(cx.theme().status().error.into()).strikethrough()
 8771                    }),
 8772            )
 8773            .when(!has_keybind, |el| {
 8774                el.child(
 8775                    h_flex().ml_1().child(
 8776                        Icon::new(IconName::Info)
 8777                            .size(IconSize::Small)
 8778                            .color(cx.theme().status().error.into()),
 8779                    ),
 8780                )
 8781            })
 8782            .when_some(icon, |element, icon| {
 8783                element.child(
 8784                    div()
 8785                        .mt(px(1.5))
 8786                        .child(Icon::new(icon).size(IconSize::Small)),
 8787                )
 8788            });
 8789
 8790        Some(result)
 8791    }
 8792
 8793    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8794        let accent_color = cx.theme().colors().text_accent;
 8795        let editor_bg_color = cx.theme().colors().editor_background;
 8796        editor_bg_color.blend(accent_color.opacity(0.1))
 8797    }
 8798
 8799    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8800        let accent_color = cx.theme().colors().text_accent;
 8801        let editor_bg_color = cx.theme().colors().editor_background;
 8802        editor_bg_color.blend(accent_color.opacity(0.6))
 8803    }
 8804
 8805    fn render_edit_prediction_cursor_popover(
 8806        &self,
 8807        min_width: Pixels,
 8808        max_width: Pixels,
 8809        cursor_point: Point,
 8810        style: &EditorStyle,
 8811        accept_keystroke: Option<&gpui::Keystroke>,
 8812        _window: &Window,
 8813        cx: &mut Context<Editor>,
 8814    ) -> Option<AnyElement> {
 8815        let provider = self.edit_prediction_provider.as_ref()?;
 8816
 8817        if provider.provider.needs_terms_acceptance(cx) {
 8818            return Some(
 8819                h_flex()
 8820                    .min_w(min_width)
 8821                    .flex_1()
 8822                    .px_2()
 8823                    .py_1()
 8824                    .gap_3()
 8825                    .elevation_2(cx)
 8826                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8827                    .id("accept-terms")
 8828                    .cursor_pointer()
 8829                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8830                    .on_click(cx.listener(|this, _event, window, cx| {
 8831                        cx.stop_propagation();
 8832                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8833                        window.dispatch_action(
 8834                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8835                            cx,
 8836                        );
 8837                    }))
 8838                    .child(
 8839                        h_flex()
 8840                            .flex_1()
 8841                            .gap_2()
 8842                            .child(Icon::new(IconName::ZedPredict))
 8843                            .child(Label::new("Accept Terms of Service"))
 8844                            .child(div().w_full())
 8845                            .child(
 8846                                Icon::new(IconName::ArrowUpRight)
 8847                                    .color(Color::Muted)
 8848                                    .size(IconSize::Small),
 8849                            )
 8850                            .into_any_element(),
 8851                    )
 8852                    .into_any(),
 8853            );
 8854        }
 8855
 8856        let is_refreshing = provider.provider.is_refreshing(cx);
 8857
 8858        fn pending_completion_container() -> Div {
 8859            h_flex()
 8860                .h_full()
 8861                .flex_1()
 8862                .gap_2()
 8863                .child(Icon::new(IconName::ZedPredict))
 8864        }
 8865
 8866        let completion = match &self.active_inline_completion {
 8867            Some(prediction) => {
 8868                if !self.has_visible_completions_menu() {
 8869                    const RADIUS: Pixels = px(6.);
 8870                    const BORDER_WIDTH: Pixels = px(1.);
 8871
 8872                    return Some(
 8873                        h_flex()
 8874                            .elevation_2(cx)
 8875                            .border(BORDER_WIDTH)
 8876                            .border_color(cx.theme().colors().border)
 8877                            .when(accept_keystroke.is_none(), |el| {
 8878                                el.border_color(cx.theme().status().error)
 8879                            })
 8880                            .rounded(RADIUS)
 8881                            .rounded_tl(px(0.))
 8882                            .overflow_hidden()
 8883                            .child(div().px_1p5().child(match &prediction.completion {
 8884                                InlineCompletion::Move { target, snapshot } => {
 8885                                    use text::ToPoint as _;
 8886                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8887                                    {
 8888                                        Icon::new(IconName::ZedPredictDown)
 8889                                    } else {
 8890                                        Icon::new(IconName::ZedPredictUp)
 8891                                    }
 8892                                }
 8893                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8894                            }))
 8895                            .child(
 8896                                h_flex()
 8897                                    .gap_1()
 8898                                    .py_1()
 8899                                    .px_2()
 8900                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8901                                    .border_l_1()
 8902                                    .border_color(cx.theme().colors().border)
 8903                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8904                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8905                                        el.child(
 8906                                            Label::new("Hold")
 8907                                                .size(LabelSize::Small)
 8908                                                .when(accept_keystroke.is_none(), |el| {
 8909                                                    el.strikethrough()
 8910                                                })
 8911                                                .line_height_style(LineHeightStyle::UiLabel),
 8912                                        )
 8913                                    })
 8914                                    .id("edit_prediction_cursor_popover_keybind")
 8915                                    .when(accept_keystroke.is_none(), |el| {
 8916                                        let status_colors = cx.theme().status();
 8917
 8918                                        el.bg(status_colors.error_background)
 8919                                            .border_color(status_colors.error.opacity(0.6))
 8920                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8921                                            .cursor_default()
 8922                                            .hoverable_tooltip(move |_window, cx| {
 8923                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8924                                                    .into()
 8925                                            })
 8926                                    })
 8927                                    .when_some(
 8928                                        accept_keystroke.as_ref(),
 8929                                        |el, accept_keystroke| {
 8930                                            el.child(h_flex().children(ui::render_modifiers(
 8931                                                &accept_keystroke.modifiers,
 8932                                                PlatformStyle::platform(),
 8933                                                Some(Color::Default),
 8934                                                Some(IconSize::XSmall.rems().into()),
 8935                                                false,
 8936                                            )))
 8937                                        },
 8938                                    ),
 8939                            )
 8940                            .into_any(),
 8941                    );
 8942                }
 8943
 8944                self.render_edit_prediction_cursor_popover_preview(
 8945                    prediction,
 8946                    cursor_point,
 8947                    style,
 8948                    cx,
 8949                )?
 8950            }
 8951
 8952            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8953                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8954                    stale_completion,
 8955                    cursor_point,
 8956                    style,
 8957                    cx,
 8958                )?,
 8959
 8960                None => {
 8961                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8962                }
 8963            },
 8964
 8965            None => pending_completion_container().child(Label::new("No Prediction")),
 8966        };
 8967
 8968        let completion = if is_refreshing {
 8969            completion
 8970                .with_animation(
 8971                    "loading-completion",
 8972                    Animation::new(Duration::from_secs(2))
 8973                        .repeat()
 8974                        .with_easing(pulsating_between(0.4, 0.8)),
 8975                    |label, delta| label.opacity(delta),
 8976                )
 8977                .into_any_element()
 8978        } else {
 8979            completion.into_any_element()
 8980        };
 8981
 8982        let has_completion = self.active_inline_completion.is_some();
 8983
 8984        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8985        Some(
 8986            h_flex()
 8987                .min_w(min_width)
 8988                .max_w(max_width)
 8989                .flex_1()
 8990                .elevation_2(cx)
 8991                .border_color(cx.theme().colors().border)
 8992                .child(
 8993                    div()
 8994                        .flex_1()
 8995                        .py_1()
 8996                        .px_2()
 8997                        .overflow_hidden()
 8998                        .child(completion),
 8999                )
 9000                .when_some(accept_keystroke, |el, accept_keystroke| {
 9001                    if !accept_keystroke.modifiers.modified() {
 9002                        return el;
 9003                    }
 9004
 9005                    el.child(
 9006                        h_flex()
 9007                            .h_full()
 9008                            .border_l_1()
 9009                            .rounded_r_lg()
 9010                            .border_color(cx.theme().colors().border)
 9011                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9012                            .gap_1()
 9013                            .py_1()
 9014                            .px_2()
 9015                            .child(
 9016                                h_flex()
 9017                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9018                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9019                                    .child(h_flex().children(ui::render_modifiers(
 9020                                        &accept_keystroke.modifiers,
 9021                                        PlatformStyle::platform(),
 9022                                        Some(if !has_completion {
 9023                                            Color::Muted
 9024                                        } else {
 9025                                            Color::Default
 9026                                        }),
 9027                                        None,
 9028                                        false,
 9029                                    ))),
 9030                            )
 9031                            .child(Label::new("Preview").into_any_element())
 9032                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9033                    )
 9034                })
 9035                .into_any(),
 9036        )
 9037    }
 9038
 9039    fn render_edit_prediction_cursor_popover_preview(
 9040        &self,
 9041        completion: &InlineCompletionState,
 9042        cursor_point: Point,
 9043        style: &EditorStyle,
 9044        cx: &mut Context<Editor>,
 9045    ) -> Option<Div> {
 9046        use text::ToPoint as _;
 9047
 9048        fn render_relative_row_jump(
 9049            prefix: impl Into<String>,
 9050            current_row: u32,
 9051            target_row: u32,
 9052        ) -> Div {
 9053            let (row_diff, arrow) = if target_row < current_row {
 9054                (current_row - target_row, IconName::ArrowUp)
 9055            } else {
 9056                (target_row - current_row, IconName::ArrowDown)
 9057            };
 9058
 9059            h_flex()
 9060                .child(
 9061                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9062                        .color(Color::Muted)
 9063                        .size(LabelSize::Small),
 9064                )
 9065                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9066        }
 9067
 9068        match &completion.completion {
 9069            InlineCompletion::Move {
 9070                target, snapshot, ..
 9071            } => Some(
 9072                h_flex()
 9073                    .px_2()
 9074                    .gap_2()
 9075                    .flex_1()
 9076                    .child(
 9077                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9078                            Icon::new(IconName::ZedPredictDown)
 9079                        } else {
 9080                            Icon::new(IconName::ZedPredictUp)
 9081                        },
 9082                    )
 9083                    .child(Label::new("Jump to Edit")),
 9084            ),
 9085
 9086            InlineCompletion::Edit {
 9087                edits,
 9088                edit_preview,
 9089                snapshot,
 9090                display_mode: _,
 9091            } => {
 9092                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9093
 9094                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9095                    &snapshot,
 9096                    &edits,
 9097                    edit_preview.as_ref()?,
 9098                    true,
 9099                    cx,
 9100                )
 9101                .first_line_preview();
 9102
 9103                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9104                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9105
 9106                let preview = h_flex()
 9107                    .gap_1()
 9108                    .min_w_16()
 9109                    .child(styled_text)
 9110                    .when(has_more_lines, |parent| parent.child(""));
 9111
 9112                let left = if first_edit_row != cursor_point.row {
 9113                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9114                        .into_any_element()
 9115                } else {
 9116                    Icon::new(IconName::ZedPredict).into_any_element()
 9117                };
 9118
 9119                Some(
 9120                    h_flex()
 9121                        .h_full()
 9122                        .flex_1()
 9123                        .gap_2()
 9124                        .pr_1()
 9125                        .overflow_x_hidden()
 9126                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9127                        .child(left)
 9128                        .child(preview),
 9129                )
 9130            }
 9131        }
 9132    }
 9133
 9134    pub fn render_context_menu(
 9135        &self,
 9136        style: &EditorStyle,
 9137        max_height_in_lines: u32,
 9138        window: &mut Window,
 9139        cx: &mut Context<Editor>,
 9140    ) -> Option<AnyElement> {
 9141        let menu = self.context_menu.borrow();
 9142        let menu = menu.as_ref()?;
 9143        if !menu.visible() {
 9144            return None;
 9145        };
 9146        Some(menu.render(style, max_height_in_lines, window, cx))
 9147    }
 9148
 9149    fn render_context_menu_aside(
 9150        &mut self,
 9151        max_size: Size<Pixels>,
 9152        window: &mut Window,
 9153        cx: &mut Context<Editor>,
 9154    ) -> Option<AnyElement> {
 9155        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9156            if menu.visible() {
 9157                menu.render_aside(max_size, window, cx)
 9158            } else {
 9159                None
 9160            }
 9161        })
 9162    }
 9163
 9164    fn hide_context_menu(
 9165        &mut self,
 9166        window: &mut Window,
 9167        cx: &mut Context<Self>,
 9168    ) -> Option<CodeContextMenu> {
 9169        cx.notify();
 9170        self.completion_tasks.clear();
 9171        let context_menu = self.context_menu.borrow_mut().take();
 9172        self.stale_inline_completion_in_menu.take();
 9173        self.update_visible_inline_completion(window, cx);
 9174        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9175            if let Some(completion_provider) = &self.completion_provider {
 9176                completion_provider.selection_changed(None, window, cx);
 9177            }
 9178        }
 9179        context_menu
 9180    }
 9181
 9182    fn show_snippet_choices(
 9183        &mut self,
 9184        choices: &Vec<String>,
 9185        selection: Range<Anchor>,
 9186        cx: &mut Context<Self>,
 9187    ) {
 9188        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9189            (Some(a), Some(b)) if a == b => a,
 9190            _ => {
 9191                log::error!("expected anchor range to have matching buffer IDs");
 9192                return;
 9193            }
 9194        };
 9195        let multi_buffer = self.buffer().read(cx);
 9196        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9197            return;
 9198        };
 9199
 9200        let id = post_inc(&mut self.next_completion_id);
 9201        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9202        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9203            CompletionsMenu::new_snippet_choices(
 9204                id,
 9205                true,
 9206                choices,
 9207                selection,
 9208                buffer,
 9209                snippet_sort_order,
 9210            ),
 9211        ));
 9212    }
 9213
 9214    pub fn insert_snippet(
 9215        &mut self,
 9216        insertion_ranges: &[Range<usize>],
 9217        snippet: Snippet,
 9218        window: &mut Window,
 9219        cx: &mut Context<Self>,
 9220    ) -> Result<()> {
 9221        struct Tabstop<T> {
 9222            is_end_tabstop: bool,
 9223            ranges: Vec<Range<T>>,
 9224            choices: Option<Vec<String>>,
 9225        }
 9226
 9227        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9228            let snippet_text: Arc<str> = snippet.text.clone().into();
 9229            let edits = insertion_ranges
 9230                .iter()
 9231                .cloned()
 9232                .map(|range| (range, snippet_text.clone()));
 9233            let autoindent_mode = AutoindentMode::Block {
 9234                original_indent_columns: Vec::new(),
 9235            };
 9236            buffer.edit(edits, Some(autoindent_mode), cx);
 9237
 9238            let snapshot = &*buffer.read(cx);
 9239            let snippet = &snippet;
 9240            snippet
 9241                .tabstops
 9242                .iter()
 9243                .map(|tabstop| {
 9244                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9245                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9246                    });
 9247                    let mut tabstop_ranges = tabstop
 9248                        .ranges
 9249                        .iter()
 9250                        .flat_map(|tabstop_range| {
 9251                            let mut delta = 0_isize;
 9252                            insertion_ranges.iter().map(move |insertion_range| {
 9253                                let insertion_start = insertion_range.start as isize + delta;
 9254                                delta +=
 9255                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9256
 9257                                let start = ((insertion_start + tabstop_range.start) as usize)
 9258                                    .min(snapshot.len());
 9259                                let end = ((insertion_start + tabstop_range.end) as usize)
 9260                                    .min(snapshot.len());
 9261                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9262                            })
 9263                        })
 9264                        .collect::<Vec<_>>();
 9265                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9266
 9267                    Tabstop {
 9268                        is_end_tabstop,
 9269                        ranges: tabstop_ranges,
 9270                        choices: tabstop.choices.clone(),
 9271                    }
 9272                })
 9273                .collect::<Vec<_>>()
 9274        });
 9275        if let Some(tabstop) = tabstops.first() {
 9276            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9277                // Reverse order so that the first range is the newest created selection.
 9278                // Completions will use it and autoscroll will prioritize it.
 9279                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9280            });
 9281
 9282            if let Some(choices) = &tabstop.choices {
 9283                if let Some(selection) = tabstop.ranges.first() {
 9284                    self.show_snippet_choices(choices, selection.clone(), cx)
 9285                }
 9286            }
 9287
 9288            // If we're already at the last tabstop and it's at the end of the snippet,
 9289            // we're done, we don't need to keep the state around.
 9290            if !tabstop.is_end_tabstop {
 9291                let choices = tabstops
 9292                    .iter()
 9293                    .map(|tabstop| tabstop.choices.clone())
 9294                    .collect();
 9295
 9296                let ranges = tabstops
 9297                    .into_iter()
 9298                    .map(|tabstop| tabstop.ranges)
 9299                    .collect::<Vec<_>>();
 9300
 9301                self.snippet_stack.push(SnippetState {
 9302                    active_index: 0,
 9303                    ranges,
 9304                    choices,
 9305                });
 9306            }
 9307
 9308            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9309            if self.autoclose_regions.is_empty() {
 9310                let snapshot = self.buffer.read(cx).snapshot(cx);
 9311                for selection in &mut self.selections.all::<Point>(cx) {
 9312                    let selection_head = selection.head();
 9313                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9314                        continue;
 9315                    };
 9316
 9317                    let mut bracket_pair = None;
 9318                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9319                    let prev_chars = snapshot
 9320                        .reversed_chars_at(selection_head)
 9321                        .collect::<String>();
 9322                    for (pair, enabled) in scope.brackets() {
 9323                        if enabled
 9324                            && pair.close
 9325                            && prev_chars.starts_with(pair.start.as_str())
 9326                            && next_chars.starts_with(pair.end.as_str())
 9327                        {
 9328                            bracket_pair = Some(pair.clone());
 9329                            break;
 9330                        }
 9331                    }
 9332                    if let Some(pair) = bracket_pair {
 9333                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9334                        let autoclose_enabled =
 9335                            self.use_autoclose && snapshot_settings.use_autoclose;
 9336                        if autoclose_enabled {
 9337                            let start = snapshot.anchor_after(selection_head);
 9338                            let end = snapshot.anchor_after(selection_head);
 9339                            self.autoclose_regions.push(AutocloseRegion {
 9340                                selection_id: selection.id,
 9341                                range: start..end,
 9342                                pair,
 9343                            });
 9344                        }
 9345                    }
 9346                }
 9347            }
 9348        }
 9349        Ok(())
 9350    }
 9351
 9352    pub fn move_to_next_snippet_tabstop(
 9353        &mut self,
 9354        window: &mut Window,
 9355        cx: &mut Context<Self>,
 9356    ) -> bool {
 9357        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9358    }
 9359
 9360    pub fn move_to_prev_snippet_tabstop(
 9361        &mut self,
 9362        window: &mut Window,
 9363        cx: &mut Context<Self>,
 9364    ) -> bool {
 9365        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9366    }
 9367
 9368    pub fn move_to_snippet_tabstop(
 9369        &mut self,
 9370        bias: Bias,
 9371        window: &mut Window,
 9372        cx: &mut Context<Self>,
 9373    ) -> bool {
 9374        if let Some(mut snippet) = self.snippet_stack.pop() {
 9375            match bias {
 9376                Bias::Left => {
 9377                    if snippet.active_index > 0 {
 9378                        snippet.active_index -= 1;
 9379                    } else {
 9380                        self.snippet_stack.push(snippet);
 9381                        return false;
 9382                    }
 9383                }
 9384                Bias::Right => {
 9385                    if snippet.active_index + 1 < snippet.ranges.len() {
 9386                        snippet.active_index += 1;
 9387                    } else {
 9388                        self.snippet_stack.push(snippet);
 9389                        return false;
 9390                    }
 9391                }
 9392            }
 9393            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9394                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9395                    // Reverse order so that the first range is the newest created selection.
 9396                    // Completions will use it and autoscroll will prioritize it.
 9397                    s.select_ranges(current_ranges.iter().rev().cloned())
 9398                });
 9399
 9400                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9401                    if let Some(selection) = current_ranges.first() {
 9402                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9403                    }
 9404                }
 9405
 9406                // If snippet state is not at the last tabstop, push it back on the stack
 9407                if snippet.active_index + 1 < snippet.ranges.len() {
 9408                    self.snippet_stack.push(snippet);
 9409                }
 9410                return true;
 9411            }
 9412        }
 9413
 9414        false
 9415    }
 9416
 9417    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9418        self.transact(window, cx, |this, window, cx| {
 9419            this.select_all(&SelectAll, window, cx);
 9420            this.insert("", window, cx);
 9421        });
 9422    }
 9423
 9424    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9425        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9426        self.transact(window, cx, |this, window, cx| {
 9427            this.select_autoclose_pair(window, cx);
 9428            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9429            if !this.linked_edit_ranges.is_empty() {
 9430                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9431                let snapshot = this.buffer.read(cx).snapshot(cx);
 9432
 9433                for selection in selections.iter() {
 9434                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9435                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9436                    if selection_start.buffer_id != selection_end.buffer_id {
 9437                        continue;
 9438                    }
 9439                    if let Some(ranges) =
 9440                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9441                    {
 9442                        for (buffer, entries) in ranges {
 9443                            linked_ranges.entry(buffer).or_default().extend(entries);
 9444                        }
 9445                    }
 9446                }
 9447            }
 9448
 9449            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9450            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9451            for selection in &mut selections {
 9452                if selection.is_empty() {
 9453                    let old_head = selection.head();
 9454                    let mut new_head =
 9455                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9456                            .to_point(&display_map);
 9457                    if let Some((buffer, line_buffer_range)) = display_map
 9458                        .buffer_snapshot
 9459                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9460                    {
 9461                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9462                        let indent_len = match indent_size.kind {
 9463                            IndentKind::Space => {
 9464                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9465                            }
 9466                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9467                        };
 9468                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9469                            let indent_len = indent_len.get();
 9470                            new_head = cmp::min(
 9471                                new_head,
 9472                                MultiBufferPoint::new(
 9473                                    old_head.row,
 9474                                    ((old_head.column - 1) / indent_len) * indent_len,
 9475                                ),
 9476                            );
 9477                        }
 9478                    }
 9479
 9480                    selection.set_head(new_head, SelectionGoal::None);
 9481                }
 9482            }
 9483
 9484            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9485                s.select(selections)
 9486            });
 9487            this.insert("", window, cx);
 9488            let empty_str: Arc<str> = Arc::from("");
 9489            for (buffer, edits) in linked_ranges {
 9490                let snapshot = buffer.read(cx).snapshot();
 9491                use text::ToPoint as TP;
 9492
 9493                let edits = edits
 9494                    .into_iter()
 9495                    .map(|range| {
 9496                        let end_point = TP::to_point(&range.end, &snapshot);
 9497                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9498
 9499                        if end_point == start_point {
 9500                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9501                                .saturating_sub(1);
 9502                            start_point =
 9503                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9504                        };
 9505
 9506                        (start_point..end_point, empty_str.clone())
 9507                    })
 9508                    .sorted_by_key(|(range, _)| range.start)
 9509                    .collect::<Vec<_>>();
 9510                buffer.update(cx, |this, cx| {
 9511                    this.edit(edits, None, cx);
 9512                })
 9513            }
 9514            this.refresh_inline_completion(true, false, window, cx);
 9515            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9516        });
 9517    }
 9518
 9519    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9520        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9521        self.transact(window, cx, |this, window, cx| {
 9522            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9523                s.move_with(|map, selection| {
 9524                    if selection.is_empty() {
 9525                        let cursor = movement::right(map, selection.head());
 9526                        selection.end = cursor;
 9527                        selection.reversed = true;
 9528                        selection.goal = SelectionGoal::None;
 9529                    }
 9530                })
 9531            });
 9532            this.insert("", window, cx);
 9533            this.refresh_inline_completion(true, false, window, cx);
 9534        });
 9535    }
 9536
 9537    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9538        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9539        if self.move_to_prev_snippet_tabstop(window, cx) {
 9540            return;
 9541        }
 9542        self.outdent(&Outdent, window, cx);
 9543    }
 9544
 9545    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9546        if self.move_to_next_snippet_tabstop(window, cx) {
 9547            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9548            return;
 9549        }
 9550        if self.read_only(cx) {
 9551            return;
 9552        }
 9553        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9554        let mut selections = self.selections.all_adjusted(cx);
 9555        let buffer = self.buffer.read(cx);
 9556        let snapshot = buffer.snapshot(cx);
 9557        let rows_iter = selections.iter().map(|s| s.head().row);
 9558        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9559
 9560        let has_some_cursor_in_whitespace = selections
 9561            .iter()
 9562            .filter(|selection| selection.is_empty())
 9563            .any(|selection| {
 9564                let cursor = selection.head();
 9565                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9566                cursor.column < current_indent.len
 9567            });
 9568
 9569        let mut edits = Vec::new();
 9570        let mut prev_edited_row = 0;
 9571        let mut row_delta = 0;
 9572        for selection in &mut selections {
 9573            if selection.start.row != prev_edited_row {
 9574                row_delta = 0;
 9575            }
 9576            prev_edited_row = selection.end.row;
 9577
 9578            // If the selection is non-empty, then increase the indentation of the selected lines.
 9579            if !selection.is_empty() {
 9580                row_delta =
 9581                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9582                continue;
 9583            }
 9584
 9585            let cursor = selection.head();
 9586            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9587            if let Some(suggested_indent) =
 9588                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9589            {
 9590                // Don't do anything if already at suggested indent
 9591                // and there is any other cursor which is not
 9592                if has_some_cursor_in_whitespace
 9593                    && cursor.column == current_indent.len
 9594                    && current_indent.len == suggested_indent.len
 9595                {
 9596                    continue;
 9597                }
 9598
 9599                // Adjust line and move cursor to suggested indent
 9600                // if cursor is not at suggested indent
 9601                if cursor.column < suggested_indent.len
 9602                    && cursor.column <= current_indent.len
 9603                    && current_indent.len <= suggested_indent.len
 9604                {
 9605                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9606                    selection.end = selection.start;
 9607                    if row_delta == 0 {
 9608                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9609                            cursor.row,
 9610                            current_indent,
 9611                            suggested_indent,
 9612                        ));
 9613                        row_delta = suggested_indent.len - current_indent.len;
 9614                    }
 9615                    continue;
 9616                }
 9617
 9618                // If current indent is more than suggested indent
 9619                // only move cursor to current indent and skip indent
 9620                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9621                    selection.start = Point::new(cursor.row, current_indent.len);
 9622                    selection.end = selection.start;
 9623                    continue;
 9624                }
 9625            }
 9626
 9627            // Otherwise, insert a hard or soft tab.
 9628            let settings = buffer.language_settings_at(cursor, cx);
 9629            let tab_size = if settings.hard_tabs {
 9630                IndentSize::tab()
 9631            } else {
 9632                let tab_size = settings.tab_size.get();
 9633                let indent_remainder = snapshot
 9634                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9635                    .flat_map(str::chars)
 9636                    .fold(row_delta % tab_size, |counter: u32, c| {
 9637                        if c == '\t' {
 9638                            0
 9639                        } else {
 9640                            (counter + 1) % tab_size
 9641                        }
 9642                    });
 9643
 9644                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9645                IndentSize::spaces(chars_to_next_tab_stop)
 9646            };
 9647            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9648            selection.end = selection.start;
 9649            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9650            row_delta += tab_size.len;
 9651        }
 9652
 9653        self.transact(window, cx, |this, window, cx| {
 9654            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9655            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9656                s.select(selections)
 9657            });
 9658            this.refresh_inline_completion(true, false, window, cx);
 9659        });
 9660    }
 9661
 9662    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9663        if self.read_only(cx) {
 9664            return;
 9665        }
 9666        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9667        let mut selections = self.selections.all::<Point>(cx);
 9668        let mut prev_edited_row = 0;
 9669        let mut row_delta = 0;
 9670        let mut edits = Vec::new();
 9671        let buffer = self.buffer.read(cx);
 9672        let snapshot = buffer.snapshot(cx);
 9673        for selection in &mut selections {
 9674            if selection.start.row != prev_edited_row {
 9675                row_delta = 0;
 9676            }
 9677            prev_edited_row = selection.end.row;
 9678
 9679            row_delta =
 9680                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9681        }
 9682
 9683        self.transact(window, cx, |this, window, cx| {
 9684            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9685            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9686                s.select(selections)
 9687            });
 9688        });
 9689    }
 9690
 9691    fn indent_selection(
 9692        buffer: &MultiBuffer,
 9693        snapshot: &MultiBufferSnapshot,
 9694        selection: &mut Selection<Point>,
 9695        edits: &mut Vec<(Range<Point>, String)>,
 9696        delta_for_start_row: u32,
 9697        cx: &App,
 9698    ) -> u32 {
 9699        let settings = buffer.language_settings_at(selection.start, cx);
 9700        let tab_size = settings.tab_size.get();
 9701        let indent_kind = if settings.hard_tabs {
 9702            IndentKind::Tab
 9703        } else {
 9704            IndentKind::Space
 9705        };
 9706        let mut start_row = selection.start.row;
 9707        let mut end_row = selection.end.row + 1;
 9708
 9709        // If a selection ends at the beginning of a line, don't indent
 9710        // that last line.
 9711        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9712            end_row -= 1;
 9713        }
 9714
 9715        // Avoid re-indenting a row that has already been indented by a
 9716        // previous selection, but still update this selection's column
 9717        // to reflect that indentation.
 9718        if delta_for_start_row > 0 {
 9719            start_row += 1;
 9720            selection.start.column += delta_for_start_row;
 9721            if selection.end.row == selection.start.row {
 9722                selection.end.column += delta_for_start_row;
 9723            }
 9724        }
 9725
 9726        let mut delta_for_end_row = 0;
 9727        let has_multiple_rows = start_row + 1 != end_row;
 9728        for row in start_row..end_row {
 9729            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9730            let indent_delta = match (current_indent.kind, indent_kind) {
 9731                (IndentKind::Space, IndentKind::Space) => {
 9732                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9733                    IndentSize::spaces(columns_to_next_tab_stop)
 9734                }
 9735                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9736                (_, IndentKind::Tab) => IndentSize::tab(),
 9737            };
 9738
 9739            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9740                0
 9741            } else {
 9742                selection.start.column
 9743            };
 9744            let row_start = Point::new(row, start);
 9745            edits.push((
 9746                row_start..row_start,
 9747                indent_delta.chars().collect::<String>(),
 9748            ));
 9749
 9750            // Update this selection's endpoints to reflect the indentation.
 9751            if row == selection.start.row {
 9752                selection.start.column += indent_delta.len;
 9753            }
 9754            if row == selection.end.row {
 9755                selection.end.column += indent_delta.len;
 9756                delta_for_end_row = indent_delta.len;
 9757            }
 9758        }
 9759
 9760        if selection.start.row == selection.end.row {
 9761            delta_for_start_row + delta_for_end_row
 9762        } else {
 9763            delta_for_end_row
 9764        }
 9765    }
 9766
 9767    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9768        if self.read_only(cx) {
 9769            return;
 9770        }
 9771        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9772        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9773        let selections = self.selections.all::<Point>(cx);
 9774        let mut deletion_ranges = Vec::new();
 9775        let mut last_outdent = None;
 9776        {
 9777            let buffer = self.buffer.read(cx);
 9778            let snapshot = buffer.snapshot(cx);
 9779            for selection in &selections {
 9780                let settings = buffer.language_settings_at(selection.start, cx);
 9781                let tab_size = settings.tab_size.get();
 9782                let mut rows = selection.spanned_rows(false, &display_map);
 9783
 9784                // Avoid re-outdenting a row that has already been outdented by a
 9785                // previous selection.
 9786                if let Some(last_row) = last_outdent {
 9787                    if last_row == rows.start {
 9788                        rows.start = rows.start.next_row();
 9789                    }
 9790                }
 9791                let has_multiple_rows = rows.len() > 1;
 9792                for row in rows.iter_rows() {
 9793                    let indent_size = snapshot.indent_size_for_line(row);
 9794                    if indent_size.len > 0 {
 9795                        let deletion_len = match indent_size.kind {
 9796                            IndentKind::Space => {
 9797                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9798                                if columns_to_prev_tab_stop == 0 {
 9799                                    tab_size
 9800                                } else {
 9801                                    columns_to_prev_tab_stop
 9802                                }
 9803                            }
 9804                            IndentKind::Tab => 1,
 9805                        };
 9806                        let start = if has_multiple_rows
 9807                            || deletion_len > selection.start.column
 9808                            || indent_size.len < selection.start.column
 9809                        {
 9810                            0
 9811                        } else {
 9812                            selection.start.column - deletion_len
 9813                        };
 9814                        deletion_ranges.push(
 9815                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9816                        );
 9817                        last_outdent = Some(row);
 9818                    }
 9819                }
 9820            }
 9821        }
 9822
 9823        self.transact(window, cx, |this, window, cx| {
 9824            this.buffer.update(cx, |buffer, cx| {
 9825                let empty_str: Arc<str> = Arc::default();
 9826                buffer.edit(
 9827                    deletion_ranges
 9828                        .into_iter()
 9829                        .map(|range| (range, empty_str.clone())),
 9830                    None,
 9831                    cx,
 9832                );
 9833            });
 9834            let selections = this.selections.all::<usize>(cx);
 9835            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9836                s.select(selections)
 9837            });
 9838        });
 9839    }
 9840
 9841    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9842        if self.read_only(cx) {
 9843            return;
 9844        }
 9845        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9846        let selections = self
 9847            .selections
 9848            .all::<usize>(cx)
 9849            .into_iter()
 9850            .map(|s| s.range());
 9851
 9852        self.transact(window, cx, |this, window, cx| {
 9853            this.buffer.update(cx, |buffer, cx| {
 9854                buffer.autoindent_ranges(selections, cx);
 9855            });
 9856            let selections = this.selections.all::<usize>(cx);
 9857            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9858                s.select(selections)
 9859            });
 9860        });
 9861    }
 9862
 9863    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9864        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9865        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9866        let selections = self.selections.all::<Point>(cx);
 9867
 9868        let mut new_cursors = Vec::new();
 9869        let mut edit_ranges = Vec::new();
 9870        let mut selections = selections.iter().peekable();
 9871        while let Some(selection) = selections.next() {
 9872            let mut rows = selection.spanned_rows(false, &display_map);
 9873            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9874
 9875            // Accumulate contiguous regions of rows that we want to delete.
 9876            while let Some(next_selection) = selections.peek() {
 9877                let next_rows = next_selection.spanned_rows(false, &display_map);
 9878                if next_rows.start <= rows.end {
 9879                    rows.end = next_rows.end;
 9880                    selections.next().unwrap();
 9881                } else {
 9882                    break;
 9883                }
 9884            }
 9885
 9886            let buffer = &display_map.buffer_snapshot;
 9887            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9888            let edit_end;
 9889            let cursor_buffer_row;
 9890            if buffer.max_point().row >= rows.end.0 {
 9891                // If there's a line after the range, delete the \n from the end of the row range
 9892                // and position the cursor on the next line.
 9893                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9894                cursor_buffer_row = rows.end;
 9895            } else {
 9896                // If there isn't a line after the range, delete the \n from the line before the
 9897                // start of the row range and position the cursor there.
 9898                edit_start = edit_start.saturating_sub(1);
 9899                edit_end = buffer.len();
 9900                cursor_buffer_row = rows.start.previous_row();
 9901            }
 9902
 9903            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9904            *cursor.column_mut() =
 9905                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9906
 9907            new_cursors.push((
 9908                selection.id,
 9909                buffer.anchor_after(cursor.to_point(&display_map)),
 9910            ));
 9911            edit_ranges.push(edit_start..edit_end);
 9912        }
 9913
 9914        self.transact(window, cx, |this, window, cx| {
 9915            let buffer = this.buffer.update(cx, |buffer, cx| {
 9916                let empty_str: Arc<str> = Arc::default();
 9917                buffer.edit(
 9918                    edit_ranges
 9919                        .into_iter()
 9920                        .map(|range| (range, empty_str.clone())),
 9921                    None,
 9922                    cx,
 9923                );
 9924                buffer.snapshot(cx)
 9925            });
 9926            let new_selections = new_cursors
 9927                .into_iter()
 9928                .map(|(id, cursor)| {
 9929                    let cursor = cursor.to_point(&buffer);
 9930                    Selection {
 9931                        id,
 9932                        start: cursor,
 9933                        end: cursor,
 9934                        reversed: false,
 9935                        goal: SelectionGoal::None,
 9936                    }
 9937                })
 9938                .collect();
 9939
 9940            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9941                s.select(new_selections);
 9942            });
 9943        });
 9944    }
 9945
 9946    pub fn join_lines_impl(
 9947        &mut self,
 9948        insert_whitespace: bool,
 9949        window: &mut Window,
 9950        cx: &mut Context<Self>,
 9951    ) {
 9952        if self.read_only(cx) {
 9953            return;
 9954        }
 9955        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9956        for selection in self.selections.all::<Point>(cx) {
 9957            let start = MultiBufferRow(selection.start.row);
 9958            // Treat single line selections as if they include the next line. Otherwise this action
 9959            // would do nothing for single line selections individual cursors.
 9960            let end = if selection.start.row == selection.end.row {
 9961                MultiBufferRow(selection.start.row + 1)
 9962            } else {
 9963                MultiBufferRow(selection.end.row)
 9964            };
 9965
 9966            if let Some(last_row_range) = row_ranges.last_mut() {
 9967                if start <= last_row_range.end {
 9968                    last_row_range.end = end;
 9969                    continue;
 9970                }
 9971            }
 9972            row_ranges.push(start..end);
 9973        }
 9974
 9975        let snapshot = self.buffer.read(cx).snapshot(cx);
 9976        let mut cursor_positions = Vec::new();
 9977        for row_range in &row_ranges {
 9978            let anchor = snapshot.anchor_before(Point::new(
 9979                row_range.end.previous_row().0,
 9980                snapshot.line_len(row_range.end.previous_row()),
 9981            ));
 9982            cursor_positions.push(anchor..anchor);
 9983        }
 9984
 9985        self.transact(window, cx, |this, window, cx| {
 9986            for row_range in row_ranges.into_iter().rev() {
 9987                for row in row_range.iter_rows().rev() {
 9988                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9989                    let next_line_row = row.next_row();
 9990                    let indent = snapshot.indent_size_for_line(next_line_row);
 9991                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9992
 9993                    let replace =
 9994                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9995                            " "
 9996                        } else {
 9997                            ""
 9998                        };
 9999
10000                    this.buffer.update(cx, |buffer, cx| {
10001                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10002                    });
10003                }
10004            }
10005
10006            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10007                s.select_anchor_ranges(cursor_positions)
10008            });
10009        });
10010    }
10011
10012    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10013        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10014        self.join_lines_impl(true, window, cx);
10015    }
10016
10017    pub fn sort_lines_case_sensitive(
10018        &mut self,
10019        _: &SortLinesCaseSensitive,
10020        window: &mut Window,
10021        cx: &mut Context<Self>,
10022    ) {
10023        self.manipulate_lines(window, cx, |lines| lines.sort())
10024    }
10025
10026    pub fn sort_lines_case_insensitive(
10027        &mut self,
10028        _: &SortLinesCaseInsensitive,
10029        window: &mut Window,
10030        cx: &mut Context<Self>,
10031    ) {
10032        self.manipulate_lines(window, cx, |lines| {
10033            lines.sort_by_key(|line| line.to_lowercase())
10034        })
10035    }
10036
10037    pub fn unique_lines_case_insensitive(
10038        &mut self,
10039        _: &UniqueLinesCaseInsensitive,
10040        window: &mut Window,
10041        cx: &mut Context<Self>,
10042    ) {
10043        self.manipulate_lines(window, cx, |lines| {
10044            let mut seen = HashSet::default();
10045            lines.retain(|line| seen.insert(line.to_lowercase()));
10046        })
10047    }
10048
10049    pub fn unique_lines_case_sensitive(
10050        &mut self,
10051        _: &UniqueLinesCaseSensitive,
10052        window: &mut Window,
10053        cx: &mut Context<Self>,
10054    ) {
10055        self.manipulate_lines(window, cx, |lines| {
10056            let mut seen = HashSet::default();
10057            lines.retain(|line| seen.insert(*line));
10058        })
10059    }
10060
10061    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10062        let Some(project) = self.project.clone() else {
10063            return;
10064        };
10065        self.reload(project, window, cx)
10066            .detach_and_notify_err(window, cx);
10067    }
10068
10069    pub fn restore_file(
10070        &mut self,
10071        _: &::git::RestoreFile,
10072        window: &mut Window,
10073        cx: &mut Context<Self>,
10074    ) {
10075        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10076        let mut buffer_ids = HashSet::default();
10077        let snapshot = self.buffer().read(cx).snapshot(cx);
10078        for selection in self.selections.all::<usize>(cx) {
10079            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10080        }
10081
10082        let buffer = self.buffer().read(cx);
10083        let ranges = buffer_ids
10084            .into_iter()
10085            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10086            .collect::<Vec<_>>();
10087
10088        self.restore_hunks_in_ranges(ranges, window, cx);
10089    }
10090
10091    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10092        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10093        let selections = self
10094            .selections
10095            .all(cx)
10096            .into_iter()
10097            .map(|s| s.range())
10098            .collect();
10099        self.restore_hunks_in_ranges(selections, window, cx);
10100    }
10101
10102    pub fn restore_hunks_in_ranges(
10103        &mut self,
10104        ranges: Vec<Range<Point>>,
10105        window: &mut Window,
10106        cx: &mut Context<Editor>,
10107    ) {
10108        let mut revert_changes = HashMap::default();
10109        let chunk_by = self
10110            .snapshot(window, cx)
10111            .hunks_for_ranges(ranges)
10112            .into_iter()
10113            .chunk_by(|hunk| hunk.buffer_id);
10114        for (buffer_id, hunks) in &chunk_by {
10115            let hunks = hunks.collect::<Vec<_>>();
10116            for hunk in &hunks {
10117                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10118            }
10119            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10120        }
10121        drop(chunk_by);
10122        if !revert_changes.is_empty() {
10123            self.transact(window, cx, |editor, window, cx| {
10124                editor.restore(revert_changes, window, cx);
10125            });
10126        }
10127    }
10128
10129    pub fn open_active_item_in_terminal(
10130        &mut self,
10131        _: &OpenInTerminal,
10132        window: &mut Window,
10133        cx: &mut Context<Self>,
10134    ) {
10135        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10136            let project_path = buffer.read(cx).project_path(cx)?;
10137            let project = self.project.as_ref()?.read(cx);
10138            let entry = project.entry_for_path(&project_path, cx)?;
10139            let parent = match &entry.canonical_path {
10140                Some(canonical_path) => canonical_path.to_path_buf(),
10141                None => project.absolute_path(&project_path, cx)?,
10142            }
10143            .parent()?
10144            .to_path_buf();
10145            Some(parent)
10146        }) {
10147            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10148        }
10149    }
10150
10151    fn set_breakpoint_context_menu(
10152        &mut self,
10153        display_row: DisplayRow,
10154        position: Option<Anchor>,
10155        clicked_point: gpui::Point<Pixels>,
10156        window: &mut Window,
10157        cx: &mut Context<Self>,
10158    ) {
10159        let source = self
10160            .buffer
10161            .read(cx)
10162            .snapshot(cx)
10163            .anchor_before(Point::new(display_row.0, 0u32));
10164
10165        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10166
10167        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10168            self,
10169            source,
10170            clicked_point,
10171            context_menu,
10172            window,
10173            cx,
10174        );
10175    }
10176
10177    fn add_edit_breakpoint_block(
10178        &mut self,
10179        anchor: Anchor,
10180        breakpoint: &Breakpoint,
10181        edit_action: BreakpointPromptEditAction,
10182        window: &mut Window,
10183        cx: &mut Context<Self>,
10184    ) {
10185        let weak_editor = cx.weak_entity();
10186        let bp_prompt = cx.new(|cx| {
10187            BreakpointPromptEditor::new(
10188                weak_editor,
10189                anchor,
10190                breakpoint.clone(),
10191                edit_action,
10192                window,
10193                cx,
10194            )
10195        });
10196
10197        let height = bp_prompt.update(cx, |this, cx| {
10198            this.prompt
10199                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10200        });
10201        let cloned_prompt = bp_prompt.clone();
10202        let blocks = vec![BlockProperties {
10203            style: BlockStyle::Sticky,
10204            placement: BlockPlacement::Above(anchor),
10205            height: Some(height),
10206            render: Arc::new(move |cx| {
10207                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10208                cloned_prompt.clone().into_any_element()
10209            }),
10210            priority: 0,
10211            render_in_minimap: true,
10212        }];
10213
10214        let focus_handle = bp_prompt.focus_handle(cx);
10215        window.focus(&focus_handle);
10216
10217        let block_ids = self.insert_blocks(blocks, None, cx);
10218        bp_prompt.update(cx, |prompt, _| {
10219            prompt.add_block_ids(block_ids);
10220        });
10221    }
10222
10223    pub(crate) fn breakpoint_at_row(
10224        &self,
10225        row: u32,
10226        window: &mut Window,
10227        cx: &mut Context<Self>,
10228    ) -> Option<(Anchor, Breakpoint)> {
10229        let snapshot = self.snapshot(window, cx);
10230        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10231
10232        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10233    }
10234
10235    pub(crate) fn breakpoint_at_anchor(
10236        &self,
10237        breakpoint_position: Anchor,
10238        snapshot: &EditorSnapshot,
10239        cx: &mut Context<Self>,
10240    ) -> Option<(Anchor, Breakpoint)> {
10241        let project = self.project.clone()?;
10242
10243        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10244            snapshot
10245                .buffer_snapshot
10246                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10247        })?;
10248
10249        let enclosing_excerpt = breakpoint_position.excerpt_id;
10250        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10251        let buffer_snapshot = buffer.read(cx).snapshot();
10252
10253        let row = buffer_snapshot
10254            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10255            .row;
10256
10257        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10258        let anchor_end = snapshot
10259            .buffer_snapshot
10260            .anchor_after(Point::new(row, line_len));
10261
10262        let bp = self
10263            .breakpoint_store
10264            .as_ref()?
10265            .read_with(cx, |breakpoint_store, cx| {
10266                breakpoint_store
10267                    .breakpoints(
10268                        &buffer,
10269                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10270                        &buffer_snapshot,
10271                        cx,
10272                    )
10273                    .next()
10274                    .and_then(|(bp, _)| {
10275                        let breakpoint_row = buffer_snapshot
10276                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10277                            .row;
10278
10279                        if breakpoint_row == row {
10280                            snapshot
10281                                .buffer_snapshot
10282                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10283                                .map(|position| (position, bp.bp.clone()))
10284                        } else {
10285                            None
10286                        }
10287                    })
10288            });
10289        bp
10290    }
10291
10292    pub fn edit_log_breakpoint(
10293        &mut self,
10294        _: &EditLogBreakpoint,
10295        window: &mut Window,
10296        cx: &mut Context<Self>,
10297    ) {
10298        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10299            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10300                message: None,
10301                state: BreakpointState::Enabled,
10302                condition: None,
10303                hit_condition: None,
10304            });
10305
10306            self.add_edit_breakpoint_block(
10307                anchor,
10308                &breakpoint,
10309                BreakpointPromptEditAction::Log,
10310                window,
10311                cx,
10312            );
10313        }
10314    }
10315
10316    fn breakpoints_at_cursors(
10317        &self,
10318        window: &mut Window,
10319        cx: &mut Context<Self>,
10320    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10321        let snapshot = self.snapshot(window, cx);
10322        let cursors = self
10323            .selections
10324            .disjoint_anchors()
10325            .into_iter()
10326            .map(|selection| {
10327                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10328
10329                let breakpoint_position = self
10330                    .breakpoint_at_row(cursor_position.row, window, cx)
10331                    .map(|bp| bp.0)
10332                    .unwrap_or_else(|| {
10333                        snapshot
10334                            .display_snapshot
10335                            .buffer_snapshot
10336                            .anchor_after(Point::new(cursor_position.row, 0))
10337                    });
10338
10339                let breakpoint = self
10340                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10341                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10342
10343                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10344            })
10345            // 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.
10346            .collect::<HashMap<Anchor, _>>();
10347
10348        cursors.into_iter().collect()
10349    }
10350
10351    pub fn enable_breakpoint(
10352        &mut self,
10353        _: &crate::actions::EnableBreakpoint,
10354        window: &mut Window,
10355        cx: &mut Context<Self>,
10356    ) {
10357        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10358            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10359                continue;
10360            };
10361            self.edit_breakpoint_at_anchor(
10362                anchor,
10363                breakpoint,
10364                BreakpointEditAction::InvertState,
10365                cx,
10366            );
10367        }
10368    }
10369
10370    pub fn disable_breakpoint(
10371        &mut self,
10372        _: &crate::actions::DisableBreakpoint,
10373        window: &mut Window,
10374        cx: &mut Context<Self>,
10375    ) {
10376        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10377            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10378                continue;
10379            };
10380            self.edit_breakpoint_at_anchor(
10381                anchor,
10382                breakpoint,
10383                BreakpointEditAction::InvertState,
10384                cx,
10385            );
10386        }
10387    }
10388
10389    pub fn toggle_breakpoint(
10390        &mut self,
10391        _: &crate::actions::ToggleBreakpoint,
10392        window: &mut Window,
10393        cx: &mut Context<Self>,
10394    ) {
10395        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10396            if let Some(breakpoint) = breakpoint {
10397                self.edit_breakpoint_at_anchor(
10398                    anchor,
10399                    breakpoint,
10400                    BreakpointEditAction::Toggle,
10401                    cx,
10402                );
10403            } else {
10404                self.edit_breakpoint_at_anchor(
10405                    anchor,
10406                    Breakpoint::new_standard(),
10407                    BreakpointEditAction::Toggle,
10408                    cx,
10409                );
10410            }
10411        }
10412    }
10413
10414    pub fn edit_breakpoint_at_anchor(
10415        &mut self,
10416        breakpoint_position: Anchor,
10417        breakpoint: Breakpoint,
10418        edit_action: BreakpointEditAction,
10419        cx: &mut Context<Self>,
10420    ) {
10421        let Some(breakpoint_store) = &self.breakpoint_store else {
10422            return;
10423        };
10424
10425        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10426            if breakpoint_position == Anchor::min() {
10427                self.buffer()
10428                    .read(cx)
10429                    .excerpt_buffer_ids()
10430                    .into_iter()
10431                    .next()
10432            } else {
10433                None
10434            }
10435        }) else {
10436            return;
10437        };
10438
10439        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10440            return;
10441        };
10442
10443        breakpoint_store.update(cx, |breakpoint_store, cx| {
10444            breakpoint_store.toggle_breakpoint(
10445                buffer,
10446                BreakpointWithPosition {
10447                    position: breakpoint_position.text_anchor,
10448                    bp: breakpoint,
10449                },
10450                edit_action,
10451                cx,
10452            );
10453        });
10454
10455        cx.notify();
10456    }
10457
10458    #[cfg(any(test, feature = "test-support"))]
10459    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10460        self.breakpoint_store.clone()
10461    }
10462
10463    pub fn prepare_restore_change(
10464        &self,
10465        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10466        hunk: &MultiBufferDiffHunk,
10467        cx: &mut App,
10468    ) -> Option<()> {
10469        if hunk.is_created_file() {
10470            return None;
10471        }
10472        let buffer = self.buffer.read(cx);
10473        let diff = buffer.diff_for(hunk.buffer_id)?;
10474        let buffer = buffer.buffer(hunk.buffer_id)?;
10475        let buffer = buffer.read(cx);
10476        let original_text = diff
10477            .read(cx)
10478            .base_text()
10479            .as_rope()
10480            .slice(hunk.diff_base_byte_range.clone());
10481        let buffer_snapshot = buffer.snapshot();
10482        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10483        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10484            probe
10485                .0
10486                .start
10487                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10488                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10489        }) {
10490            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10491            Some(())
10492        } else {
10493            None
10494        }
10495    }
10496
10497    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10498        self.manipulate_lines(window, cx, |lines| lines.reverse())
10499    }
10500
10501    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10502        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10503    }
10504
10505    fn manipulate_lines<Fn>(
10506        &mut self,
10507        window: &mut Window,
10508        cx: &mut Context<Self>,
10509        mut callback: Fn,
10510    ) where
10511        Fn: FnMut(&mut Vec<&str>),
10512    {
10513        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10514
10515        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10516        let buffer = self.buffer.read(cx).snapshot(cx);
10517
10518        let mut edits = Vec::new();
10519
10520        let selections = self.selections.all::<Point>(cx);
10521        let mut selections = selections.iter().peekable();
10522        let mut contiguous_row_selections = Vec::new();
10523        let mut new_selections = Vec::new();
10524        let mut added_lines = 0;
10525        let mut removed_lines = 0;
10526
10527        while let Some(selection) = selections.next() {
10528            let (start_row, end_row) = consume_contiguous_rows(
10529                &mut contiguous_row_selections,
10530                selection,
10531                &display_map,
10532                &mut selections,
10533            );
10534
10535            let start_point = Point::new(start_row.0, 0);
10536            let end_point = Point::new(
10537                end_row.previous_row().0,
10538                buffer.line_len(end_row.previous_row()),
10539            );
10540            let text = buffer
10541                .text_for_range(start_point..end_point)
10542                .collect::<String>();
10543
10544            let mut lines = text.split('\n').collect_vec();
10545
10546            let lines_before = lines.len();
10547            callback(&mut lines);
10548            let lines_after = lines.len();
10549
10550            edits.push((start_point..end_point, lines.join("\n")));
10551
10552            // Selections must change based on added and removed line count
10553            let start_row =
10554                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10555            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10556            new_selections.push(Selection {
10557                id: selection.id,
10558                start: start_row,
10559                end: end_row,
10560                goal: SelectionGoal::None,
10561                reversed: selection.reversed,
10562            });
10563
10564            if lines_after > lines_before {
10565                added_lines += lines_after - lines_before;
10566            } else if lines_before > lines_after {
10567                removed_lines += lines_before - lines_after;
10568            }
10569        }
10570
10571        self.transact(window, cx, |this, window, cx| {
10572            let buffer = this.buffer.update(cx, |buffer, cx| {
10573                buffer.edit(edits, None, cx);
10574                buffer.snapshot(cx)
10575            });
10576
10577            // Recalculate offsets on newly edited buffer
10578            let new_selections = new_selections
10579                .iter()
10580                .map(|s| {
10581                    let start_point = Point::new(s.start.0, 0);
10582                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10583                    Selection {
10584                        id: s.id,
10585                        start: buffer.point_to_offset(start_point),
10586                        end: buffer.point_to_offset(end_point),
10587                        goal: s.goal,
10588                        reversed: s.reversed,
10589                    }
10590                })
10591                .collect();
10592
10593            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10594                s.select(new_selections);
10595            });
10596
10597            this.request_autoscroll(Autoscroll::fit(), cx);
10598        });
10599    }
10600
10601    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10602        self.manipulate_text(window, cx, |text| {
10603            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10604            if has_upper_case_characters {
10605                text.to_lowercase()
10606            } else {
10607                text.to_uppercase()
10608            }
10609        })
10610    }
10611
10612    pub fn convert_to_upper_case(
10613        &mut self,
10614        _: &ConvertToUpperCase,
10615        window: &mut Window,
10616        cx: &mut Context<Self>,
10617    ) {
10618        self.manipulate_text(window, cx, |text| text.to_uppercase())
10619    }
10620
10621    pub fn convert_to_lower_case(
10622        &mut self,
10623        _: &ConvertToLowerCase,
10624        window: &mut Window,
10625        cx: &mut Context<Self>,
10626    ) {
10627        self.manipulate_text(window, cx, |text| text.to_lowercase())
10628    }
10629
10630    pub fn convert_to_title_case(
10631        &mut self,
10632        _: &ConvertToTitleCase,
10633        window: &mut Window,
10634        cx: &mut Context<Self>,
10635    ) {
10636        self.manipulate_text(window, cx, |text| {
10637            text.split('\n')
10638                .map(|line| line.to_case(Case::Title))
10639                .join("\n")
10640        })
10641    }
10642
10643    pub fn convert_to_snake_case(
10644        &mut self,
10645        _: &ConvertToSnakeCase,
10646        window: &mut Window,
10647        cx: &mut Context<Self>,
10648    ) {
10649        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10650    }
10651
10652    pub fn convert_to_kebab_case(
10653        &mut self,
10654        _: &ConvertToKebabCase,
10655        window: &mut Window,
10656        cx: &mut Context<Self>,
10657    ) {
10658        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10659    }
10660
10661    pub fn convert_to_upper_camel_case(
10662        &mut self,
10663        _: &ConvertToUpperCamelCase,
10664        window: &mut Window,
10665        cx: &mut Context<Self>,
10666    ) {
10667        self.manipulate_text(window, cx, |text| {
10668            text.split('\n')
10669                .map(|line| line.to_case(Case::UpperCamel))
10670                .join("\n")
10671        })
10672    }
10673
10674    pub fn convert_to_lower_camel_case(
10675        &mut self,
10676        _: &ConvertToLowerCamelCase,
10677        window: &mut Window,
10678        cx: &mut Context<Self>,
10679    ) {
10680        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10681    }
10682
10683    pub fn convert_to_opposite_case(
10684        &mut self,
10685        _: &ConvertToOppositeCase,
10686        window: &mut Window,
10687        cx: &mut Context<Self>,
10688    ) {
10689        self.manipulate_text(window, cx, |text| {
10690            text.chars()
10691                .fold(String::with_capacity(text.len()), |mut t, c| {
10692                    if c.is_uppercase() {
10693                        t.extend(c.to_lowercase());
10694                    } else {
10695                        t.extend(c.to_uppercase());
10696                    }
10697                    t
10698                })
10699        })
10700    }
10701
10702    pub fn convert_to_rot13(
10703        &mut self,
10704        _: &ConvertToRot13,
10705        window: &mut Window,
10706        cx: &mut Context<Self>,
10707    ) {
10708        self.manipulate_text(window, cx, |text| {
10709            text.chars()
10710                .map(|c| match c {
10711                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10712                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10713                    _ => c,
10714                })
10715                .collect()
10716        })
10717    }
10718
10719    pub fn convert_to_rot47(
10720        &mut self,
10721        _: &ConvertToRot47,
10722        window: &mut Window,
10723        cx: &mut Context<Self>,
10724    ) {
10725        self.manipulate_text(window, cx, |text| {
10726            text.chars()
10727                .map(|c| {
10728                    let code_point = c as u32;
10729                    if code_point >= 33 && code_point <= 126 {
10730                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10731                    }
10732                    c
10733                })
10734                .collect()
10735        })
10736    }
10737
10738    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10739    where
10740        Fn: FnMut(&str) -> String,
10741    {
10742        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10743        let buffer = self.buffer.read(cx).snapshot(cx);
10744
10745        let mut new_selections = Vec::new();
10746        let mut edits = Vec::new();
10747        let mut selection_adjustment = 0i32;
10748
10749        for selection in self.selections.all::<usize>(cx) {
10750            let selection_is_empty = selection.is_empty();
10751
10752            let (start, end) = if selection_is_empty {
10753                let word_range = movement::surrounding_word(
10754                    &display_map,
10755                    selection.start.to_display_point(&display_map),
10756                );
10757                let start = word_range.start.to_offset(&display_map, Bias::Left);
10758                let end = word_range.end.to_offset(&display_map, Bias::Left);
10759                (start, end)
10760            } else {
10761                (selection.start, selection.end)
10762            };
10763
10764            let text = buffer.text_for_range(start..end).collect::<String>();
10765            let old_length = text.len() as i32;
10766            let text = callback(&text);
10767
10768            new_selections.push(Selection {
10769                start: (start as i32 - selection_adjustment) as usize,
10770                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10771                goal: SelectionGoal::None,
10772                ..selection
10773            });
10774
10775            selection_adjustment += old_length - text.len() as i32;
10776
10777            edits.push((start..end, text));
10778        }
10779
10780        self.transact(window, cx, |this, window, cx| {
10781            this.buffer.update(cx, |buffer, cx| {
10782                buffer.edit(edits, None, cx);
10783            });
10784
10785            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10786                s.select(new_selections);
10787            });
10788
10789            this.request_autoscroll(Autoscroll::fit(), cx);
10790        });
10791    }
10792
10793    pub fn move_selection_on_drop(
10794        &mut self,
10795        selection: &Selection<Anchor>,
10796        target: DisplayPoint,
10797        is_cut: bool,
10798        window: &mut Window,
10799        cx: &mut Context<Self>,
10800    ) {
10801        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10802        let buffer = &display_map.buffer_snapshot;
10803        let mut edits = Vec::new();
10804        let insert_point = display_map
10805            .clip_point(target, Bias::Left)
10806            .to_point(&display_map);
10807        let text = buffer
10808            .text_for_range(selection.start..selection.end)
10809            .collect::<String>();
10810        if is_cut {
10811            edits.push(((selection.start..selection.end), String::new()));
10812        }
10813        let insert_anchor = buffer.anchor_before(insert_point);
10814        edits.push(((insert_anchor..insert_anchor), text));
10815        let last_edit_start = insert_anchor.bias_left(buffer);
10816        let last_edit_end = insert_anchor.bias_right(buffer);
10817        self.transact(window, cx, |this, window, cx| {
10818            this.buffer.update(cx, |buffer, cx| {
10819                buffer.edit(edits, None, cx);
10820            });
10821            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10822                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10823            });
10824        });
10825    }
10826
10827    pub fn clear_selection_drag_state(&mut self) {
10828        self.selection_drag_state = SelectionDragState::None;
10829    }
10830
10831    pub fn duplicate(
10832        &mut self,
10833        upwards: bool,
10834        whole_lines: bool,
10835        window: &mut Window,
10836        cx: &mut Context<Self>,
10837    ) {
10838        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10839
10840        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10841        let buffer = &display_map.buffer_snapshot;
10842        let selections = self.selections.all::<Point>(cx);
10843
10844        let mut edits = Vec::new();
10845        let mut selections_iter = selections.iter().peekable();
10846        while let Some(selection) = selections_iter.next() {
10847            let mut rows = selection.spanned_rows(false, &display_map);
10848            // duplicate line-wise
10849            if whole_lines || selection.start == selection.end {
10850                // Avoid duplicating the same lines twice.
10851                while let Some(next_selection) = selections_iter.peek() {
10852                    let next_rows = next_selection.spanned_rows(false, &display_map);
10853                    if next_rows.start < rows.end {
10854                        rows.end = next_rows.end;
10855                        selections_iter.next().unwrap();
10856                    } else {
10857                        break;
10858                    }
10859                }
10860
10861                // Copy the text from the selected row region and splice it either at the start
10862                // or end of the region.
10863                let start = Point::new(rows.start.0, 0);
10864                let end = Point::new(
10865                    rows.end.previous_row().0,
10866                    buffer.line_len(rows.end.previous_row()),
10867                );
10868                let text = buffer
10869                    .text_for_range(start..end)
10870                    .chain(Some("\n"))
10871                    .collect::<String>();
10872                let insert_location = if upwards {
10873                    Point::new(rows.end.0, 0)
10874                } else {
10875                    start
10876                };
10877                edits.push((insert_location..insert_location, text));
10878            } else {
10879                // duplicate character-wise
10880                let start = selection.start;
10881                let end = selection.end;
10882                let text = buffer.text_for_range(start..end).collect::<String>();
10883                edits.push((selection.end..selection.end, text));
10884            }
10885        }
10886
10887        self.transact(window, cx, |this, _, cx| {
10888            this.buffer.update(cx, |buffer, cx| {
10889                buffer.edit(edits, None, cx);
10890            });
10891
10892            this.request_autoscroll(Autoscroll::fit(), cx);
10893        });
10894    }
10895
10896    pub fn duplicate_line_up(
10897        &mut self,
10898        _: &DuplicateLineUp,
10899        window: &mut Window,
10900        cx: &mut Context<Self>,
10901    ) {
10902        self.duplicate(true, true, window, cx);
10903    }
10904
10905    pub fn duplicate_line_down(
10906        &mut self,
10907        _: &DuplicateLineDown,
10908        window: &mut Window,
10909        cx: &mut Context<Self>,
10910    ) {
10911        self.duplicate(false, true, window, cx);
10912    }
10913
10914    pub fn duplicate_selection(
10915        &mut self,
10916        _: &DuplicateSelection,
10917        window: &mut Window,
10918        cx: &mut Context<Self>,
10919    ) {
10920        self.duplicate(false, false, window, cx);
10921    }
10922
10923    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10924        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10925
10926        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10927        let buffer = self.buffer.read(cx).snapshot(cx);
10928
10929        let mut edits = Vec::new();
10930        let mut unfold_ranges = Vec::new();
10931        let mut refold_creases = Vec::new();
10932
10933        let selections = self.selections.all::<Point>(cx);
10934        let mut selections = selections.iter().peekable();
10935        let mut contiguous_row_selections = Vec::new();
10936        let mut new_selections = Vec::new();
10937
10938        while let Some(selection) = selections.next() {
10939            // Find all the selections that span a contiguous row range
10940            let (start_row, end_row) = consume_contiguous_rows(
10941                &mut contiguous_row_selections,
10942                selection,
10943                &display_map,
10944                &mut selections,
10945            );
10946
10947            // Move the text spanned by the row range to be before the line preceding the row range
10948            if start_row.0 > 0 {
10949                let range_to_move = Point::new(
10950                    start_row.previous_row().0,
10951                    buffer.line_len(start_row.previous_row()),
10952                )
10953                    ..Point::new(
10954                        end_row.previous_row().0,
10955                        buffer.line_len(end_row.previous_row()),
10956                    );
10957                let insertion_point = display_map
10958                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10959                    .0;
10960
10961                // Don't move lines across excerpts
10962                if buffer
10963                    .excerpt_containing(insertion_point..range_to_move.end)
10964                    .is_some()
10965                {
10966                    let text = buffer
10967                        .text_for_range(range_to_move.clone())
10968                        .flat_map(|s| s.chars())
10969                        .skip(1)
10970                        .chain(['\n'])
10971                        .collect::<String>();
10972
10973                    edits.push((
10974                        buffer.anchor_after(range_to_move.start)
10975                            ..buffer.anchor_before(range_to_move.end),
10976                        String::new(),
10977                    ));
10978                    let insertion_anchor = buffer.anchor_after(insertion_point);
10979                    edits.push((insertion_anchor..insertion_anchor, text));
10980
10981                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10982
10983                    // Move selections up
10984                    new_selections.extend(contiguous_row_selections.drain(..).map(
10985                        |mut selection| {
10986                            selection.start.row -= row_delta;
10987                            selection.end.row -= row_delta;
10988                            selection
10989                        },
10990                    ));
10991
10992                    // Move folds up
10993                    unfold_ranges.push(range_to_move.clone());
10994                    for fold in display_map.folds_in_range(
10995                        buffer.anchor_before(range_to_move.start)
10996                            ..buffer.anchor_after(range_to_move.end),
10997                    ) {
10998                        let mut start = fold.range.start.to_point(&buffer);
10999                        let mut end = fold.range.end.to_point(&buffer);
11000                        start.row -= row_delta;
11001                        end.row -= row_delta;
11002                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11003                    }
11004                }
11005            }
11006
11007            // If we didn't move line(s), preserve the existing selections
11008            new_selections.append(&mut contiguous_row_selections);
11009        }
11010
11011        self.transact(window, cx, |this, window, cx| {
11012            this.unfold_ranges(&unfold_ranges, true, true, cx);
11013            this.buffer.update(cx, |buffer, cx| {
11014                for (range, text) in edits {
11015                    buffer.edit([(range, text)], None, cx);
11016                }
11017            });
11018            this.fold_creases(refold_creases, true, window, cx);
11019            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11020                s.select(new_selections);
11021            })
11022        });
11023    }
11024
11025    pub fn move_line_down(
11026        &mut self,
11027        _: &MoveLineDown,
11028        window: &mut Window,
11029        cx: &mut Context<Self>,
11030    ) {
11031        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11032
11033        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11034        let buffer = self.buffer.read(cx).snapshot(cx);
11035
11036        let mut edits = Vec::new();
11037        let mut unfold_ranges = Vec::new();
11038        let mut refold_creases = Vec::new();
11039
11040        let selections = self.selections.all::<Point>(cx);
11041        let mut selections = selections.iter().peekable();
11042        let mut contiguous_row_selections = Vec::new();
11043        let mut new_selections = Vec::new();
11044
11045        while let Some(selection) = selections.next() {
11046            // Find all the selections that span a contiguous row range
11047            let (start_row, end_row) = consume_contiguous_rows(
11048                &mut contiguous_row_selections,
11049                selection,
11050                &display_map,
11051                &mut selections,
11052            );
11053
11054            // Move the text spanned by the row range to be after the last line of the row range
11055            if end_row.0 <= buffer.max_point().row {
11056                let range_to_move =
11057                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11058                let insertion_point = display_map
11059                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11060                    .0;
11061
11062                // Don't move lines across excerpt boundaries
11063                if buffer
11064                    .excerpt_containing(range_to_move.start..insertion_point)
11065                    .is_some()
11066                {
11067                    let mut text = String::from("\n");
11068                    text.extend(buffer.text_for_range(range_to_move.clone()));
11069                    text.pop(); // Drop trailing newline
11070                    edits.push((
11071                        buffer.anchor_after(range_to_move.start)
11072                            ..buffer.anchor_before(range_to_move.end),
11073                        String::new(),
11074                    ));
11075                    let insertion_anchor = buffer.anchor_after(insertion_point);
11076                    edits.push((insertion_anchor..insertion_anchor, text));
11077
11078                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11079
11080                    // Move selections down
11081                    new_selections.extend(contiguous_row_selections.drain(..).map(
11082                        |mut selection| {
11083                            selection.start.row += row_delta;
11084                            selection.end.row += row_delta;
11085                            selection
11086                        },
11087                    ));
11088
11089                    // Move folds down
11090                    unfold_ranges.push(range_to_move.clone());
11091                    for fold in display_map.folds_in_range(
11092                        buffer.anchor_before(range_to_move.start)
11093                            ..buffer.anchor_after(range_to_move.end),
11094                    ) {
11095                        let mut start = fold.range.start.to_point(&buffer);
11096                        let mut end = fold.range.end.to_point(&buffer);
11097                        start.row += row_delta;
11098                        end.row += row_delta;
11099                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11100                    }
11101                }
11102            }
11103
11104            // If we didn't move line(s), preserve the existing selections
11105            new_selections.append(&mut contiguous_row_selections);
11106        }
11107
11108        self.transact(window, cx, |this, window, cx| {
11109            this.unfold_ranges(&unfold_ranges, true, true, cx);
11110            this.buffer.update(cx, |buffer, cx| {
11111                for (range, text) in edits {
11112                    buffer.edit([(range, text)], None, cx);
11113                }
11114            });
11115            this.fold_creases(refold_creases, true, window, cx);
11116            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11117                s.select(new_selections)
11118            });
11119        });
11120    }
11121
11122    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11123        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11124        let text_layout_details = &self.text_layout_details(window);
11125        self.transact(window, cx, |this, window, cx| {
11126            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11127                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11128                s.move_with(|display_map, selection| {
11129                    if !selection.is_empty() {
11130                        return;
11131                    }
11132
11133                    let mut head = selection.head();
11134                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11135                    if head.column() == display_map.line_len(head.row()) {
11136                        transpose_offset = display_map
11137                            .buffer_snapshot
11138                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11139                    }
11140
11141                    if transpose_offset == 0 {
11142                        return;
11143                    }
11144
11145                    *head.column_mut() += 1;
11146                    head = display_map.clip_point(head, Bias::Right);
11147                    let goal = SelectionGoal::HorizontalPosition(
11148                        display_map
11149                            .x_for_display_point(head, text_layout_details)
11150                            .into(),
11151                    );
11152                    selection.collapse_to(head, goal);
11153
11154                    let transpose_start = display_map
11155                        .buffer_snapshot
11156                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11157                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11158                        let transpose_end = display_map
11159                            .buffer_snapshot
11160                            .clip_offset(transpose_offset + 1, Bias::Right);
11161                        if let Some(ch) =
11162                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11163                        {
11164                            edits.push((transpose_start..transpose_offset, String::new()));
11165                            edits.push((transpose_end..transpose_end, ch.to_string()));
11166                        }
11167                    }
11168                });
11169                edits
11170            });
11171            this.buffer
11172                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11173            let selections = this.selections.all::<usize>(cx);
11174            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11175                s.select(selections);
11176            });
11177        });
11178    }
11179
11180    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11181        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11182        self.rewrap_impl(RewrapOptions::default(), cx)
11183    }
11184
11185    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11186        let buffer = self.buffer.read(cx).snapshot(cx);
11187        let selections = self.selections.all::<Point>(cx);
11188
11189        // Shrink and split selections to respect paragraph boundaries.
11190        let ranges = selections.into_iter().flat_map(|selection| {
11191            let language_settings = buffer.language_settings_at(selection.head(), cx);
11192            let language_scope = buffer.language_scope_at(selection.head());
11193
11194            let Some(start_row) = (selection.start.row..=selection.end.row)
11195                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11196            else {
11197                return vec![];
11198            };
11199            let Some(end_row) = (selection.start.row..=selection.end.row)
11200                .rev()
11201                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11202            else {
11203                return vec![];
11204            };
11205
11206            let mut row = start_row;
11207            let mut ranges = Vec::new();
11208            while let Some(blank_row) =
11209                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11210            {
11211                let next_paragraph_start = (blank_row + 1..=end_row)
11212                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11213                    .unwrap();
11214                ranges.push((
11215                    language_settings.clone(),
11216                    language_scope.clone(),
11217                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11218                ));
11219                row = next_paragraph_start;
11220            }
11221            ranges.push((
11222                language_settings.clone(),
11223                language_scope.clone(),
11224                Point::new(row, 0)..Point::new(end_row, 0),
11225            ));
11226
11227            ranges
11228        });
11229
11230        let mut edits = Vec::new();
11231        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11232
11233        for (language_settings, language_scope, range) in ranges {
11234            let mut start_row = range.start.row;
11235            let mut end_row = range.end.row;
11236
11237            // Skip selections that overlap with a range that has already been rewrapped.
11238            let selection_range = start_row..end_row;
11239            if rewrapped_row_ranges
11240                .iter()
11241                .any(|range| range.overlaps(&selection_range))
11242            {
11243                continue;
11244            }
11245
11246            let tab_size = language_settings.tab_size;
11247
11248            // Since not all lines in the selection may be at the same indent
11249            // level, choose the indent size that is the most common between all
11250            // of the lines.
11251            //
11252            // If there is a tie, we use the deepest indent.
11253            let (indent_size, indent_end) = {
11254                let mut indent_size_occurrences = HashMap::default();
11255                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11256
11257                for row in start_row..=end_row {
11258                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11259                    rows_by_indent_size.entry(indent).or_default().push(row);
11260                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11261                }
11262
11263                let indent_size = indent_size_occurrences
11264                    .into_iter()
11265                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11266                    .map(|(indent, _)| indent)
11267                    .unwrap_or_default();
11268                let row = rows_by_indent_size[&indent_size][0];
11269                let indent_end = Point::new(row, indent_size.len);
11270
11271                (indent_size, indent_end)
11272            };
11273
11274            let mut line_prefix = indent_size.chars().collect::<String>();
11275
11276            let mut inside_comment = false;
11277            if let Some(comment_prefix) = language_scope.and_then(|language| {
11278                language
11279                    .line_comment_prefixes()
11280                    .iter()
11281                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11282                    .cloned()
11283            }) {
11284                line_prefix.push_str(&comment_prefix);
11285                inside_comment = true;
11286            }
11287
11288            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11289                RewrapBehavior::InComments => inside_comment,
11290                RewrapBehavior::InSelections => !range.is_empty(),
11291                RewrapBehavior::Anywhere => true,
11292            };
11293
11294            let should_rewrap = options.override_language_settings
11295                || allow_rewrap_based_on_language
11296                || self.hard_wrap.is_some();
11297            if !should_rewrap {
11298                continue;
11299            }
11300
11301            if range.is_empty() {
11302                'expand_upwards: while start_row > 0 {
11303                    let prev_row = start_row - 1;
11304                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11305                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11306                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11307                    {
11308                        start_row = prev_row;
11309                    } else {
11310                        break 'expand_upwards;
11311                    }
11312                }
11313
11314                'expand_downwards: while end_row < buffer.max_point().row {
11315                    let next_row = end_row + 1;
11316                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11317                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11318                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11319                    {
11320                        end_row = next_row;
11321                    } else {
11322                        break 'expand_downwards;
11323                    }
11324                }
11325            }
11326
11327            let start = Point::new(start_row, 0);
11328            let start_offset = start.to_offset(&buffer);
11329            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11330            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11331            let Some(lines_without_prefixes) = selection_text
11332                .lines()
11333                .map(|line| {
11334                    line.strip_prefix(&line_prefix)
11335                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11336                        .with_context(|| {
11337                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11338                        })
11339                })
11340                .collect::<Result<Vec<_>, _>>()
11341                .log_err()
11342            else {
11343                continue;
11344            };
11345
11346            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11347                buffer
11348                    .language_settings_at(Point::new(start_row, 0), cx)
11349                    .preferred_line_length as usize
11350            });
11351            let wrapped_text = wrap_with_prefix(
11352                line_prefix,
11353                lines_without_prefixes.join("\n"),
11354                wrap_column,
11355                tab_size,
11356                options.preserve_existing_whitespace,
11357            );
11358
11359            // TODO: should always use char-based diff while still supporting cursor behavior that
11360            // matches vim.
11361            let mut diff_options = DiffOptions::default();
11362            if options.override_language_settings {
11363                diff_options.max_word_diff_len = 0;
11364                diff_options.max_word_diff_line_count = 0;
11365            } else {
11366                diff_options.max_word_diff_len = usize::MAX;
11367                diff_options.max_word_diff_line_count = usize::MAX;
11368            }
11369
11370            for (old_range, new_text) in
11371                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11372            {
11373                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11374                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11375                edits.push((edit_start..edit_end, new_text));
11376            }
11377
11378            rewrapped_row_ranges.push(start_row..=end_row);
11379        }
11380
11381        self.buffer
11382            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11383    }
11384
11385    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11386        let mut text = String::new();
11387        let buffer = self.buffer.read(cx).snapshot(cx);
11388        let mut selections = self.selections.all::<Point>(cx);
11389        let mut clipboard_selections = Vec::with_capacity(selections.len());
11390        {
11391            let max_point = buffer.max_point();
11392            let mut is_first = true;
11393            for selection in &mut selections {
11394                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11395                if is_entire_line {
11396                    selection.start = Point::new(selection.start.row, 0);
11397                    if !selection.is_empty() && selection.end.column == 0 {
11398                        selection.end = cmp::min(max_point, selection.end);
11399                    } else {
11400                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11401                    }
11402                    selection.goal = SelectionGoal::None;
11403                }
11404                if is_first {
11405                    is_first = false;
11406                } else {
11407                    text += "\n";
11408                }
11409                let mut len = 0;
11410                for chunk in buffer.text_for_range(selection.start..selection.end) {
11411                    text.push_str(chunk);
11412                    len += chunk.len();
11413                }
11414                clipboard_selections.push(ClipboardSelection {
11415                    len,
11416                    is_entire_line,
11417                    first_line_indent: buffer
11418                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11419                        .len,
11420                });
11421            }
11422        }
11423
11424        self.transact(window, cx, |this, window, cx| {
11425            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11426                s.select(selections);
11427            });
11428            this.insert("", window, cx);
11429        });
11430        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11431    }
11432
11433    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11434        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11435        let item = self.cut_common(window, cx);
11436        cx.write_to_clipboard(item);
11437    }
11438
11439    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11440        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11441        self.change_selections(None, window, cx, |s| {
11442            s.move_with(|snapshot, sel| {
11443                if sel.is_empty() {
11444                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11445                }
11446            });
11447        });
11448        let item = self.cut_common(window, cx);
11449        cx.set_global(KillRing(item))
11450    }
11451
11452    pub fn kill_ring_yank(
11453        &mut self,
11454        _: &KillRingYank,
11455        window: &mut Window,
11456        cx: &mut Context<Self>,
11457    ) {
11458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11459        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11460            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11461                (kill_ring.text().to_string(), kill_ring.metadata_json())
11462            } else {
11463                return;
11464            }
11465        } else {
11466            return;
11467        };
11468        self.do_paste(&text, metadata, false, window, cx);
11469    }
11470
11471    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11472        self.do_copy(true, cx);
11473    }
11474
11475    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11476        self.do_copy(false, cx);
11477    }
11478
11479    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11480        let selections = self.selections.all::<Point>(cx);
11481        let buffer = self.buffer.read(cx).read(cx);
11482        let mut text = String::new();
11483
11484        let mut clipboard_selections = Vec::with_capacity(selections.len());
11485        {
11486            let max_point = buffer.max_point();
11487            let mut is_first = true;
11488            for selection in &selections {
11489                let mut start = selection.start;
11490                let mut end = selection.end;
11491                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11492                if is_entire_line {
11493                    start = Point::new(start.row, 0);
11494                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11495                }
11496
11497                let mut trimmed_selections = Vec::new();
11498                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11499                    let row = MultiBufferRow(start.row);
11500                    let first_indent = buffer.indent_size_for_line(row);
11501                    if first_indent.len == 0 || start.column > first_indent.len {
11502                        trimmed_selections.push(start..end);
11503                    } else {
11504                        trimmed_selections.push(
11505                            Point::new(row.0, first_indent.len)
11506                                ..Point::new(row.0, buffer.line_len(row)),
11507                        );
11508                        for row in start.row + 1..=end.row {
11509                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11510                            if row == end.row {
11511                                line_len = end.column;
11512                            }
11513                            if line_len == 0 {
11514                                trimmed_selections
11515                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11516                                continue;
11517                            }
11518                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11519                            if row_indent_size.len >= first_indent.len {
11520                                trimmed_selections.push(
11521                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11522                                );
11523                            } else {
11524                                trimmed_selections.clear();
11525                                trimmed_selections.push(start..end);
11526                                break;
11527                            }
11528                        }
11529                    }
11530                } else {
11531                    trimmed_selections.push(start..end);
11532                }
11533
11534                for trimmed_range in trimmed_selections {
11535                    if is_first {
11536                        is_first = false;
11537                    } else {
11538                        text += "\n";
11539                    }
11540                    let mut len = 0;
11541                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11542                        text.push_str(chunk);
11543                        len += chunk.len();
11544                    }
11545                    clipboard_selections.push(ClipboardSelection {
11546                        len,
11547                        is_entire_line,
11548                        first_line_indent: buffer
11549                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11550                            .len,
11551                    });
11552                }
11553            }
11554        }
11555
11556        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11557            text,
11558            clipboard_selections,
11559        ));
11560    }
11561
11562    pub fn do_paste(
11563        &mut self,
11564        text: &String,
11565        clipboard_selections: Option<Vec<ClipboardSelection>>,
11566        handle_entire_lines: bool,
11567        window: &mut Window,
11568        cx: &mut Context<Self>,
11569    ) {
11570        if self.read_only(cx) {
11571            return;
11572        }
11573
11574        let clipboard_text = Cow::Borrowed(text);
11575
11576        self.transact(window, cx, |this, window, cx| {
11577            if let Some(mut clipboard_selections) = clipboard_selections {
11578                let old_selections = this.selections.all::<usize>(cx);
11579                let all_selections_were_entire_line =
11580                    clipboard_selections.iter().all(|s| s.is_entire_line);
11581                let first_selection_indent_column =
11582                    clipboard_selections.first().map(|s| s.first_line_indent);
11583                if clipboard_selections.len() != old_selections.len() {
11584                    clipboard_selections.drain(..);
11585                }
11586                let cursor_offset = this.selections.last::<usize>(cx).head();
11587                let mut auto_indent_on_paste = true;
11588
11589                this.buffer.update(cx, |buffer, cx| {
11590                    let snapshot = buffer.read(cx);
11591                    auto_indent_on_paste = snapshot
11592                        .language_settings_at(cursor_offset, cx)
11593                        .auto_indent_on_paste;
11594
11595                    let mut start_offset = 0;
11596                    let mut edits = Vec::new();
11597                    let mut original_indent_columns = Vec::new();
11598                    for (ix, selection) in old_selections.iter().enumerate() {
11599                        let to_insert;
11600                        let entire_line;
11601                        let original_indent_column;
11602                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11603                            let end_offset = start_offset + clipboard_selection.len;
11604                            to_insert = &clipboard_text[start_offset..end_offset];
11605                            entire_line = clipboard_selection.is_entire_line;
11606                            start_offset = end_offset + 1;
11607                            original_indent_column = Some(clipboard_selection.first_line_indent);
11608                        } else {
11609                            to_insert = clipboard_text.as_str();
11610                            entire_line = all_selections_were_entire_line;
11611                            original_indent_column = first_selection_indent_column
11612                        }
11613
11614                        // If the corresponding selection was empty when this slice of the
11615                        // clipboard text was written, then the entire line containing the
11616                        // selection was copied. If this selection is also currently empty,
11617                        // then paste the line before the current line of the buffer.
11618                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11619                            let column = selection.start.to_point(&snapshot).column as usize;
11620                            let line_start = selection.start - column;
11621                            line_start..line_start
11622                        } else {
11623                            selection.range()
11624                        };
11625
11626                        edits.push((range, to_insert));
11627                        original_indent_columns.push(original_indent_column);
11628                    }
11629                    drop(snapshot);
11630
11631                    buffer.edit(
11632                        edits,
11633                        if auto_indent_on_paste {
11634                            Some(AutoindentMode::Block {
11635                                original_indent_columns,
11636                            })
11637                        } else {
11638                            None
11639                        },
11640                        cx,
11641                    );
11642                });
11643
11644                let selections = this.selections.all::<usize>(cx);
11645                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11646                    s.select(selections)
11647                });
11648            } else {
11649                this.insert(&clipboard_text, window, cx);
11650            }
11651        });
11652    }
11653
11654    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11655        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11656        if let Some(item) = cx.read_from_clipboard() {
11657            let entries = item.entries();
11658
11659            match entries.first() {
11660                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11661                // of all the pasted entries.
11662                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11663                    .do_paste(
11664                        clipboard_string.text(),
11665                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11666                        true,
11667                        window,
11668                        cx,
11669                    ),
11670                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11671            }
11672        }
11673    }
11674
11675    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11676        if self.read_only(cx) {
11677            return;
11678        }
11679
11680        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11681
11682        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11683            if let Some((selections, _)) =
11684                self.selection_history.transaction(transaction_id).cloned()
11685            {
11686                self.change_selections(None, window, cx, |s| {
11687                    s.select_anchors(selections.to_vec());
11688                });
11689            } else {
11690                log::error!(
11691                    "No entry in selection_history found for undo. \
11692                     This may correspond to a bug where undo does not update the selection. \
11693                     If this is occurring, please add details to \
11694                     https://github.com/zed-industries/zed/issues/22692"
11695                );
11696            }
11697            self.request_autoscroll(Autoscroll::fit(), cx);
11698            self.unmark_text(window, cx);
11699            self.refresh_inline_completion(true, false, window, cx);
11700            cx.emit(EditorEvent::Edited { transaction_id });
11701            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11702        }
11703    }
11704
11705    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11706        if self.read_only(cx) {
11707            return;
11708        }
11709
11710        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11711
11712        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11713            if let Some((_, Some(selections))) =
11714                self.selection_history.transaction(transaction_id).cloned()
11715            {
11716                self.change_selections(None, window, cx, |s| {
11717                    s.select_anchors(selections.to_vec());
11718                });
11719            } else {
11720                log::error!(
11721                    "No entry in selection_history found for redo. \
11722                     This may correspond to a bug where undo does not update the selection. \
11723                     If this is occurring, please add details to \
11724                     https://github.com/zed-industries/zed/issues/22692"
11725                );
11726            }
11727            self.request_autoscroll(Autoscroll::fit(), cx);
11728            self.unmark_text(window, cx);
11729            self.refresh_inline_completion(true, false, window, cx);
11730            cx.emit(EditorEvent::Edited { transaction_id });
11731        }
11732    }
11733
11734    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11735        self.buffer
11736            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11737    }
11738
11739    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11740        self.buffer
11741            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11742    }
11743
11744    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11745        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11746        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11747            s.move_with(|map, selection| {
11748                let cursor = if selection.is_empty() {
11749                    movement::left(map, selection.start)
11750                } else {
11751                    selection.start
11752                };
11753                selection.collapse_to(cursor, SelectionGoal::None);
11754            });
11755        })
11756    }
11757
11758    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11759        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11760        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11761            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11762        })
11763    }
11764
11765    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11766        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11767        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11768            s.move_with(|map, selection| {
11769                let cursor = if selection.is_empty() {
11770                    movement::right(map, selection.end)
11771                } else {
11772                    selection.end
11773                };
11774                selection.collapse_to(cursor, SelectionGoal::None)
11775            });
11776        })
11777    }
11778
11779    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11780        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11781        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11782            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11783        })
11784    }
11785
11786    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11787        if self.take_rename(true, window, cx).is_some() {
11788            return;
11789        }
11790
11791        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11792            cx.propagate();
11793            return;
11794        }
11795
11796        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11797
11798        let text_layout_details = &self.text_layout_details(window);
11799        let selection_count = self.selections.count();
11800        let first_selection = self.selections.first_anchor();
11801
11802        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11803            s.move_with(|map, selection| {
11804                if !selection.is_empty() {
11805                    selection.goal = SelectionGoal::None;
11806                }
11807                let (cursor, goal) = movement::up(
11808                    map,
11809                    selection.start,
11810                    selection.goal,
11811                    false,
11812                    text_layout_details,
11813                );
11814                selection.collapse_to(cursor, goal);
11815            });
11816        });
11817
11818        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11819        {
11820            cx.propagate();
11821        }
11822    }
11823
11824    pub fn move_up_by_lines(
11825        &mut self,
11826        action: &MoveUpByLines,
11827        window: &mut Window,
11828        cx: &mut Context<Self>,
11829    ) {
11830        if self.take_rename(true, window, cx).is_some() {
11831            return;
11832        }
11833
11834        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11835            cx.propagate();
11836            return;
11837        }
11838
11839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11840
11841        let text_layout_details = &self.text_layout_details(window);
11842
11843        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11844            s.move_with(|map, selection| {
11845                if !selection.is_empty() {
11846                    selection.goal = SelectionGoal::None;
11847                }
11848                let (cursor, goal) = movement::up_by_rows(
11849                    map,
11850                    selection.start,
11851                    action.lines,
11852                    selection.goal,
11853                    false,
11854                    text_layout_details,
11855                );
11856                selection.collapse_to(cursor, goal);
11857            });
11858        })
11859    }
11860
11861    pub fn move_down_by_lines(
11862        &mut self,
11863        action: &MoveDownByLines,
11864        window: &mut Window,
11865        cx: &mut Context<Self>,
11866    ) {
11867        if self.take_rename(true, window, cx).is_some() {
11868            return;
11869        }
11870
11871        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11872            cx.propagate();
11873            return;
11874        }
11875
11876        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11877
11878        let text_layout_details = &self.text_layout_details(window);
11879
11880        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11881            s.move_with(|map, selection| {
11882                if !selection.is_empty() {
11883                    selection.goal = SelectionGoal::None;
11884                }
11885                let (cursor, goal) = movement::down_by_rows(
11886                    map,
11887                    selection.start,
11888                    action.lines,
11889                    selection.goal,
11890                    false,
11891                    text_layout_details,
11892                );
11893                selection.collapse_to(cursor, goal);
11894            });
11895        })
11896    }
11897
11898    pub fn select_down_by_lines(
11899        &mut self,
11900        action: &SelectDownByLines,
11901        window: &mut Window,
11902        cx: &mut Context<Self>,
11903    ) {
11904        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11905        let text_layout_details = &self.text_layout_details(window);
11906        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11907            s.move_heads_with(|map, head, goal| {
11908                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11909            })
11910        })
11911    }
11912
11913    pub fn select_up_by_lines(
11914        &mut self,
11915        action: &SelectUpByLines,
11916        window: &mut Window,
11917        cx: &mut Context<Self>,
11918    ) {
11919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11920        let text_layout_details = &self.text_layout_details(window);
11921        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11922            s.move_heads_with(|map, head, goal| {
11923                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11924            })
11925        })
11926    }
11927
11928    pub fn select_page_up(
11929        &mut self,
11930        _: &SelectPageUp,
11931        window: &mut Window,
11932        cx: &mut Context<Self>,
11933    ) {
11934        let Some(row_count) = self.visible_row_count() else {
11935            return;
11936        };
11937
11938        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11939
11940        let text_layout_details = &self.text_layout_details(window);
11941
11942        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11943            s.move_heads_with(|map, head, goal| {
11944                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11945            })
11946        })
11947    }
11948
11949    pub fn move_page_up(
11950        &mut self,
11951        action: &MovePageUp,
11952        window: &mut Window,
11953        cx: &mut Context<Self>,
11954    ) {
11955        if self.take_rename(true, window, cx).is_some() {
11956            return;
11957        }
11958
11959        if self
11960            .context_menu
11961            .borrow_mut()
11962            .as_mut()
11963            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11964            .unwrap_or(false)
11965        {
11966            return;
11967        }
11968
11969        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11970            cx.propagate();
11971            return;
11972        }
11973
11974        let Some(row_count) = self.visible_row_count() else {
11975            return;
11976        };
11977
11978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11979
11980        let autoscroll = if action.center_cursor {
11981            Autoscroll::center()
11982        } else {
11983            Autoscroll::fit()
11984        };
11985
11986        let text_layout_details = &self.text_layout_details(window);
11987
11988        self.change_selections(Some(autoscroll), window, cx, |s| {
11989            s.move_with(|map, selection| {
11990                if !selection.is_empty() {
11991                    selection.goal = SelectionGoal::None;
11992                }
11993                let (cursor, goal) = movement::up_by_rows(
11994                    map,
11995                    selection.end,
11996                    row_count,
11997                    selection.goal,
11998                    false,
11999                    text_layout_details,
12000                );
12001                selection.collapse_to(cursor, goal);
12002            });
12003        });
12004    }
12005
12006    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12007        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12008        let text_layout_details = &self.text_layout_details(window);
12009        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12010            s.move_heads_with(|map, head, goal| {
12011                movement::up(map, head, goal, false, text_layout_details)
12012            })
12013        })
12014    }
12015
12016    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12017        self.take_rename(true, window, cx);
12018
12019        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12020            cx.propagate();
12021            return;
12022        }
12023
12024        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12025
12026        let text_layout_details = &self.text_layout_details(window);
12027        let selection_count = self.selections.count();
12028        let first_selection = self.selections.first_anchor();
12029
12030        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12031            s.move_with(|map, selection| {
12032                if !selection.is_empty() {
12033                    selection.goal = SelectionGoal::None;
12034                }
12035                let (cursor, goal) = movement::down(
12036                    map,
12037                    selection.end,
12038                    selection.goal,
12039                    false,
12040                    text_layout_details,
12041                );
12042                selection.collapse_to(cursor, goal);
12043            });
12044        });
12045
12046        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12047        {
12048            cx.propagate();
12049        }
12050    }
12051
12052    pub fn select_page_down(
12053        &mut self,
12054        _: &SelectPageDown,
12055        window: &mut Window,
12056        cx: &mut Context<Self>,
12057    ) {
12058        let Some(row_count) = self.visible_row_count() else {
12059            return;
12060        };
12061
12062        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12063
12064        let text_layout_details = &self.text_layout_details(window);
12065
12066        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12067            s.move_heads_with(|map, head, goal| {
12068                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12069            })
12070        })
12071    }
12072
12073    pub fn move_page_down(
12074        &mut self,
12075        action: &MovePageDown,
12076        window: &mut Window,
12077        cx: &mut Context<Self>,
12078    ) {
12079        if self.take_rename(true, window, cx).is_some() {
12080            return;
12081        }
12082
12083        if self
12084            .context_menu
12085            .borrow_mut()
12086            .as_mut()
12087            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12088            .unwrap_or(false)
12089        {
12090            return;
12091        }
12092
12093        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12094            cx.propagate();
12095            return;
12096        }
12097
12098        let Some(row_count) = self.visible_row_count() else {
12099            return;
12100        };
12101
12102        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12103
12104        let autoscroll = if action.center_cursor {
12105            Autoscroll::center()
12106        } else {
12107            Autoscroll::fit()
12108        };
12109
12110        let text_layout_details = &self.text_layout_details(window);
12111        self.change_selections(Some(autoscroll), window, cx, |s| {
12112            s.move_with(|map, selection| {
12113                if !selection.is_empty() {
12114                    selection.goal = SelectionGoal::None;
12115                }
12116                let (cursor, goal) = movement::down_by_rows(
12117                    map,
12118                    selection.end,
12119                    row_count,
12120                    selection.goal,
12121                    false,
12122                    text_layout_details,
12123                );
12124                selection.collapse_to(cursor, goal);
12125            });
12126        });
12127    }
12128
12129    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12130        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12131        let text_layout_details = &self.text_layout_details(window);
12132        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12133            s.move_heads_with(|map, head, goal| {
12134                movement::down(map, head, goal, false, text_layout_details)
12135            })
12136        });
12137    }
12138
12139    pub fn context_menu_first(
12140        &mut self,
12141        _: &ContextMenuFirst,
12142        window: &mut Window,
12143        cx: &mut Context<Self>,
12144    ) {
12145        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12146            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12147        }
12148    }
12149
12150    pub fn context_menu_prev(
12151        &mut self,
12152        _: &ContextMenuPrevious,
12153        window: &mut Window,
12154        cx: &mut Context<Self>,
12155    ) {
12156        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12157            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12158        }
12159    }
12160
12161    pub fn context_menu_next(
12162        &mut self,
12163        _: &ContextMenuNext,
12164        window: &mut Window,
12165        cx: &mut Context<Self>,
12166    ) {
12167        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12168            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12169        }
12170    }
12171
12172    pub fn context_menu_last(
12173        &mut self,
12174        _: &ContextMenuLast,
12175        window: &mut Window,
12176        cx: &mut Context<Self>,
12177    ) {
12178        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12179            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12180        }
12181    }
12182
12183    pub fn move_to_previous_word_start(
12184        &mut self,
12185        _: &MoveToPreviousWordStart,
12186        window: &mut Window,
12187        cx: &mut Context<Self>,
12188    ) {
12189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12190        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12191            s.move_cursors_with(|map, head, _| {
12192                (
12193                    movement::previous_word_start(map, head),
12194                    SelectionGoal::None,
12195                )
12196            });
12197        })
12198    }
12199
12200    pub fn move_to_previous_subword_start(
12201        &mut self,
12202        _: &MoveToPreviousSubwordStart,
12203        window: &mut Window,
12204        cx: &mut Context<Self>,
12205    ) {
12206        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12207        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12208            s.move_cursors_with(|map, head, _| {
12209                (
12210                    movement::previous_subword_start(map, head),
12211                    SelectionGoal::None,
12212                )
12213            });
12214        })
12215    }
12216
12217    pub fn select_to_previous_word_start(
12218        &mut self,
12219        _: &SelectToPreviousWordStart,
12220        window: &mut Window,
12221        cx: &mut Context<Self>,
12222    ) {
12223        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12224        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12225            s.move_heads_with(|map, head, _| {
12226                (
12227                    movement::previous_word_start(map, head),
12228                    SelectionGoal::None,
12229                )
12230            });
12231        })
12232    }
12233
12234    pub fn select_to_previous_subword_start(
12235        &mut self,
12236        _: &SelectToPreviousSubwordStart,
12237        window: &mut Window,
12238        cx: &mut Context<Self>,
12239    ) {
12240        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12241        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12242            s.move_heads_with(|map, head, _| {
12243                (
12244                    movement::previous_subword_start(map, head),
12245                    SelectionGoal::None,
12246                )
12247            });
12248        })
12249    }
12250
12251    pub fn delete_to_previous_word_start(
12252        &mut self,
12253        action: &DeleteToPreviousWordStart,
12254        window: &mut Window,
12255        cx: &mut Context<Self>,
12256    ) {
12257        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12258        self.transact(window, cx, |this, window, cx| {
12259            this.select_autoclose_pair(window, cx);
12260            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12261                s.move_with(|map, selection| {
12262                    if selection.is_empty() {
12263                        let cursor = if action.ignore_newlines {
12264                            movement::previous_word_start(map, selection.head())
12265                        } else {
12266                            movement::previous_word_start_or_newline(map, selection.head())
12267                        };
12268                        selection.set_head(cursor, SelectionGoal::None);
12269                    }
12270                });
12271            });
12272            this.insert("", window, cx);
12273        });
12274    }
12275
12276    pub fn delete_to_previous_subword_start(
12277        &mut self,
12278        _: &DeleteToPreviousSubwordStart,
12279        window: &mut Window,
12280        cx: &mut Context<Self>,
12281    ) {
12282        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12283        self.transact(window, cx, |this, window, cx| {
12284            this.select_autoclose_pair(window, cx);
12285            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12286                s.move_with(|map, selection| {
12287                    if selection.is_empty() {
12288                        let cursor = movement::previous_subword_start(map, selection.head());
12289                        selection.set_head(cursor, SelectionGoal::None);
12290                    }
12291                });
12292            });
12293            this.insert("", window, cx);
12294        });
12295    }
12296
12297    pub fn move_to_next_word_end(
12298        &mut self,
12299        _: &MoveToNextWordEnd,
12300        window: &mut Window,
12301        cx: &mut Context<Self>,
12302    ) {
12303        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12304        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12305            s.move_cursors_with(|map, head, _| {
12306                (movement::next_word_end(map, head), SelectionGoal::None)
12307            });
12308        })
12309    }
12310
12311    pub fn move_to_next_subword_end(
12312        &mut self,
12313        _: &MoveToNextSubwordEnd,
12314        window: &mut Window,
12315        cx: &mut Context<Self>,
12316    ) {
12317        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12318        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12319            s.move_cursors_with(|map, head, _| {
12320                (movement::next_subword_end(map, head), SelectionGoal::None)
12321            });
12322        })
12323    }
12324
12325    pub fn select_to_next_word_end(
12326        &mut self,
12327        _: &SelectToNextWordEnd,
12328        window: &mut Window,
12329        cx: &mut Context<Self>,
12330    ) {
12331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12332        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12333            s.move_heads_with(|map, head, _| {
12334                (movement::next_word_end(map, head), SelectionGoal::None)
12335            });
12336        })
12337    }
12338
12339    pub fn select_to_next_subword_end(
12340        &mut self,
12341        _: &SelectToNextSubwordEnd,
12342        window: &mut Window,
12343        cx: &mut Context<Self>,
12344    ) {
12345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12346        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12347            s.move_heads_with(|map, head, _| {
12348                (movement::next_subword_end(map, head), SelectionGoal::None)
12349            });
12350        })
12351    }
12352
12353    pub fn delete_to_next_word_end(
12354        &mut self,
12355        action: &DeleteToNextWordEnd,
12356        window: &mut Window,
12357        cx: &mut Context<Self>,
12358    ) {
12359        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12360        self.transact(window, cx, |this, window, cx| {
12361            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12362                s.move_with(|map, selection| {
12363                    if selection.is_empty() {
12364                        let cursor = if action.ignore_newlines {
12365                            movement::next_word_end(map, selection.head())
12366                        } else {
12367                            movement::next_word_end_or_newline(map, selection.head())
12368                        };
12369                        selection.set_head(cursor, SelectionGoal::None);
12370                    }
12371                });
12372            });
12373            this.insert("", window, cx);
12374        });
12375    }
12376
12377    pub fn delete_to_next_subword_end(
12378        &mut self,
12379        _: &DeleteToNextSubwordEnd,
12380        window: &mut Window,
12381        cx: &mut Context<Self>,
12382    ) {
12383        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12384        self.transact(window, cx, |this, window, cx| {
12385            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12386                s.move_with(|map, selection| {
12387                    if selection.is_empty() {
12388                        let cursor = movement::next_subword_end(map, selection.head());
12389                        selection.set_head(cursor, SelectionGoal::None);
12390                    }
12391                });
12392            });
12393            this.insert("", window, cx);
12394        });
12395    }
12396
12397    pub fn move_to_beginning_of_line(
12398        &mut self,
12399        action: &MoveToBeginningOfLine,
12400        window: &mut Window,
12401        cx: &mut Context<Self>,
12402    ) {
12403        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12404        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12405            s.move_cursors_with(|map, head, _| {
12406                (
12407                    movement::indented_line_beginning(
12408                        map,
12409                        head,
12410                        action.stop_at_soft_wraps,
12411                        action.stop_at_indent,
12412                    ),
12413                    SelectionGoal::None,
12414                )
12415            });
12416        })
12417    }
12418
12419    pub fn select_to_beginning_of_line(
12420        &mut self,
12421        action: &SelectToBeginningOfLine,
12422        window: &mut Window,
12423        cx: &mut Context<Self>,
12424    ) {
12425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12426        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12427            s.move_heads_with(|map, head, _| {
12428                (
12429                    movement::indented_line_beginning(
12430                        map,
12431                        head,
12432                        action.stop_at_soft_wraps,
12433                        action.stop_at_indent,
12434                    ),
12435                    SelectionGoal::None,
12436                )
12437            });
12438        });
12439    }
12440
12441    pub fn delete_to_beginning_of_line(
12442        &mut self,
12443        action: &DeleteToBeginningOfLine,
12444        window: &mut Window,
12445        cx: &mut Context<Self>,
12446    ) {
12447        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12448        self.transact(window, cx, |this, window, cx| {
12449            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12450                s.move_with(|_, selection| {
12451                    selection.reversed = true;
12452                });
12453            });
12454
12455            this.select_to_beginning_of_line(
12456                &SelectToBeginningOfLine {
12457                    stop_at_soft_wraps: false,
12458                    stop_at_indent: action.stop_at_indent,
12459                },
12460                window,
12461                cx,
12462            );
12463            this.backspace(&Backspace, window, cx);
12464        });
12465    }
12466
12467    pub fn move_to_end_of_line(
12468        &mut self,
12469        action: &MoveToEndOfLine,
12470        window: &mut Window,
12471        cx: &mut Context<Self>,
12472    ) {
12473        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12474        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12475            s.move_cursors_with(|map, head, _| {
12476                (
12477                    movement::line_end(map, head, action.stop_at_soft_wraps),
12478                    SelectionGoal::None,
12479                )
12480            });
12481        })
12482    }
12483
12484    pub fn select_to_end_of_line(
12485        &mut self,
12486        action: &SelectToEndOfLine,
12487        window: &mut Window,
12488        cx: &mut Context<Self>,
12489    ) {
12490        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12491        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12492            s.move_heads_with(|map, head, _| {
12493                (
12494                    movement::line_end(map, head, action.stop_at_soft_wraps),
12495                    SelectionGoal::None,
12496                )
12497            });
12498        })
12499    }
12500
12501    pub fn delete_to_end_of_line(
12502        &mut self,
12503        _: &DeleteToEndOfLine,
12504        window: &mut Window,
12505        cx: &mut Context<Self>,
12506    ) {
12507        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12508        self.transact(window, cx, |this, window, cx| {
12509            this.select_to_end_of_line(
12510                &SelectToEndOfLine {
12511                    stop_at_soft_wraps: false,
12512                },
12513                window,
12514                cx,
12515            );
12516            this.delete(&Delete, window, cx);
12517        });
12518    }
12519
12520    pub fn cut_to_end_of_line(
12521        &mut self,
12522        _: &CutToEndOfLine,
12523        window: &mut Window,
12524        cx: &mut Context<Self>,
12525    ) {
12526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12527        self.transact(window, cx, |this, window, cx| {
12528            this.select_to_end_of_line(
12529                &SelectToEndOfLine {
12530                    stop_at_soft_wraps: false,
12531                },
12532                window,
12533                cx,
12534            );
12535            this.cut(&Cut, window, cx);
12536        });
12537    }
12538
12539    pub fn move_to_start_of_paragraph(
12540        &mut self,
12541        _: &MoveToStartOfParagraph,
12542        window: &mut Window,
12543        cx: &mut Context<Self>,
12544    ) {
12545        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12546            cx.propagate();
12547            return;
12548        }
12549        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12550        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12551            s.move_with(|map, selection| {
12552                selection.collapse_to(
12553                    movement::start_of_paragraph(map, selection.head(), 1),
12554                    SelectionGoal::None,
12555                )
12556            });
12557        })
12558    }
12559
12560    pub fn move_to_end_of_paragraph(
12561        &mut self,
12562        _: &MoveToEndOfParagraph,
12563        window: &mut Window,
12564        cx: &mut Context<Self>,
12565    ) {
12566        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12567            cx.propagate();
12568            return;
12569        }
12570        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12571        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12572            s.move_with(|map, selection| {
12573                selection.collapse_to(
12574                    movement::end_of_paragraph(map, selection.head(), 1),
12575                    SelectionGoal::None,
12576                )
12577            });
12578        })
12579    }
12580
12581    pub fn select_to_start_of_paragraph(
12582        &mut self,
12583        _: &SelectToStartOfParagraph,
12584        window: &mut Window,
12585        cx: &mut Context<Self>,
12586    ) {
12587        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12588            cx.propagate();
12589            return;
12590        }
12591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12592        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12593            s.move_heads_with(|map, head, _| {
12594                (
12595                    movement::start_of_paragraph(map, head, 1),
12596                    SelectionGoal::None,
12597                )
12598            });
12599        })
12600    }
12601
12602    pub fn select_to_end_of_paragraph(
12603        &mut self,
12604        _: &SelectToEndOfParagraph,
12605        window: &mut Window,
12606        cx: &mut Context<Self>,
12607    ) {
12608        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12609            cx.propagate();
12610            return;
12611        }
12612        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12613        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12614            s.move_heads_with(|map, head, _| {
12615                (
12616                    movement::end_of_paragraph(map, head, 1),
12617                    SelectionGoal::None,
12618                )
12619            });
12620        })
12621    }
12622
12623    pub fn move_to_start_of_excerpt(
12624        &mut self,
12625        _: &MoveToStartOfExcerpt,
12626        window: &mut Window,
12627        cx: &mut Context<Self>,
12628    ) {
12629        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12630            cx.propagate();
12631            return;
12632        }
12633        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12634        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12635            s.move_with(|map, selection| {
12636                selection.collapse_to(
12637                    movement::start_of_excerpt(
12638                        map,
12639                        selection.head(),
12640                        workspace::searchable::Direction::Prev,
12641                    ),
12642                    SelectionGoal::None,
12643                )
12644            });
12645        })
12646    }
12647
12648    pub fn move_to_start_of_next_excerpt(
12649        &mut self,
12650        _: &MoveToStartOfNextExcerpt,
12651        window: &mut Window,
12652        cx: &mut Context<Self>,
12653    ) {
12654        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12655            cx.propagate();
12656            return;
12657        }
12658
12659        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12660            s.move_with(|map, selection| {
12661                selection.collapse_to(
12662                    movement::start_of_excerpt(
12663                        map,
12664                        selection.head(),
12665                        workspace::searchable::Direction::Next,
12666                    ),
12667                    SelectionGoal::None,
12668                )
12669            });
12670        })
12671    }
12672
12673    pub fn move_to_end_of_excerpt(
12674        &mut self,
12675        _: &MoveToEndOfExcerpt,
12676        window: &mut Window,
12677        cx: &mut Context<Self>,
12678    ) {
12679        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12680            cx.propagate();
12681            return;
12682        }
12683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12684        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12685            s.move_with(|map, selection| {
12686                selection.collapse_to(
12687                    movement::end_of_excerpt(
12688                        map,
12689                        selection.head(),
12690                        workspace::searchable::Direction::Next,
12691                    ),
12692                    SelectionGoal::None,
12693                )
12694            });
12695        })
12696    }
12697
12698    pub fn move_to_end_of_previous_excerpt(
12699        &mut self,
12700        _: &MoveToEndOfPreviousExcerpt,
12701        window: &mut Window,
12702        cx: &mut Context<Self>,
12703    ) {
12704        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12705            cx.propagate();
12706            return;
12707        }
12708        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12709        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12710            s.move_with(|map, selection| {
12711                selection.collapse_to(
12712                    movement::end_of_excerpt(
12713                        map,
12714                        selection.head(),
12715                        workspace::searchable::Direction::Prev,
12716                    ),
12717                    SelectionGoal::None,
12718                )
12719            });
12720        })
12721    }
12722
12723    pub fn select_to_start_of_excerpt(
12724        &mut self,
12725        _: &SelectToStartOfExcerpt,
12726        window: &mut Window,
12727        cx: &mut Context<Self>,
12728    ) {
12729        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12730            cx.propagate();
12731            return;
12732        }
12733        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12734        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12735            s.move_heads_with(|map, head, _| {
12736                (
12737                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12738                    SelectionGoal::None,
12739                )
12740            });
12741        })
12742    }
12743
12744    pub fn select_to_start_of_next_excerpt(
12745        &mut self,
12746        _: &SelectToStartOfNextExcerpt,
12747        window: &mut Window,
12748        cx: &mut Context<Self>,
12749    ) {
12750        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12751            cx.propagate();
12752            return;
12753        }
12754        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12755        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12756            s.move_heads_with(|map, head, _| {
12757                (
12758                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12759                    SelectionGoal::None,
12760                )
12761            });
12762        })
12763    }
12764
12765    pub fn select_to_end_of_excerpt(
12766        &mut self,
12767        _: &SelectToEndOfExcerpt,
12768        window: &mut Window,
12769        cx: &mut Context<Self>,
12770    ) {
12771        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12772            cx.propagate();
12773            return;
12774        }
12775        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12776        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12777            s.move_heads_with(|map, head, _| {
12778                (
12779                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12780                    SelectionGoal::None,
12781                )
12782            });
12783        })
12784    }
12785
12786    pub fn select_to_end_of_previous_excerpt(
12787        &mut self,
12788        _: &SelectToEndOfPreviousExcerpt,
12789        window: &mut Window,
12790        cx: &mut Context<Self>,
12791    ) {
12792        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12793            cx.propagate();
12794            return;
12795        }
12796        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12797        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12798            s.move_heads_with(|map, head, _| {
12799                (
12800                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12801                    SelectionGoal::None,
12802                )
12803            });
12804        })
12805    }
12806
12807    pub fn move_to_beginning(
12808        &mut self,
12809        _: &MoveToBeginning,
12810        window: &mut Window,
12811        cx: &mut Context<Self>,
12812    ) {
12813        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12814            cx.propagate();
12815            return;
12816        }
12817        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12818        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12819            s.select_ranges(vec![0..0]);
12820        });
12821    }
12822
12823    pub fn select_to_beginning(
12824        &mut self,
12825        _: &SelectToBeginning,
12826        window: &mut Window,
12827        cx: &mut Context<Self>,
12828    ) {
12829        let mut selection = self.selections.last::<Point>(cx);
12830        selection.set_head(Point::zero(), SelectionGoal::None);
12831        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12832        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12833            s.select(vec![selection]);
12834        });
12835    }
12836
12837    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12838        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12839            cx.propagate();
12840            return;
12841        }
12842        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12843        let cursor = self.buffer.read(cx).read(cx).len();
12844        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12845            s.select_ranges(vec![cursor..cursor])
12846        });
12847    }
12848
12849    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12850        self.nav_history = nav_history;
12851    }
12852
12853    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12854        self.nav_history.as_ref()
12855    }
12856
12857    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12858        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12859    }
12860
12861    fn push_to_nav_history(
12862        &mut self,
12863        cursor_anchor: Anchor,
12864        new_position: Option<Point>,
12865        is_deactivate: bool,
12866        cx: &mut Context<Self>,
12867    ) {
12868        if let Some(nav_history) = self.nav_history.as_mut() {
12869            let buffer = self.buffer.read(cx).read(cx);
12870            let cursor_position = cursor_anchor.to_point(&buffer);
12871            let scroll_state = self.scroll_manager.anchor();
12872            let scroll_top_row = scroll_state.top_row(&buffer);
12873            drop(buffer);
12874
12875            if let Some(new_position) = new_position {
12876                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12877                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12878                    return;
12879                }
12880            }
12881
12882            nav_history.push(
12883                Some(NavigationData {
12884                    cursor_anchor,
12885                    cursor_position,
12886                    scroll_anchor: scroll_state,
12887                    scroll_top_row,
12888                }),
12889                cx,
12890            );
12891            cx.emit(EditorEvent::PushedToNavHistory {
12892                anchor: cursor_anchor,
12893                is_deactivate,
12894            })
12895        }
12896    }
12897
12898    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12899        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12900        let buffer = self.buffer.read(cx).snapshot(cx);
12901        let mut selection = self.selections.first::<usize>(cx);
12902        selection.set_head(buffer.len(), SelectionGoal::None);
12903        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12904            s.select(vec![selection]);
12905        });
12906    }
12907
12908    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12910        let end = self.buffer.read(cx).read(cx).len();
12911        self.change_selections(None, window, cx, |s| {
12912            s.select_ranges(vec![0..end]);
12913        });
12914    }
12915
12916    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12917        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12918        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12919        let mut selections = self.selections.all::<Point>(cx);
12920        let max_point = display_map.buffer_snapshot.max_point();
12921        for selection in &mut selections {
12922            let rows = selection.spanned_rows(true, &display_map);
12923            selection.start = Point::new(rows.start.0, 0);
12924            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12925            selection.reversed = false;
12926        }
12927        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12928            s.select(selections);
12929        });
12930    }
12931
12932    pub fn split_selection_into_lines(
12933        &mut self,
12934        _: &SplitSelectionIntoLines,
12935        window: &mut Window,
12936        cx: &mut Context<Self>,
12937    ) {
12938        let selections = self
12939            .selections
12940            .all::<Point>(cx)
12941            .into_iter()
12942            .map(|selection| selection.start..selection.end)
12943            .collect::<Vec<_>>();
12944        self.unfold_ranges(&selections, true, true, cx);
12945
12946        let mut new_selection_ranges = Vec::new();
12947        {
12948            let buffer = self.buffer.read(cx).read(cx);
12949            for selection in selections {
12950                for row in selection.start.row..selection.end.row {
12951                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12952                    new_selection_ranges.push(cursor..cursor);
12953                }
12954
12955                let is_multiline_selection = selection.start.row != selection.end.row;
12956                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12957                // so this action feels more ergonomic when paired with other selection operations
12958                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12959                if !should_skip_last {
12960                    new_selection_ranges.push(selection.end..selection.end);
12961                }
12962            }
12963        }
12964        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12965            s.select_ranges(new_selection_ranges);
12966        });
12967    }
12968
12969    pub fn add_selection_above(
12970        &mut self,
12971        _: &AddSelectionAbove,
12972        window: &mut Window,
12973        cx: &mut Context<Self>,
12974    ) {
12975        self.add_selection(true, window, cx);
12976    }
12977
12978    pub fn add_selection_below(
12979        &mut self,
12980        _: &AddSelectionBelow,
12981        window: &mut Window,
12982        cx: &mut Context<Self>,
12983    ) {
12984        self.add_selection(false, window, cx);
12985    }
12986
12987    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12989
12990        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12991        let all_selections = self.selections.all::<Point>(cx);
12992        let text_layout_details = self.text_layout_details(window);
12993
12994        let (mut columnar_selections, new_selections_to_columnarize) = {
12995            if let Some(state) = self.add_selections_state.as_ref() {
12996                let columnar_selection_ids: HashSet<_> = state
12997                    .groups
12998                    .iter()
12999                    .flat_map(|group| group.stack.iter())
13000                    .copied()
13001                    .collect();
13002
13003                all_selections
13004                    .into_iter()
13005                    .partition(|s| columnar_selection_ids.contains(&s.id))
13006            } else {
13007                (Vec::new(), all_selections)
13008            }
13009        };
13010
13011        let mut state = self
13012            .add_selections_state
13013            .take()
13014            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13015
13016        for selection in new_selections_to_columnarize {
13017            let range = selection.display_range(&display_map).sorted();
13018            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13019            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13020            let positions = start_x.min(end_x)..start_x.max(end_x);
13021            let mut stack = Vec::new();
13022            for row in range.start.row().0..=range.end.row().0 {
13023                if let Some(selection) = self.selections.build_columnar_selection(
13024                    &display_map,
13025                    DisplayRow(row),
13026                    &positions,
13027                    selection.reversed,
13028                    &text_layout_details,
13029                ) {
13030                    stack.push(selection.id);
13031                    columnar_selections.push(selection);
13032                }
13033            }
13034            if !stack.is_empty() {
13035                if above {
13036                    stack.reverse();
13037                }
13038                state.groups.push(AddSelectionsGroup { above, stack });
13039            }
13040        }
13041
13042        let mut final_selections = Vec::new();
13043        let end_row = if above {
13044            DisplayRow(0)
13045        } else {
13046            display_map.max_point().row()
13047        };
13048
13049        let mut last_added_item_per_group = HashMap::default();
13050        for group in state.groups.iter_mut() {
13051            if let Some(last_id) = group.stack.last() {
13052                last_added_item_per_group.insert(*last_id, group);
13053            }
13054        }
13055
13056        for selection in columnar_selections {
13057            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13058                if above == group.above {
13059                    let range = selection.display_range(&display_map).sorted();
13060                    debug_assert_eq!(range.start.row(), range.end.row());
13061                    let mut row = range.start.row();
13062                    let positions =
13063                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13064                            px(start)..px(end)
13065                        } else {
13066                            let start_x =
13067                                display_map.x_for_display_point(range.start, &text_layout_details);
13068                            let end_x =
13069                                display_map.x_for_display_point(range.end, &text_layout_details);
13070                            start_x.min(end_x)..start_x.max(end_x)
13071                        };
13072
13073                    let mut maybe_new_selection = None;
13074                    while row != end_row {
13075                        if above {
13076                            row.0 -= 1;
13077                        } else {
13078                            row.0 += 1;
13079                        }
13080                        if let Some(new_selection) = self.selections.build_columnar_selection(
13081                            &display_map,
13082                            row,
13083                            &positions,
13084                            selection.reversed,
13085                            &text_layout_details,
13086                        ) {
13087                            maybe_new_selection = Some(new_selection);
13088                            break;
13089                        }
13090                    }
13091
13092                    if let Some(new_selection) = maybe_new_selection {
13093                        group.stack.push(new_selection.id);
13094                        if above {
13095                            final_selections.push(new_selection);
13096                            final_selections.push(selection);
13097                        } else {
13098                            final_selections.push(selection);
13099                            final_selections.push(new_selection);
13100                        }
13101                    } else {
13102                        final_selections.push(selection);
13103                    }
13104                } else {
13105                    group.stack.pop();
13106                }
13107            } else {
13108                final_selections.push(selection);
13109            }
13110        }
13111
13112        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13113            s.select(final_selections);
13114        });
13115
13116        let final_selection_ids: HashSet<_> = self
13117            .selections
13118            .all::<Point>(cx)
13119            .iter()
13120            .map(|s| s.id)
13121            .collect();
13122        state.groups.retain_mut(|group| {
13123            // selections might get merged above so we remove invalid items from stacks
13124            group.stack.retain(|id| final_selection_ids.contains(id));
13125
13126            // single selection in stack can be treated as initial state
13127            group.stack.len() > 1
13128        });
13129
13130        if !state.groups.is_empty() {
13131            self.add_selections_state = Some(state);
13132        }
13133    }
13134
13135    fn select_match_ranges(
13136        &mut self,
13137        range: Range<usize>,
13138        reversed: bool,
13139        replace_newest: bool,
13140        auto_scroll: Option<Autoscroll>,
13141        window: &mut Window,
13142        cx: &mut Context<Editor>,
13143    ) {
13144        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13145        self.change_selections(auto_scroll, window, cx, |s| {
13146            if replace_newest {
13147                s.delete(s.newest_anchor().id);
13148            }
13149            if reversed {
13150                s.insert_range(range.end..range.start);
13151            } else {
13152                s.insert_range(range);
13153            }
13154        });
13155    }
13156
13157    pub fn select_next_match_internal(
13158        &mut self,
13159        display_map: &DisplaySnapshot,
13160        replace_newest: bool,
13161        autoscroll: Option<Autoscroll>,
13162        window: &mut Window,
13163        cx: &mut Context<Self>,
13164    ) -> Result<()> {
13165        let buffer = &display_map.buffer_snapshot;
13166        let mut selections = self.selections.all::<usize>(cx);
13167        if let Some(mut select_next_state) = self.select_next_state.take() {
13168            let query = &select_next_state.query;
13169            if !select_next_state.done {
13170                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13171                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13172                let mut next_selected_range = None;
13173
13174                let bytes_after_last_selection =
13175                    buffer.bytes_in_range(last_selection.end..buffer.len());
13176                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13177                let query_matches = query
13178                    .stream_find_iter(bytes_after_last_selection)
13179                    .map(|result| (last_selection.end, result))
13180                    .chain(
13181                        query
13182                            .stream_find_iter(bytes_before_first_selection)
13183                            .map(|result| (0, result)),
13184                    );
13185
13186                for (start_offset, query_match) in query_matches {
13187                    let query_match = query_match.unwrap(); // can only fail due to I/O
13188                    let offset_range =
13189                        start_offset + query_match.start()..start_offset + query_match.end();
13190                    let display_range = offset_range.start.to_display_point(display_map)
13191                        ..offset_range.end.to_display_point(display_map);
13192
13193                    if !select_next_state.wordwise
13194                        || (!movement::is_inside_word(display_map, display_range.start)
13195                            && !movement::is_inside_word(display_map, display_range.end))
13196                    {
13197                        // TODO: This is n^2, because we might check all the selections
13198                        if !selections
13199                            .iter()
13200                            .any(|selection| selection.range().overlaps(&offset_range))
13201                        {
13202                            next_selected_range = Some(offset_range);
13203                            break;
13204                        }
13205                    }
13206                }
13207
13208                if let Some(next_selected_range) = next_selected_range {
13209                    self.select_match_ranges(
13210                        next_selected_range,
13211                        last_selection.reversed,
13212                        replace_newest,
13213                        autoscroll,
13214                        window,
13215                        cx,
13216                    );
13217                } else {
13218                    select_next_state.done = true;
13219                }
13220            }
13221
13222            self.select_next_state = Some(select_next_state);
13223        } else {
13224            let mut only_carets = true;
13225            let mut same_text_selected = true;
13226            let mut selected_text = None;
13227
13228            let mut selections_iter = selections.iter().peekable();
13229            while let Some(selection) = selections_iter.next() {
13230                if selection.start != selection.end {
13231                    only_carets = false;
13232                }
13233
13234                if same_text_selected {
13235                    if selected_text.is_none() {
13236                        selected_text =
13237                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13238                    }
13239
13240                    if let Some(next_selection) = selections_iter.peek() {
13241                        if next_selection.range().len() == selection.range().len() {
13242                            let next_selected_text = buffer
13243                                .text_for_range(next_selection.range())
13244                                .collect::<String>();
13245                            if Some(next_selected_text) != selected_text {
13246                                same_text_selected = false;
13247                                selected_text = None;
13248                            }
13249                        } else {
13250                            same_text_selected = false;
13251                            selected_text = None;
13252                        }
13253                    }
13254                }
13255            }
13256
13257            if only_carets {
13258                for selection in &mut selections {
13259                    let word_range = movement::surrounding_word(
13260                        display_map,
13261                        selection.start.to_display_point(display_map),
13262                    );
13263                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13264                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13265                    selection.goal = SelectionGoal::None;
13266                    selection.reversed = false;
13267                    self.select_match_ranges(
13268                        selection.start..selection.end,
13269                        selection.reversed,
13270                        replace_newest,
13271                        autoscroll,
13272                        window,
13273                        cx,
13274                    );
13275                }
13276
13277                if selections.len() == 1 {
13278                    let selection = selections
13279                        .last()
13280                        .expect("ensured that there's only one selection");
13281                    let query = buffer
13282                        .text_for_range(selection.start..selection.end)
13283                        .collect::<String>();
13284                    let is_empty = query.is_empty();
13285                    let select_state = SelectNextState {
13286                        query: AhoCorasick::new(&[query])?,
13287                        wordwise: true,
13288                        done: is_empty,
13289                    };
13290                    self.select_next_state = Some(select_state);
13291                } else {
13292                    self.select_next_state = None;
13293                }
13294            } else if let Some(selected_text) = selected_text {
13295                self.select_next_state = Some(SelectNextState {
13296                    query: AhoCorasick::new(&[selected_text])?,
13297                    wordwise: false,
13298                    done: false,
13299                });
13300                self.select_next_match_internal(
13301                    display_map,
13302                    replace_newest,
13303                    autoscroll,
13304                    window,
13305                    cx,
13306                )?;
13307            }
13308        }
13309        Ok(())
13310    }
13311
13312    pub fn select_all_matches(
13313        &mut self,
13314        _action: &SelectAllMatches,
13315        window: &mut Window,
13316        cx: &mut Context<Self>,
13317    ) -> Result<()> {
13318        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13319
13320        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13321
13322        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13323        let Some(select_next_state) = self.select_next_state.as_mut() else {
13324            return Ok(());
13325        };
13326        if select_next_state.done {
13327            return Ok(());
13328        }
13329
13330        let mut new_selections = Vec::new();
13331
13332        let reversed = self.selections.oldest::<usize>(cx).reversed;
13333        let buffer = &display_map.buffer_snapshot;
13334        let query_matches = select_next_state
13335            .query
13336            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13337
13338        for query_match in query_matches.into_iter() {
13339            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13340            let offset_range = if reversed {
13341                query_match.end()..query_match.start()
13342            } else {
13343                query_match.start()..query_match.end()
13344            };
13345            let display_range = offset_range.start.to_display_point(&display_map)
13346                ..offset_range.end.to_display_point(&display_map);
13347
13348            if !select_next_state.wordwise
13349                || (!movement::is_inside_word(&display_map, display_range.start)
13350                    && !movement::is_inside_word(&display_map, display_range.end))
13351            {
13352                new_selections.push(offset_range.start..offset_range.end);
13353            }
13354        }
13355
13356        select_next_state.done = true;
13357        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13358        self.change_selections(None, window, cx, |selections| {
13359            selections.select_ranges(new_selections)
13360        });
13361
13362        Ok(())
13363    }
13364
13365    pub fn select_next(
13366        &mut self,
13367        action: &SelectNext,
13368        window: &mut Window,
13369        cx: &mut Context<Self>,
13370    ) -> Result<()> {
13371        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13372        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13373        self.select_next_match_internal(
13374            &display_map,
13375            action.replace_newest,
13376            Some(Autoscroll::newest()),
13377            window,
13378            cx,
13379        )?;
13380        Ok(())
13381    }
13382
13383    pub fn select_previous(
13384        &mut self,
13385        action: &SelectPrevious,
13386        window: &mut Window,
13387        cx: &mut Context<Self>,
13388    ) -> Result<()> {
13389        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13390        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13391        let buffer = &display_map.buffer_snapshot;
13392        let mut selections = self.selections.all::<usize>(cx);
13393        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13394            let query = &select_prev_state.query;
13395            if !select_prev_state.done {
13396                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13397                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13398                let mut next_selected_range = None;
13399                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13400                let bytes_before_last_selection =
13401                    buffer.reversed_bytes_in_range(0..last_selection.start);
13402                let bytes_after_first_selection =
13403                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13404                let query_matches = query
13405                    .stream_find_iter(bytes_before_last_selection)
13406                    .map(|result| (last_selection.start, result))
13407                    .chain(
13408                        query
13409                            .stream_find_iter(bytes_after_first_selection)
13410                            .map(|result| (buffer.len(), result)),
13411                    );
13412                for (end_offset, query_match) in query_matches {
13413                    let query_match = query_match.unwrap(); // can only fail due to I/O
13414                    let offset_range =
13415                        end_offset - query_match.end()..end_offset - query_match.start();
13416                    let display_range = offset_range.start.to_display_point(&display_map)
13417                        ..offset_range.end.to_display_point(&display_map);
13418
13419                    if !select_prev_state.wordwise
13420                        || (!movement::is_inside_word(&display_map, display_range.start)
13421                            && !movement::is_inside_word(&display_map, display_range.end))
13422                    {
13423                        next_selected_range = Some(offset_range);
13424                        break;
13425                    }
13426                }
13427
13428                if let Some(next_selected_range) = next_selected_range {
13429                    self.select_match_ranges(
13430                        next_selected_range,
13431                        last_selection.reversed,
13432                        action.replace_newest,
13433                        Some(Autoscroll::newest()),
13434                        window,
13435                        cx,
13436                    );
13437                } else {
13438                    select_prev_state.done = true;
13439                }
13440            }
13441
13442            self.select_prev_state = Some(select_prev_state);
13443        } else {
13444            let mut only_carets = true;
13445            let mut same_text_selected = true;
13446            let mut selected_text = None;
13447
13448            let mut selections_iter = selections.iter().peekable();
13449            while let Some(selection) = selections_iter.next() {
13450                if selection.start != selection.end {
13451                    only_carets = false;
13452                }
13453
13454                if same_text_selected {
13455                    if selected_text.is_none() {
13456                        selected_text =
13457                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13458                    }
13459
13460                    if let Some(next_selection) = selections_iter.peek() {
13461                        if next_selection.range().len() == selection.range().len() {
13462                            let next_selected_text = buffer
13463                                .text_for_range(next_selection.range())
13464                                .collect::<String>();
13465                            if Some(next_selected_text) != selected_text {
13466                                same_text_selected = false;
13467                                selected_text = None;
13468                            }
13469                        } else {
13470                            same_text_selected = false;
13471                            selected_text = None;
13472                        }
13473                    }
13474                }
13475            }
13476
13477            if only_carets {
13478                for selection in &mut selections {
13479                    let word_range = movement::surrounding_word(
13480                        &display_map,
13481                        selection.start.to_display_point(&display_map),
13482                    );
13483                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13484                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13485                    selection.goal = SelectionGoal::None;
13486                    selection.reversed = false;
13487                    self.select_match_ranges(
13488                        selection.start..selection.end,
13489                        selection.reversed,
13490                        action.replace_newest,
13491                        Some(Autoscroll::newest()),
13492                        window,
13493                        cx,
13494                    );
13495                }
13496                if selections.len() == 1 {
13497                    let selection = selections
13498                        .last()
13499                        .expect("ensured that there's only one selection");
13500                    let query = buffer
13501                        .text_for_range(selection.start..selection.end)
13502                        .collect::<String>();
13503                    let is_empty = query.is_empty();
13504                    let select_state = SelectNextState {
13505                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13506                        wordwise: true,
13507                        done: is_empty,
13508                    };
13509                    self.select_prev_state = Some(select_state);
13510                } else {
13511                    self.select_prev_state = None;
13512                }
13513            } else if let Some(selected_text) = selected_text {
13514                self.select_prev_state = Some(SelectNextState {
13515                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13516                    wordwise: false,
13517                    done: false,
13518                });
13519                self.select_previous(action, window, cx)?;
13520            }
13521        }
13522        Ok(())
13523    }
13524
13525    pub fn find_next_match(
13526        &mut self,
13527        _: &FindNextMatch,
13528        window: &mut Window,
13529        cx: &mut Context<Self>,
13530    ) -> Result<()> {
13531        let selections = self.selections.disjoint_anchors();
13532        match selections.first() {
13533            Some(first) if selections.len() >= 2 => {
13534                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13535                    s.select_ranges([first.range()]);
13536                });
13537            }
13538            _ => self.select_next(
13539                &SelectNext {
13540                    replace_newest: true,
13541                },
13542                window,
13543                cx,
13544            )?,
13545        }
13546        Ok(())
13547    }
13548
13549    pub fn find_previous_match(
13550        &mut self,
13551        _: &FindPreviousMatch,
13552        window: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) -> Result<()> {
13555        let selections = self.selections.disjoint_anchors();
13556        match selections.last() {
13557            Some(last) if selections.len() >= 2 => {
13558                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13559                    s.select_ranges([last.range()]);
13560                });
13561            }
13562            _ => self.select_previous(
13563                &SelectPrevious {
13564                    replace_newest: true,
13565                },
13566                window,
13567                cx,
13568            )?,
13569        }
13570        Ok(())
13571    }
13572
13573    pub fn toggle_comments(
13574        &mut self,
13575        action: &ToggleComments,
13576        window: &mut Window,
13577        cx: &mut Context<Self>,
13578    ) {
13579        if self.read_only(cx) {
13580            return;
13581        }
13582        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13583        let text_layout_details = &self.text_layout_details(window);
13584        self.transact(window, cx, |this, window, cx| {
13585            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13586            let mut edits = Vec::new();
13587            let mut selection_edit_ranges = Vec::new();
13588            let mut last_toggled_row = None;
13589            let snapshot = this.buffer.read(cx).read(cx);
13590            let empty_str: Arc<str> = Arc::default();
13591            let mut suffixes_inserted = Vec::new();
13592            let ignore_indent = action.ignore_indent;
13593
13594            fn comment_prefix_range(
13595                snapshot: &MultiBufferSnapshot,
13596                row: MultiBufferRow,
13597                comment_prefix: &str,
13598                comment_prefix_whitespace: &str,
13599                ignore_indent: bool,
13600            ) -> Range<Point> {
13601                let indent_size = if ignore_indent {
13602                    0
13603                } else {
13604                    snapshot.indent_size_for_line(row).len
13605                };
13606
13607                let start = Point::new(row.0, indent_size);
13608
13609                let mut line_bytes = snapshot
13610                    .bytes_in_range(start..snapshot.max_point())
13611                    .flatten()
13612                    .copied();
13613
13614                // If this line currently begins with the line comment prefix, then record
13615                // the range containing the prefix.
13616                if line_bytes
13617                    .by_ref()
13618                    .take(comment_prefix.len())
13619                    .eq(comment_prefix.bytes())
13620                {
13621                    // Include any whitespace that matches the comment prefix.
13622                    let matching_whitespace_len = line_bytes
13623                        .zip(comment_prefix_whitespace.bytes())
13624                        .take_while(|(a, b)| a == b)
13625                        .count() as u32;
13626                    let end = Point::new(
13627                        start.row,
13628                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13629                    );
13630                    start..end
13631                } else {
13632                    start..start
13633                }
13634            }
13635
13636            fn comment_suffix_range(
13637                snapshot: &MultiBufferSnapshot,
13638                row: MultiBufferRow,
13639                comment_suffix: &str,
13640                comment_suffix_has_leading_space: bool,
13641            ) -> Range<Point> {
13642                let end = Point::new(row.0, snapshot.line_len(row));
13643                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13644
13645                let mut line_end_bytes = snapshot
13646                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13647                    .flatten()
13648                    .copied();
13649
13650                let leading_space_len = if suffix_start_column > 0
13651                    && line_end_bytes.next() == Some(b' ')
13652                    && comment_suffix_has_leading_space
13653                {
13654                    1
13655                } else {
13656                    0
13657                };
13658
13659                // If this line currently begins with the line comment prefix, then record
13660                // the range containing the prefix.
13661                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13662                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13663                    start..end
13664                } else {
13665                    end..end
13666                }
13667            }
13668
13669            // TODO: Handle selections that cross excerpts
13670            for selection in &mut selections {
13671                let start_column = snapshot
13672                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13673                    .len;
13674                let language = if let Some(language) =
13675                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13676                {
13677                    language
13678                } else {
13679                    continue;
13680                };
13681
13682                selection_edit_ranges.clear();
13683
13684                // If multiple selections contain a given row, avoid processing that
13685                // row more than once.
13686                let mut start_row = MultiBufferRow(selection.start.row);
13687                if last_toggled_row == Some(start_row) {
13688                    start_row = start_row.next_row();
13689                }
13690                let end_row =
13691                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13692                        MultiBufferRow(selection.end.row - 1)
13693                    } else {
13694                        MultiBufferRow(selection.end.row)
13695                    };
13696                last_toggled_row = Some(end_row);
13697
13698                if start_row > end_row {
13699                    continue;
13700                }
13701
13702                // If the language has line comments, toggle those.
13703                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13704
13705                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13706                if ignore_indent {
13707                    full_comment_prefixes = full_comment_prefixes
13708                        .into_iter()
13709                        .map(|s| Arc::from(s.trim_end()))
13710                        .collect();
13711                }
13712
13713                if !full_comment_prefixes.is_empty() {
13714                    let first_prefix = full_comment_prefixes
13715                        .first()
13716                        .expect("prefixes is non-empty");
13717                    let prefix_trimmed_lengths = full_comment_prefixes
13718                        .iter()
13719                        .map(|p| p.trim_end_matches(' ').len())
13720                        .collect::<SmallVec<[usize; 4]>>();
13721
13722                    let mut all_selection_lines_are_comments = true;
13723
13724                    for row in start_row.0..=end_row.0 {
13725                        let row = MultiBufferRow(row);
13726                        if start_row < end_row && snapshot.is_line_blank(row) {
13727                            continue;
13728                        }
13729
13730                        let prefix_range = full_comment_prefixes
13731                            .iter()
13732                            .zip(prefix_trimmed_lengths.iter().copied())
13733                            .map(|(prefix, trimmed_prefix_len)| {
13734                                comment_prefix_range(
13735                                    snapshot.deref(),
13736                                    row,
13737                                    &prefix[..trimmed_prefix_len],
13738                                    &prefix[trimmed_prefix_len..],
13739                                    ignore_indent,
13740                                )
13741                            })
13742                            .max_by_key(|range| range.end.column - range.start.column)
13743                            .expect("prefixes is non-empty");
13744
13745                        if prefix_range.is_empty() {
13746                            all_selection_lines_are_comments = false;
13747                        }
13748
13749                        selection_edit_ranges.push(prefix_range);
13750                    }
13751
13752                    if all_selection_lines_are_comments {
13753                        edits.extend(
13754                            selection_edit_ranges
13755                                .iter()
13756                                .cloned()
13757                                .map(|range| (range, empty_str.clone())),
13758                        );
13759                    } else {
13760                        let min_column = selection_edit_ranges
13761                            .iter()
13762                            .map(|range| range.start.column)
13763                            .min()
13764                            .unwrap_or(0);
13765                        edits.extend(selection_edit_ranges.iter().map(|range| {
13766                            let position = Point::new(range.start.row, min_column);
13767                            (position..position, first_prefix.clone())
13768                        }));
13769                    }
13770                } else if let Some((full_comment_prefix, comment_suffix)) =
13771                    language.block_comment_delimiters()
13772                {
13773                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13774                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13775                    let prefix_range = comment_prefix_range(
13776                        snapshot.deref(),
13777                        start_row,
13778                        comment_prefix,
13779                        comment_prefix_whitespace,
13780                        ignore_indent,
13781                    );
13782                    let suffix_range = comment_suffix_range(
13783                        snapshot.deref(),
13784                        end_row,
13785                        comment_suffix.trim_start_matches(' '),
13786                        comment_suffix.starts_with(' '),
13787                    );
13788
13789                    if prefix_range.is_empty() || suffix_range.is_empty() {
13790                        edits.push((
13791                            prefix_range.start..prefix_range.start,
13792                            full_comment_prefix.clone(),
13793                        ));
13794                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13795                        suffixes_inserted.push((end_row, comment_suffix.len()));
13796                    } else {
13797                        edits.push((prefix_range, empty_str.clone()));
13798                        edits.push((suffix_range, empty_str.clone()));
13799                    }
13800                } else {
13801                    continue;
13802                }
13803            }
13804
13805            drop(snapshot);
13806            this.buffer.update(cx, |buffer, cx| {
13807                buffer.edit(edits, None, cx);
13808            });
13809
13810            // Adjust selections so that they end before any comment suffixes that
13811            // were inserted.
13812            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13813            let mut selections = this.selections.all::<Point>(cx);
13814            let snapshot = this.buffer.read(cx).read(cx);
13815            for selection in &mut selections {
13816                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13817                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13818                        Ordering::Less => {
13819                            suffixes_inserted.next();
13820                            continue;
13821                        }
13822                        Ordering::Greater => break,
13823                        Ordering::Equal => {
13824                            if selection.end.column == snapshot.line_len(row) {
13825                                if selection.is_empty() {
13826                                    selection.start.column -= suffix_len as u32;
13827                                }
13828                                selection.end.column -= suffix_len as u32;
13829                            }
13830                            break;
13831                        }
13832                    }
13833                }
13834            }
13835
13836            drop(snapshot);
13837            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13838                s.select(selections)
13839            });
13840
13841            let selections = this.selections.all::<Point>(cx);
13842            let selections_on_single_row = selections.windows(2).all(|selections| {
13843                selections[0].start.row == selections[1].start.row
13844                    && selections[0].end.row == selections[1].end.row
13845                    && selections[0].start.row == selections[0].end.row
13846            });
13847            let selections_selecting = selections
13848                .iter()
13849                .any(|selection| selection.start != selection.end);
13850            let advance_downwards = action.advance_downwards
13851                && selections_on_single_row
13852                && !selections_selecting
13853                && !matches!(this.mode, EditorMode::SingleLine { .. });
13854
13855            if advance_downwards {
13856                let snapshot = this.buffer.read(cx).snapshot(cx);
13857
13858                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13859                    s.move_cursors_with(|display_snapshot, display_point, _| {
13860                        let mut point = display_point.to_point(display_snapshot);
13861                        point.row += 1;
13862                        point = snapshot.clip_point(point, Bias::Left);
13863                        let display_point = point.to_display_point(display_snapshot);
13864                        let goal = SelectionGoal::HorizontalPosition(
13865                            display_snapshot
13866                                .x_for_display_point(display_point, text_layout_details)
13867                                .into(),
13868                        );
13869                        (display_point, goal)
13870                    })
13871                });
13872            }
13873        });
13874    }
13875
13876    pub fn select_enclosing_symbol(
13877        &mut self,
13878        _: &SelectEnclosingSymbol,
13879        window: &mut Window,
13880        cx: &mut Context<Self>,
13881    ) {
13882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13883
13884        let buffer = self.buffer.read(cx).snapshot(cx);
13885        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13886
13887        fn update_selection(
13888            selection: &Selection<usize>,
13889            buffer_snap: &MultiBufferSnapshot,
13890        ) -> Option<Selection<usize>> {
13891            let cursor = selection.head();
13892            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13893            for symbol in symbols.iter().rev() {
13894                let start = symbol.range.start.to_offset(buffer_snap);
13895                let end = symbol.range.end.to_offset(buffer_snap);
13896                let new_range = start..end;
13897                if start < selection.start || end > selection.end {
13898                    return Some(Selection {
13899                        id: selection.id,
13900                        start: new_range.start,
13901                        end: new_range.end,
13902                        goal: SelectionGoal::None,
13903                        reversed: selection.reversed,
13904                    });
13905                }
13906            }
13907            None
13908        }
13909
13910        let mut selected_larger_symbol = false;
13911        let new_selections = old_selections
13912            .iter()
13913            .map(|selection| match update_selection(selection, &buffer) {
13914                Some(new_selection) => {
13915                    if new_selection.range() != selection.range() {
13916                        selected_larger_symbol = true;
13917                    }
13918                    new_selection
13919                }
13920                None => selection.clone(),
13921            })
13922            .collect::<Vec<_>>();
13923
13924        if selected_larger_symbol {
13925            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13926                s.select(new_selections);
13927            });
13928        }
13929    }
13930
13931    pub fn select_larger_syntax_node(
13932        &mut self,
13933        _: &SelectLargerSyntaxNode,
13934        window: &mut Window,
13935        cx: &mut Context<Self>,
13936    ) {
13937        let Some(visible_row_count) = self.visible_row_count() else {
13938            return;
13939        };
13940        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13941        if old_selections.is_empty() {
13942            return;
13943        }
13944
13945        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13946
13947        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13948        let buffer = self.buffer.read(cx).snapshot(cx);
13949
13950        let mut selected_larger_node = false;
13951        let mut new_selections = old_selections
13952            .iter()
13953            .map(|selection| {
13954                let old_range = selection.start..selection.end;
13955
13956                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13957                    // manually select word at selection
13958                    if ["string_content", "inline"].contains(&node.kind()) {
13959                        let word_range = {
13960                            let display_point = buffer
13961                                .offset_to_point(old_range.start)
13962                                .to_display_point(&display_map);
13963                            let Range { start, end } =
13964                                movement::surrounding_word(&display_map, display_point);
13965                            start.to_point(&display_map).to_offset(&buffer)
13966                                ..end.to_point(&display_map).to_offset(&buffer)
13967                        };
13968                        // ignore if word is already selected
13969                        if !word_range.is_empty() && old_range != word_range {
13970                            let last_word_range = {
13971                                let display_point = buffer
13972                                    .offset_to_point(old_range.end)
13973                                    .to_display_point(&display_map);
13974                                let Range { start, end } =
13975                                    movement::surrounding_word(&display_map, display_point);
13976                                start.to_point(&display_map).to_offset(&buffer)
13977                                    ..end.to_point(&display_map).to_offset(&buffer)
13978                            };
13979                            // only select word if start and end point belongs to same word
13980                            if word_range == last_word_range {
13981                                selected_larger_node = true;
13982                                return Selection {
13983                                    id: selection.id,
13984                                    start: word_range.start,
13985                                    end: word_range.end,
13986                                    goal: SelectionGoal::None,
13987                                    reversed: selection.reversed,
13988                                };
13989                            }
13990                        }
13991                    }
13992                }
13993
13994                let mut new_range = old_range.clone();
13995                while let Some((_node, containing_range)) =
13996                    buffer.syntax_ancestor(new_range.clone())
13997                {
13998                    new_range = match containing_range {
13999                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14000                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14001                    };
14002                    if !display_map.intersects_fold(new_range.start)
14003                        && !display_map.intersects_fold(new_range.end)
14004                    {
14005                        break;
14006                    }
14007                }
14008
14009                selected_larger_node |= new_range != old_range;
14010                Selection {
14011                    id: selection.id,
14012                    start: new_range.start,
14013                    end: new_range.end,
14014                    goal: SelectionGoal::None,
14015                    reversed: selection.reversed,
14016                }
14017            })
14018            .collect::<Vec<_>>();
14019
14020        if !selected_larger_node {
14021            return; // don't put this call in the history
14022        }
14023
14024        // scroll based on transformation done to the last selection created by the user
14025        let (last_old, last_new) = old_selections
14026            .last()
14027            .zip(new_selections.last().cloned())
14028            .expect("old_selections isn't empty");
14029
14030        // revert selection
14031        let is_selection_reversed = {
14032            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14033            new_selections.last_mut().expect("checked above").reversed =
14034                should_newest_selection_be_reversed;
14035            should_newest_selection_be_reversed
14036        };
14037
14038        if selected_larger_node {
14039            self.select_syntax_node_history.disable_clearing = true;
14040            self.change_selections(None, window, cx, |s| {
14041                s.select(new_selections.clone());
14042            });
14043            self.select_syntax_node_history.disable_clearing = false;
14044        }
14045
14046        let start_row = last_new.start.to_display_point(&display_map).row().0;
14047        let end_row = last_new.end.to_display_point(&display_map).row().0;
14048        let selection_height = end_row - start_row + 1;
14049        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14050
14051        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14052        let scroll_behavior = if fits_on_the_screen {
14053            self.request_autoscroll(Autoscroll::fit(), cx);
14054            SelectSyntaxNodeScrollBehavior::FitSelection
14055        } else if is_selection_reversed {
14056            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14057            SelectSyntaxNodeScrollBehavior::CursorTop
14058        } else {
14059            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14060            SelectSyntaxNodeScrollBehavior::CursorBottom
14061        };
14062
14063        self.select_syntax_node_history.push((
14064            old_selections,
14065            scroll_behavior,
14066            is_selection_reversed,
14067        ));
14068    }
14069
14070    pub fn select_smaller_syntax_node(
14071        &mut self,
14072        _: &SelectSmallerSyntaxNode,
14073        window: &mut Window,
14074        cx: &mut Context<Self>,
14075    ) {
14076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14077
14078        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14079            self.select_syntax_node_history.pop()
14080        {
14081            if let Some(selection) = selections.last_mut() {
14082                selection.reversed = is_selection_reversed;
14083            }
14084
14085            self.select_syntax_node_history.disable_clearing = true;
14086            self.change_selections(None, window, cx, |s| {
14087                s.select(selections.to_vec());
14088            });
14089            self.select_syntax_node_history.disable_clearing = false;
14090
14091            match scroll_behavior {
14092                SelectSyntaxNodeScrollBehavior::CursorTop => {
14093                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14094                }
14095                SelectSyntaxNodeScrollBehavior::FitSelection => {
14096                    self.request_autoscroll(Autoscroll::fit(), cx);
14097                }
14098                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14099                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14100                }
14101            }
14102        }
14103    }
14104
14105    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14106        if !EditorSettings::get_global(cx).gutter.runnables {
14107            self.clear_tasks();
14108            return Task::ready(());
14109        }
14110        let project = self.project.as_ref().map(Entity::downgrade);
14111        let task_sources = self.lsp_task_sources(cx);
14112        let multi_buffer = self.buffer.downgrade();
14113        cx.spawn_in(window, async move |editor, cx| {
14114            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14115            let Some(project) = project.and_then(|p| p.upgrade()) else {
14116                return;
14117            };
14118            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14119                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14120            }) else {
14121                return;
14122            };
14123
14124            let hide_runnables = project
14125                .update(cx, |project, cx| {
14126                    // Do not display any test indicators in non-dev server remote projects.
14127                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14128                })
14129                .unwrap_or(true);
14130            if hide_runnables {
14131                return;
14132            }
14133            let new_rows =
14134                cx.background_spawn({
14135                    let snapshot = display_snapshot.clone();
14136                    async move {
14137                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14138                    }
14139                })
14140                    .await;
14141            let Ok(lsp_tasks) =
14142                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14143            else {
14144                return;
14145            };
14146            let lsp_tasks = lsp_tasks.await;
14147
14148            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14149                lsp_tasks
14150                    .into_iter()
14151                    .flat_map(|(kind, tasks)| {
14152                        tasks.into_iter().filter_map(move |(location, task)| {
14153                            Some((kind.clone(), location?, task))
14154                        })
14155                    })
14156                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14157                        let buffer = location.target.buffer;
14158                        let buffer_snapshot = buffer.read(cx).snapshot();
14159                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14160                            |(excerpt_id, snapshot, _)| {
14161                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14162                                    display_snapshot
14163                                        .buffer_snapshot
14164                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14165                                } else {
14166                                    None
14167                                }
14168                            },
14169                        );
14170                        if let Some(offset) = offset {
14171                            let task_buffer_range =
14172                                location.target.range.to_point(&buffer_snapshot);
14173                            let context_buffer_range =
14174                                task_buffer_range.to_offset(&buffer_snapshot);
14175                            let context_range = BufferOffset(context_buffer_range.start)
14176                                ..BufferOffset(context_buffer_range.end);
14177
14178                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14179                                .or_insert_with(|| RunnableTasks {
14180                                    templates: Vec::new(),
14181                                    offset,
14182                                    column: task_buffer_range.start.column,
14183                                    extra_variables: HashMap::default(),
14184                                    context_range,
14185                                })
14186                                .templates
14187                                .push((kind, task.original_task().clone()));
14188                        }
14189
14190                        acc
14191                    })
14192            }) else {
14193                return;
14194            };
14195
14196            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14197                buffer.language_settings(cx).tasks.prefer_lsp
14198            }) else {
14199                return;
14200            };
14201
14202            let rows = Self::runnable_rows(
14203                project,
14204                display_snapshot,
14205                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14206                new_rows,
14207                cx.clone(),
14208            )
14209            .await;
14210            editor
14211                .update(cx, |editor, _| {
14212                    editor.clear_tasks();
14213                    for (key, mut value) in rows {
14214                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14215                            value.templates.extend(lsp_tasks.templates);
14216                        }
14217
14218                        editor.insert_tasks(key, value);
14219                    }
14220                    for (key, value) in lsp_tasks_by_rows {
14221                        editor.insert_tasks(key, value);
14222                    }
14223                })
14224                .ok();
14225        })
14226    }
14227    fn fetch_runnable_ranges(
14228        snapshot: &DisplaySnapshot,
14229        range: Range<Anchor>,
14230    ) -> Vec<language::RunnableRange> {
14231        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14232    }
14233
14234    fn runnable_rows(
14235        project: Entity<Project>,
14236        snapshot: DisplaySnapshot,
14237        prefer_lsp: bool,
14238        runnable_ranges: Vec<RunnableRange>,
14239        cx: AsyncWindowContext,
14240    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14241        cx.spawn(async move |cx| {
14242            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14243            for mut runnable in runnable_ranges {
14244                let Some(tasks) = cx
14245                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14246                    .ok()
14247                else {
14248                    continue;
14249                };
14250                let mut tasks = tasks.await;
14251
14252                if prefer_lsp {
14253                    tasks.retain(|(task_kind, _)| {
14254                        !matches!(task_kind, TaskSourceKind::Language { .. })
14255                    });
14256                }
14257                if tasks.is_empty() {
14258                    continue;
14259                }
14260
14261                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14262                let Some(row) = snapshot
14263                    .buffer_snapshot
14264                    .buffer_line_for_row(MultiBufferRow(point.row))
14265                    .map(|(_, range)| range.start.row)
14266                else {
14267                    continue;
14268                };
14269
14270                let context_range =
14271                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14272                runnable_rows.push((
14273                    (runnable.buffer_id, row),
14274                    RunnableTasks {
14275                        templates: tasks,
14276                        offset: snapshot
14277                            .buffer_snapshot
14278                            .anchor_before(runnable.run_range.start),
14279                        context_range,
14280                        column: point.column,
14281                        extra_variables: runnable.extra_captures,
14282                    },
14283                ));
14284            }
14285            runnable_rows
14286        })
14287    }
14288
14289    fn templates_with_tags(
14290        project: &Entity<Project>,
14291        runnable: &mut Runnable,
14292        cx: &mut App,
14293    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14294        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14295            let (worktree_id, file) = project
14296                .buffer_for_id(runnable.buffer, cx)
14297                .and_then(|buffer| buffer.read(cx).file())
14298                .map(|file| (file.worktree_id(cx), file.clone()))
14299                .unzip();
14300
14301            (
14302                project.task_store().read(cx).task_inventory().cloned(),
14303                worktree_id,
14304                file,
14305            )
14306        });
14307
14308        let tags = mem::take(&mut runnable.tags);
14309        let language = runnable.language.clone();
14310        cx.spawn(async move |cx| {
14311            let mut templates_with_tags = Vec::new();
14312            if let Some(inventory) = inventory {
14313                for RunnableTag(tag) in tags {
14314                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14315                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14316                    }) else {
14317                        return templates_with_tags;
14318                    };
14319                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14320                        move |(_, template)| {
14321                            template.tags.iter().any(|source_tag| source_tag == &tag)
14322                        },
14323                    ));
14324                }
14325            }
14326            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14327
14328            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14329                // Strongest source wins; if we have worktree tag binding, prefer that to
14330                // global and language bindings;
14331                // if we have a global binding, prefer that to language binding.
14332                let first_mismatch = templates_with_tags
14333                    .iter()
14334                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14335                if let Some(index) = first_mismatch {
14336                    templates_with_tags.truncate(index);
14337                }
14338            }
14339
14340            templates_with_tags
14341        })
14342    }
14343
14344    pub fn move_to_enclosing_bracket(
14345        &mut self,
14346        _: &MoveToEnclosingBracket,
14347        window: &mut Window,
14348        cx: &mut Context<Self>,
14349    ) {
14350        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14351        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14352            s.move_offsets_with(|snapshot, selection| {
14353                let Some(enclosing_bracket_ranges) =
14354                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14355                else {
14356                    return;
14357                };
14358
14359                let mut best_length = usize::MAX;
14360                let mut best_inside = false;
14361                let mut best_in_bracket_range = false;
14362                let mut best_destination = None;
14363                for (open, close) in enclosing_bracket_ranges {
14364                    let close = close.to_inclusive();
14365                    let length = close.end() - open.start;
14366                    let inside = selection.start >= open.end && selection.end <= *close.start();
14367                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14368                        || close.contains(&selection.head());
14369
14370                    // If best is next to a bracket and current isn't, skip
14371                    if !in_bracket_range && best_in_bracket_range {
14372                        continue;
14373                    }
14374
14375                    // Prefer smaller lengths unless best is inside and current isn't
14376                    if length > best_length && (best_inside || !inside) {
14377                        continue;
14378                    }
14379
14380                    best_length = length;
14381                    best_inside = inside;
14382                    best_in_bracket_range = in_bracket_range;
14383                    best_destination = Some(
14384                        if close.contains(&selection.start) && close.contains(&selection.end) {
14385                            if inside { open.end } else { open.start }
14386                        } else if inside {
14387                            *close.start()
14388                        } else {
14389                            *close.end()
14390                        },
14391                    );
14392                }
14393
14394                if let Some(destination) = best_destination {
14395                    selection.collapse_to(destination, SelectionGoal::None);
14396                }
14397            })
14398        });
14399    }
14400
14401    pub fn undo_selection(
14402        &mut self,
14403        _: &UndoSelection,
14404        window: &mut Window,
14405        cx: &mut Context<Self>,
14406    ) {
14407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14408        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14409            self.selection_history.mode = SelectionHistoryMode::Undoing;
14410            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14411                this.end_selection(window, cx);
14412                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14413                    s.select_anchors(entry.selections.to_vec())
14414                });
14415            });
14416            self.selection_history.mode = SelectionHistoryMode::Normal;
14417
14418            self.select_next_state = entry.select_next_state;
14419            self.select_prev_state = entry.select_prev_state;
14420            self.add_selections_state = entry.add_selections_state;
14421        }
14422    }
14423
14424    pub fn redo_selection(
14425        &mut self,
14426        _: &RedoSelection,
14427        window: &mut Window,
14428        cx: &mut Context<Self>,
14429    ) {
14430        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14431        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14432            self.selection_history.mode = SelectionHistoryMode::Redoing;
14433            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14434                this.end_selection(window, cx);
14435                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14436                    s.select_anchors(entry.selections.to_vec())
14437                });
14438            });
14439            self.selection_history.mode = SelectionHistoryMode::Normal;
14440
14441            self.select_next_state = entry.select_next_state;
14442            self.select_prev_state = entry.select_prev_state;
14443            self.add_selections_state = entry.add_selections_state;
14444        }
14445    }
14446
14447    pub fn expand_excerpts(
14448        &mut self,
14449        action: &ExpandExcerpts,
14450        _: &mut Window,
14451        cx: &mut Context<Self>,
14452    ) {
14453        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14454    }
14455
14456    pub fn expand_excerpts_down(
14457        &mut self,
14458        action: &ExpandExcerptsDown,
14459        _: &mut Window,
14460        cx: &mut Context<Self>,
14461    ) {
14462        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14463    }
14464
14465    pub fn expand_excerpts_up(
14466        &mut self,
14467        action: &ExpandExcerptsUp,
14468        _: &mut Window,
14469        cx: &mut Context<Self>,
14470    ) {
14471        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14472    }
14473
14474    pub fn expand_excerpts_for_direction(
14475        &mut self,
14476        lines: u32,
14477        direction: ExpandExcerptDirection,
14478
14479        cx: &mut Context<Self>,
14480    ) {
14481        let selections = self.selections.disjoint_anchors();
14482
14483        let lines = if lines == 0 {
14484            EditorSettings::get_global(cx).expand_excerpt_lines
14485        } else {
14486            lines
14487        };
14488
14489        self.buffer.update(cx, |buffer, cx| {
14490            let snapshot = buffer.snapshot(cx);
14491            let mut excerpt_ids = selections
14492                .iter()
14493                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14494                .collect::<Vec<_>>();
14495            excerpt_ids.sort();
14496            excerpt_ids.dedup();
14497            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14498        })
14499    }
14500
14501    pub fn expand_excerpt(
14502        &mut self,
14503        excerpt: ExcerptId,
14504        direction: ExpandExcerptDirection,
14505        window: &mut Window,
14506        cx: &mut Context<Self>,
14507    ) {
14508        let current_scroll_position = self.scroll_position(cx);
14509        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14510        let mut should_scroll_up = false;
14511
14512        if direction == ExpandExcerptDirection::Down {
14513            let multi_buffer = self.buffer.read(cx);
14514            let snapshot = multi_buffer.snapshot(cx);
14515            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14516                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14517                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14518                        let buffer_snapshot = buffer.read(cx).snapshot();
14519                        let excerpt_end_row =
14520                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14521                        let last_row = buffer_snapshot.max_point().row;
14522                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14523                        should_scroll_up = lines_below >= lines_to_expand;
14524                    }
14525                }
14526            }
14527        }
14528
14529        self.buffer.update(cx, |buffer, cx| {
14530            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14531        });
14532
14533        if should_scroll_up {
14534            let new_scroll_position =
14535                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14536            self.set_scroll_position(new_scroll_position, window, cx);
14537        }
14538    }
14539
14540    pub fn go_to_singleton_buffer_point(
14541        &mut self,
14542        point: Point,
14543        window: &mut Window,
14544        cx: &mut Context<Self>,
14545    ) {
14546        self.go_to_singleton_buffer_range(point..point, window, cx);
14547    }
14548
14549    pub fn go_to_singleton_buffer_range(
14550        &mut self,
14551        range: Range<Point>,
14552        window: &mut Window,
14553        cx: &mut Context<Self>,
14554    ) {
14555        let multibuffer = self.buffer().read(cx);
14556        let Some(buffer) = multibuffer.as_singleton() else {
14557            return;
14558        };
14559        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14560            return;
14561        };
14562        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14563            return;
14564        };
14565        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14566            s.select_anchor_ranges([start..end])
14567        });
14568    }
14569
14570    pub fn go_to_diagnostic(
14571        &mut self,
14572        _: &GoToDiagnostic,
14573        window: &mut Window,
14574        cx: &mut Context<Self>,
14575    ) {
14576        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14577        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14578    }
14579
14580    pub fn go_to_prev_diagnostic(
14581        &mut self,
14582        _: &GoToPreviousDiagnostic,
14583        window: &mut Window,
14584        cx: &mut Context<Self>,
14585    ) {
14586        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14587        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14588    }
14589
14590    pub fn go_to_diagnostic_impl(
14591        &mut self,
14592        direction: Direction,
14593        window: &mut Window,
14594        cx: &mut Context<Self>,
14595    ) {
14596        let buffer = self.buffer.read(cx).snapshot(cx);
14597        let selection = self.selections.newest::<usize>(cx);
14598
14599        let mut active_group_id = None;
14600        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14601            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14602                active_group_id = Some(active_group.group_id);
14603            }
14604        }
14605
14606        fn filtered(
14607            snapshot: EditorSnapshot,
14608            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14609        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14610            diagnostics
14611                .filter(|entry| entry.range.start != entry.range.end)
14612                .filter(|entry| !entry.diagnostic.is_unnecessary)
14613                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14614        }
14615
14616        let snapshot = self.snapshot(window, cx);
14617        let before = filtered(
14618            snapshot.clone(),
14619            buffer
14620                .diagnostics_in_range(0..selection.start)
14621                .filter(|entry| entry.range.start <= selection.start),
14622        );
14623        let after = filtered(
14624            snapshot,
14625            buffer
14626                .diagnostics_in_range(selection.start..buffer.len())
14627                .filter(|entry| entry.range.start >= selection.start),
14628        );
14629
14630        let mut found: Option<DiagnosticEntry<usize>> = None;
14631        if direction == Direction::Prev {
14632            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14633            {
14634                for diagnostic in prev_diagnostics.into_iter().rev() {
14635                    if diagnostic.range.start != selection.start
14636                        || active_group_id
14637                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14638                    {
14639                        found = Some(diagnostic);
14640                        break 'outer;
14641                    }
14642                }
14643            }
14644        } else {
14645            for diagnostic in after.chain(before) {
14646                if diagnostic.range.start != selection.start
14647                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14648                {
14649                    found = Some(diagnostic);
14650                    break;
14651                }
14652            }
14653        }
14654        let Some(next_diagnostic) = found else {
14655            return;
14656        };
14657
14658        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14659            return;
14660        };
14661        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14662            s.select_ranges(vec![
14663                next_diagnostic.range.start..next_diagnostic.range.start,
14664            ])
14665        });
14666        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14667        self.refresh_inline_completion(false, true, window, cx);
14668    }
14669
14670    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14671        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14672        let snapshot = self.snapshot(window, cx);
14673        let selection = self.selections.newest::<Point>(cx);
14674        self.go_to_hunk_before_or_after_position(
14675            &snapshot,
14676            selection.head(),
14677            Direction::Next,
14678            window,
14679            cx,
14680        );
14681    }
14682
14683    pub fn go_to_hunk_before_or_after_position(
14684        &mut self,
14685        snapshot: &EditorSnapshot,
14686        position: Point,
14687        direction: Direction,
14688        window: &mut Window,
14689        cx: &mut Context<Editor>,
14690    ) {
14691        let row = if direction == Direction::Next {
14692            self.hunk_after_position(snapshot, position)
14693                .map(|hunk| hunk.row_range.start)
14694        } else {
14695            self.hunk_before_position(snapshot, position)
14696        };
14697
14698        if let Some(row) = row {
14699            let destination = Point::new(row.0, 0);
14700            let autoscroll = Autoscroll::center();
14701
14702            self.unfold_ranges(&[destination..destination], false, false, cx);
14703            self.change_selections(Some(autoscroll), window, cx, |s| {
14704                s.select_ranges([destination..destination]);
14705            });
14706        }
14707    }
14708
14709    fn hunk_after_position(
14710        &mut self,
14711        snapshot: &EditorSnapshot,
14712        position: Point,
14713    ) -> Option<MultiBufferDiffHunk> {
14714        snapshot
14715            .buffer_snapshot
14716            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14717            .find(|hunk| hunk.row_range.start.0 > position.row)
14718            .or_else(|| {
14719                snapshot
14720                    .buffer_snapshot
14721                    .diff_hunks_in_range(Point::zero()..position)
14722                    .find(|hunk| hunk.row_range.end.0 < position.row)
14723            })
14724    }
14725
14726    fn go_to_prev_hunk(
14727        &mut self,
14728        _: &GoToPreviousHunk,
14729        window: &mut Window,
14730        cx: &mut Context<Self>,
14731    ) {
14732        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14733        let snapshot = self.snapshot(window, cx);
14734        let selection = self.selections.newest::<Point>(cx);
14735        self.go_to_hunk_before_or_after_position(
14736            &snapshot,
14737            selection.head(),
14738            Direction::Prev,
14739            window,
14740            cx,
14741        );
14742    }
14743
14744    fn hunk_before_position(
14745        &mut self,
14746        snapshot: &EditorSnapshot,
14747        position: Point,
14748    ) -> Option<MultiBufferRow> {
14749        snapshot
14750            .buffer_snapshot
14751            .diff_hunk_before(position)
14752            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14753    }
14754
14755    fn go_to_next_change(
14756        &mut self,
14757        _: &GoToNextChange,
14758        window: &mut Window,
14759        cx: &mut Context<Self>,
14760    ) {
14761        if let Some(selections) = self
14762            .change_list
14763            .next_change(1, Direction::Next)
14764            .map(|s| s.to_vec())
14765        {
14766            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14767                let map = s.display_map();
14768                s.select_display_ranges(selections.iter().map(|a| {
14769                    let point = a.to_display_point(&map);
14770                    point..point
14771                }))
14772            })
14773        }
14774    }
14775
14776    fn go_to_previous_change(
14777        &mut self,
14778        _: &GoToPreviousChange,
14779        window: &mut Window,
14780        cx: &mut Context<Self>,
14781    ) {
14782        if let Some(selections) = self
14783            .change_list
14784            .next_change(1, Direction::Prev)
14785            .map(|s| s.to_vec())
14786        {
14787            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14788                let map = s.display_map();
14789                s.select_display_ranges(selections.iter().map(|a| {
14790                    let point = a.to_display_point(&map);
14791                    point..point
14792                }))
14793            })
14794        }
14795    }
14796
14797    fn go_to_line<T: 'static>(
14798        &mut self,
14799        position: Anchor,
14800        highlight_color: Option<Hsla>,
14801        window: &mut Window,
14802        cx: &mut Context<Self>,
14803    ) {
14804        let snapshot = self.snapshot(window, cx).display_snapshot;
14805        let position = position.to_point(&snapshot.buffer_snapshot);
14806        let start = snapshot
14807            .buffer_snapshot
14808            .clip_point(Point::new(position.row, 0), Bias::Left);
14809        let end = start + Point::new(1, 0);
14810        let start = snapshot.buffer_snapshot.anchor_before(start);
14811        let end = snapshot.buffer_snapshot.anchor_before(end);
14812
14813        self.highlight_rows::<T>(
14814            start..end,
14815            highlight_color
14816                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14817            Default::default(),
14818            cx,
14819        );
14820
14821        if self.buffer.read(cx).is_singleton() {
14822            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14823        }
14824    }
14825
14826    pub fn go_to_definition(
14827        &mut self,
14828        _: &GoToDefinition,
14829        window: &mut Window,
14830        cx: &mut Context<Self>,
14831    ) -> Task<Result<Navigated>> {
14832        let definition =
14833            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14834        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14835        cx.spawn_in(window, async move |editor, cx| {
14836            if definition.await? == Navigated::Yes {
14837                return Ok(Navigated::Yes);
14838            }
14839            match fallback_strategy {
14840                GoToDefinitionFallback::None => Ok(Navigated::No),
14841                GoToDefinitionFallback::FindAllReferences => {
14842                    match editor.update_in(cx, |editor, window, cx| {
14843                        editor.find_all_references(&FindAllReferences, window, cx)
14844                    })? {
14845                        Some(references) => references.await,
14846                        None => Ok(Navigated::No),
14847                    }
14848                }
14849            }
14850        })
14851    }
14852
14853    pub fn go_to_declaration(
14854        &mut self,
14855        _: &GoToDeclaration,
14856        window: &mut Window,
14857        cx: &mut Context<Self>,
14858    ) -> Task<Result<Navigated>> {
14859        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14860    }
14861
14862    pub fn go_to_declaration_split(
14863        &mut self,
14864        _: &GoToDeclaration,
14865        window: &mut Window,
14866        cx: &mut Context<Self>,
14867    ) -> Task<Result<Navigated>> {
14868        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14869    }
14870
14871    pub fn go_to_implementation(
14872        &mut self,
14873        _: &GoToImplementation,
14874        window: &mut Window,
14875        cx: &mut Context<Self>,
14876    ) -> Task<Result<Navigated>> {
14877        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14878    }
14879
14880    pub fn go_to_implementation_split(
14881        &mut self,
14882        _: &GoToImplementationSplit,
14883        window: &mut Window,
14884        cx: &mut Context<Self>,
14885    ) -> Task<Result<Navigated>> {
14886        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14887    }
14888
14889    pub fn go_to_type_definition(
14890        &mut self,
14891        _: &GoToTypeDefinition,
14892        window: &mut Window,
14893        cx: &mut Context<Self>,
14894    ) -> Task<Result<Navigated>> {
14895        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14896    }
14897
14898    pub fn go_to_definition_split(
14899        &mut self,
14900        _: &GoToDefinitionSplit,
14901        window: &mut Window,
14902        cx: &mut Context<Self>,
14903    ) -> Task<Result<Navigated>> {
14904        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14905    }
14906
14907    pub fn go_to_type_definition_split(
14908        &mut self,
14909        _: &GoToTypeDefinitionSplit,
14910        window: &mut Window,
14911        cx: &mut Context<Self>,
14912    ) -> Task<Result<Navigated>> {
14913        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14914    }
14915
14916    fn go_to_definition_of_kind(
14917        &mut self,
14918        kind: GotoDefinitionKind,
14919        split: bool,
14920        window: &mut Window,
14921        cx: &mut Context<Self>,
14922    ) -> Task<Result<Navigated>> {
14923        let Some(provider) = self.semantics_provider.clone() else {
14924            return Task::ready(Ok(Navigated::No));
14925        };
14926        let head = self.selections.newest::<usize>(cx).head();
14927        let buffer = self.buffer.read(cx);
14928        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14929            text_anchor
14930        } else {
14931            return Task::ready(Ok(Navigated::No));
14932        };
14933
14934        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14935            return Task::ready(Ok(Navigated::No));
14936        };
14937
14938        cx.spawn_in(window, async move |editor, cx| {
14939            let definitions = definitions.await?;
14940            let navigated = editor
14941                .update_in(cx, |editor, window, cx| {
14942                    editor.navigate_to_hover_links(
14943                        Some(kind),
14944                        definitions
14945                            .into_iter()
14946                            .filter(|location| {
14947                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14948                            })
14949                            .map(HoverLink::Text)
14950                            .collect::<Vec<_>>(),
14951                        split,
14952                        window,
14953                        cx,
14954                    )
14955                })?
14956                .await?;
14957            anyhow::Ok(navigated)
14958        })
14959    }
14960
14961    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14962        let selection = self.selections.newest_anchor();
14963        let head = selection.head();
14964        let tail = selection.tail();
14965
14966        let Some((buffer, start_position)) =
14967            self.buffer.read(cx).text_anchor_for_position(head, cx)
14968        else {
14969            return;
14970        };
14971
14972        let end_position = if head != tail {
14973            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14974                return;
14975            };
14976            Some(pos)
14977        } else {
14978            None
14979        };
14980
14981        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14982            let url = if let Some(end_pos) = end_position {
14983                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14984            } else {
14985                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14986            };
14987
14988            if let Some(url) = url {
14989                editor.update(cx, |_, cx| {
14990                    cx.open_url(&url);
14991                })
14992            } else {
14993                Ok(())
14994            }
14995        });
14996
14997        url_finder.detach();
14998    }
14999
15000    pub fn open_selected_filename(
15001        &mut self,
15002        _: &OpenSelectedFilename,
15003        window: &mut Window,
15004        cx: &mut Context<Self>,
15005    ) {
15006        let Some(workspace) = self.workspace() else {
15007            return;
15008        };
15009
15010        let position = self.selections.newest_anchor().head();
15011
15012        let Some((buffer, buffer_position)) =
15013            self.buffer.read(cx).text_anchor_for_position(position, cx)
15014        else {
15015            return;
15016        };
15017
15018        let project = self.project.clone();
15019
15020        cx.spawn_in(window, async move |_, cx| {
15021            let result = find_file(&buffer, project, buffer_position, cx).await;
15022
15023            if let Some((_, path)) = result {
15024                workspace
15025                    .update_in(cx, |workspace, window, cx| {
15026                        workspace.open_resolved_path(path, window, cx)
15027                    })?
15028                    .await?;
15029            }
15030            anyhow::Ok(())
15031        })
15032        .detach();
15033    }
15034
15035    pub(crate) fn navigate_to_hover_links(
15036        &mut self,
15037        kind: Option<GotoDefinitionKind>,
15038        mut definitions: Vec<HoverLink>,
15039        split: bool,
15040        window: &mut Window,
15041        cx: &mut Context<Editor>,
15042    ) -> Task<Result<Navigated>> {
15043        // If there is one definition, just open it directly
15044        if definitions.len() == 1 {
15045            let definition = definitions.pop().unwrap();
15046
15047            enum TargetTaskResult {
15048                Location(Option<Location>),
15049                AlreadyNavigated,
15050            }
15051
15052            let target_task = match definition {
15053                HoverLink::Text(link) => {
15054                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15055                }
15056                HoverLink::InlayHint(lsp_location, server_id) => {
15057                    let computation =
15058                        self.compute_target_location(lsp_location, server_id, window, cx);
15059                    cx.background_spawn(async move {
15060                        let location = computation.await?;
15061                        Ok(TargetTaskResult::Location(location))
15062                    })
15063                }
15064                HoverLink::Url(url) => {
15065                    cx.open_url(&url);
15066                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15067                }
15068                HoverLink::File(path) => {
15069                    if let Some(workspace) = self.workspace() {
15070                        cx.spawn_in(window, async move |_, cx| {
15071                            workspace
15072                                .update_in(cx, |workspace, window, cx| {
15073                                    workspace.open_resolved_path(path, window, cx)
15074                                })?
15075                                .await
15076                                .map(|_| TargetTaskResult::AlreadyNavigated)
15077                        })
15078                    } else {
15079                        Task::ready(Ok(TargetTaskResult::Location(None)))
15080                    }
15081                }
15082            };
15083            cx.spawn_in(window, async move |editor, cx| {
15084                let target = match target_task.await.context("target resolution task")? {
15085                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15086                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15087                    TargetTaskResult::Location(Some(target)) => target,
15088                };
15089
15090                editor.update_in(cx, |editor, window, cx| {
15091                    let Some(workspace) = editor.workspace() else {
15092                        return Navigated::No;
15093                    };
15094                    let pane = workspace.read(cx).active_pane().clone();
15095
15096                    let range = target.range.to_point(target.buffer.read(cx));
15097                    let range = editor.range_for_match(&range);
15098                    let range = collapse_multiline_range(range);
15099
15100                    if !split
15101                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15102                    {
15103                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15104                    } else {
15105                        window.defer(cx, move |window, cx| {
15106                            let target_editor: Entity<Self> =
15107                                workspace.update(cx, |workspace, cx| {
15108                                    let pane = if split {
15109                                        workspace.adjacent_pane(window, cx)
15110                                    } else {
15111                                        workspace.active_pane().clone()
15112                                    };
15113
15114                                    workspace.open_project_item(
15115                                        pane,
15116                                        target.buffer.clone(),
15117                                        true,
15118                                        true,
15119                                        window,
15120                                        cx,
15121                                    )
15122                                });
15123                            target_editor.update(cx, |target_editor, cx| {
15124                                // When selecting a definition in a different buffer, disable the nav history
15125                                // to avoid creating a history entry at the previous cursor location.
15126                                pane.update(cx, |pane, _| pane.disable_history());
15127                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15128                                pane.update(cx, |pane, _| pane.enable_history());
15129                            });
15130                        });
15131                    }
15132                    Navigated::Yes
15133                })
15134            })
15135        } else if !definitions.is_empty() {
15136            cx.spawn_in(window, async move |editor, cx| {
15137                let (title, location_tasks, workspace) = editor
15138                    .update_in(cx, |editor, window, cx| {
15139                        let tab_kind = match kind {
15140                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15141                            _ => "Definitions",
15142                        };
15143                        let title = definitions
15144                            .iter()
15145                            .find_map(|definition| match definition {
15146                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15147                                    let buffer = origin.buffer.read(cx);
15148                                    format!(
15149                                        "{} for {}",
15150                                        tab_kind,
15151                                        buffer
15152                                            .text_for_range(origin.range.clone())
15153                                            .collect::<String>()
15154                                    )
15155                                }),
15156                                HoverLink::InlayHint(_, _) => None,
15157                                HoverLink::Url(_) => None,
15158                                HoverLink::File(_) => None,
15159                            })
15160                            .unwrap_or(tab_kind.to_string());
15161                        let location_tasks = definitions
15162                            .into_iter()
15163                            .map(|definition| match definition {
15164                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15165                                HoverLink::InlayHint(lsp_location, server_id) => editor
15166                                    .compute_target_location(lsp_location, server_id, window, cx),
15167                                HoverLink::Url(_) => Task::ready(Ok(None)),
15168                                HoverLink::File(_) => Task::ready(Ok(None)),
15169                            })
15170                            .collect::<Vec<_>>();
15171                        (title, location_tasks, editor.workspace().clone())
15172                    })
15173                    .context("location tasks preparation")?;
15174
15175                let locations: Vec<Location> = future::join_all(location_tasks)
15176                    .await
15177                    .into_iter()
15178                    .filter_map(|location| location.transpose())
15179                    .collect::<Result<_>>()
15180                    .context("location tasks")?;
15181
15182                if locations.is_empty() {
15183                    return Ok(Navigated::No);
15184                }
15185
15186                let Some(workspace) = workspace else {
15187                    return Ok(Navigated::No);
15188                };
15189
15190                let opened = workspace
15191                    .update_in(cx, |workspace, window, cx| {
15192                        Self::open_locations_in_multibuffer(
15193                            workspace,
15194                            locations,
15195                            title,
15196                            split,
15197                            MultibufferSelectionMode::First,
15198                            window,
15199                            cx,
15200                        )
15201                    })
15202                    .ok();
15203
15204                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15205            })
15206        } else {
15207            Task::ready(Ok(Navigated::No))
15208        }
15209    }
15210
15211    fn compute_target_location(
15212        &self,
15213        lsp_location: lsp::Location,
15214        server_id: LanguageServerId,
15215        window: &mut Window,
15216        cx: &mut Context<Self>,
15217    ) -> Task<anyhow::Result<Option<Location>>> {
15218        let Some(project) = self.project.clone() else {
15219            return Task::ready(Ok(None));
15220        };
15221
15222        cx.spawn_in(window, async move |editor, cx| {
15223            let location_task = editor.update(cx, |_, cx| {
15224                project.update(cx, |project, cx| {
15225                    let language_server_name = project
15226                        .language_server_statuses(cx)
15227                        .find(|(id, _)| server_id == *id)
15228                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15229                    language_server_name.map(|language_server_name| {
15230                        project.open_local_buffer_via_lsp(
15231                            lsp_location.uri.clone(),
15232                            server_id,
15233                            language_server_name,
15234                            cx,
15235                        )
15236                    })
15237                })
15238            })?;
15239            let location = match location_task {
15240                Some(task) => Some({
15241                    let target_buffer_handle = task.await.context("open local buffer")?;
15242                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15243                        let target_start = target_buffer
15244                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15245                        let target_end = target_buffer
15246                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15247                        target_buffer.anchor_after(target_start)
15248                            ..target_buffer.anchor_before(target_end)
15249                    })?;
15250                    Location {
15251                        buffer: target_buffer_handle,
15252                        range,
15253                    }
15254                }),
15255                None => None,
15256            };
15257            Ok(location)
15258        })
15259    }
15260
15261    pub fn find_all_references(
15262        &mut self,
15263        _: &FindAllReferences,
15264        window: &mut Window,
15265        cx: &mut Context<Self>,
15266    ) -> Option<Task<Result<Navigated>>> {
15267        let selection = self.selections.newest::<usize>(cx);
15268        let multi_buffer = self.buffer.read(cx);
15269        let head = selection.head();
15270
15271        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15272        let head_anchor = multi_buffer_snapshot.anchor_at(
15273            head,
15274            if head < selection.tail() {
15275                Bias::Right
15276            } else {
15277                Bias::Left
15278            },
15279        );
15280
15281        match self
15282            .find_all_references_task_sources
15283            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15284        {
15285            Ok(_) => {
15286                log::info!(
15287                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15288                );
15289                return None;
15290            }
15291            Err(i) => {
15292                self.find_all_references_task_sources.insert(i, head_anchor);
15293            }
15294        }
15295
15296        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15297        let workspace = self.workspace()?;
15298        let project = workspace.read(cx).project().clone();
15299        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15300        Some(cx.spawn_in(window, async move |editor, cx| {
15301            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15302                if let Ok(i) = editor
15303                    .find_all_references_task_sources
15304                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15305                {
15306                    editor.find_all_references_task_sources.remove(i);
15307                }
15308            });
15309
15310            let locations = references.await?;
15311            if locations.is_empty() {
15312                return anyhow::Ok(Navigated::No);
15313            }
15314
15315            workspace.update_in(cx, |workspace, window, cx| {
15316                let title = locations
15317                    .first()
15318                    .as_ref()
15319                    .map(|location| {
15320                        let buffer = location.buffer.read(cx);
15321                        format!(
15322                            "References to `{}`",
15323                            buffer
15324                                .text_for_range(location.range.clone())
15325                                .collect::<String>()
15326                        )
15327                    })
15328                    .unwrap();
15329                Self::open_locations_in_multibuffer(
15330                    workspace,
15331                    locations,
15332                    title,
15333                    false,
15334                    MultibufferSelectionMode::First,
15335                    window,
15336                    cx,
15337                );
15338                Navigated::Yes
15339            })
15340        }))
15341    }
15342
15343    /// Opens a multibuffer with the given project locations in it
15344    pub fn open_locations_in_multibuffer(
15345        workspace: &mut Workspace,
15346        mut locations: Vec<Location>,
15347        title: String,
15348        split: bool,
15349        multibuffer_selection_mode: MultibufferSelectionMode,
15350        window: &mut Window,
15351        cx: &mut Context<Workspace>,
15352    ) {
15353        if locations.is_empty() {
15354            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15355            return;
15356        }
15357
15358        // If there are multiple definitions, open them in a multibuffer
15359        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15360        let mut locations = locations.into_iter().peekable();
15361        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15362        let capability = workspace.project().read(cx).capability();
15363
15364        let excerpt_buffer = cx.new(|cx| {
15365            let mut multibuffer = MultiBuffer::new(capability);
15366            while let Some(location) = locations.next() {
15367                let buffer = location.buffer.read(cx);
15368                let mut ranges_for_buffer = Vec::new();
15369                let range = location.range.to_point(buffer);
15370                ranges_for_buffer.push(range.clone());
15371
15372                while let Some(next_location) = locations.peek() {
15373                    if next_location.buffer == location.buffer {
15374                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15375                        locations.next();
15376                    } else {
15377                        break;
15378                    }
15379                }
15380
15381                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15382                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15383                    PathKey::for_buffer(&location.buffer, cx),
15384                    location.buffer.clone(),
15385                    ranges_for_buffer,
15386                    DEFAULT_MULTIBUFFER_CONTEXT,
15387                    cx,
15388                );
15389                ranges.extend(new_ranges)
15390            }
15391
15392            multibuffer.with_title(title)
15393        });
15394
15395        let editor = cx.new(|cx| {
15396            Editor::for_multibuffer(
15397                excerpt_buffer,
15398                Some(workspace.project().clone()),
15399                window,
15400                cx,
15401            )
15402        });
15403        editor.update(cx, |editor, cx| {
15404            match multibuffer_selection_mode {
15405                MultibufferSelectionMode::First => {
15406                    if let Some(first_range) = ranges.first() {
15407                        editor.change_selections(None, window, cx, |selections| {
15408                            selections.clear_disjoint();
15409                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15410                        });
15411                    }
15412                    editor.highlight_background::<Self>(
15413                        &ranges,
15414                        |theme| theme.colors().editor_highlighted_line_background,
15415                        cx,
15416                    );
15417                }
15418                MultibufferSelectionMode::All => {
15419                    editor.change_selections(None, window, cx, |selections| {
15420                        selections.clear_disjoint();
15421                        selections.select_anchor_ranges(ranges);
15422                    });
15423                }
15424            }
15425            editor.register_buffers_with_language_servers(cx);
15426        });
15427
15428        let item = Box::new(editor);
15429        let item_id = item.item_id();
15430
15431        if split {
15432            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15433        } else {
15434            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15435                let (preview_item_id, preview_item_idx) =
15436                    workspace.active_pane().read_with(cx, |pane, _| {
15437                        (pane.preview_item_id(), pane.preview_item_idx())
15438                    });
15439
15440                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15441
15442                if let Some(preview_item_id) = preview_item_id {
15443                    workspace.active_pane().update(cx, |pane, cx| {
15444                        pane.remove_item(preview_item_id, false, false, window, cx);
15445                    });
15446                }
15447            } else {
15448                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15449            }
15450        }
15451        workspace.active_pane().update(cx, |pane, cx| {
15452            pane.set_preview_item_id(Some(item_id), cx);
15453        });
15454    }
15455
15456    pub fn rename(
15457        &mut self,
15458        _: &Rename,
15459        window: &mut Window,
15460        cx: &mut Context<Self>,
15461    ) -> Option<Task<Result<()>>> {
15462        use language::ToOffset as _;
15463
15464        let provider = self.semantics_provider.clone()?;
15465        let selection = self.selections.newest_anchor().clone();
15466        let (cursor_buffer, cursor_buffer_position) = self
15467            .buffer
15468            .read(cx)
15469            .text_anchor_for_position(selection.head(), cx)?;
15470        let (tail_buffer, cursor_buffer_position_end) = self
15471            .buffer
15472            .read(cx)
15473            .text_anchor_for_position(selection.tail(), cx)?;
15474        if tail_buffer != cursor_buffer {
15475            return None;
15476        }
15477
15478        let snapshot = cursor_buffer.read(cx).snapshot();
15479        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15480        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15481        let prepare_rename = provider
15482            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15483            .unwrap_or_else(|| Task::ready(Ok(None)));
15484        drop(snapshot);
15485
15486        Some(cx.spawn_in(window, async move |this, cx| {
15487            let rename_range = if let Some(range) = prepare_rename.await? {
15488                Some(range)
15489            } else {
15490                this.update(cx, |this, cx| {
15491                    let buffer = this.buffer.read(cx).snapshot(cx);
15492                    let mut buffer_highlights = this
15493                        .document_highlights_for_position(selection.head(), &buffer)
15494                        .filter(|highlight| {
15495                            highlight.start.excerpt_id == selection.head().excerpt_id
15496                                && highlight.end.excerpt_id == selection.head().excerpt_id
15497                        });
15498                    buffer_highlights
15499                        .next()
15500                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15501                })?
15502            };
15503            if let Some(rename_range) = rename_range {
15504                this.update_in(cx, |this, window, cx| {
15505                    let snapshot = cursor_buffer.read(cx).snapshot();
15506                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15507                    let cursor_offset_in_rename_range =
15508                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15509                    let cursor_offset_in_rename_range_end =
15510                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15511
15512                    this.take_rename(false, window, cx);
15513                    let buffer = this.buffer.read(cx).read(cx);
15514                    let cursor_offset = selection.head().to_offset(&buffer);
15515                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15516                    let rename_end = rename_start + rename_buffer_range.len();
15517                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15518                    let mut old_highlight_id = None;
15519                    let old_name: Arc<str> = buffer
15520                        .chunks(rename_start..rename_end, true)
15521                        .map(|chunk| {
15522                            if old_highlight_id.is_none() {
15523                                old_highlight_id = chunk.syntax_highlight_id;
15524                            }
15525                            chunk.text
15526                        })
15527                        .collect::<String>()
15528                        .into();
15529
15530                    drop(buffer);
15531
15532                    // Position the selection in the rename editor so that it matches the current selection.
15533                    this.show_local_selections = false;
15534                    let rename_editor = cx.new(|cx| {
15535                        let mut editor = Editor::single_line(window, cx);
15536                        editor.buffer.update(cx, |buffer, cx| {
15537                            buffer.edit([(0..0, old_name.clone())], None, cx)
15538                        });
15539                        let rename_selection_range = match cursor_offset_in_rename_range
15540                            .cmp(&cursor_offset_in_rename_range_end)
15541                        {
15542                            Ordering::Equal => {
15543                                editor.select_all(&SelectAll, window, cx);
15544                                return editor;
15545                            }
15546                            Ordering::Less => {
15547                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15548                            }
15549                            Ordering::Greater => {
15550                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15551                            }
15552                        };
15553                        if rename_selection_range.end > old_name.len() {
15554                            editor.select_all(&SelectAll, window, cx);
15555                        } else {
15556                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15557                                s.select_ranges([rename_selection_range]);
15558                            });
15559                        }
15560                        editor
15561                    });
15562                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15563                        if e == &EditorEvent::Focused {
15564                            cx.emit(EditorEvent::FocusedIn)
15565                        }
15566                    })
15567                    .detach();
15568
15569                    let write_highlights =
15570                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15571                    let read_highlights =
15572                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15573                    let ranges = write_highlights
15574                        .iter()
15575                        .flat_map(|(_, ranges)| ranges.iter())
15576                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15577                        .cloned()
15578                        .collect();
15579
15580                    this.highlight_text::<Rename>(
15581                        ranges,
15582                        HighlightStyle {
15583                            fade_out: Some(0.6),
15584                            ..Default::default()
15585                        },
15586                        cx,
15587                    );
15588                    let rename_focus_handle = rename_editor.focus_handle(cx);
15589                    window.focus(&rename_focus_handle);
15590                    let block_id = this.insert_blocks(
15591                        [BlockProperties {
15592                            style: BlockStyle::Flex,
15593                            placement: BlockPlacement::Below(range.start),
15594                            height: Some(1),
15595                            render: Arc::new({
15596                                let rename_editor = rename_editor.clone();
15597                                move |cx: &mut BlockContext| {
15598                                    let mut text_style = cx.editor_style.text.clone();
15599                                    if let Some(highlight_style) = old_highlight_id
15600                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15601                                    {
15602                                        text_style = text_style.highlight(highlight_style);
15603                                    }
15604                                    div()
15605                                        .block_mouse_except_scroll()
15606                                        .pl(cx.anchor_x)
15607                                        .child(EditorElement::new(
15608                                            &rename_editor,
15609                                            EditorStyle {
15610                                                background: cx.theme().system().transparent,
15611                                                local_player: cx.editor_style.local_player,
15612                                                text: text_style,
15613                                                scrollbar_width: cx.editor_style.scrollbar_width,
15614                                                syntax: cx.editor_style.syntax.clone(),
15615                                                status: cx.editor_style.status.clone(),
15616                                                inlay_hints_style: HighlightStyle {
15617                                                    font_weight: Some(FontWeight::BOLD),
15618                                                    ..make_inlay_hints_style(cx.app)
15619                                                },
15620                                                inline_completion_styles: make_suggestion_styles(
15621                                                    cx.app,
15622                                                ),
15623                                                ..EditorStyle::default()
15624                                            },
15625                                        ))
15626                                        .into_any_element()
15627                                }
15628                            }),
15629                            priority: 0,
15630                            render_in_minimap: true,
15631                        }],
15632                        Some(Autoscroll::fit()),
15633                        cx,
15634                    )[0];
15635                    this.pending_rename = Some(RenameState {
15636                        range,
15637                        old_name,
15638                        editor: rename_editor,
15639                        block_id,
15640                    });
15641                })?;
15642            }
15643
15644            Ok(())
15645        }))
15646    }
15647
15648    pub fn confirm_rename(
15649        &mut self,
15650        _: &ConfirmRename,
15651        window: &mut Window,
15652        cx: &mut Context<Self>,
15653    ) -> Option<Task<Result<()>>> {
15654        let rename = self.take_rename(false, window, cx)?;
15655        let workspace = self.workspace()?.downgrade();
15656        let (buffer, start) = self
15657            .buffer
15658            .read(cx)
15659            .text_anchor_for_position(rename.range.start, cx)?;
15660        let (end_buffer, _) = self
15661            .buffer
15662            .read(cx)
15663            .text_anchor_for_position(rename.range.end, cx)?;
15664        if buffer != end_buffer {
15665            return None;
15666        }
15667
15668        let old_name = rename.old_name;
15669        let new_name = rename.editor.read(cx).text(cx);
15670
15671        let rename = self.semantics_provider.as_ref()?.perform_rename(
15672            &buffer,
15673            start,
15674            new_name.clone(),
15675            cx,
15676        )?;
15677
15678        Some(cx.spawn_in(window, async move |editor, cx| {
15679            let project_transaction = rename.await?;
15680            Self::open_project_transaction(
15681                &editor,
15682                workspace,
15683                project_transaction,
15684                format!("Rename: {}{}", old_name, new_name),
15685                cx,
15686            )
15687            .await?;
15688
15689            editor.update(cx, |editor, cx| {
15690                editor.refresh_document_highlights(cx);
15691            })?;
15692            Ok(())
15693        }))
15694    }
15695
15696    fn take_rename(
15697        &mut self,
15698        moving_cursor: bool,
15699        window: &mut Window,
15700        cx: &mut Context<Self>,
15701    ) -> Option<RenameState> {
15702        let rename = self.pending_rename.take()?;
15703        if rename.editor.focus_handle(cx).is_focused(window) {
15704            window.focus(&self.focus_handle);
15705        }
15706
15707        self.remove_blocks(
15708            [rename.block_id].into_iter().collect(),
15709            Some(Autoscroll::fit()),
15710            cx,
15711        );
15712        self.clear_highlights::<Rename>(cx);
15713        self.show_local_selections = true;
15714
15715        if moving_cursor {
15716            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15717                editor.selections.newest::<usize>(cx).head()
15718            });
15719
15720            // Update the selection to match the position of the selection inside
15721            // the rename editor.
15722            let snapshot = self.buffer.read(cx).read(cx);
15723            let rename_range = rename.range.to_offset(&snapshot);
15724            let cursor_in_editor = snapshot
15725                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15726                .min(rename_range.end);
15727            drop(snapshot);
15728
15729            self.change_selections(None, window, cx, |s| {
15730                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15731            });
15732        } else {
15733            self.refresh_document_highlights(cx);
15734        }
15735
15736        Some(rename)
15737    }
15738
15739    pub fn pending_rename(&self) -> Option<&RenameState> {
15740        self.pending_rename.as_ref()
15741    }
15742
15743    fn format(
15744        &mut self,
15745        _: &Format,
15746        window: &mut Window,
15747        cx: &mut Context<Self>,
15748    ) -> Option<Task<Result<()>>> {
15749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15750
15751        let project = match &self.project {
15752            Some(project) => project.clone(),
15753            None => return None,
15754        };
15755
15756        Some(self.perform_format(
15757            project,
15758            FormatTrigger::Manual,
15759            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15760            window,
15761            cx,
15762        ))
15763    }
15764
15765    fn format_selections(
15766        &mut self,
15767        _: &FormatSelections,
15768        window: &mut Window,
15769        cx: &mut Context<Self>,
15770    ) -> Option<Task<Result<()>>> {
15771        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15772
15773        let project = match &self.project {
15774            Some(project) => project.clone(),
15775            None => return None,
15776        };
15777
15778        let ranges = self
15779            .selections
15780            .all_adjusted(cx)
15781            .into_iter()
15782            .map(|selection| selection.range())
15783            .collect_vec();
15784
15785        Some(self.perform_format(
15786            project,
15787            FormatTrigger::Manual,
15788            FormatTarget::Ranges(ranges),
15789            window,
15790            cx,
15791        ))
15792    }
15793
15794    fn perform_format(
15795        &mut self,
15796        project: Entity<Project>,
15797        trigger: FormatTrigger,
15798        target: FormatTarget,
15799        window: &mut Window,
15800        cx: &mut Context<Self>,
15801    ) -> Task<Result<()>> {
15802        let buffer = self.buffer.clone();
15803        let (buffers, target) = match target {
15804            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15805            FormatTarget::Ranges(selection_ranges) => {
15806                let multi_buffer = buffer.read(cx);
15807                let snapshot = multi_buffer.read(cx);
15808                let mut buffers = HashSet::default();
15809                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15810                    BTreeMap::new();
15811                for selection_range in selection_ranges {
15812                    for (buffer, buffer_range, _) in
15813                        snapshot.range_to_buffer_ranges(selection_range)
15814                    {
15815                        let buffer_id = buffer.remote_id();
15816                        let start = buffer.anchor_before(buffer_range.start);
15817                        let end = buffer.anchor_after(buffer_range.end);
15818                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15819                        buffer_id_to_ranges
15820                            .entry(buffer_id)
15821                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15822                            .or_insert_with(|| vec![start..end]);
15823                    }
15824                }
15825                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15826            }
15827        };
15828
15829        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15830        let selections_prev = transaction_id_prev
15831            .and_then(|transaction_id_prev| {
15832                // default to selections as they were after the last edit, if we have them,
15833                // instead of how they are now.
15834                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15835                // will take you back to where you made the last edit, instead of staying where you scrolled
15836                self.selection_history
15837                    .transaction(transaction_id_prev)
15838                    .map(|t| t.0.clone())
15839            })
15840            .unwrap_or_else(|| {
15841                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15842                self.selections.disjoint_anchors()
15843            });
15844
15845        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15846        let format = project.update(cx, |project, cx| {
15847            project.format(buffers, target, true, trigger, cx)
15848        });
15849
15850        cx.spawn_in(window, async move |editor, cx| {
15851            let transaction = futures::select_biased! {
15852                transaction = format.log_err().fuse() => transaction,
15853                () = timeout => {
15854                    log::warn!("timed out waiting for formatting");
15855                    None
15856                }
15857            };
15858
15859            buffer
15860                .update(cx, |buffer, cx| {
15861                    if let Some(transaction) = transaction {
15862                        if !buffer.is_singleton() {
15863                            buffer.push_transaction(&transaction.0, cx);
15864                        }
15865                    }
15866                    cx.notify();
15867                })
15868                .ok();
15869
15870            if let Some(transaction_id_now) =
15871                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15872            {
15873                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15874                if has_new_transaction {
15875                    _ = editor.update(cx, |editor, _| {
15876                        editor
15877                            .selection_history
15878                            .insert_transaction(transaction_id_now, selections_prev);
15879                    });
15880                }
15881            }
15882
15883            Ok(())
15884        })
15885    }
15886
15887    fn organize_imports(
15888        &mut self,
15889        _: &OrganizeImports,
15890        window: &mut Window,
15891        cx: &mut Context<Self>,
15892    ) -> Option<Task<Result<()>>> {
15893        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15894        let project = match &self.project {
15895            Some(project) => project.clone(),
15896            None => return None,
15897        };
15898        Some(self.perform_code_action_kind(
15899            project,
15900            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15901            window,
15902            cx,
15903        ))
15904    }
15905
15906    fn perform_code_action_kind(
15907        &mut self,
15908        project: Entity<Project>,
15909        kind: CodeActionKind,
15910        window: &mut Window,
15911        cx: &mut Context<Self>,
15912    ) -> Task<Result<()>> {
15913        let buffer = self.buffer.clone();
15914        let buffers = buffer.read(cx).all_buffers();
15915        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15916        let apply_action = project.update(cx, |project, cx| {
15917            project.apply_code_action_kind(buffers, kind, true, cx)
15918        });
15919        cx.spawn_in(window, async move |_, cx| {
15920            let transaction = futures::select_biased! {
15921                () = timeout => {
15922                    log::warn!("timed out waiting for executing code action");
15923                    None
15924                }
15925                transaction = apply_action.log_err().fuse() => transaction,
15926            };
15927            buffer
15928                .update(cx, |buffer, cx| {
15929                    // check if we need this
15930                    if let Some(transaction) = transaction {
15931                        if !buffer.is_singleton() {
15932                            buffer.push_transaction(&transaction.0, cx);
15933                        }
15934                    }
15935                    cx.notify();
15936                })
15937                .ok();
15938            Ok(())
15939        })
15940    }
15941
15942    fn restart_language_server(
15943        &mut self,
15944        _: &RestartLanguageServer,
15945        _: &mut Window,
15946        cx: &mut Context<Self>,
15947    ) {
15948        if let Some(project) = self.project.clone() {
15949            self.buffer.update(cx, |multi_buffer, cx| {
15950                project.update(cx, |project, cx| {
15951                    project.restart_language_servers_for_buffers(
15952                        multi_buffer.all_buffers().into_iter().collect(),
15953                        cx,
15954                    );
15955                });
15956            })
15957        }
15958    }
15959
15960    fn stop_language_server(
15961        &mut self,
15962        _: &StopLanguageServer,
15963        _: &mut Window,
15964        cx: &mut Context<Self>,
15965    ) {
15966        if let Some(project) = self.project.clone() {
15967            self.buffer.update(cx, |multi_buffer, cx| {
15968                project.update(cx, |project, cx| {
15969                    project.stop_language_servers_for_buffers(
15970                        multi_buffer.all_buffers().into_iter().collect(),
15971                        cx,
15972                    );
15973                    cx.emit(project::Event::RefreshInlayHints);
15974                });
15975            });
15976        }
15977    }
15978
15979    fn cancel_language_server_work(
15980        workspace: &mut Workspace,
15981        _: &actions::CancelLanguageServerWork,
15982        _: &mut Window,
15983        cx: &mut Context<Workspace>,
15984    ) {
15985        let project = workspace.project();
15986        let buffers = workspace
15987            .active_item(cx)
15988            .and_then(|item| item.act_as::<Editor>(cx))
15989            .map_or(HashSet::default(), |editor| {
15990                editor.read(cx).buffer.read(cx).all_buffers()
15991            });
15992        project.update(cx, |project, cx| {
15993            project.cancel_language_server_work_for_buffers(buffers, cx);
15994        });
15995    }
15996
15997    fn show_character_palette(
15998        &mut self,
15999        _: &ShowCharacterPalette,
16000        window: &mut Window,
16001        _: &mut Context<Self>,
16002    ) {
16003        window.show_character_palette();
16004    }
16005
16006    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16007        if self.mode.is_minimap() {
16008            return;
16009        }
16010
16011        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16012            let buffer = self.buffer.read(cx).snapshot(cx);
16013            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16014            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16015            let is_valid = buffer
16016                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16017                .any(|entry| {
16018                    entry.diagnostic.is_primary
16019                        && !entry.range.is_empty()
16020                        && entry.range.start == primary_range_start
16021                        && entry.diagnostic.message == active_diagnostics.active_message
16022                });
16023
16024            if !is_valid {
16025                self.dismiss_diagnostics(cx);
16026            }
16027        }
16028    }
16029
16030    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16031        match &self.active_diagnostics {
16032            ActiveDiagnostic::Group(group) => Some(group),
16033            _ => None,
16034        }
16035    }
16036
16037    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16038        self.dismiss_diagnostics(cx);
16039        self.active_diagnostics = ActiveDiagnostic::All;
16040    }
16041
16042    fn activate_diagnostics(
16043        &mut self,
16044        buffer_id: BufferId,
16045        diagnostic: DiagnosticEntry<usize>,
16046        window: &mut Window,
16047        cx: &mut Context<Self>,
16048    ) {
16049        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16050            return;
16051        }
16052        self.dismiss_diagnostics(cx);
16053        let snapshot = self.snapshot(window, cx);
16054        let buffer = self.buffer.read(cx).snapshot(cx);
16055        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16056            return;
16057        };
16058
16059        let diagnostic_group = buffer
16060            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16061            .collect::<Vec<_>>();
16062
16063        let blocks =
16064            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16065
16066        let blocks = self.display_map.update(cx, |display_map, cx| {
16067            display_map.insert_blocks(blocks, cx).into_iter().collect()
16068        });
16069        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16070            active_range: buffer.anchor_before(diagnostic.range.start)
16071                ..buffer.anchor_after(diagnostic.range.end),
16072            active_message: diagnostic.diagnostic.message.clone(),
16073            group_id: diagnostic.diagnostic.group_id,
16074            blocks,
16075        });
16076        cx.notify();
16077    }
16078
16079    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16080        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16081            return;
16082        };
16083
16084        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16085        if let ActiveDiagnostic::Group(group) = prev {
16086            self.display_map.update(cx, |display_map, cx| {
16087                display_map.remove_blocks(group.blocks, cx);
16088            });
16089            cx.notify();
16090        }
16091    }
16092
16093    /// Disable inline diagnostics rendering for this editor.
16094    pub fn disable_inline_diagnostics(&mut self) {
16095        self.inline_diagnostics_enabled = false;
16096        self.inline_diagnostics_update = Task::ready(());
16097        self.inline_diagnostics.clear();
16098    }
16099
16100    pub fn diagnostics_enabled(&self) -> bool {
16101        self.mode.is_full()
16102    }
16103
16104    pub fn inline_diagnostics_enabled(&self) -> bool {
16105        self.diagnostics_enabled() && self.inline_diagnostics_enabled
16106    }
16107
16108    pub fn show_inline_diagnostics(&self) -> bool {
16109        self.show_inline_diagnostics
16110    }
16111
16112    pub fn toggle_inline_diagnostics(
16113        &mut self,
16114        _: &ToggleInlineDiagnostics,
16115        window: &mut Window,
16116        cx: &mut Context<Editor>,
16117    ) {
16118        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16119        self.refresh_inline_diagnostics(false, window, cx);
16120    }
16121
16122    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16123        self.diagnostics_max_severity = severity;
16124        self.display_map.update(cx, |display_map, _| {
16125            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16126        });
16127    }
16128
16129    pub fn toggle_diagnostics(
16130        &mut self,
16131        _: &ToggleDiagnostics,
16132        window: &mut Window,
16133        cx: &mut Context<Editor>,
16134    ) {
16135        if !self.diagnostics_enabled() {
16136            return;
16137        }
16138
16139        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16140            EditorSettings::get_global(cx)
16141                .diagnostics_max_severity
16142                .filter(|severity| severity != &DiagnosticSeverity::Off)
16143                .unwrap_or(DiagnosticSeverity::Hint)
16144        } else {
16145            DiagnosticSeverity::Off
16146        };
16147        self.set_max_diagnostics_severity(new_severity, cx);
16148        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16149            self.active_diagnostics = ActiveDiagnostic::None;
16150            self.inline_diagnostics_update = Task::ready(());
16151            self.inline_diagnostics.clear();
16152        } else {
16153            self.refresh_inline_diagnostics(false, window, cx);
16154        }
16155
16156        cx.notify();
16157    }
16158
16159    pub fn toggle_minimap(
16160        &mut self,
16161        _: &ToggleMinimap,
16162        window: &mut Window,
16163        cx: &mut Context<Editor>,
16164    ) {
16165        if self.supports_minimap(cx) {
16166            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16167        }
16168    }
16169
16170    fn refresh_inline_diagnostics(
16171        &mut self,
16172        debounce: bool,
16173        window: &mut Window,
16174        cx: &mut Context<Self>,
16175    ) {
16176        let max_severity = ProjectSettings::get_global(cx)
16177            .diagnostics
16178            .inline
16179            .max_severity
16180            .unwrap_or(self.diagnostics_max_severity);
16181
16182        if !self.inline_diagnostics_enabled()
16183            || !self.show_inline_diagnostics
16184            || max_severity == DiagnosticSeverity::Off
16185        {
16186            self.inline_diagnostics_update = Task::ready(());
16187            self.inline_diagnostics.clear();
16188            return;
16189        }
16190
16191        let debounce_ms = ProjectSettings::get_global(cx)
16192            .diagnostics
16193            .inline
16194            .update_debounce_ms;
16195        let debounce = if debounce && debounce_ms > 0 {
16196            Some(Duration::from_millis(debounce_ms))
16197        } else {
16198            None
16199        };
16200        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16201            if let Some(debounce) = debounce {
16202                cx.background_executor().timer(debounce).await;
16203            }
16204            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16205                editor
16206                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16207                    .ok()
16208            }) else {
16209                return;
16210            };
16211
16212            let new_inline_diagnostics = cx
16213                .background_spawn(async move {
16214                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16215                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16216                        let message = diagnostic_entry
16217                            .diagnostic
16218                            .message
16219                            .split_once('\n')
16220                            .map(|(line, _)| line)
16221                            .map(SharedString::new)
16222                            .unwrap_or_else(|| {
16223                                SharedString::from(diagnostic_entry.diagnostic.message)
16224                            });
16225                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16226                        let (Ok(i) | Err(i)) = inline_diagnostics
16227                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16228                        inline_diagnostics.insert(
16229                            i,
16230                            (
16231                                start_anchor,
16232                                InlineDiagnostic {
16233                                    message,
16234                                    group_id: diagnostic_entry.diagnostic.group_id,
16235                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16236                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16237                                    severity: diagnostic_entry.diagnostic.severity,
16238                                },
16239                            ),
16240                        );
16241                    }
16242                    inline_diagnostics
16243                })
16244                .await;
16245
16246            editor
16247                .update(cx, |editor, cx| {
16248                    editor.inline_diagnostics = new_inline_diagnostics;
16249                    cx.notify();
16250                })
16251                .ok();
16252        });
16253    }
16254
16255    fn pull_diagnostics(
16256        &mut self,
16257        buffer_id: Option<BufferId>,
16258        window: &Window,
16259        cx: &mut Context<Self>,
16260    ) -> Option<()> {
16261        if !self.mode().is_full() {
16262            return None;
16263        }
16264        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16265            .diagnostics
16266            .lsp_pull_diagnostics;
16267        if !pull_diagnostics_settings.enabled {
16268            return None;
16269        }
16270        let project = self.project.as_ref()?.downgrade();
16271        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16272        let mut buffers = self.buffer.read(cx).all_buffers();
16273        if let Some(buffer_id) = buffer_id {
16274            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16275        }
16276
16277        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16278            cx.background_executor().timer(debounce).await;
16279
16280            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16281                buffers
16282                    .into_iter()
16283                    .filter_map(|buffer| {
16284                        project
16285                            .update(cx, |project, cx| {
16286                                project.lsp_store().update(cx, |lsp_store, cx| {
16287                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16288                                })
16289                            })
16290                            .ok()
16291                    })
16292                    .collect::<FuturesUnordered<_>>()
16293            }) else {
16294                return;
16295            };
16296
16297            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16298                match pull_task {
16299                    Ok(()) => {
16300                        if editor
16301                            .update_in(cx, |editor, window, cx| {
16302                                editor.update_diagnostics_state(window, cx);
16303                            })
16304                            .is_err()
16305                        {
16306                            return;
16307                        }
16308                    }
16309                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16310                }
16311            }
16312        });
16313
16314        Some(())
16315    }
16316
16317    pub fn set_selections_from_remote(
16318        &mut self,
16319        selections: Vec<Selection<Anchor>>,
16320        pending_selection: Option<Selection<Anchor>>,
16321        window: &mut Window,
16322        cx: &mut Context<Self>,
16323    ) {
16324        let old_cursor_position = self.selections.newest_anchor().head();
16325        self.selections.change_with(cx, |s| {
16326            s.select_anchors(selections);
16327            if let Some(pending_selection) = pending_selection {
16328                s.set_pending(pending_selection, SelectMode::Character);
16329            } else {
16330                s.clear_pending();
16331            }
16332        });
16333        self.selections_did_change(
16334            false,
16335            &old_cursor_position,
16336            SelectionEffects::default(),
16337            window,
16338            cx,
16339        );
16340    }
16341
16342    pub fn transact(
16343        &mut self,
16344        window: &mut Window,
16345        cx: &mut Context<Self>,
16346        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16347    ) -> Option<TransactionId> {
16348        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16349            this.start_transaction_at(Instant::now(), window, cx);
16350            update(this, window, cx);
16351            this.end_transaction_at(Instant::now(), cx)
16352        })
16353    }
16354
16355    pub fn start_transaction_at(
16356        &mut self,
16357        now: Instant,
16358        window: &mut Window,
16359        cx: &mut Context<Self>,
16360    ) {
16361        self.end_selection(window, cx);
16362        if let Some(tx_id) = self
16363            .buffer
16364            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16365        {
16366            self.selection_history
16367                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16368            cx.emit(EditorEvent::TransactionBegun {
16369                transaction_id: tx_id,
16370            })
16371        }
16372    }
16373
16374    pub fn end_transaction_at(
16375        &mut self,
16376        now: Instant,
16377        cx: &mut Context<Self>,
16378    ) -> Option<TransactionId> {
16379        if let Some(transaction_id) = self
16380            .buffer
16381            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16382        {
16383            if let Some((_, end_selections)) =
16384                self.selection_history.transaction_mut(transaction_id)
16385            {
16386                *end_selections = Some(self.selections.disjoint_anchors());
16387            } else {
16388                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16389            }
16390
16391            cx.emit(EditorEvent::Edited { transaction_id });
16392            Some(transaction_id)
16393        } else {
16394            None
16395        }
16396    }
16397
16398    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16399        if self.selection_mark_mode {
16400            self.change_selections(None, window, cx, |s| {
16401                s.move_with(|_, sel| {
16402                    sel.collapse_to(sel.head(), SelectionGoal::None);
16403                });
16404            })
16405        }
16406        self.selection_mark_mode = true;
16407        cx.notify();
16408    }
16409
16410    pub fn swap_selection_ends(
16411        &mut self,
16412        _: &actions::SwapSelectionEnds,
16413        window: &mut Window,
16414        cx: &mut Context<Self>,
16415    ) {
16416        self.change_selections(None, window, cx, |s| {
16417            s.move_with(|_, sel| {
16418                if sel.start != sel.end {
16419                    sel.reversed = !sel.reversed
16420                }
16421            });
16422        });
16423        self.request_autoscroll(Autoscroll::newest(), cx);
16424        cx.notify();
16425    }
16426
16427    pub fn toggle_fold(
16428        &mut self,
16429        _: &actions::ToggleFold,
16430        window: &mut Window,
16431        cx: &mut Context<Self>,
16432    ) {
16433        if self.is_singleton(cx) {
16434            let selection = self.selections.newest::<Point>(cx);
16435
16436            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16437            let range = if selection.is_empty() {
16438                let point = selection.head().to_display_point(&display_map);
16439                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16440                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16441                    .to_point(&display_map);
16442                start..end
16443            } else {
16444                selection.range()
16445            };
16446            if display_map.folds_in_range(range).next().is_some() {
16447                self.unfold_lines(&Default::default(), window, cx)
16448            } else {
16449                self.fold(&Default::default(), window, cx)
16450            }
16451        } else {
16452            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16453            let buffer_ids: HashSet<_> = self
16454                .selections
16455                .disjoint_anchor_ranges()
16456                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16457                .collect();
16458
16459            let should_unfold = buffer_ids
16460                .iter()
16461                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16462
16463            for buffer_id in buffer_ids {
16464                if should_unfold {
16465                    self.unfold_buffer(buffer_id, cx);
16466                } else {
16467                    self.fold_buffer(buffer_id, cx);
16468                }
16469            }
16470        }
16471    }
16472
16473    pub fn toggle_fold_recursive(
16474        &mut self,
16475        _: &actions::ToggleFoldRecursive,
16476        window: &mut Window,
16477        cx: &mut Context<Self>,
16478    ) {
16479        let selection = self.selections.newest::<Point>(cx);
16480
16481        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16482        let range = if selection.is_empty() {
16483            let point = selection.head().to_display_point(&display_map);
16484            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16485            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16486                .to_point(&display_map);
16487            start..end
16488        } else {
16489            selection.range()
16490        };
16491        if display_map.folds_in_range(range).next().is_some() {
16492            self.unfold_recursive(&Default::default(), window, cx)
16493        } else {
16494            self.fold_recursive(&Default::default(), window, cx)
16495        }
16496    }
16497
16498    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16499        if self.is_singleton(cx) {
16500            let mut to_fold = Vec::new();
16501            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16502            let selections = self.selections.all_adjusted(cx);
16503
16504            for selection in selections {
16505                let range = selection.range().sorted();
16506                let buffer_start_row = range.start.row;
16507
16508                if range.start.row != range.end.row {
16509                    let mut found = false;
16510                    let mut row = range.start.row;
16511                    while row <= range.end.row {
16512                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16513                        {
16514                            found = true;
16515                            row = crease.range().end.row + 1;
16516                            to_fold.push(crease);
16517                        } else {
16518                            row += 1
16519                        }
16520                    }
16521                    if found {
16522                        continue;
16523                    }
16524                }
16525
16526                for row in (0..=range.start.row).rev() {
16527                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16528                        if crease.range().end.row >= buffer_start_row {
16529                            to_fold.push(crease);
16530                            if row <= range.start.row {
16531                                break;
16532                            }
16533                        }
16534                    }
16535                }
16536            }
16537
16538            self.fold_creases(to_fold, true, window, cx);
16539        } else {
16540            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16541            let buffer_ids = self
16542                .selections
16543                .disjoint_anchor_ranges()
16544                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16545                .collect::<HashSet<_>>();
16546            for buffer_id in buffer_ids {
16547                self.fold_buffer(buffer_id, cx);
16548            }
16549        }
16550    }
16551
16552    fn fold_at_level(
16553        &mut self,
16554        fold_at: &FoldAtLevel,
16555        window: &mut Window,
16556        cx: &mut Context<Self>,
16557    ) {
16558        if !self.buffer.read(cx).is_singleton() {
16559            return;
16560        }
16561
16562        let fold_at_level = fold_at.0;
16563        let snapshot = self.buffer.read(cx).snapshot(cx);
16564        let mut to_fold = Vec::new();
16565        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16566
16567        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16568            while start_row < end_row {
16569                match self
16570                    .snapshot(window, cx)
16571                    .crease_for_buffer_row(MultiBufferRow(start_row))
16572                {
16573                    Some(crease) => {
16574                        let nested_start_row = crease.range().start.row + 1;
16575                        let nested_end_row = crease.range().end.row;
16576
16577                        if current_level < fold_at_level {
16578                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16579                        } else if current_level == fold_at_level {
16580                            to_fold.push(crease);
16581                        }
16582
16583                        start_row = nested_end_row + 1;
16584                    }
16585                    None => start_row += 1,
16586                }
16587            }
16588        }
16589
16590        self.fold_creases(to_fold, true, window, cx);
16591    }
16592
16593    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16594        if self.buffer.read(cx).is_singleton() {
16595            let mut fold_ranges = Vec::new();
16596            let snapshot = self.buffer.read(cx).snapshot(cx);
16597
16598            for row in 0..snapshot.max_row().0 {
16599                if let Some(foldable_range) = self
16600                    .snapshot(window, cx)
16601                    .crease_for_buffer_row(MultiBufferRow(row))
16602                {
16603                    fold_ranges.push(foldable_range);
16604                }
16605            }
16606
16607            self.fold_creases(fold_ranges, true, window, cx);
16608        } else {
16609            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16610                editor
16611                    .update_in(cx, |editor, _, cx| {
16612                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16613                            editor.fold_buffer(buffer_id, cx);
16614                        }
16615                    })
16616                    .ok();
16617            });
16618        }
16619    }
16620
16621    pub fn fold_function_bodies(
16622        &mut self,
16623        _: &actions::FoldFunctionBodies,
16624        window: &mut Window,
16625        cx: &mut Context<Self>,
16626    ) {
16627        let snapshot = self.buffer.read(cx).snapshot(cx);
16628
16629        let ranges = snapshot
16630            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16631            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16632            .collect::<Vec<_>>();
16633
16634        let creases = ranges
16635            .into_iter()
16636            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16637            .collect();
16638
16639        self.fold_creases(creases, true, window, cx);
16640    }
16641
16642    pub fn fold_recursive(
16643        &mut self,
16644        _: &actions::FoldRecursive,
16645        window: &mut Window,
16646        cx: &mut Context<Self>,
16647    ) {
16648        let mut to_fold = Vec::new();
16649        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16650        let selections = self.selections.all_adjusted(cx);
16651
16652        for selection in selections {
16653            let range = selection.range().sorted();
16654            let buffer_start_row = range.start.row;
16655
16656            if range.start.row != range.end.row {
16657                let mut found = false;
16658                for row in range.start.row..=range.end.row {
16659                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16660                        found = true;
16661                        to_fold.push(crease);
16662                    }
16663                }
16664                if found {
16665                    continue;
16666                }
16667            }
16668
16669            for row in (0..=range.start.row).rev() {
16670                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16671                    if crease.range().end.row >= buffer_start_row {
16672                        to_fold.push(crease);
16673                    } else {
16674                        break;
16675                    }
16676                }
16677            }
16678        }
16679
16680        self.fold_creases(to_fold, true, window, cx);
16681    }
16682
16683    pub fn fold_at(
16684        &mut self,
16685        buffer_row: MultiBufferRow,
16686        window: &mut Window,
16687        cx: &mut Context<Self>,
16688    ) {
16689        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16690
16691        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16692            let autoscroll = self
16693                .selections
16694                .all::<Point>(cx)
16695                .iter()
16696                .any(|selection| crease.range().overlaps(&selection.range()));
16697
16698            self.fold_creases(vec![crease], autoscroll, window, cx);
16699        }
16700    }
16701
16702    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16703        if self.is_singleton(cx) {
16704            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16705            let buffer = &display_map.buffer_snapshot;
16706            let selections = self.selections.all::<Point>(cx);
16707            let ranges = selections
16708                .iter()
16709                .map(|s| {
16710                    let range = s.display_range(&display_map).sorted();
16711                    let mut start = range.start.to_point(&display_map);
16712                    let mut end = range.end.to_point(&display_map);
16713                    start.column = 0;
16714                    end.column = buffer.line_len(MultiBufferRow(end.row));
16715                    start..end
16716                })
16717                .collect::<Vec<_>>();
16718
16719            self.unfold_ranges(&ranges, true, true, cx);
16720        } else {
16721            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16722            let buffer_ids = self
16723                .selections
16724                .disjoint_anchor_ranges()
16725                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16726                .collect::<HashSet<_>>();
16727            for buffer_id in buffer_ids {
16728                self.unfold_buffer(buffer_id, cx);
16729            }
16730        }
16731    }
16732
16733    pub fn unfold_recursive(
16734        &mut self,
16735        _: &UnfoldRecursive,
16736        _window: &mut Window,
16737        cx: &mut Context<Self>,
16738    ) {
16739        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16740        let selections = self.selections.all::<Point>(cx);
16741        let ranges = selections
16742            .iter()
16743            .map(|s| {
16744                let mut range = s.display_range(&display_map).sorted();
16745                *range.start.column_mut() = 0;
16746                *range.end.column_mut() = display_map.line_len(range.end.row());
16747                let start = range.start.to_point(&display_map);
16748                let end = range.end.to_point(&display_map);
16749                start..end
16750            })
16751            .collect::<Vec<_>>();
16752
16753        self.unfold_ranges(&ranges, true, true, cx);
16754    }
16755
16756    pub fn unfold_at(
16757        &mut self,
16758        buffer_row: MultiBufferRow,
16759        _window: &mut Window,
16760        cx: &mut Context<Self>,
16761    ) {
16762        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16763
16764        let intersection_range = Point::new(buffer_row.0, 0)
16765            ..Point::new(
16766                buffer_row.0,
16767                display_map.buffer_snapshot.line_len(buffer_row),
16768            );
16769
16770        let autoscroll = self
16771            .selections
16772            .all::<Point>(cx)
16773            .iter()
16774            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16775
16776        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16777    }
16778
16779    pub fn unfold_all(
16780        &mut self,
16781        _: &actions::UnfoldAll,
16782        _window: &mut Window,
16783        cx: &mut Context<Self>,
16784    ) {
16785        if self.buffer.read(cx).is_singleton() {
16786            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16787            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16788        } else {
16789            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16790                editor
16791                    .update(cx, |editor, cx| {
16792                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16793                            editor.unfold_buffer(buffer_id, cx);
16794                        }
16795                    })
16796                    .ok();
16797            });
16798        }
16799    }
16800
16801    pub fn fold_selected_ranges(
16802        &mut self,
16803        _: &FoldSelectedRanges,
16804        window: &mut Window,
16805        cx: &mut Context<Self>,
16806    ) {
16807        let selections = self.selections.all_adjusted(cx);
16808        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16809        let ranges = selections
16810            .into_iter()
16811            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16812            .collect::<Vec<_>>();
16813        self.fold_creases(ranges, true, window, cx);
16814    }
16815
16816    pub fn fold_ranges<T: ToOffset + Clone>(
16817        &mut self,
16818        ranges: Vec<Range<T>>,
16819        auto_scroll: bool,
16820        window: &mut Window,
16821        cx: &mut Context<Self>,
16822    ) {
16823        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16824        let ranges = ranges
16825            .into_iter()
16826            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16827            .collect::<Vec<_>>();
16828        self.fold_creases(ranges, auto_scroll, window, cx);
16829    }
16830
16831    pub fn fold_creases<T: ToOffset + Clone>(
16832        &mut self,
16833        creases: Vec<Crease<T>>,
16834        auto_scroll: bool,
16835        _window: &mut Window,
16836        cx: &mut Context<Self>,
16837    ) {
16838        if creases.is_empty() {
16839            return;
16840        }
16841
16842        let mut buffers_affected = HashSet::default();
16843        let multi_buffer = self.buffer().read(cx);
16844        for crease in &creases {
16845            if let Some((_, buffer, _)) =
16846                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16847            {
16848                buffers_affected.insert(buffer.read(cx).remote_id());
16849            };
16850        }
16851
16852        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16853
16854        if auto_scroll {
16855            self.request_autoscroll(Autoscroll::fit(), cx);
16856        }
16857
16858        cx.notify();
16859
16860        self.scrollbar_marker_state.dirty = true;
16861        self.folds_did_change(cx);
16862    }
16863
16864    /// Removes any folds whose ranges intersect any of the given ranges.
16865    pub fn unfold_ranges<T: ToOffset + Clone>(
16866        &mut self,
16867        ranges: &[Range<T>],
16868        inclusive: bool,
16869        auto_scroll: bool,
16870        cx: &mut Context<Self>,
16871    ) {
16872        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16873            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16874        });
16875        self.folds_did_change(cx);
16876    }
16877
16878    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16879        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16880            return;
16881        }
16882        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16883        self.display_map.update(cx, |display_map, cx| {
16884            display_map.fold_buffers([buffer_id], cx)
16885        });
16886        cx.emit(EditorEvent::BufferFoldToggled {
16887            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16888            folded: true,
16889        });
16890        cx.notify();
16891    }
16892
16893    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16894        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16895            return;
16896        }
16897        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16898        self.display_map.update(cx, |display_map, cx| {
16899            display_map.unfold_buffers([buffer_id], cx);
16900        });
16901        cx.emit(EditorEvent::BufferFoldToggled {
16902            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16903            folded: false,
16904        });
16905        cx.notify();
16906    }
16907
16908    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16909        self.display_map.read(cx).is_buffer_folded(buffer)
16910    }
16911
16912    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16913        self.display_map.read(cx).folded_buffers()
16914    }
16915
16916    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16917        self.display_map.update(cx, |display_map, cx| {
16918            display_map.disable_header_for_buffer(buffer_id, cx);
16919        });
16920        cx.notify();
16921    }
16922
16923    /// Removes any folds with the given ranges.
16924    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16925        &mut self,
16926        ranges: &[Range<T>],
16927        type_id: TypeId,
16928        auto_scroll: bool,
16929        cx: &mut Context<Self>,
16930    ) {
16931        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16932            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16933        });
16934        self.folds_did_change(cx);
16935    }
16936
16937    fn remove_folds_with<T: ToOffset + Clone>(
16938        &mut self,
16939        ranges: &[Range<T>],
16940        auto_scroll: bool,
16941        cx: &mut Context<Self>,
16942        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16943    ) {
16944        if ranges.is_empty() {
16945            return;
16946        }
16947
16948        let mut buffers_affected = HashSet::default();
16949        let multi_buffer = self.buffer().read(cx);
16950        for range in ranges {
16951            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16952                buffers_affected.insert(buffer.read(cx).remote_id());
16953            };
16954        }
16955
16956        self.display_map.update(cx, update);
16957
16958        if auto_scroll {
16959            self.request_autoscroll(Autoscroll::fit(), cx);
16960        }
16961
16962        cx.notify();
16963        self.scrollbar_marker_state.dirty = true;
16964        self.active_indent_guides_state.dirty = true;
16965    }
16966
16967    pub fn update_fold_widths(
16968        &mut self,
16969        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16970        cx: &mut Context<Self>,
16971    ) -> bool {
16972        self.display_map
16973            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16974    }
16975
16976    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16977        self.display_map.read(cx).fold_placeholder.clone()
16978    }
16979
16980    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16981        self.buffer.update(cx, |buffer, cx| {
16982            buffer.set_all_diff_hunks_expanded(cx);
16983        });
16984    }
16985
16986    pub fn expand_all_diff_hunks(
16987        &mut self,
16988        _: &ExpandAllDiffHunks,
16989        _window: &mut Window,
16990        cx: &mut Context<Self>,
16991    ) {
16992        self.buffer.update(cx, |buffer, cx| {
16993            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16994        });
16995    }
16996
16997    pub fn toggle_selected_diff_hunks(
16998        &mut self,
16999        _: &ToggleSelectedDiffHunks,
17000        _window: &mut Window,
17001        cx: &mut Context<Self>,
17002    ) {
17003        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17004        self.toggle_diff_hunks_in_ranges(ranges, cx);
17005    }
17006
17007    pub fn diff_hunks_in_ranges<'a>(
17008        &'a self,
17009        ranges: &'a [Range<Anchor>],
17010        buffer: &'a MultiBufferSnapshot,
17011    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17012        ranges.iter().flat_map(move |range| {
17013            let end_excerpt_id = range.end.excerpt_id;
17014            let range = range.to_point(buffer);
17015            let mut peek_end = range.end;
17016            if range.end.row < buffer.max_row().0 {
17017                peek_end = Point::new(range.end.row + 1, 0);
17018            }
17019            buffer
17020                .diff_hunks_in_range(range.start..peek_end)
17021                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17022        })
17023    }
17024
17025    pub fn has_stageable_diff_hunks_in_ranges(
17026        &self,
17027        ranges: &[Range<Anchor>],
17028        snapshot: &MultiBufferSnapshot,
17029    ) -> bool {
17030        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17031        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17032    }
17033
17034    pub fn toggle_staged_selected_diff_hunks(
17035        &mut self,
17036        _: &::git::ToggleStaged,
17037        _: &mut Window,
17038        cx: &mut Context<Self>,
17039    ) {
17040        let snapshot = self.buffer.read(cx).snapshot(cx);
17041        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17042        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17043        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17044    }
17045
17046    pub fn set_render_diff_hunk_controls(
17047        &mut self,
17048        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17049        cx: &mut Context<Self>,
17050    ) {
17051        self.render_diff_hunk_controls = render_diff_hunk_controls;
17052        cx.notify();
17053    }
17054
17055    pub fn stage_and_next(
17056        &mut self,
17057        _: &::git::StageAndNext,
17058        window: &mut Window,
17059        cx: &mut Context<Self>,
17060    ) {
17061        self.do_stage_or_unstage_and_next(true, window, cx);
17062    }
17063
17064    pub fn unstage_and_next(
17065        &mut self,
17066        _: &::git::UnstageAndNext,
17067        window: &mut Window,
17068        cx: &mut Context<Self>,
17069    ) {
17070        self.do_stage_or_unstage_and_next(false, window, cx);
17071    }
17072
17073    pub fn stage_or_unstage_diff_hunks(
17074        &mut self,
17075        stage: bool,
17076        ranges: Vec<Range<Anchor>>,
17077        cx: &mut Context<Self>,
17078    ) {
17079        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17080        cx.spawn(async move |this, cx| {
17081            task.await?;
17082            this.update(cx, |this, cx| {
17083                let snapshot = this.buffer.read(cx).snapshot(cx);
17084                let chunk_by = this
17085                    .diff_hunks_in_ranges(&ranges, &snapshot)
17086                    .chunk_by(|hunk| hunk.buffer_id);
17087                for (buffer_id, hunks) in &chunk_by {
17088                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17089                }
17090            })
17091        })
17092        .detach_and_log_err(cx);
17093    }
17094
17095    fn save_buffers_for_ranges_if_needed(
17096        &mut self,
17097        ranges: &[Range<Anchor>],
17098        cx: &mut Context<Editor>,
17099    ) -> Task<Result<()>> {
17100        let multibuffer = self.buffer.read(cx);
17101        let snapshot = multibuffer.read(cx);
17102        let buffer_ids: HashSet<_> = ranges
17103            .iter()
17104            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17105            .collect();
17106        drop(snapshot);
17107
17108        let mut buffers = HashSet::default();
17109        for buffer_id in buffer_ids {
17110            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17111                let buffer = buffer_entity.read(cx);
17112                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17113                {
17114                    buffers.insert(buffer_entity);
17115                }
17116            }
17117        }
17118
17119        if let Some(project) = &self.project {
17120            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17121        } else {
17122            Task::ready(Ok(()))
17123        }
17124    }
17125
17126    fn do_stage_or_unstage_and_next(
17127        &mut self,
17128        stage: bool,
17129        window: &mut Window,
17130        cx: &mut Context<Self>,
17131    ) {
17132        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17133
17134        if ranges.iter().any(|range| range.start != range.end) {
17135            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17136            return;
17137        }
17138
17139        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17140        let snapshot = self.snapshot(window, cx);
17141        let position = self.selections.newest::<Point>(cx).head();
17142        let mut row = snapshot
17143            .buffer_snapshot
17144            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17145            .find(|hunk| hunk.row_range.start.0 > position.row)
17146            .map(|hunk| hunk.row_range.start);
17147
17148        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17149        // Outside of the project diff editor, wrap around to the beginning.
17150        if !all_diff_hunks_expanded {
17151            row = row.or_else(|| {
17152                snapshot
17153                    .buffer_snapshot
17154                    .diff_hunks_in_range(Point::zero()..position)
17155                    .find(|hunk| hunk.row_range.end.0 < position.row)
17156                    .map(|hunk| hunk.row_range.start)
17157            });
17158        }
17159
17160        if let Some(row) = row {
17161            let destination = Point::new(row.0, 0);
17162            let autoscroll = Autoscroll::center();
17163
17164            self.unfold_ranges(&[destination..destination], false, false, cx);
17165            self.change_selections(Some(autoscroll), window, cx, |s| {
17166                s.select_ranges([destination..destination]);
17167            });
17168        }
17169    }
17170
17171    fn do_stage_or_unstage(
17172        &self,
17173        stage: bool,
17174        buffer_id: BufferId,
17175        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17176        cx: &mut App,
17177    ) -> Option<()> {
17178        let project = self.project.as_ref()?;
17179        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17180        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17181        let buffer_snapshot = buffer.read(cx).snapshot();
17182        let file_exists = buffer_snapshot
17183            .file()
17184            .is_some_and(|file| file.disk_state().exists());
17185        diff.update(cx, |diff, cx| {
17186            diff.stage_or_unstage_hunks(
17187                stage,
17188                &hunks
17189                    .map(|hunk| buffer_diff::DiffHunk {
17190                        buffer_range: hunk.buffer_range,
17191                        diff_base_byte_range: hunk.diff_base_byte_range,
17192                        secondary_status: hunk.secondary_status,
17193                        range: Point::zero()..Point::zero(), // unused
17194                    })
17195                    .collect::<Vec<_>>(),
17196                &buffer_snapshot,
17197                file_exists,
17198                cx,
17199            )
17200        });
17201        None
17202    }
17203
17204    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17205        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17206        self.buffer
17207            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17208    }
17209
17210    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17211        self.buffer.update(cx, |buffer, cx| {
17212            let ranges = vec![Anchor::min()..Anchor::max()];
17213            if !buffer.all_diff_hunks_expanded()
17214                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17215            {
17216                buffer.collapse_diff_hunks(ranges, cx);
17217                true
17218            } else {
17219                false
17220            }
17221        })
17222    }
17223
17224    fn toggle_diff_hunks_in_ranges(
17225        &mut self,
17226        ranges: Vec<Range<Anchor>>,
17227        cx: &mut Context<Editor>,
17228    ) {
17229        self.buffer.update(cx, |buffer, cx| {
17230            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17231            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17232        })
17233    }
17234
17235    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17236        self.buffer.update(cx, |buffer, cx| {
17237            let snapshot = buffer.snapshot(cx);
17238            let excerpt_id = range.end.excerpt_id;
17239            let point_range = range.to_point(&snapshot);
17240            let expand = !buffer.single_hunk_is_expanded(range, cx);
17241            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17242        })
17243    }
17244
17245    pub(crate) fn apply_all_diff_hunks(
17246        &mut self,
17247        _: &ApplyAllDiffHunks,
17248        window: &mut Window,
17249        cx: &mut Context<Self>,
17250    ) {
17251        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17252
17253        let buffers = self.buffer.read(cx).all_buffers();
17254        for branch_buffer in buffers {
17255            branch_buffer.update(cx, |branch_buffer, cx| {
17256                branch_buffer.merge_into_base(Vec::new(), cx);
17257            });
17258        }
17259
17260        if let Some(project) = self.project.clone() {
17261            self.save(
17262                SaveOptions {
17263                    format: true,
17264                    autosave: false,
17265                },
17266                project,
17267                window,
17268                cx,
17269            )
17270            .detach_and_log_err(cx);
17271        }
17272    }
17273
17274    pub(crate) fn apply_selected_diff_hunks(
17275        &mut self,
17276        _: &ApplyDiffHunk,
17277        window: &mut Window,
17278        cx: &mut Context<Self>,
17279    ) {
17280        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17281        let snapshot = self.snapshot(window, cx);
17282        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17283        let mut ranges_by_buffer = HashMap::default();
17284        self.transact(window, cx, |editor, _window, cx| {
17285            for hunk in hunks {
17286                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17287                    ranges_by_buffer
17288                        .entry(buffer.clone())
17289                        .or_insert_with(Vec::new)
17290                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17291                }
17292            }
17293
17294            for (buffer, ranges) in ranges_by_buffer {
17295                buffer.update(cx, |buffer, cx| {
17296                    buffer.merge_into_base(ranges, cx);
17297                });
17298            }
17299        });
17300
17301        if let Some(project) = self.project.clone() {
17302            self.save(
17303                SaveOptions {
17304                    format: true,
17305                    autosave: false,
17306                },
17307                project,
17308                window,
17309                cx,
17310            )
17311            .detach_and_log_err(cx);
17312        }
17313    }
17314
17315    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17316        if hovered != self.gutter_hovered {
17317            self.gutter_hovered = hovered;
17318            cx.notify();
17319        }
17320    }
17321
17322    pub fn insert_blocks(
17323        &mut self,
17324        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17325        autoscroll: Option<Autoscroll>,
17326        cx: &mut Context<Self>,
17327    ) -> Vec<CustomBlockId> {
17328        let blocks = self
17329            .display_map
17330            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17331        if let Some(autoscroll) = autoscroll {
17332            self.request_autoscroll(autoscroll, cx);
17333        }
17334        cx.notify();
17335        blocks
17336    }
17337
17338    pub fn resize_blocks(
17339        &mut self,
17340        heights: HashMap<CustomBlockId, u32>,
17341        autoscroll: Option<Autoscroll>,
17342        cx: &mut Context<Self>,
17343    ) {
17344        self.display_map
17345            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17346        if let Some(autoscroll) = autoscroll {
17347            self.request_autoscroll(autoscroll, cx);
17348        }
17349        cx.notify();
17350    }
17351
17352    pub fn replace_blocks(
17353        &mut self,
17354        renderers: HashMap<CustomBlockId, RenderBlock>,
17355        autoscroll: Option<Autoscroll>,
17356        cx: &mut Context<Self>,
17357    ) {
17358        self.display_map
17359            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17360        if let Some(autoscroll) = autoscroll {
17361            self.request_autoscroll(autoscroll, cx);
17362        }
17363        cx.notify();
17364    }
17365
17366    pub fn remove_blocks(
17367        &mut self,
17368        block_ids: HashSet<CustomBlockId>,
17369        autoscroll: Option<Autoscroll>,
17370        cx: &mut Context<Self>,
17371    ) {
17372        self.display_map.update(cx, |display_map, cx| {
17373            display_map.remove_blocks(block_ids, cx)
17374        });
17375        if let Some(autoscroll) = autoscroll {
17376            self.request_autoscroll(autoscroll, cx);
17377        }
17378        cx.notify();
17379    }
17380
17381    pub fn row_for_block(
17382        &self,
17383        block_id: CustomBlockId,
17384        cx: &mut Context<Self>,
17385    ) -> Option<DisplayRow> {
17386        self.display_map
17387            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17388    }
17389
17390    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17391        self.focused_block = Some(focused_block);
17392    }
17393
17394    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17395        self.focused_block.take()
17396    }
17397
17398    pub fn insert_creases(
17399        &mut self,
17400        creases: impl IntoIterator<Item = Crease<Anchor>>,
17401        cx: &mut Context<Self>,
17402    ) -> Vec<CreaseId> {
17403        self.display_map
17404            .update(cx, |map, cx| map.insert_creases(creases, cx))
17405    }
17406
17407    pub fn remove_creases(
17408        &mut self,
17409        ids: impl IntoIterator<Item = CreaseId>,
17410        cx: &mut Context<Self>,
17411    ) -> Vec<(CreaseId, Range<Anchor>)> {
17412        self.display_map
17413            .update(cx, |map, cx| map.remove_creases(ids, cx))
17414    }
17415
17416    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17417        self.display_map
17418            .update(cx, |map, cx| map.snapshot(cx))
17419            .longest_row()
17420    }
17421
17422    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17423        self.display_map
17424            .update(cx, |map, cx| map.snapshot(cx))
17425            .max_point()
17426    }
17427
17428    pub fn text(&self, cx: &App) -> String {
17429        self.buffer.read(cx).read(cx).text()
17430    }
17431
17432    pub fn is_empty(&self, cx: &App) -> bool {
17433        self.buffer.read(cx).read(cx).is_empty()
17434    }
17435
17436    pub fn text_option(&self, cx: &App) -> Option<String> {
17437        let text = self.text(cx);
17438        let text = text.trim();
17439
17440        if text.is_empty() {
17441            return None;
17442        }
17443
17444        Some(text.to_string())
17445    }
17446
17447    pub fn set_text(
17448        &mut self,
17449        text: impl Into<Arc<str>>,
17450        window: &mut Window,
17451        cx: &mut Context<Self>,
17452    ) {
17453        self.transact(window, cx, |this, _, cx| {
17454            this.buffer
17455                .read(cx)
17456                .as_singleton()
17457                .expect("you can only call set_text on editors for singleton buffers")
17458                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17459        });
17460    }
17461
17462    pub fn display_text(&self, cx: &mut App) -> String {
17463        self.display_map
17464            .update(cx, |map, cx| map.snapshot(cx))
17465            .text()
17466    }
17467
17468    fn create_minimap(
17469        &self,
17470        minimap_settings: MinimapSettings,
17471        window: &mut Window,
17472        cx: &mut Context<Self>,
17473    ) -> Option<Entity<Self>> {
17474        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17475            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17476    }
17477
17478    fn initialize_new_minimap(
17479        &self,
17480        minimap_settings: MinimapSettings,
17481        window: &mut Window,
17482        cx: &mut Context<Self>,
17483    ) -> Entity<Self> {
17484        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17485
17486        let mut minimap = Editor::new_internal(
17487            EditorMode::Minimap {
17488                parent: cx.weak_entity(),
17489            },
17490            self.buffer.clone(),
17491            self.project.clone(),
17492            Some(self.display_map.clone()),
17493            window,
17494            cx,
17495        );
17496        minimap.scroll_manager.clone_state(&self.scroll_manager);
17497        minimap.set_text_style_refinement(TextStyleRefinement {
17498            font_size: Some(MINIMAP_FONT_SIZE),
17499            font_weight: Some(MINIMAP_FONT_WEIGHT),
17500            ..Default::default()
17501        });
17502        minimap.update_minimap_configuration(minimap_settings, cx);
17503        cx.new(|_| minimap)
17504    }
17505
17506    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17507        let current_line_highlight = minimap_settings
17508            .current_line_highlight
17509            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17510        self.set_current_line_highlight(Some(current_line_highlight));
17511    }
17512
17513    pub fn minimap(&self) -> Option<&Entity<Self>> {
17514        self.minimap
17515            .as_ref()
17516            .filter(|_| self.minimap_visibility.visible())
17517    }
17518
17519    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17520        let mut wrap_guides = smallvec![];
17521
17522        if self.show_wrap_guides == Some(false) {
17523            return wrap_guides;
17524        }
17525
17526        let settings = self.buffer.read(cx).language_settings(cx);
17527        if settings.show_wrap_guides {
17528            match self.soft_wrap_mode(cx) {
17529                SoftWrap::Column(soft_wrap) => {
17530                    wrap_guides.push((soft_wrap as usize, true));
17531                }
17532                SoftWrap::Bounded(soft_wrap) => {
17533                    wrap_guides.push((soft_wrap as usize, true));
17534                }
17535                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17536            }
17537            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17538        }
17539
17540        wrap_guides
17541    }
17542
17543    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17544        let settings = self.buffer.read(cx).language_settings(cx);
17545        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17546        match mode {
17547            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17548                SoftWrap::None
17549            }
17550            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17551            language_settings::SoftWrap::PreferredLineLength => {
17552                SoftWrap::Column(settings.preferred_line_length)
17553            }
17554            language_settings::SoftWrap::Bounded => {
17555                SoftWrap::Bounded(settings.preferred_line_length)
17556            }
17557        }
17558    }
17559
17560    pub fn set_soft_wrap_mode(
17561        &mut self,
17562        mode: language_settings::SoftWrap,
17563
17564        cx: &mut Context<Self>,
17565    ) {
17566        self.soft_wrap_mode_override = Some(mode);
17567        cx.notify();
17568    }
17569
17570    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17571        self.hard_wrap = hard_wrap;
17572        cx.notify();
17573    }
17574
17575    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17576        self.text_style_refinement = Some(style);
17577    }
17578
17579    /// called by the Element so we know what style we were most recently rendered with.
17580    pub(crate) fn set_style(
17581        &mut self,
17582        style: EditorStyle,
17583        window: &mut Window,
17584        cx: &mut Context<Self>,
17585    ) {
17586        // We intentionally do not inform the display map about the minimap style
17587        // so that wrapping is not recalculated and stays consistent for the editor
17588        // and its linked minimap.
17589        if !self.mode.is_minimap() {
17590            let rem_size = window.rem_size();
17591            self.display_map.update(cx, |map, cx| {
17592                map.set_font(
17593                    style.text.font(),
17594                    style.text.font_size.to_pixels(rem_size),
17595                    cx,
17596                )
17597            });
17598        }
17599        self.style = Some(style);
17600    }
17601
17602    pub fn style(&self) -> Option<&EditorStyle> {
17603        self.style.as_ref()
17604    }
17605
17606    // Called by the element. This method is not designed to be called outside of the editor
17607    // element's layout code because it does not notify when rewrapping is computed synchronously.
17608    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17609        self.display_map
17610            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17611    }
17612
17613    pub fn set_soft_wrap(&mut self) {
17614        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17615    }
17616
17617    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17618        if self.soft_wrap_mode_override.is_some() {
17619            self.soft_wrap_mode_override.take();
17620        } else {
17621            let soft_wrap = match self.soft_wrap_mode(cx) {
17622                SoftWrap::GitDiff => return,
17623                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17624                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17625                    language_settings::SoftWrap::None
17626                }
17627            };
17628            self.soft_wrap_mode_override = Some(soft_wrap);
17629        }
17630        cx.notify();
17631    }
17632
17633    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17634        let Some(workspace) = self.workspace() else {
17635            return;
17636        };
17637        let fs = workspace.read(cx).app_state().fs.clone();
17638        let current_show = TabBarSettings::get_global(cx).show;
17639        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17640            setting.show = Some(!current_show);
17641        });
17642    }
17643
17644    pub fn toggle_indent_guides(
17645        &mut self,
17646        _: &ToggleIndentGuides,
17647        _: &mut Window,
17648        cx: &mut Context<Self>,
17649    ) {
17650        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17651            self.buffer
17652                .read(cx)
17653                .language_settings(cx)
17654                .indent_guides
17655                .enabled
17656        });
17657        self.show_indent_guides = Some(!currently_enabled);
17658        cx.notify();
17659    }
17660
17661    fn should_show_indent_guides(&self) -> Option<bool> {
17662        self.show_indent_guides
17663    }
17664
17665    pub fn toggle_line_numbers(
17666        &mut self,
17667        _: &ToggleLineNumbers,
17668        _: &mut Window,
17669        cx: &mut Context<Self>,
17670    ) {
17671        let mut editor_settings = EditorSettings::get_global(cx).clone();
17672        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17673        EditorSettings::override_global(editor_settings, cx);
17674    }
17675
17676    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17677        if let Some(show_line_numbers) = self.show_line_numbers {
17678            return show_line_numbers;
17679        }
17680        EditorSettings::get_global(cx).gutter.line_numbers
17681    }
17682
17683    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17684        self.use_relative_line_numbers
17685            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17686    }
17687
17688    pub fn toggle_relative_line_numbers(
17689        &mut self,
17690        _: &ToggleRelativeLineNumbers,
17691        _: &mut Window,
17692        cx: &mut Context<Self>,
17693    ) {
17694        let is_relative = self.should_use_relative_line_numbers(cx);
17695        self.set_relative_line_number(Some(!is_relative), cx)
17696    }
17697
17698    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17699        self.use_relative_line_numbers = is_relative;
17700        cx.notify();
17701    }
17702
17703    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17704        self.show_gutter = show_gutter;
17705        cx.notify();
17706    }
17707
17708    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17709        self.show_scrollbars = ScrollbarAxes {
17710            horizontal: show,
17711            vertical: show,
17712        };
17713        cx.notify();
17714    }
17715
17716    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17717        self.show_scrollbars.vertical = show;
17718        cx.notify();
17719    }
17720
17721    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17722        self.show_scrollbars.horizontal = show;
17723        cx.notify();
17724    }
17725
17726    pub fn set_minimap_visibility(
17727        &mut self,
17728        minimap_visibility: MinimapVisibility,
17729        window: &mut Window,
17730        cx: &mut Context<Self>,
17731    ) {
17732        if self.minimap_visibility != minimap_visibility {
17733            if minimap_visibility.visible() && self.minimap.is_none() {
17734                let minimap_settings = EditorSettings::get_global(cx).minimap;
17735                self.minimap =
17736                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17737            }
17738            self.minimap_visibility = minimap_visibility;
17739            cx.notify();
17740        }
17741    }
17742
17743    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17744        self.set_show_scrollbars(false, cx);
17745        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17746    }
17747
17748    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17749        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17750    }
17751
17752    /// Normally the text in full mode and auto height editors is padded on the
17753    /// left side by roughly half a character width for improved hit testing.
17754    ///
17755    /// Use this method to disable this for cases where this is not wanted (e.g.
17756    /// if you want to align the editor text with some other text above or below)
17757    /// or if you want to add this padding to single-line editors.
17758    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17759        self.offset_content = offset_content;
17760        cx.notify();
17761    }
17762
17763    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17764        self.show_line_numbers = Some(show_line_numbers);
17765        cx.notify();
17766    }
17767
17768    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17769        self.disable_expand_excerpt_buttons = true;
17770        cx.notify();
17771    }
17772
17773    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17774        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17775        cx.notify();
17776    }
17777
17778    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17779        self.show_code_actions = Some(show_code_actions);
17780        cx.notify();
17781    }
17782
17783    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17784        self.show_runnables = Some(show_runnables);
17785        cx.notify();
17786    }
17787
17788    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17789        self.show_breakpoints = Some(show_breakpoints);
17790        cx.notify();
17791    }
17792
17793    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17794        if self.display_map.read(cx).masked != masked {
17795            self.display_map.update(cx, |map, _| map.masked = masked);
17796        }
17797        cx.notify()
17798    }
17799
17800    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17801        self.show_wrap_guides = Some(show_wrap_guides);
17802        cx.notify();
17803    }
17804
17805    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17806        self.show_indent_guides = Some(show_indent_guides);
17807        cx.notify();
17808    }
17809
17810    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17811        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17812            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17813                if let Some(dir) = file.abs_path(cx).parent() {
17814                    return Some(dir.to_owned());
17815                }
17816            }
17817
17818            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17819                return Some(project_path.path.to_path_buf());
17820            }
17821        }
17822
17823        None
17824    }
17825
17826    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17827        self.active_excerpt(cx)?
17828            .1
17829            .read(cx)
17830            .file()
17831            .and_then(|f| f.as_local())
17832    }
17833
17834    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17835        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17836            let buffer = buffer.read(cx);
17837            if let Some(project_path) = buffer.project_path(cx) {
17838                let project = self.project.as_ref()?.read(cx);
17839                project.absolute_path(&project_path, cx)
17840            } else {
17841                buffer
17842                    .file()
17843                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17844            }
17845        })
17846    }
17847
17848    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17849        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17850            let project_path = buffer.read(cx).project_path(cx)?;
17851            let project = self.project.as_ref()?.read(cx);
17852            let entry = project.entry_for_path(&project_path, cx)?;
17853            let path = entry.path.to_path_buf();
17854            Some(path)
17855        })
17856    }
17857
17858    pub fn reveal_in_finder(
17859        &mut self,
17860        _: &RevealInFileManager,
17861        _window: &mut Window,
17862        cx: &mut Context<Self>,
17863    ) {
17864        if let Some(target) = self.target_file(cx) {
17865            cx.reveal_path(&target.abs_path(cx));
17866        }
17867    }
17868
17869    pub fn copy_path(
17870        &mut self,
17871        _: &zed_actions::workspace::CopyPath,
17872        _window: &mut Window,
17873        cx: &mut Context<Self>,
17874    ) {
17875        if let Some(path) = self.target_file_abs_path(cx) {
17876            if let Some(path) = path.to_str() {
17877                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17878            }
17879        }
17880    }
17881
17882    pub fn copy_relative_path(
17883        &mut self,
17884        _: &zed_actions::workspace::CopyRelativePath,
17885        _window: &mut Window,
17886        cx: &mut Context<Self>,
17887    ) {
17888        if let Some(path) = self.target_file_path(cx) {
17889            if let Some(path) = path.to_str() {
17890                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17891            }
17892        }
17893    }
17894
17895    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17896        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17897            buffer.read(cx).project_path(cx)
17898        } else {
17899            None
17900        }
17901    }
17902
17903    // Returns true if the editor handled a go-to-line request
17904    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17905        maybe!({
17906            let breakpoint_store = self.breakpoint_store.as_ref()?;
17907
17908            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17909            else {
17910                self.clear_row_highlights::<ActiveDebugLine>();
17911                return None;
17912            };
17913
17914            let position = active_stack_frame.position;
17915            let buffer_id = position.buffer_id?;
17916            let snapshot = self
17917                .project
17918                .as_ref()?
17919                .read(cx)
17920                .buffer_for_id(buffer_id, cx)?
17921                .read(cx)
17922                .snapshot();
17923
17924            let mut handled = false;
17925            for (id, ExcerptRange { context, .. }) in
17926                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17927            {
17928                if context.start.cmp(&position, &snapshot).is_ge()
17929                    || context.end.cmp(&position, &snapshot).is_lt()
17930                {
17931                    continue;
17932                }
17933                let snapshot = self.buffer.read(cx).snapshot(cx);
17934                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17935
17936                handled = true;
17937                self.clear_row_highlights::<ActiveDebugLine>();
17938
17939                self.go_to_line::<ActiveDebugLine>(
17940                    multibuffer_anchor,
17941                    Some(cx.theme().colors().editor_debugger_active_line_background),
17942                    window,
17943                    cx,
17944                );
17945
17946                cx.notify();
17947            }
17948
17949            handled.then_some(())
17950        })
17951        .is_some()
17952    }
17953
17954    pub fn copy_file_name_without_extension(
17955        &mut self,
17956        _: &CopyFileNameWithoutExtension,
17957        _: &mut Window,
17958        cx: &mut Context<Self>,
17959    ) {
17960        if let Some(file) = self.target_file(cx) {
17961            if let Some(file_stem) = file.path().file_stem() {
17962                if let Some(name) = file_stem.to_str() {
17963                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17964                }
17965            }
17966        }
17967    }
17968
17969    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17970        if let Some(file) = self.target_file(cx) {
17971            if let Some(file_name) = file.path().file_name() {
17972                if let Some(name) = file_name.to_str() {
17973                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17974                }
17975            }
17976        }
17977    }
17978
17979    pub fn toggle_git_blame(
17980        &mut self,
17981        _: &::git::Blame,
17982        window: &mut Window,
17983        cx: &mut Context<Self>,
17984    ) {
17985        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17986
17987        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17988            self.start_git_blame(true, window, cx);
17989        }
17990
17991        cx.notify();
17992    }
17993
17994    pub fn toggle_git_blame_inline(
17995        &mut self,
17996        _: &ToggleGitBlameInline,
17997        window: &mut Window,
17998        cx: &mut Context<Self>,
17999    ) {
18000        self.toggle_git_blame_inline_internal(true, window, cx);
18001        cx.notify();
18002    }
18003
18004    pub fn open_git_blame_commit(
18005        &mut self,
18006        _: &OpenGitBlameCommit,
18007        window: &mut Window,
18008        cx: &mut Context<Self>,
18009    ) {
18010        self.open_git_blame_commit_internal(window, cx);
18011    }
18012
18013    fn open_git_blame_commit_internal(
18014        &mut self,
18015        window: &mut Window,
18016        cx: &mut Context<Self>,
18017    ) -> Option<()> {
18018        let blame = self.blame.as_ref()?;
18019        let snapshot = self.snapshot(window, cx);
18020        let cursor = self.selections.newest::<Point>(cx).head();
18021        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18022        let blame_entry = blame
18023            .update(cx, |blame, cx| {
18024                blame
18025                    .blame_for_rows(
18026                        &[RowInfo {
18027                            buffer_id: Some(buffer.remote_id()),
18028                            buffer_row: Some(point.row),
18029                            ..Default::default()
18030                        }],
18031                        cx,
18032                    )
18033                    .next()
18034            })
18035            .flatten()?;
18036        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18037        let repo = blame.read(cx).repository(cx)?;
18038        let workspace = self.workspace()?.downgrade();
18039        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18040        None
18041    }
18042
18043    pub fn git_blame_inline_enabled(&self) -> bool {
18044        self.git_blame_inline_enabled
18045    }
18046
18047    pub fn toggle_selection_menu(
18048        &mut self,
18049        _: &ToggleSelectionMenu,
18050        _: &mut Window,
18051        cx: &mut Context<Self>,
18052    ) {
18053        self.show_selection_menu = self
18054            .show_selection_menu
18055            .map(|show_selections_menu| !show_selections_menu)
18056            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18057
18058        cx.notify();
18059    }
18060
18061    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18062        self.show_selection_menu
18063            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18064    }
18065
18066    fn start_git_blame(
18067        &mut self,
18068        user_triggered: bool,
18069        window: &mut Window,
18070        cx: &mut Context<Self>,
18071    ) {
18072        if let Some(project) = self.project.as_ref() {
18073            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18074                return;
18075            };
18076
18077            if buffer.read(cx).file().is_none() {
18078                return;
18079            }
18080
18081            let focused = self.focus_handle(cx).contains_focused(window, cx);
18082
18083            let project = project.clone();
18084            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18085            self.blame_subscription =
18086                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18087            self.blame = Some(blame);
18088        }
18089    }
18090
18091    fn toggle_git_blame_inline_internal(
18092        &mut self,
18093        user_triggered: bool,
18094        window: &mut Window,
18095        cx: &mut Context<Self>,
18096    ) {
18097        if self.git_blame_inline_enabled {
18098            self.git_blame_inline_enabled = false;
18099            self.show_git_blame_inline = false;
18100            self.show_git_blame_inline_delay_task.take();
18101        } else {
18102            self.git_blame_inline_enabled = true;
18103            self.start_git_blame_inline(user_triggered, window, cx);
18104        }
18105
18106        cx.notify();
18107    }
18108
18109    fn start_git_blame_inline(
18110        &mut self,
18111        user_triggered: bool,
18112        window: &mut Window,
18113        cx: &mut Context<Self>,
18114    ) {
18115        self.start_git_blame(user_triggered, window, cx);
18116
18117        if ProjectSettings::get_global(cx)
18118            .git
18119            .inline_blame_delay()
18120            .is_some()
18121        {
18122            self.start_inline_blame_timer(window, cx);
18123        } else {
18124            self.show_git_blame_inline = true
18125        }
18126    }
18127
18128    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18129        self.blame.as_ref()
18130    }
18131
18132    pub fn show_git_blame_gutter(&self) -> bool {
18133        self.show_git_blame_gutter
18134    }
18135
18136    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18137        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18138    }
18139
18140    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18141        self.show_git_blame_inline
18142            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18143            && !self.newest_selection_head_on_empty_line(cx)
18144            && self.has_blame_entries(cx)
18145    }
18146
18147    fn has_blame_entries(&self, cx: &App) -> bool {
18148        self.blame()
18149            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18150    }
18151
18152    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18153        let cursor_anchor = self.selections.newest_anchor().head();
18154
18155        let snapshot = self.buffer.read(cx).snapshot(cx);
18156        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18157
18158        snapshot.line_len(buffer_row) == 0
18159    }
18160
18161    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18162        let buffer_and_selection = maybe!({
18163            let selection = self.selections.newest::<Point>(cx);
18164            let selection_range = selection.range();
18165
18166            let multi_buffer = self.buffer().read(cx);
18167            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18168            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18169
18170            let (buffer, range, _) = if selection.reversed {
18171                buffer_ranges.first()
18172            } else {
18173                buffer_ranges.last()
18174            }?;
18175
18176            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18177                ..text::ToPoint::to_point(&range.end, &buffer).row;
18178            Some((
18179                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18180                selection,
18181            ))
18182        });
18183
18184        let Some((buffer, selection)) = buffer_and_selection else {
18185            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18186        };
18187
18188        let Some(project) = self.project.as_ref() else {
18189            return Task::ready(Err(anyhow!("editor does not have project")));
18190        };
18191
18192        project.update(cx, |project, cx| {
18193            project.get_permalink_to_line(&buffer, selection, cx)
18194        })
18195    }
18196
18197    pub fn copy_permalink_to_line(
18198        &mut self,
18199        _: &CopyPermalinkToLine,
18200        window: &mut Window,
18201        cx: &mut Context<Self>,
18202    ) {
18203        let permalink_task = self.get_permalink_to_line(cx);
18204        let workspace = self.workspace();
18205
18206        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18207            Ok(permalink) => {
18208                cx.update(|_, cx| {
18209                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18210                })
18211                .ok();
18212            }
18213            Err(err) => {
18214                let message = format!("Failed to copy permalink: {err}");
18215
18216                anyhow::Result::<()>::Err(err).log_err();
18217
18218                if let Some(workspace) = workspace {
18219                    workspace
18220                        .update_in(cx, |workspace, _, cx| {
18221                            struct CopyPermalinkToLine;
18222
18223                            workspace.show_toast(
18224                                Toast::new(
18225                                    NotificationId::unique::<CopyPermalinkToLine>(),
18226                                    message,
18227                                ),
18228                                cx,
18229                            )
18230                        })
18231                        .ok();
18232                }
18233            }
18234        })
18235        .detach();
18236    }
18237
18238    pub fn copy_file_location(
18239        &mut self,
18240        _: &CopyFileLocation,
18241        _: &mut Window,
18242        cx: &mut Context<Self>,
18243    ) {
18244        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18245        if let Some(file) = self.target_file(cx) {
18246            if let Some(path) = file.path().to_str() {
18247                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18248            }
18249        }
18250    }
18251
18252    pub fn open_permalink_to_line(
18253        &mut self,
18254        _: &OpenPermalinkToLine,
18255        window: &mut Window,
18256        cx: &mut Context<Self>,
18257    ) {
18258        let permalink_task = self.get_permalink_to_line(cx);
18259        let workspace = self.workspace();
18260
18261        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18262            Ok(permalink) => {
18263                cx.update(|_, cx| {
18264                    cx.open_url(permalink.as_ref());
18265                })
18266                .ok();
18267            }
18268            Err(err) => {
18269                let message = format!("Failed to open permalink: {err}");
18270
18271                anyhow::Result::<()>::Err(err).log_err();
18272
18273                if let Some(workspace) = workspace {
18274                    workspace
18275                        .update(cx, |workspace, cx| {
18276                            struct OpenPermalinkToLine;
18277
18278                            workspace.show_toast(
18279                                Toast::new(
18280                                    NotificationId::unique::<OpenPermalinkToLine>(),
18281                                    message,
18282                                ),
18283                                cx,
18284                            )
18285                        })
18286                        .ok();
18287                }
18288            }
18289        })
18290        .detach();
18291    }
18292
18293    pub fn insert_uuid_v4(
18294        &mut self,
18295        _: &InsertUuidV4,
18296        window: &mut Window,
18297        cx: &mut Context<Self>,
18298    ) {
18299        self.insert_uuid(UuidVersion::V4, window, cx);
18300    }
18301
18302    pub fn insert_uuid_v7(
18303        &mut self,
18304        _: &InsertUuidV7,
18305        window: &mut Window,
18306        cx: &mut Context<Self>,
18307    ) {
18308        self.insert_uuid(UuidVersion::V7, window, cx);
18309    }
18310
18311    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18312        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18313        self.transact(window, cx, |this, window, cx| {
18314            let edits = this
18315                .selections
18316                .all::<Point>(cx)
18317                .into_iter()
18318                .map(|selection| {
18319                    let uuid = match version {
18320                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18321                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18322                    };
18323
18324                    (selection.range(), uuid.to_string())
18325                });
18326            this.edit(edits, cx);
18327            this.refresh_inline_completion(true, false, window, cx);
18328        });
18329    }
18330
18331    pub fn open_selections_in_multibuffer(
18332        &mut self,
18333        _: &OpenSelectionsInMultibuffer,
18334        window: &mut Window,
18335        cx: &mut Context<Self>,
18336    ) {
18337        let multibuffer = self.buffer.read(cx);
18338
18339        let Some(buffer) = multibuffer.as_singleton() else {
18340            return;
18341        };
18342
18343        let Some(workspace) = self.workspace() else {
18344            return;
18345        };
18346
18347        let title = multibuffer.title(cx).to_string();
18348
18349        let locations = self
18350            .selections
18351            .all_anchors(cx)
18352            .into_iter()
18353            .map(|selection| Location {
18354                buffer: buffer.clone(),
18355                range: selection.start.text_anchor..selection.end.text_anchor,
18356            })
18357            .collect::<Vec<_>>();
18358
18359        cx.spawn_in(window, async move |_, cx| {
18360            workspace.update_in(cx, |workspace, window, cx| {
18361                Self::open_locations_in_multibuffer(
18362                    workspace,
18363                    locations,
18364                    format!("Selections for '{title}'"),
18365                    false,
18366                    MultibufferSelectionMode::All,
18367                    window,
18368                    cx,
18369                );
18370            })
18371        })
18372        .detach();
18373    }
18374
18375    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18376    /// last highlight added will be used.
18377    ///
18378    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18379    pub fn highlight_rows<T: 'static>(
18380        &mut self,
18381        range: Range<Anchor>,
18382        color: Hsla,
18383        options: RowHighlightOptions,
18384        cx: &mut Context<Self>,
18385    ) {
18386        let snapshot = self.buffer().read(cx).snapshot(cx);
18387        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18388        let ix = row_highlights.binary_search_by(|highlight| {
18389            Ordering::Equal
18390                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18391                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18392        });
18393
18394        if let Err(mut ix) = ix {
18395            let index = post_inc(&mut self.highlight_order);
18396
18397            // If this range intersects with the preceding highlight, then merge it with
18398            // the preceding highlight. Otherwise insert a new highlight.
18399            let mut merged = false;
18400            if ix > 0 {
18401                let prev_highlight = &mut row_highlights[ix - 1];
18402                if prev_highlight
18403                    .range
18404                    .end
18405                    .cmp(&range.start, &snapshot)
18406                    .is_ge()
18407                {
18408                    ix -= 1;
18409                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18410                        prev_highlight.range.end = range.end;
18411                    }
18412                    merged = true;
18413                    prev_highlight.index = index;
18414                    prev_highlight.color = color;
18415                    prev_highlight.options = options;
18416                }
18417            }
18418
18419            if !merged {
18420                row_highlights.insert(
18421                    ix,
18422                    RowHighlight {
18423                        range: range.clone(),
18424                        index,
18425                        color,
18426                        options,
18427                        type_id: TypeId::of::<T>(),
18428                    },
18429                );
18430            }
18431
18432            // If any of the following highlights intersect with this one, merge them.
18433            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18434                let highlight = &row_highlights[ix];
18435                if next_highlight
18436                    .range
18437                    .start
18438                    .cmp(&highlight.range.end, &snapshot)
18439                    .is_le()
18440                {
18441                    if next_highlight
18442                        .range
18443                        .end
18444                        .cmp(&highlight.range.end, &snapshot)
18445                        .is_gt()
18446                    {
18447                        row_highlights[ix].range.end = next_highlight.range.end;
18448                    }
18449                    row_highlights.remove(ix + 1);
18450                } else {
18451                    break;
18452                }
18453            }
18454        }
18455    }
18456
18457    /// Remove any highlighted row ranges of the given type that intersect the
18458    /// given ranges.
18459    pub fn remove_highlighted_rows<T: 'static>(
18460        &mut self,
18461        ranges_to_remove: Vec<Range<Anchor>>,
18462        cx: &mut Context<Self>,
18463    ) {
18464        let snapshot = self.buffer().read(cx).snapshot(cx);
18465        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18466        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18467        row_highlights.retain(|highlight| {
18468            while let Some(range_to_remove) = ranges_to_remove.peek() {
18469                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18470                    Ordering::Less | Ordering::Equal => {
18471                        ranges_to_remove.next();
18472                    }
18473                    Ordering::Greater => {
18474                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18475                            Ordering::Less | Ordering::Equal => {
18476                                return false;
18477                            }
18478                            Ordering::Greater => break,
18479                        }
18480                    }
18481                }
18482            }
18483
18484            true
18485        })
18486    }
18487
18488    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18489    pub fn clear_row_highlights<T: 'static>(&mut self) {
18490        self.highlighted_rows.remove(&TypeId::of::<T>());
18491    }
18492
18493    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18494    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18495        self.highlighted_rows
18496            .get(&TypeId::of::<T>())
18497            .map_or(&[] as &[_], |vec| vec.as_slice())
18498            .iter()
18499            .map(|highlight| (highlight.range.clone(), highlight.color))
18500    }
18501
18502    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18503    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18504    /// Allows to ignore certain kinds of highlights.
18505    pub fn highlighted_display_rows(
18506        &self,
18507        window: &mut Window,
18508        cx: &mut App,
18509    ) -> BTreeMap<DisplayRow, LineHighlight> {
18510        let snapshot = self.snapshot(window, cx);
18511        let mut used_highlight_orders = HashMap::default();
18512        self.highlighted_rows
18513            .iter()
18514            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18515            .fold(
18516                BTreeMap::<DisplayRow, LineHighlight>::new(),
18517                |mut unique_rows, highlight| {
18518                    let start = highlight.range.start.to_display_point(&snapshot);
18519                    let end = highlight.range.end.to_display_point(&snapshot);
18520                    let start_row = start.row().0;
18521                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18522                        && end.column() == 0
18523                    {
18524                        end.row().0.saturating_sub(1)
18525                    } else {
18526                        end.row().0
18527                    };
18528                    for row in start_row..=end_row {
18529                        let used_index =
18530                            used_highlight_orders.entry(row).or_insert(highlight.index);
18531                        if highlight.index >= *used_index {
18532                            *used_index = highlight.index;
18533                            unique_rows.insert(
18534                                DisplayRow(row),
18535                                LineHighlight {
18536                                    include_gutter: highlight.options.include_gutter,
18537                                    border: None,
18538                                    background: highlight.color.into(),
18539                                    type_id: Some(highlight.type_id),
18540                                },
18541                            );
18542                        }
18543                    }
18544                    unique_rows
18545                },
18546            )
18547    }
18548
18549    pub fn highlighted_display_row_for_autoscroll(
18550        &self,
18551        snapshot: &DisplaySnapshot,
18552    ) -> Option<DisplayRow> {
18553        self.highlighted_rows
18554            .values()
18555            .flat_map(|highlighted_rows| highlighted_rows.iter())
18556            .filter_map(|highlight| {
18557                if highlight.options.autoscroll {
18558                    Some(highlight.range.start.to_display_point(snapshot).row())
18559                } else {
18560                    None
18561                }
18562            })
18563            .min()
18564    }
18565
18566    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18567        self.highlight_background::<SearchWithinRange>(
18568            ranges,
18569            |colors| colors.colors().editor_document_highlight_read_background,
18570            cx,
18571        )
18572    }
18573
18574    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18575        self.breadcrumb_header = Some(new_header);
18576    }
18577
18578    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18579        self.clear_background_highlights::<SearchWithinRange>(cx);
18580    }
18581
18582    pub fn highlight_background<T: 'static>(
18583        &mut self,
18584        ranges: &[Range<Anchor>],
18585        color_fetcher: fn(&Theme) -> Hsla,
18586        cx: &mut Context<Self>,
18587    ) {
18588        self.background_highlights.insert(
18589            HighlightKey::Type(TypeId::of::<T>()),
18590            (color_fetcher, Arc::from(ranges)),
18591        );
18592        self.scrollbar_marker_state.dirty = true;
18593        cx.notify();
18594    }
18595
18596    pub fn highlight_background_key<T: 'static>(
18597        &mut self,
18598        key: usize,
18599        ranges: &[Range<Anchor>],
18600        color_fetcher: fn(&Theme) -> Hsla,
18601        cx: &mut Context<Self>,
18602    ) {
18603        self.background_highlights.insert(
18604            HighlightKey::TypePlus(TypeId::of::<T>(), key),
18605            (color_fetcher, Arc::from(ranges)),
18606        );
18607        self.scrollbar_marker_state.dirty = true;
18608        cx.notify();
18609    }
18610
18611    pub fn clear_background_highlights<T: 'static>(
18612        &mut self,
18613        cx: &mut Context<Self>,
18614    ) -> Option<BackgroundHighlight> {
18615        let text_highlights = self
18616            .background_highlights
18617            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
18618        if !text_highlights.1.is_empty() {
18619            self.scrollbar_marker_state.dirty = true;
18620            cx.notify();
18621        }
18622        Some(text_highlights)
18623    }
18624
18625    pub fn highlight_gutter<T: 'static>(
18626        &mut self,
18627        ranges: impl Into<Vec<Range<Anchor>>>,
18628        color_fetcher: fn(&App) -> Hsla,
18629        cx: &mut Context<Self>,
18630    ) {
18631        self.gutter_highlights
18632            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18633        cx.notify();
18634    }
18635
18636    pub fn clear_gutter_highlights<T: 'static>(
18637        &mut self,
18638        cx: &mut Context<Self>,
18639    ) -> Option<GutterHighlight> {
18640        cx.notify();
18641        self.gutter_highlights.remove(&TypeId::of::<T>())
18642    }
18643
18644    pub fn insert_gutter_highlight<T: 'static>(
18645        &mut self,
18646        range: Range<Anchor>,
18647        color_fetcher: fn(&App) -> Hsla,
18648        cx: &mut Context<Self>,
18649    ) {
18650        let snapshot = self.buffer().read(cx).snapshot(cx);
18651        let mut highlights = self
18652            .gutter_highlights
18653            .remove(&TypeId::of::<T>())
18654            .map(|(_, highlights)| highlights)
18655            .unwrap_or_default();
18656        let ix = highlights.binary_search_by(|highlight| {
18657            Ordering::Equal
18658                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18659                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18660        });
18661        if let Err(ix) = ix {
18662            highlights.insert(ix, range);
18663        }
18664        self.gutter_highlights
18665            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18666    }
18667
18668    pub fn remove_gutter_highlights<T: 'static>(
18669        &mut self,
18670        ranges_to_remove: Vec<Range<Anchor>>,
18671        cx: &mut Context<Self>,
18672    ) {
18673        let snapshot = self.buffer().read(cx).snapshot(cx);
18674        let Some((color_fetcher, mut gutter_highlights)) =
18675            self.gutter_highlights.remove(&TypeId::of::<T>())
18676        else {
18677            return;
18678        };
18679        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18680        gutter_highlights.retain(|highlight| {
18681            while let Some(range_to_remove) = ranges_to_remove.peek() {
18682                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18683                    Ordering::Less | Ordering::Equal => {
18684                        ranges_to_remove.next();
18685                    }
18686                    Ordering::Greater => {
18687                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18688                            Ordering::Less | Ordering::Equal => {
18689                                return false;
18690                            }
18691                            Ordering::Greater => break,
18692                        }
18693                    }
18694                }
18695            }
18696
18697            true
18698        });
18699        self.gutter_highlights
18700            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18701    }
18702
18703    #[cfg(feature = "test-support")]
18704    pub fn all_text_highlights(
18705        &self,
18706        window: &mut Window,
18707        cx: &mut Context<Self>,
18708    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
18709        let snapshot = self.snapshot(window, cx);
18710        self.display_map.update(cx, |display_map, _| {
18711            display_map
18712                .all_text_highlights()
18713                .map(|highlight| {
18714                    let (style, ranges) = highlight.as_ref();
18715                    (
18716                        *style,
18717                        ranges
18718                            .iter()
18719                            .map(|range| range.clone().to_display_points(&snapshot))
18720                            .collect(),
18721                    )
18722                })
18723                .collect()
18724        })
18725    }
18726
18727    #[cfg(feature = "test-support")]
18728    pub fn all_text_background_highlights(
18729        &self,
18730        window: &mut Window,
18731        cx: &mut Context<Self>,
18732    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18733        let snapshot = self.snapshot(window, cx);
18734        let buffer = &snapshot.buffer_snapshot;
18735        let start = buffer.anchor_before(0);
18736        let end = buffer.anchor_after(buffer.len());
18737        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
18738    }
18739
18740    #[cfg(feature = "test-support")]
18741    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18742        let snapshot = self.buffer().read(cx).snapshot(cx);
18743
18744        let highlights = self
18745            .background_highlights
18746            .get(&HighlightKey::Type(TypeId::of::<
18747                items::BufferSearchHighlights,
18748            >()));
18749
18750        if let Some((_color, ranges)) = highlights {
18751            ranges
18752                .iter()
18753                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18754                .collect_vec()
18755        } else {
18756            vec![]
18757        }
18758    }
18759
18760    fn document_highlights_for_position<'a>(
18761        &'a self,
18762        position: Anchor,
18763        buffer: &'a MultiBufferSnapshot,
18764    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18765        let read_highlights = self
18766            .background_highlights
18767            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
18768            .map(|h| &h.1);
18769        let write_highlights = self
18770            .background_highlights
18771            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
18772            .map(|h| &h.1);
18773        let left_position = position.bias_left(buffer);
18774        let right_position = position.bias_right(buffer);
18775        read_highlights
18776            .into_iter()
18777            .chain(write_highlights)
18778            .flat_map(move |ranges| {
18779                let start_ix = match ranges.binary_search_by(|probe| {
18780                    let cmp = probe.end.cmp(&left_position, buffer);
18781                    if cmp.is_ge() {
18782                        Ordering::Greater
18783                    } else {
18784                        Ordering::Less
18785                    }
18786                }) {
18787                    Ok(i) | Err(i) => i,
18788                };
18789
18790                ranges[start_ix..]
18791                    .iter()
18792                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18793            })
18794    }
18795
18796    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18797        self.background_highlights
18798            .get(&HighlightKey::Type(TypeId::of::<T>()))
18799            .map_or(false, |(_, highlights)| !highlights.is_empty())
18800    }
18801
18802    pub fn background_highlights_in_range(
18803        &self,
18804        search_range: Range<Anchor>,
18805        display_snapshot: &DisplaySnapshot,
18806        theme: &Theme,
18807    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18808        let mut results = Vec::new();
18809        for (color_fetcher, ranges) in self.background_highlights.values() {
18810            let color = color_fetcher(theme);
18811            let start_ix = match ranges.binary_search_by(|probe| {
18812                let cmp = probe
18813                    .end
18814                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18815                if cmp.is_gt() {
18816                    Ordering::Greater
18817                } else {
18818                    Ordering::Less
18819                }
18820            }) {
18821                Ok(i) | Err(i) => i,
18822            };
18823            for range in &ranges[start_ix..] {
18824                if range
18825                    .start
18826                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18827                    .is_ge()
18828                {
18829                    break;
18830                }
18831
18832                let start = range.start.to_display_point(display_snapshot);
18833                let end = range.end.to_display_point(display_snapshot);
18834                results.push((start..end, color))
18835            }
18836        }
18837        results
18838    }
18839
18840    pub fn background_highlight_row_ranges<T: 'static>(
18841        &self,
18842        search_range: Range<Anchor>,
18843        display_snapshot: &DisplaySnapshot,
18844        count: usize,
18845    ) -> Vec<RangeInclusive<DisplayPoint>> {
18846        let mut results = Vec::new();
18847        let Some((_, ranges)) = self
18848            .background_highlights
18849            .get(&HighlightKey::Type(TypeId::of::<T>()))
18850        else {
18851            return vec![];
18852        };
18853
18854        let start_ix = match ranges.binary_search_by(|probe| {
18855            let cmp = probe
18856                .end
18857                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18858            if cmp.is_gt() {
18859                Ordering::Greater
18860            } else {
18861                Ordering::Less
18862            }
18863        }) {
18864            Ok(i) | Err(i) => i,
18865        };
18866        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18867            if let (Some(start_display), Some(end_display)) = (start, end) {
18868                results.push(
18869                    start_display.to_display_point(display_snapshot)
18870                        ..=end_display.to_display_point(display_snapshot),
18871                );
18872            }
18873        };
18874        let mut start_row: Option<Point> = None;
18875        let mut end_row: Option<Point> = None;
18876        if ranges.len() > count {
18877            return Vec::new();
18878        }
18879        for range in &ranges[start_ix..] {
18880            if range
18881                .start
18882                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18883                .is_ge()
18884            {
18885                break;
18886            }
18887            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18888            if let Some(current_row) = &end_row {
18889                if end.row == current_row.row {
18890                    continue;
18891                }
18892            }
18893            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18894            if start_row.is_none() {
18895                assert_eq!(end_row, None);
18896                start_row = Some(start);
18897                end_row = Some(end);
18898                continue;
18899            }
18900            if let Some(current_end) = end_row.as_mut() {
18901                if start.row > current_end.row + 1 {
18902                    push_region(start_row, end_row);
18903                    start_row = Some(start);
18904                    end_row = Some(end);
18905                } else {
18906                    // Merge two hunks.
18907                    *current_end = end;
18908                }
18909            } else {
18910                unreachable!();
18911            }
18912        }
18913        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18914        push_region(start_row, end_row);
18915        results
18916    }
18917
18918    pub fn gutter_highlights_in_range(
18919        &self,
18920        search_range: Range<Anchor>,
18921        display_snapshot: &DisplaySnapshot,
18922        cx: &App,
18923    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18924        let mut results = Vec::new();
18925        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18926            let color = color_fetcher(cx);
18927            let start_ix = match ranges.binary_search_by(|probe| {
18928                let cmp = probe
18929                    .end
18930                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18931                if cmp.is_gt() {
18932                    Ordering::Greater
18933                } else {
18934                    Ordering::Less
18935                }
18936            }) {
18937                Ok(i) | Err(i) => i,
18938            };
18939            for range in &ranges[start_ix..] {
18940                if range
18941                    .start
18942                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18943                    .is_ge()
18944                {
18945                    break;
18946                }
18947
18948                let start = range.start.to_display_point(display_snapshot);
18949                let end = range.end.to_display_point(display_snapshot);
18950                results.push((start..end, color))
18951            }
18952        }
18953        results
18954    }
18955
18956    /// Get the text ranges corresponding to the redaction query
18957    pub fn redacted_ranges(
18958        &self,
18959        search_range: Range<Anchor>,
18960        display_snapshot: &DisplaySnapshot,
18961        cx: &App,
18962    ) -> Vec<Range<DisplayPoint>> {
18963        display_snapshot
18964            .buffer_snapshot
18965            .redacted_ranges(search_range, |file| {
18966                if let Some(file) = file {
18967                    file.is_private()
18968                        && EditorSettings::get(
18969                            Some(SettingsLocation {
18970                                worktree_id: file.worktree_id(cx),
18971                                path: file.path().as_ref(),
18972                            }),
18973                            cx,
18974                        )
18975                        .redact_private_values
18976                } else {
18977                    false
18978                }
18979            })
18980            .map(|range| {
18981                range.start.to_display_point(display_snapshot)
18982                    ..range.end.to_display_point(display_snapshot)
18983            })
18984            .collect()
18985    }
18986
18987    pub fn highlight_text_key<T: 'static>(
18988        &mut self,
18989        key: usize,
18990        ranges: Vec<Range<Anchor>>,
18991        style: HighlightStyle,
18992        cx: &mut Context<Self>,
18993    ) {
18994        self.display_map.update(cx, |map, _| {
18995            map.highlight_text(
18996                HighlightKey::TypePlus(TypeId::of::<T>(), key),
18997                ranges,
18998                style,
18999            );
19000        });
19001        cx.notify();
19002    }
19003
19004    pub fn highlight_text<T: 'static>(
19005        &mut self,
19006        ranges: Vec<Range<Anchor>>,
19007        style: HighlightStyle,
19008        cx: &mut Context<Self>,
19009    ) {
19010        self.display_map.update(cx, |map, _| {
19011            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19012        });
19013        cx.notify();
19014    }
19015
19016    pub(crate) fn highlight_inlays<T: 'static>(
19017        &mut self,
19018        highlights: Vec<InlayHighlight>,
19019        style: HighlightStyle,
19020        cx: &mut Context<Self>,
19021    ) {
19022        self.display_map.update(cx, |map, _| {
19023            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19024        });
19025        cx.notify();
19026    }
19027
19028    pub fn text_highlights<'a, T: 'static>(
19029        &'a self,
19030        cx: &'a App,
19031    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19032        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19033    }
19034
19035    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19036        let cleared = self
19037            .display_map
19038            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19039        if cleared {
19040            cx.notify();
19041        }
19042    }
19043
19044    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19045        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19046            && self.focus_handle.is_focused(window)
19047    }
19048
19049    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19050        self.show_cursor_when_unfocused = is_enabled;
19051        cx.notify();
19052    }
19053
19054    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19055        cx.notify();
19056    }
19057
19058    fn on_debug_session_event(
19059        &mut self,
19060        _session: Entity<Session>,
19061        event: &SessionEvent,
19062        cx: &mut Context<Self>,
19063    ) {
19064        match event {
19065            SessionEvent::InvalidateInlineValue => {
19066                self.refresh_inline_values(cx);
19067            }
19068            _ => {}
19069        }
19070    }
19071
19072    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19073        let Some(project) = self.project.clone() else {
19074            return;
19075        };
19076
19077        if !self.inline_value_cache.enabled {
19078            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19079            self.splice_inlays(&inlays, Vec::new(), cx);
19080            return;
19081        }
19082
19083        let current_execution_position = self
19084            .highlighted_rows
19085            .get(&TypeId::of::<ActiveDebugLine>())
19086            .and_then(|lines| lines.last().map(|line| line.range.start));
19087
19088        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19089            let inline_values = editor
19090                .update(cx, |editor, cx| {
19091                    let Some(current_execution_position) = current_execution_position else {
19092                        return Some(Task::ready(Ok(Vec::new())));
19093                    };
19094
19095                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19096                        let snapshot = buffer.snapshot(cx);
19097
19098                        let excerpt = snapshot.excerpt_containing(
19099                            current_execution_position..current_execution_position,
19100                        )?;
19101
19102                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19103                    })?;
19104
19105                    let range =
19106                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19107
19108                    project.inline_values(buffer, range, cx)
19109                })
19110                .ok()
19111                .flatten()?
19112                .await
19113                .context("refreshing debugger inlays")
19114                .log_err()?;
19115
19116            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19117
19118            for (buffer_id, inline_value) in inline_values
19119                .into_iter()
19120                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19121            {
19122                buffer_inline_values
19123                    .entry(buffer_id)
19124                    .or_default()
19125                    .push(inline_value);
19126            }
19127
19128            editor
19129                .update(cx, |editor, cx| {
19130                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19131                    let mut new_inlays = Vec::default();
19132
19133                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19134                        let buffer_id = buffer_snapshot.remote_id();
19135                        buffer_inline_values
19136                            .get(&buffer_id)
19137                            .into_iter()
19138                            .flatten()
19139                            .for_each(|hint| {
19140                                let inlay = Inlay::debugger(
19141                                    post_inc(&mut editor.next_inlay_id),
19142                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19143                                    hint.text(),
19144                                );
19145
19146                                new_inlays.push(inlay);
19147                            });
19148                    }
19149
19150                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19151                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19152
19153                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19154                })
19155                .ok()?;
19156            Some(())
19157        });
19158    }
19159
19160    fn on_buffer_event(
19161        &mut self,
19162        multibuffer: &Entity<MultiBuffer>,
19163        event: &multi_buffer::Event,
19164        window: &mut Window,
19165        cx: &mut Context<Self>,
19166    ) {
19167        match event {
19168            multi_buffer::Event::Edited {
19169                singleton_buffer_edited,
19170                edited_buffer,
19171            } => {
19172                self.scrollbar_marker_state.dirty = true;
19173                self.active_indent_guides_state.dirty = true;
19174                self.refresh_active_diagnostics(cx);
19175                self.refresh_code_actions(window, cx);
19176                self.refresh_selected_text_highlights(true, window, cx);
19177                refresh_matching_bracket_highlights(self, window, cx);
19178                if self.has_active_inline_completion() {
19179                    self.update_visible_inline_completion(window, cx);
19180                }
19181                if let Some(project) = self.project.as_ref() {
19182                    if let Some(edited_buffer) = edited_buffer {
19183                        project.update(cx, |project, cx| {
19184                            self.registered_buffers
19185                                .entry(edited_buffer.read(cx).remote_id())
19186                                .or_insert_with(|| {
19187                                    project
19188                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19189                                });
19190                        });
19191                    }
19192                }
19193                cx.emit(EditorEvent::BufferEdited);
19194                cx.emit(SearchEvent::MatchesInvalidated);
19195
19196                if let Some(buffer) = edited_buffer {
19197                    self.update_lsp_data(true, None, Some(buffer.read(cx).remote_id()), window, cx);
19198                }
19199
19200                if *singleton_buffer_edited {
19201                    if let Some(buffer) = edited_buffer {
19202                        if buffer.read(cx).file().is_none() {
19203                            cx.emit(EditorEvent::TitleChanged);
19204                        }
19205                    }
19206                    if let Some(project) = &self.project {
19207                        #[allow(clippy::mutable_key_type)]
19208                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19209                            multibuffer
19210                                .all_buffers()
19211                                .into_iter()
19212                                .filter_map(|buffer| {
19213                                    buffer.update(cx, |buffer, cx| {
19214                                        let language = buffer.language()?;
19215                                        let should_discard = project.update(cx, |project, cx| {
19216                                            project.is_local()
19217                                                && !project.has_language_servers_for(buffer, cx)
19218                                        });
19219                                        should_discard.not().then_some(language.clone())
19220                                    })
19221                                })
19222                                .collect::<HashSet<_>>()
19223                        });
19224                        if !languages_affected.is_empty() {
19225                            self.refresh_inlay_hints(
19226                                InlayHintRefreshReason::BufferEdited(languages_affected),
19227                                cx,
19228                            );
19229                        }
19230                    }
19231                }
19232
19233                let Some(project) = &self.project else { return };
19234                let (telemetry, is_via_ssh) = {
19235                    let project = project.read(cx);
19236                    let telemetry = project.client().telemetry().clone();
19237                    let is_via_ssh = project.is_via_ssh();
19238                    (telemetry, is_via_ssh)
19239                };
19240                refresh_linked_ranges(self, window, cx);
19241                telemetry.log_edit_event("editor", is_via_ssh);
19242            }
19243            multi_buffer::Event::ExcerptsAdded {
19244                buffer,
19245                predecessor,
19246                excerpts,
19247            } => {
19248                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19249                let buffer_id = buffer.read(cx).remote_id();
19250                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19251                    if let Some(project) = &self.project {
19252                        update_uncommitted_diff_for_buffer(
19253                            cx.entity(),
19254                            project,
19255                            [buffer.clone()],
19256                            self.buffer.clone(),
19257                            cx,
19258                        )
19259                        .detach();
19260                    }
19261                }
19262                self.update_lsp_data(false, None, Some(buffer_id), window, cx);
19263                cx.emit(EditorEvent::ExcerptsAdded {
19264                    buffer: buffer.clone(),
19265                    predecessor: *predecessor,
19266                    excerpts: excerpts.clone(),
19267                });
19268                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19269            }
19270            multi_buffer::Event::ExcerptsRemoved {
19271                ids,
19272                removed_buffer_ids,
19273            } => {
19274                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19275                let buffer = self.buffer.read(cx);
19276                self.registered_buffers
19277                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19278                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19279                cx.emit(EditorEvent::ExcerptsRemoved {
19280                    ids: ids.clone(),
19281                    removed_buffer_ids: removed_buffer_ids.clone(),
19282                });
19283            }
19284            multi_buffer::Event::ExcerptsEdited {
19285                excerpt_ids,
19286                buffer_ids,
19287            } => {
19288                self.display_map.update(cx, |map, cx| {
19289                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19290                });
19291                cx.emit(EditorEvent::ExcerptsEdited {
19292                    ids: excerpt_ids.clone(),
19293                });
19294            }
19295            multi_buffer::Event::ExcerptsExpanded { ids } => {
19296                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19297                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19298            }
19299            multi_buffer::Event::Reparsed(buffer_id) => {
19300                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19301                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19302
19303                cx.emit(EditorEvent::Reparsed(*buffer_id));
19304            }
19305            multi_buffer::Event::DiffHunksToggled => {
19306                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19307            }
19308            multi_buffer::Event::LanguageChanged(buffer_id) => {
19309                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19310                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19311                cx.emit(EditorEvent::Reparsed(*buffer_id));
19312                cx.notify();
19313            }
19314            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19315            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19316            multi_buffer::Event::FileHandleChanged
19317            | multi_buffer::Event::Reloaded
19318            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19319            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19320            multi_buffer::Event::DiagnosticsUpdated => {
19321                self.update_diagnostics_state(window, cx);
19322            }
19323            _ => {}
19324        };
19325    }
19326
19327    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19328        self.refresh_active_diagnostics(cx);
19329        self.refresh_inline_diagnostics(true, window, cx);
19330        self.scrollbar_marker_state.dirty = true;
19331        cx.notify();
19332    }
19333
19334    pub fn start_temporary_diff_override(&mut self) {
19335        self.load_diff_task.take();
19336        self.temporary_diff_override = true;
19337    }
19338
19339    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19340        self.temporary_diff_override = false;
19341        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19342        self.buffer.update(cx, |buffer, cx| {
19343            buffer.set_all_diff_hunks_collapsed(cx);
19344        });
19345
19346        if let Some(project) = self.project.clone() {
19347            self.load_diff_task = Some(
19348                update_uncommitted_diff_for_buffer(
19349                    cx.entity(),
19350                    &project,
19351                    self.buffer.read(cx).all_buffers(),
19352                    self.buffer.clone(),
19353                    cx,
19354                )
19355                .shared(),
19356            );
19357        }
19358    }
19359
19360    fn on_display_map_changed(
19361        &mut self,
19362        _: Entity<DisplayMap>,
19363        _: &mut Window,
19364        cx: &mut Context<Self>,
19365    ) {
19366        cx.notify();
19367    }
19368
19369    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19370        let new_severity = if self.diagnostics_enabled() {
19371            EditorSettings::get_global(cx)
19372                .diagnostics_max_severity
19373                .unwrap_or(DiagnosticSeverity::Hint)
19374        } else {
19375            DiagnosticSeverity::Off
19376        };
19377        self.set_max_diagnostics_severity(new_severity, cx);
19378        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19379        self.update_edit_prediction_settings(cx);
19380        self.refresh_inline_completion(true, false, window, cx);
19381        self.refresh_inlay_hints(
19382            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19383                self.selections.newest_anchor().head(),
19384                &self.buffer.read(cx).snapshot(cx),
19385                cx,
19386            )),
19387            cx,
19388        );
19389
19390        let old_cursor_shape = self.cursor_shape;
19391
19392        {
19393            let editor_settings = EditorSettings::get_global(cx);
19394            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19395            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19396            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19397            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19398            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19399        }
19400
19401        if old_cursor_shape != self.cursor_shape {
19402            cx.emit(EditorEvent::CursorShapeChanged);
19403        }
19404
19405        let project_settings = ProjectSettings::get_global(cx);
19406        self.serialize_dirty_buffers =
19407            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19408
19409        if self.mode.is_full() {
19410            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19411            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19412            if self.show_inline_diagnostics != show_inline_diagnostics {
19413                self.show_inline_diagnostics = show_inline_diagnostics;
19414                self.refresh_inline_diagnostics(false, window, cx);
19415            }
19416
19417            if self.git_blame_inline_enabled != inline_blame_enabled {
19418                self.toggle_git_blame_inline_internal(false, window, cx);
19419            }
19420
19421            let minimap_settings = EditorSettings::get_global(cx).minimap;
19422            if self.minimap_visibility != MinimapVisibility::Disabled {
19423                if self.minimap_visibility.settings_visibility()
19424                    != minimap_settings.minimap_enabled()
19425                {
19426                    self.set_minimap_visibility(
19427                        MinimapVisibility::for_mode(self.mode(), cx),
19428                        window,
19429                        cx,
19430                    );
19431                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19432                    minimap_entity.update(cx, |minimap_editor, cx| {
19433                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19434                    })
19435                }
19436            }
19437        }
19438
19439        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19440            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19441        }) {
19442            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19443                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19444            }
19445            self.refresh_colors(true, None, None, window, cx);
19446        }
19447
19448        cx.notify();
19449    }
19450
19451    pub fn set_searchable(&mut self, searchable: bool) {
19452        self.searchable = searchable;
19453    }
19454
19455    pub fn searchable(&self) -> bool {
19456        self.searchable
19457    }
19458
19459    fn open_proposed_changes_editor(
19460        &mut self,
19461        _: &OpenProposedChangesEditor,
19462        window: &mut Window,
19463        cx: &mut Context<Self>,
19464    ) {
19465        let Some(workspace) = self.workspace() else {
19466            cx.propagate();
19467            return;
19468        };
19469
19470        let selections = self.selections.all::<usize>(cx);
19471        let multi_buffer = self.buffer.read(cx);
19472        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19473        let mut new_selections_by_buffer = HashMap::default();
19474        for selection in selections {
19475            for (buffer, range, _) in
19476                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19477            {
19478                let mut range = range.to_point(buffer);
19479                range.start.column = 0;
19480                range.end.column = buffer.line_len(range.end.row);
19481                new_selections_by_buffer
19482                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19483                    .or_insert(Vec::new())
19484                    .push(range)
19485            }
19486        }
19487
19488        let proposed_changes_buffers = new_selections_by_buffer
19489            .into_iter()
19490            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19491            .collect::<Vec<_>>();
19492        let proposed_changes_editor = cx.new(|cx| {
19493            ProposedChangesEditor::new(
19494                "Proposed changes",
19495                proposed_changes_buffers,
19496                self.project.clone(),
19497                window,
19498                cx,
19499            )
19500        });
19501
19502        window.defer(cx, move |window, cx| {
19503            workspace.update(cx, |workspace, cx| {
19504                workspace.active_pane().update(cx, |pane, cx| {
19505                    pane.add_item(
19506                        Box::new(proposed_changes_editor),
19507                        true,
19508                        true,
19509                        None,
19510                        window,
19511                        cx,
19512                    );
19513                });
19514            });
19515        });
19516    }
19517
19518    pub fn open_excerpts_in_split(
19519        &mut self,
19520        _: &OpenExcerptsSplit,
19521        window: &mut Window,
19522        cx: &mut Context<Self>,
19523    ) {
19524        self.open_excerpts_common(None, true, window, cx)
19525    }
19526
19527    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19528        self.open_excerpts_common(None, false, window, cx)
19529    }
19530
19531    fn open_excerpts_common(
19532        &mut self,
19533        jump_data: Option<JumpData>,
19534        split: bool,
19535        window: &mut Window,
19536        cx: &mut Context<Self>,
19537    ) {
19538        let Some(workspace) = self.workspace() else {
19539            cx.propagate();
19540            return;
19541        };
19542
19543        if self.buffer.read(cx).is_singleton() {
19544            cx.propagate();
19545            return;
19546        }
19547
19548        let mut new_selections_by_buffer = HashMap::default();
19549        match &jump_data {
19550            Some(JumpData::MultiBufferPoint {
19551                excerpt_id,
19552                position,
19553                anchor,
19554                line_offset_from_top,
19555            }) => {
19556                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19557                if let Some(buffer) = multi_buffer_snapshot
19558                    .buffer_id_for_excerpt(*excerpt_id)
19559                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19560                {
19561                    let buffer_snapshot = buffer.read(cx).snapshot();
19562                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19563                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19564                    } else {
19565                        buffer_snapshot.clip_point(*position, Bias::Left)
19566                    };
19567                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19568                    new_selections_by_buffer.insert(
19569                        buffer,
19570                        (
19571                            vec![jump_to_offset..jump_to_offset],
19572                            Some(*line_offset_from_top),
19573                        ),
19574                    );
19575                }
19576            }
19577            Some(JumpData::MultiBufferRow {
19578                row,
19579                line_offset_from_top,
19580            }) => {
19581                let point = MultiBufferPoint::new(row.0, 0);
19582                if let Some((buffer, buffer_point, _)) =
19583                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19584                {
19585                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19586                    new_selections_by_buffer
19587                        .entry(buffer)
19588                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19589                        .0
19590                        .push(buffer_offset..buffer_offset)
19591                }
19592            }
19593            None => {
19594                let selections = self.selections.all::<usize>(cx);
19595                let multi_buffer = self.buffer.read(cx);
19596                for selection in selections {
19597                    for (snapshot, range, _, anchor) in multi_buffer
19598                        .snapshot(cx)
19599                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19600                    {
19601                        if let Some(anchor) = anchor {
19602                            // selection is in a deleted hunk
19603                            let Some(buffer_id) = anchor.buffer_id else {
19604                                continue;
19605                            };
19606                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19607                                continue;
19608                            };
19609                            let offset = text::ToOffset::to_offset(
19610                                &anchor.text_anchor,
19611                                &buffer_handle.read(cx).snapshot(),
19612                            );
19613                            let range = offset..offset;
19614                            new_selections_by_buffer
19615                                .entry(buffer_handle)
19616                                .or_insert((Vec::new(), None))
19617                                .0
19618                                .push(range)
19619                        } else {
19620                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19621                            else {
19622                                continue;
19623                            };
19624                            new_selections_by_buffer
19625                                .entry(buffer_handle)
19626                                .or_insert((Vec::new(), None))
19627                                .0
19628                                .push(range)
19629                        }
19630                    }
19631                }
19632            }
19633        }
19634
19635        new_selections_by_buffer
19636            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19637
19638        if new_selections_by_buffer.is_empty() {
19639            return;
19640        }
19641
19642        // We defer the pane interaction because we ourselves are a workspace item
19643        // and activating a new item causes the pane to call a method on us reentrantly,
19644        // which panics if we're on the stack.
19645        window.defer(cx, move |window, cx| {
19646            workspace.update(cx, |workspace, cx| {
19647                let pane = if split {
19648                    workspace.adjacent_pane(window, cx)
19649                } else {
19650                    workspace.active_pane().clone()
19651                };
19652
19653                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19654                    let editor = buffer
19655                        .read(cx)
19656                        .file()
19657                        .is_none()
19658                        .then(|| {
19659                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19660                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19661                            // Instead, we try to activate the existing editor in the pane first.
19662                            let (editor, pane_item_index) =
19663                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19664                                    let editor = item.downcast::<Editor>()?;
19665                                    let singleton_buffer =
19666                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19667                                    if singleton_buffer == buffer {
19668                                        Some((editor, i))
19669                                    } else {
19670                                        None
19671                                    }
19672                                })?;
19673                            pane.update(cx, |pane, cx| {
19674                                pane.activate_item(pane_item_index, true, true, window, cx)
19675                            });
19676                            Some(editor)
19677                        })
19678                        .flatten()
19679                        .unwrap_or_else(|| {
19680                            workspace.open_project_item::<Self>(
19681                                pane.clone(),
19682                                buffer,
19683                                true,
19684                                true,
19685                                window,
19686                                cx,
19687                            )
19688                        });
19689
19690                    editor.update(cx, |editor, cx| {
19691                        let autoscroll = match scroll_offset {
19692                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19693                            None => Autoscroll::newest(),
19694                        };
19695                        let nav_history = editor.nav_history.take();
19696                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19697                            s.select_ranges(ranges);
19698                        });
19699                        editor.nav_history = nav_history;
19700                    });
19701                }
19702            })
19703        });
19704    }
19705
19706    // For now, don't allow opening excerpts in buffers that aren't backed by
19707    // regular project files.
19708    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19709        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19710    }
19711
19712    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19713        let snapshot = self.buffer.read(cx).read(cx);
19714        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19715        Some(
19716            ranges
19717                .iter()
19718                .map(move |range| {
19719                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19720                })
19721                .collect(),
19722        )
19723    }
19724
19725    fn selection_replacement_ranges(
19726        &self,
19727        range: Range<OffsetUtf16>,
19728        cx: &mut App,
19729    ) -> Vec<Range<OffsetUtf16>> {
19730        let selections = self.selections.all::<OffsetUtf16>(cx);
19731        let newest_selection = selections
19732            .iter()
19733            .max_by_key(|selection| selection.id)
19734            .unwrap();
19735        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19736        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19737        let snapshot = self.buffer.read(cx).read(cx);
19738        selections
19739            .into_iter()
19740            .map(|mut selection| {
19741                selection.start.0 =
19742                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19743                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19744                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19745                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19746            })
19747            .collect()
19748    }
19749
19750    fn report_editor_event(
19751        &self,
19752        event_type: &'static str,
19753        file_extension: Option<String>,
19754        cx: &App,
19755    ) {
19756        if cfg!(any(test, feature = "test-support")) {
19757            return;
19758        }
19759
19760        let Some(project) = &self.project else { return };
19761
19762        // If None, we are in a file without an extension
19763        let file = self
19764            .buffer
19765            .read(cx)
19766            .as_singleton()
19767            .and_then(|b| b.read(cx).file());
19768        let file_extension = file_extension.or(file
19769            .as_ref()
19770            .and_then(|file| Path::new(file.file_name(cx)).extension())
19771            .and_then(|e| e.to_str())
19772            .map(|a| a.to_string()));
19773
19774        let vim_mode = vim_enabled(cx);
19775
19776        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19777        let copilot_enabled = edit_predictions_provider
19778            == language::language_settings::EditPredictionProvider::Copilot;
19779        let copilot_enabled_for_language = self
19780            .buffer
19781            .read(cx)
19782            .language_settings(cx)
19783            .show_edit_predictions;
19784
19785        let project = project.read(cx);
19786        telemetry::event!(
19787            event_type,
19788            file_extension,
19789            vim_mode,
19790            copilot_enabled,
19791            copilot_enabled_for_language,
19792            edit_predictions_provider,
19793            is_via_ssh = project.is_via_ssh(),
19794        );
19795    }
19796
19797    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19798    /// with each line being an array of {text, highlight} objects.
19799    fn copy_highlight_json(
19800        &mut self,
19801        _: &CopyHighlightJson,
19802        window: &mut Window,
19803        cx: &mut Context<Self>,
19804    ) {
19805        #[derive(Serialize)]
19806        struct Chunk<'a> {
19807            text: String,
19808            highlight: Option<&'a str>,
19809        }
19810
19811        let snapshot = self.buffer.read(cx).snapshot(cx);
19812        let range = self
19813            .selected_text_range(false, window, cx)
19814            .and_then(|selection| {
19815                if selection.range.is_empty() {
19816                    None
19817                } else {
19818                    Some(selection.range)
19819                }
19820            })
19821            .unwrap_or_else(|| 0..snapshot.len());
19822
19823        let chunks = snapshot.chunks(range, true);
19824        let mut lines = Vec::new();
19825        let mut line: VecDeque<Chunk> = VecDeque::new();
19826
19827        let Some(style) = self.style.as_ref() else {
19828            return;
19829        };
19830
19831        for chunk in chunks {
19832            let highlight = chunk
19833                .syntax_highlight_id
19834                .and_then(|id| id.name(&style.syntax));
19835            let mut chunk_lines = chunk.text.split('\n').peekable();
19836            while let Some(text) = chunk_lines.next() {
19837                let mut merged_with_last_token = false;
19838                if let Some(last_token) = line.back_mut() {
19839                    if last_token.highlight == highlight {
19840                        last_token.text.push_str(text);
19841                        merged_with_last_token = true;
19842                    }
19843                }
19844
19845                if !merged_with_last_token {
19846                    line.push_back(Chunk {
19847                        text: text.into(),
19848                        highlight,
19849                    });
19850                }
19851
19852                if chunk_lines.peek().is_some() {
19853                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19854                        line.pop_front();
19855                    }
19856                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19857                        line.pop_back();
19858                    }
19859
19860                    lines.push(mem::take(&mut line));
19861                }
19862            }
19863        }
19864
19865        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19866            return;
19867        };
19868        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19869    }
19870
19871    pub fn open_context_menu(
19872        &mut self,
19873        _: &OpenContextMenu,
19874        window: &mut Window,
19875        cx: &mut Context<Self>,
19876    ) {
19877        self.request_autoscroll(Autoscroll::newest(), cx);
19878        let position = self.selections.newest_display(cx).start;
19879        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19880    }
19881
19882    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19883        &self.inlay_hint_cache
19884    }
19885
19886    pub fn replay_insert_event(
19887        &mut self,
19888        text: &str,
19889        relative_utf16_range: Option<Range<isize>>,
19890        window: &mut Window,
19891        cx: &mut Context<Self>,
19892    ) {
19893        if !self.input_enabled {
19894            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19895            return;
19896        }
19897        if let Some(relative_utf16_range) = relative_utf16_range {
19898            let selections = self.selections.all::<OffsetUtf16>(cx);
19899            self.change_selections(None, window, cx, |s| {
19900                let new_ranges = selections.into_iter().map(|range| {
19901                    let start = OffsetUtf16(
19902                        range
19903                            .head()
19904                            .0
19905                            .saturating_add_signed(relative_utf16_range.start),
19906                    );
19907                    let end = OffsetUtf16(
19908                        range
19909                            .head()
19910                            .0
19911                            .saturating_add_signed(relative_utf16_range.end),
19912                    );
19913                    start..end
19914                });
19915                s.select_ranges(new_ranges);
19916            });
19917        }
19918
19919        self.handle_input(text, window, cx);
19920    }
19921
19922    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19923        let Some(provider) = self.semantics_provider.as_ref() else {
19924            return false;
19925        };
19926
19927        let mut supports = false;
19928        self.buffer().update(cx, |this, cx| {
19929            this.for_each_buffer(|buffer| {
19930                supports |= provider.supports_inlay_hints(buffer, cx);
19931            });
19932        });
19933
19934        supports
19935    }
19936
19937    pub fn is_focused(&self, window: &Window) -> bool {
19938        self.focus_handle.is_focused(window)
19939    }
19940
19941    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19942        cx.emit(EditorEvent::Focused);
19943
19944        if let Some(descendant) = self
19945            .last_focused_descendant
19946            .take()
19947            .and_then(|descendant| descendant.upgrade())
19948        {
19949            window.focus(&descendant);
19950        } else {
19951            if let Some(blame) = self.blame.as_ref() {
19952                blame.update(cx, GitBlame::focus)
19953            }
19954
19955            self.blink_manager.update(cx, BlinkManager::enable);
19956            self.show_cursor_names(window, cx);
19957            self.buffer.update(cx, |buffer, cx| {
19958                buffer.finalize_last_transaction(cx);
19959                if self.leader_id.is_none() {
19960                    buffer.set_active_selections(
19961                        &self.selections.disjoint_anchors(),
19962                        self.selections.line_mode,
19963                        self.cursor_shape,
19964                        cx,
19965                    );
19966                }
19967            });
19968        }
19969    }
19970
19971    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19972        cx.emit(EditorEvent::FocusedIn)
19973    }
19974
19975    fn handle_focus_out(
19976        &mut self,
19977        event: FocusOutEvent,
19978        _window: &mut Window,
19979        cx: &mut Context<Self>,
19980    ) {
19981        if event.blurred != self.focus_handle {
19982            self.last_focused_descendant = Some(event.blurred);
19983        }
19984        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19985    }
19986
19987    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19988        self.blink_manager.update(cx, BlinkManager::disable);
19989        self.buffer
19990            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19991
19992        if let Some(blame) = self.blame.as_ref() {
19993            blame.update(cx, GitBlame::blur)
19994        }
19995        if !self.hover_state.focused(window, cx) {
19996            hide_hover(self, cx);
19997        }
19998        if !self
19999            .context_menu
20000            .borrow()
20001            .as_ref()
20002            .is_some_and(|context_menu| context_menu.focused(window, cx))
20003        {
20004            self.hide_context_menu(window, cx);
20005        }
20006        self.discard_inline_completion(false, cx);
20007        cx.emit(EditorEvent::Blurred);
20008        cx.notify();
20009    }
20010
20011    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20012        let mut pending: String = window
20013            .pending_input_keystrokes()
20014            .into_iter()
20015            .flatten()
20016            .filter_map(|keystroke| {
20017                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20018                    keystroke.key_char.clone()
20019                } else {
20020                    None
20021                }
20022            })
20023            .collect();
20024
20025        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20026            pending = "".to_string();
20027        }
20028
20029        let existing_pending = self
20030            .text_highlights::<PendingInput>(cx)
20031            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20032        if existing_pending.is_none() && pending.is_empty() {
20033            return;
20034        }
20035        let transaction =
20036            self.transact(window, cx, |this, window, cx| {
20037                let selections = this.selections.all::<usize>(cx);
20038                let edits = selections
20039                    .iter()
20040                    .map(|selection| (selection.end..selection.end, pending.clone()));
20041                this.edit(edits, cx);
20042                this.change_selections(None, window, cx, |s| {
20043                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20044                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20045                    }));
20046                });
20047                if let Some(existing_ranges) = existing_pending {
20048                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20049                    this.edit(edits, cx);
20050                }
20051            });
20052
20053        let snapshot = self.snapshot(window, cx);
20054        let ranges = self
20055            .selections
20056            .all::<usize>(cx)
20057            .into_iter()
20058            .map(|selection| {
20059                snapshot.buffer_snapshot.anchor_after(selection.end)
20060                    ..snapshot
20061                        .buffer_snapshot
20062                        .anchor_before(selection.end + pending.len())
20063            })
20064            .collect();
20065
20066        if pending.is_empty() {
20067            self.clear_highlights::<PendingInput>(cx);
20068        } else {
20069            self.highlight_text::<PendingInput>(
20070                ranges,
20071                HighlightStyle {
20072                    underline: Some(UnderlineStyle {
20073                        thickness: px(1.),
20074                        color: None,
20075                        wavy: false,
20076                    }),
20077                    ..Default::default()
20078                },
20079                cx,
20080            );
20081        }
20082
20083        self.ime_transaction = self.ime_transaction.or(transaction);
20084        if let Some(transaction) = self.ime_transaction {
20085            self.buffer.update(cx, |buffer, cx| {
20086                buffer.group_until_transaction(transaction, cx);
20087            });
20088        }
20089
20090        if self.text_highlights::<PendingInput>(cx).is_none() {
20091            self.ime_transaction.take();
20092        }
20093    }
20094
20095    pub fn register_action_renderer(
20096        &mut self,
20097        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20098    ) -> Subscription {
20099        let id = self.next_editor_action_id.post_inc();
20100        self.editor_actions
20101            .borrow_mut()
20102            .insert(id, Box::new(listener));
20103
20104        let editor_actions = self.editor_actions.clone();
20105        Subscription::new(move || {
20106            editor_actions.borrow_mut().remove(&id);
20107        })
20108    }
20109
20110    pub fn register_action<A: Action>(
20111        &mut self,
20112        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20113    ) -> Subscription {
20114        let id = self.next_editor_action_id.post_inc();
20115        let listener = Arc::new(listener);
20116        self.editor_actions.borrow_mut().insert(
20117            id,
20118            Box::new(move |_, window, _| {
20119                let listener = listener.clone();
20120                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20121                    let action = action.downcast_ref().unwrap();
20122                    if phase == DispatchPhase::Bubble {
20123                        listener(action, window, cx)
20124                    }
20125                })
20126            }),
20127        );
20128
20129        let editor_actions = self.editor_actions.clone();
20130        Subscription::new(move || {
20131            editor_actions.borrow_mut().remove(&id);
20132        })
20133    }
20134
20135    pub fn file_header_size(&self) -> u32 {
20136        FILE_HEADER_HEIGHT
20137    }
20138
20139    pub fn restore(
20140        &mut self,
20141        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20142        window: &mut Window,
20143        cx: &mut Context<Self>,
20144    ) {
20145        let workspace = self.workspace();
20146        let project = self.project.as_ref();
20147        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20148            let mut tasks = Vec::new();
20149            for (buffer_id, changes) in revert_changes {
20150                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20151                    buffer.update(cx, |buffer, cx| {
20152                        buffer.edit(
20153                            changes
20154                                .into_iter()
20155                                .map(|(range, text)| (range, text.to_string())),
20156                            None,
20157                            cx,
20158                        );
20159                    });
20160
20161                    if let Some(project) =
20162                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20163                    {
20164                        project.update(cx, |project, cx| {
20165                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20166                        })
20167                    }
20168                }
20169            }
20170            tasks
20171        });
20172        cx.spawn_in(window, async move |_, cx| {
20173            for (buffer, task) in save_tasks {
20174                let result = task.await;
20175                if result.is_err() {
20176                    let Some(path) = buffer
20177                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20178                        .ok()
20179                    else {
20180                        continue;
20181                    };
20182                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20183                        let Some(task) = cx
20184                            .update_window_entity(&workspace, |workspace, window, cx| {
20185                                workspace
20186                                    .open_path_preview(path, None, false, false, false, window, cx)
20187                            })
20188                            .ok()
20189                        else {
20190                            continue;
20191                        };
20192                        task.await.log_err();
20193                    }
20194                }
20195            }
20196        })
20197        .detach();
20198        self.change_selections(None, window, cx, |selections| selections.refresh());
20199    }
20200
20201    pub fn to_pixel_point(
20202        &self,
20203        source: multi_buffer::Anchor,
20204        editor_snapshot: &EditorSnapshot,
20205        window: &mut Window,
20206    ) -> Option<gpui::Point<Pixels>> {
20207        let source_point = source.to_display_point(editor_snapshot);
20208        self.display_to_pixel_point(source_point, editor_snapshot, window)
20209    }
20210
20211    pub fn display_to_pixel_point(
20212        &self,
20213        source: DisplayPoint,
20214        editor_snapshot: &EditorSnapshot,
20215        window: &mut Window,
20216    ) -> Option<gpui::Point<Pixels>> {
20217        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20218        let text_layout_details = self.text_layout_details(window);
20219        let scroll_top = text_layout_details
20220            .scroll_anchor
20221            .scroll_position(editor_snapshot)
20222            .y;
20223
20224        if source.row().as_f32() < scroll_top.floor() {
20225            return None;
20226        }
20227        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20228        let source_y = line_height * (source.row().as_f32() - scroll_top);
20229        Some(gpui::Point::new(source_x, source_y))
20230    }
20231
20232    pub fn has_visible_completions_menu(&self) -> bool {
20233        !self.edit_prediction_preview_is_active()
20234            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20235                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20236            })
20237    }
20238
20239    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20240        if self.mode.is_minimap() {
20241            return;
20242        }
20243        self.addons
20244            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20245    }
20246
20247    pub fn unregister_addon<T: Addon>(&mut self) {
20248        self.addons.remove(&std::any::TypeId::of::<T>());
20249    }
20250
20251    pub fn addon<T: Addon>(&self) -> Option<&T> {
20252        let type_id = std::any::TypeId::of::<T>();
20253        self.addons
20254            .get(&type_id)
20255            .and_then(|item| item.to_any().downcast_ref::<T>())
20256    }
20257
20258    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20259        let type_id = std::any::TypeId::of::<T>();
20260        self.addons
20261            .get_mut(&type_id)
20262            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20263    }
20264
20265    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20266        let text_layout_details = self.text_layout_details(window);
20267        let style = &text_layout_details.editor_style;
20268        let font_id = window.text_system().resolve_font(&style.text.font());
20269        let font_size = style.text.font_size.to_pixels(window.rem_size());
20270        let line_height = style.text.line_height_in_pixels(window.rem_size());
20271        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20272
20273        gpui::Size::new(em_width, line_height)
20274    }
20275
20276    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20277        self.load_diff_task.clone()
20278    }
20279
20280    fn read_metadata_from_db(
20281        &mut self,
20282        item_id: u64,
20283        workspace_id: WorkspaceId,
20284        window: &mut Window,
20285        cx: &mut Context<Editor>,
20286    ) {
20287        if self.is_singleton(cx)
20288            && !self.mode.is_minimap()
20289            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20290        {
20291            let buffer_snapshot = OnceCell::new();
20292
20293            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20294                if !folds.is_empty() {
20295                    let snapshot =
20296                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20297                    self.fold_ranges(
20298                        folds
20299                            .into_iter()
20300                            .map(|(start, end)| {
20301                                snapshot.clip_offset(start, Bias::Left)
20302                                    ..snapshot.clip_offset(end, Bias::Right)
20303                            })
20304                            .collect(),
20305                        false,
20306                        window,
20307                        cx,
20308                    );
20309                }
20310            }
20311
20312            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20313                if !selections.is_empty() {
20314                    let snapshot =
20315                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20316                    // skip adding the initial selection to selection history
20317                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20318                    self.change_selections(None, window, cx, |s| {
20319                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20320                            snapshot.clip_offset(start, Bias::Left)
20321                                ..snapshot.clip_offset(end, Bias::Right)
20322                        }));
20323                    });
20324                    self.selection_history.mode = SelectionHistoryMode::Normal;
20325                }
20326            };
20327        }
20328
20329        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20330    }
20331
20332    fn update_lsp_data(
20333        &mut self,
20334        update_on_edit: bool,
20335        for_server_id: Option<LanguageServerId>,
20336        for_buffer: Option<BufferId>,
20337        window: &mut Window,
20338        cx: &mut Context<'_, Self>,
20339    ) {
20340        self.pull_diagnostics(for_buffer, window, cx);
20341        self.refresh_colors(update_on_edit, for_server_id, for_buffer, window, cx);
20342    }
20343}
20344
20345fn vim_enabled(cx: &App) -> bool {
20346    cx.global::<SettingsStore>()
20347        .raw_user_settings()
20348        .get("vim_mode")
20349        == Some(&serde_json::Value::Bool(true))
20350}
20351
20352fn process_completion_for_edit(
20353    completion: &Completion,
20354    intent: CompletionIntent,
20355    buffer: &Entity<Buffer>,
20356    cursor_position: &text::Anchor,
20357    cx: &mut Context<Editor>,
20358) -> CompletionEdit {
20359    let buffer = buffer.read(cx);
20360    let buffer_snapshot = buffer.snapshot();
20361    let (snippet, new_text) = if completion.is_snippet() {
20362        // Workaround for typescript language server issues so that methods don't expand within
20363        // strings and functions with type expressions. The previous point is used because the query
20364        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20365        let mut snippet_source = completion.new_text.clone();
20366        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20367        previous_point.column = previous_point.column.saturating_sub(1);
20368        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20369            if scope.prefers_label_for_snippet_in_completion() {
20370                if let Some(label) = completion.label() {
20371                    if matches!(
20372                        completion.kind(),
20373                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20374                    ) {
20375                        snippet_source = label;
20376                    }
20377                }
20378            }
20379        }
20380        match Snippet::parse(&snippet_source).log_err() {
20381            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20382            None => (None, completion.new_text.clone()),
20383        }
20384    } else {
20385        (None, completion.new_text.clone())
20386    };
20387
20388    let mut range_to_replace = {
20389        let replace_range = &completion.replace_range;
20390        if let CompletionSource::Lsp {
20391            insert_range: Some(insert_range),
20392            ..
20393        } = &completion.source
20394        {
20395            debug_assert_eq!(
20396                insert_range.start, replace_range.start,
20397                "insert_range and replace_range should start at the same position"
20398            );
20399            debug_assert!(
20400                insert_range
20401                    .start
20402                    .cmp(&cursor_position, &buffer_snapshot)
20403                    .is_le(),
20404                "insert_range should start before or at cursor position"
20405            );
20406            debug_assert!(
20407                replace_range
20408                    .start
20409                    .cmp(&cursor_position, &buffer_snapshot)
20410                    .is_le(),
20411                "replace_range should start before or at cursor position"
20412            );
20413            debug_assert!(
20414                insert_range
20415                    .end
20416                    .cmp(&cursor_position, &buffer_snapshot)
20417                    .is_le(),
20418                "insert_range should end before or at cursor position"
20419            );
20420
20421            let should_replace = match intent {
20422                CompletionIntent::CompleteWithInsert => false,
20423                CompletionIntent::CompleteWithReplace => true,
20424                CompletionIntent::Complete | CompletionIntent::Compose => {
20425                    let insert_mode =
20426                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20427                            .completions
20428                            .lsp_insert_mode;
20429                    match insert_mode {
20430                        LspInsertMode::Insert => false,
20431                        LspInsertMode::Replace => true,
20432                        LspInsertMode::ReplaceSubsequence => {
20433                            let mut text_to_replace = buffer.chars_for_range(
20434                                buffer.anchor_before(replace_range.start)
20435                                    ..buffer.anchor_after(replace_range.end),
20436                            );
20437                            let mut current_needle = text_to_replace.next();
20438                            for haystack_ch in completion.label.text.chars() {
20439                                if let Some(needle_ch) = current_needle {
20440                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20441                                        current_needle = text_to_replace.next();
20442                                    }
20443                                }
20444                            }
20445                            current_needle.is_none()
20446                        }
20447                        LspInsertMode::ReplaceSuffix => {
20448                            if replace_range
20449                                .end
20450                                .cmp(&cursor_position, &buffer_snapshot)
20451                                .is_gt()
20452                            {
20453                                let range_after_cursor = *cursor_position..replace_range.end;
20454                                let text_after_cursor = buffer
20455                                    .text_for_range(
20456                                        buffer.anchor_before(range_after_cursor.start)
20457                                            ..buffer.anchor_after(range_after_cursor.end),
20458                                    )
20459                                    .collect::<String>()
20460                                    .to_ascii_lowercase();
20461                                completion
20462                                    .label
20463                                    .text
20464                                    .to_ascii_lowercase()
20465                                    .ends_with(&text_after_cursor)
20466                            } else {
20467                                true
20468                            }
20469                        }
20470                    }
20471                }
20472            };
20473
20474            if should_replace {
20475                replace_range.clone()
20476            } else {
20477                insert_range.clone()
20478            }
20479        } else {
20480            replace_range.clone()
20481        }
20482    };
20483
20484    if range_to_replace
20485        .end
20486        .cmp(&cursor_position, &buffer_snapshot)
20487        .is_lt()
20488    {
20489        range_to_replace.end = *cursor_position;
20490    }
20491
20492    CompletionEdit {
20493        new_text,
20494        replace_range: range_to_replace.to_offset(&buffer),
20495        snippet,
20496    }
20497}
20498
20499struct CompletionEdit {
20500    new_text: String,
20501    replace_range: Range<usize>,
20502    snippet: Option<Snippet>,
20503}
20504
20505fn insert_extra_newline_brackets(
20506    buffer: &MultiBufferSnapshot,
20507    range: Range<usize>,
20508    language: &language::LanguageScope,
20509) -> bool {
20510    let leading_whitespace_len = buffer
20511        .reversed_chars_at(range.start)
20512        .take_while(|c| c.is_whitespace() && *c != '\n')
20513        .map(|c| c.len_utf8())
20514        .sum::<usize>();
20515    let trailing_whitespace_len = buffer
20516        .chars_at(range.end)
20517        .take_while(|c| c.is_whitespace() && *c != '\n')
20518        .map(|c| c.len_utf8())
20519        .sum::<usize>();
20520    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20521
20522    language.brackets().any(|(pair, enabled)| {
20523        let pair_start = pair.start.trim_end();
20524        let pair_end = pair.end.trim_start();
20525
20526        enabled
20527            && pair.newline
20528            && buffer.contains_str_at(range.end, pair_end)
20529            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20530    })
20531}
20532
20533fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20534    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20535        [(buffer, range, _)] => (*buffer, range.clone()),
20536        _ => return false,
20537    };
20538    let pair = {
20539        let mut result: Option<BracketMatch> = None;
20540
20541        for pair in buffer
20542            .all_bracket_ranges(range.clone())
20543            .filter(move |pair| {
20544                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20545            })
20546        {
20547            let len = pair.close_range.end - pair.open_range.start;
20548
20549            if let Some(existing) = &result {
20550                let existing_len = existing.close_range.end - existing.open_range.start;
20551                if len > existing_len {
20552                    continue;
20553                }
20554            }
20555
20556            result = Some(pair);
20557        }
20558
20559        result
20560    };
20561    let Some(pair) = pair else {
20562        return false;
20563    };
20564    pair.newline_only
20565        && buffer
20566            .chars_for_range(pair.open_range.end..range.start)
20567            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20568            .all(|c| c.is_whitespace() && c != '\n')
20569}
20570
20571fn update_uncommitted_diff_for_buffer(
20572    editor: Entity<Editor>,
20573    project: &Entity<Project>,
20574    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20575    buffer: Entity<MultiBuffer>,
20576    cx: &mut App,
20577) -> Task<()> {
20578    let mut tasks = Vec::new();
20579    project.update(cx, |project, cx| {
20580        for buffer in buffers {
20581            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20582                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20583            }
20584        }
20585    });
20586    cx.spawn(async move |cx| {
20587        let diffs = future::join_all(tasks).await;
20588        if editor
20589            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20590            .unwrap_or(false)
20591        {
20592            return;
20593        }
20594
20595        buffer
20596            .update(cx, |buffer, cx| {
20597                for diff in diffs.into_iter().flatten() {
20598                    buffer.add_diff(diff, cx);
20599                }
20600            })
20601            .ok();
20602    })
20603}
20604
20605fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20606    let tab_size = tab_size.get() as usize;
20607    let mut width = offset;
20608
20609    for ch in text.chars() {
20610        width += if ch == '\t' {
20611            tab_size - (width % tab_size)
20612        } else {
20613            1
20614        };
20615    }
20616
20617    width - offset
20618}
20619
20620#[cfg(test)]
20621mod tests {
20622    use super::*;
20623
20624    #[test]
20625    fn test_string_size_with_expanded_tabs() {
20626        let nz = |val| NonZeroU32::new(val).unwrap();
20627        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20628        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20629        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20630        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20631        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20632        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20633        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20634        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20635    }
20636}
20637
20638/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20639struct WordBreakingTokenizer<'a> {
20640    input: &'a str,
20641}
20642
20643impl<'a> WordBreakingTokenizer<'a> {
20644    fn new(input: &'a str) -> Self {
20645        Self { input }
20646    }
20647}
20648
20649fn is_char_ideographic(ch: char) -> bool {
20650    use unicode_script::Script::*;
20651    use unicode_script::UnicodeScript;
20652    matches!(ch.script(), Han | Tangut | Yi)
20653}
20654
20655fn is_grapheme_ideographic(text: &str) -> bool {
20656    text.chars().any(is_char_ideographic)
20657}
20658
20659fn is_grapheme_whitespace(text: &str) -> bool {
20660    text.chars().any(|x| x.is_whitespace())
20661}
20662
20663fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20664    text.chars().next().map_or(false, |ch| {
20665        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20666    })
20667}
20668
20669#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20670enum WordBreakToken<'a> {
20671    Word { token: &'a str, grapheme_len: usize },
20672    InlineWhitespace { token: &'a str, grapheme_len: usize },
20673    Newline,
20674}
20675
20676impl<'a> Iterator for WordBreakingTokenizer<'a> {
20677    /// Yields a span, the count of graphemes in the token, and whether it was
20678    /// whitespace. Note that it also breaks at word boundaries.
20679    type Item = WordBreakToken<'a>;
20680
20681    fn next(&mut self) -> Option<Self::Item> {
20682        use unicode_segmentation::UnicodeSegmentation;
20683        if self.input.is_empty() {
20684            return None;
20685        }
20686
20687        let mut iter = self.input.graphemes(true).peekable();
20688        let mut offset = 0;
20689        let mut grapheme_len = 0;
20690        if let Some(first_grapheme) = iter.next() {
20691            let is_newline = first_grapheme == "\n";
20692            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20693            offset += first_grapheme.len();
20694            grapheme_len += 1;
20695            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20696                if let Some(grapheme) = iter.peek().copied() {
20697                    if should_stay_with_preceding_ideograph(grapheme) {
20698                        offset += grapheme.len();
20699                        grapheme_len += 1;
20700                    }
20701                }
20702            } else {
20703                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20704                let mut next_word_bound = words.peek().copied();
20705                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20706                    next_word_bound = words.next();
20707                }
20708                while let Some(grapheme) = iter.peek().copied() {
20709                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20710                        break;
20711                    };
20712                    if is_grapheme_whitespace(grapheme) != is_whitespace
20713                        || (grapheme == "\n") != is_newline
20714                    {
20715                        break;
20716                    };
20717                    offset += grapheme.len();
20718                    grapheme_len += 1;
20719                    iter.next();
20720                }
20721            }
20722            let token = &self.input[..offset];
20723            self.input = &self.input[offset..];
20724            if token == "\n" {
20725                Some(WordBreakToken::Newline)
20726            } else if is_whitespace {
20727                Some(WordBreakToken::InlineWhitespace {
20728                    token,
20729                    grapheme_len,
20730                })
20731            } else {
20732                Some(WordBreakToken::Word {
20733                    token,
20734                    grapheme_len,
20735                })
20736            }
20737        } else {
20738            None
20739        }
20740    }
20741}
20742
20743#[test]
20744fn test_word_breaking_tokenizer() {
20745    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20746        ("", &[]),
20747        ("  ", &[whitespace("  ", 2)]),
20748        ("Ʒ", &[word("Ʒ", 1)]),
20749        ("Ǽ", &[word("Ǽ", 1)]),
20750        ("", &[word("", 1)]),
20751        ("⋑⋑", &[word("⋑⋑", 2)]),
20752        (
20753            "原理,进而",
20754            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20755        ),
20756        (
20757            "hello world",
20758            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20759        ),
20760        (
20761            "hello, world",
20762            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20763        ),
20764        (
20765            "  hello world",
20766            &[
20767                whitespace("  ", 2),
20768                word("hello", 5),
20769                whitespace(" ", 1),
20770                word("world", 5),
20771            ],
20772        ),
20773        (
20774            "这是什么 \n 钢笔",
20775            &[
20776                word("", 1),
20777                word("", 1),
20778                word("", 1),
20779                word("", 1),
20780                whitespace(" ", 1),
20781                newline(),
20782                whitespace(" ", 1),
20783                word("", 1),
20784                word("", 1),
20785            ],
20786        ),
20787        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20788    ];
20789
20790    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20791        WordBreakToken::Word {
20792            token,
20793            grapheme_len,
20794        }
20795    }
20796
20797    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20798        WordBreakToken::InlineWhitespace {
20799            token,
20800            grapheme_len,
20801        }
20802    }
20803
20804    fn newline() -> WordBreakToken<'static> {
20805        WordBreakToken::Newline
20806    }
20807
20808    for (input, result) in tests {
20809        assert_eq!(
20810            WordBreakingTokenizer::new(input)
20811                .collect::<Vec<_>>()
20812                .as_slice(),
20813            *result,
20814        );
20815    }
20816}
20817
20818fn wrap_with_prefix(
20819    line_prefix: String,
20820    unwrapped_text: String,
20821    wrap_column: usize,
20822    tab_size: NonZeroU32,
20823    preserve_existing_whitespace: bool,
20824) -> String {
20825    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20826    let mut wrapped_text = String::new();
20827    let mut current_line = line_prefix.clone();
20828
20829    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20830    let mut current_line_len = line_prefix_len;
20831    let mut in_whitespace = false;
20832    for token in tokenizer {
20833        let have_preceding_whitespace = in_whitespace;
20834        match token {
20835            WordBreakToken::Word {
20836                token,
20837                grapheme_len,
20838            } => {
20839                in_whitespace = false;
20840                if current_line_len + grapheme_len > wrap_column
20841                    && current_line_len != line_prefix_len
20842                {
20843                    wrapped_text.push_str(current_line.trim_end());
20844                    wrapped_text.push('\n');
20845                    current_line.truncate(line_prefix.len());
20846                    current_line_len = line_prefix_len;
20847                }
20848                current_line.push_str(token);
20849                current_line_len += grapheme_len;
20850            }
20851            WordBreakToken::InlineWhitespace {
20852                mut token,
20853                mut grapheme_len,
20854            } => {
20855                in_whitespace = true;
20856                if have_preceding_whitespace && !preserve_existing_whitespace {
20857                    continue;
20858                }
20859                if !preserve_existing_whitespace {
20860                    token = " ";
20861                    grapheme_len = 1;
20862                }
20863                if current_line_len + grapheme_len > wrap_column {
20864                    wrapped_text.push_str(current_line.trim_end());
20865                    wrapped_text.push('\n');
20866                    current_line.truncate(line_prefix.len());
20867                    current_line_len = line_prefix_len;
20868                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20869                    current_line.push_str(token);
20870                    current_line_len += grapheme_len;
20871                }
20872            }
20873            WordBreakToken::Newline => {
20874                in_whitespace = true;
20875                if preserve_existing_whitespace {
20876                    wrapped_text.push_str(current_line.trim_end());
20877                    wrapped_text.push('\n');
20878                    current_line.truncate(line_prefix.len());
20879                    current_line_len = line_prefix_len;
20880                } else if have_preceding_whitespace {
20881                    continue;
20882                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20883                {
20884                    wrapped_text.push_str(current_line.trim_end());
20885                    wrapped_text.push('\n');
20886                    current_line.truncate(line_prefix.len());
20887                    current_line_len = line_prefix_len;
20888                } else if current_line_len != line_prefix_len {
20889                    current_line.push(' ');
20890                    current_line_len += 1;
20891                }
20892            }
20893        }
20894    }
20895
20896    if !current_line.is_empty() {
20897        wrapped_text.push_str(&current_line);
20898    }
20899    wrapped_text
20900}
20901
20902#[test]
20903fn test_wrap_with_prefix() {
20904    assert_eq!(
20905        wrap_with_prefix(
20906            "# ".to_string(),
20907            "abcdefg".to_string(),
20908            4,
20909            NonZeroU32::new(4).unwrap(),
20910            false,
20911        ),
20912        "# abcdefg"
20913    );
20914    assert_eq!(
20915        wrap_with_prefix(
20916            "".to_string(),
20917            "\thello world".to_string(),
20918            8,
20919            NonZeroU32::new(4).unwrap(),
20920            false,
20921        ),
20922        "hello\nworld"
20923    );
20924    assert_eq!(
20925        wrap_with_prefix(
20926            "// ".to_string(),
20927            "xx \nyy zz aa bb cc".to_string(),
20928            12,
20929            NonZeroU32::new(4).unwrap(),
20930            false,
20931        ),
20932        "// xx yy zz\n// aa bb cc"
20933    );
20934    assert_eq!(
20935        wrap_with_prefix(
20936            String::new(),
20937            "这是什么 \n 钢笔".to_string(),
20938            3,
20939            NonZeroU32::new(4).unwrap(),
20940            false,
20941        ),
20942        "这是什\n么 钢\n"
20943    );
20944}
20945
20946pub trait CollaborationHub {
20947    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20948    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20949    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20950}
20951
20952impl CollaborationHub for Entity<Project> {
20953    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20954        self.read(cx).collaborators()
20955    }
20956
20957    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20958        self.read(cx).user_store().read(cx).participant_indices()
20959    }
20960
20961    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20962        let this = self.read(cx);
20963        let user_ids = this.collaborators().values().map(|c| c.user_id);
20964        this.user_store().read(cx).participant_names(user_ids, cx)
20965    }
20966}
20967
20968pub trait SemanticsProvider {
20969    fn hover(
20970        &self,
20971        buffer: &Entity<Buffer>,
20972        position: text::Anchor,
20973        cx: &mut App,
20974    ) -> Option<Task<Vec<project::Hover>>>;
20975
20976    fn inline_values(
20977        &self,
20978        buffer_handle: Entity<Buffer>,
20979        range: Range<text::Anchor>,
20980        cx: &mut App,
20981    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20982
20983    fn inlay_hints(
20984        &self,
20985        buffer_handle: Entity<Buffer>,
20986        range: Range<text::Anchor>,
20987        cx: &mut App,
20988    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20989
20990    fn resolve_inlay_hint(
20991        &self,
20992        hint: InlayHint,
20993        buffer_handle: Entity<Buffer>,
20994        server_id: LanguageServerId,
20995        cx: &mut App,
20996    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20997
20998    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20999
21000    fn document_highlights(
21001        &self,
21002        buffer: &Entity<Buffer>,
21003        position: text::Anchor,
21004        cx: &mut App,
21005    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21006
21007    fn definitions(
21008        &self,
21009        buffer: &Entity<Buffer>,
21010        position: text::Anchor,
21011        kind: GotoDefinitionKind,
21012        cx: &mut App,
21013    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21014
21015    fn range_for_rename(
21016        &self,
21017        buffer: &Entity<Buffer>,
21018        position: text::Anchor,
21019        cx: &mut App,
21020    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21021
21022    fn perform_rename(
21023        &self,
21024        buffer: &Entity<Buffer>,
21025        position: text::Anchor,
21026        new_name: String,
21027        cx: &mut App,
21028    ) -> Option<Task<Result<ProjectTransaction>>>;
21029}
21030
21031pub trait CompletionProvider {
21032    fn completions(
21033        &self,
21034        excerpt_id: ExcerptId,
21035        buffer: &Entity<Buffer>,
21036        buffer_position: text::Anchor,
21037        trigger: CompletionContext,
21038        window: &mut Window,
21039        cx: &mut Context<Editor>,
21040    ) -> Task<Result<Vec<CompletionResponse>>>;
21041
21042    fn resolve_completions(
21043        &self,
21044        _buffer: Entity<Buffer>,
21045        _completion_indices: Vec<usize>,
21046        _completions: Rc<RefCell<Box<[Completion]>>>,
21047        _cx: &mut Context<Editor>,
21048    ) -> Task<Result<bool>> {
21049        Task::ready(Ok(false))
21050    }
21051
21052    fn apply_additional_edits_for_completion(
21053        &self,
21054        _buffer: Entity<Buffer>,
21055        _completions: Rc<RefCell<Box<[Completion]>>>,
21056        _completion_index: usize,
21057        _push_to_history: bool,
21058        _cx: &mut Context<Editor>,
21059    ) -> Task<Result<Option<language::Transaction>>> {
21060        Task::ready(Ok(None))
21061    }
21062
21063    fn is_completion_trigger(
21064        &self,
21065        buffer: &Entity<Buffer>,
21066        position: language::Anchor,
21067        text: &str,
21068        trigger_in_words: bool,
21069        menu_is_open: bool,
21070        cx: &mut Context<Editor>,
21071    ) -> bool;
21072
21073    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21074
21075    fn sort_completions(&self) -> bool {
21076        true
21077    }
21078
21079    fn filter_completions(&self) -> bool {
21080        true
21081    }
21082}
21083
21084pub trait CodeActionProvider {
21085    fn id(&self) -> Arc<str>;
21086
21087    fn code_actions(
21088        &self,
21089        buffer: &Entity<Buffer>,
21090        range: Range<text::Anchor>,
21091        window: &mut Window,
21092        cx: &mut App,
21093    ) -> Task<Result<Vec<CodeAction>>>;
21094
21095    fn apply_code_action(
21096        &self,
21097        buffer_handle: Entity<Buffer>,
21098        action: CodeAction,
21099        excerpt_id: ExcerptId,
21100        push_to_history: bool,
21101        window: &mut Window,
21102        cx: &mut App,
21103    ) -> Task<Result<ProjectTransaction>>;
21104}
21105
21106impl CodeActionProvider for Entity<Project> {
21107    fn id(&self) -> Arc<str> {
21108        "project".into()
21109    }
21110
21111    fn code_actions(
21112        &self,
21113        buffer: &Entity<Buffer>,
21114        range: Range<text::Anchor>,
21115        _window: &mut Window,
21116        cx: &mut App,
21117    ) -> Task<Result<Vec<CodeAction>>> {
21118        self.update(cx, |project, cx| {
21119            let code_lens = project.code_lens(buffer, range.clone(), cx);
21120            let code_actions = project.code_actions(buffer, range, None, cx);
21121            cx.background_spawn(async move {
21122                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21123                Ok(code_lens
21124                    .context("code lens fetch")?
21125                    .into_iter()
21126                    .chain(code_actions.context("code action fetch")?)
21127                    .collect())
21128            })
21129        })
21130    }
21131
21132    fn apply_code_action(
21133        &self,
21134        buffer_handle: Entity<Buffer>,
21135        action: CodeAction,
21136        _excerpt_id: ExcerptId,
21137        push_to_history: bool,
21138        _window: &mut Window,
21139        cx: &mut App,
21140    ) -> Task<Result<ProjectTransaction>> {
21141        self.update(cx, |project, cx| {
21142            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21143        })
21144    }
21145}
21146
21147fn snippet_completions(
21148    project: &Project,
21149    buffer: &Entity<Buffer>,
21150    buffer_position: text::Anchor,
21151    cx: &mut App,
21152) -> Task<Result<CompletionResponse>> {
21153    let languages = buffer.read(cx).languages_at(buffer_position);
21154    let snippet_store = project.snippets().read(cx);
21155
21156    let scopes: Vec<_> = languages
21157        .iter()
21158        .filter_map(|language| {
21159            let language_name = language.lsp_id();
21160            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21161
21162            if snippets.is_empty() {
21163                None
21164            } else {
21165                Some((language.default_scope(), snippets))
21166            }
21167        })
21168        .collect();
21169
21170    if scopes.is_empty() {
21171        return Task::ready(Ok(CompletionResponse {
21172            completions: vec![],
21173            is_incomplete: false,
21174        }));
21175    }
21176
21177    let snapshot = buffer.read(cx).text_snapshot();
21178    let chars: String = snapshot
21179        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21180        .collect();
21181    let executor = cx.background_executor().clone();
21182
21183    cx.background_spawn(async move {
21184        let mut is_incomplete = false;
21185        let mut completions: Vec<Completion> = Vec::new();
21186        for (scope, snippets) in scopes.into_iter() {
21187            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21188            let mut last_word = chars
21189                .chars()
21190                .take_while(|c| classifier.is_word(*c))
21191                .collect::<String>();
21192            last_word = last_word.chars().rev().collect();
21193
21194            if last_word.is_empty() {
21195                return Ok(CompletionResponse {
21196                    completions: vec![],
21197                    is_incomplete: true,
21198                });
21199            }
21200
21201            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21202            let to_lsp = |point: &text::Anchor| {
21203                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21204                point_to_lsp(end)
21205            };
21206            let lsp_end = to_lsp(&buffer_position);
21207
21208            let candidates = snippets
21209                .iter()
21210                .enumerate()
21211                .flat_map(|(ix, snippet)| {
21212                    snippet
21213                        .prefix
21214                        .iter()
21215                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21216                })
21217                .collect::<Vec<StringMatchCandidate>>();
21218
21219            const MAX_RESULTS: usize = 100;
21220            let mut matches = fuzzy::match_strings(
21221                &candidates,
21222                &last_word,
21223                last_word.chars().any(|c| c.is_uppercase()),
21224                true,
21225                MAX_RESULTS,
21226                &Default::default(),
21227                executor.clone(),
21228            )
21229            .await;
21230
21231            if matches.len() >= MAX_RESULTS {
21232                is_incomplete = true;
21233            }
21234
21235            // Remove all candidates where the query's start does not match the start of any word in the candidate
21236            if let Some(query_start) = last_word.chars().next() {
21237                matches.retain(|string_match| {
21238                    split_words(&string_match.string).any(|word| {
21239                        // Check that the first codepoint of the word as lowercase matches the first
21240                        // codepoint of the query as lowercase
21241                        word.chars()
21242                            .flat_map(|codepoint| codepoint.to_lowercase())
21243                            .zip(query_start.to_lowercase())
21244                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21245                    })
21246                });
21247            }
21248
21249            let matched_strings = matches
21250                .into_iter()
21251                .map(|m| m.string)
21252                .collect::<HashSet<_>>();
21253
21254            completions.extend(snippets.iter().filter_map(|snippet| {
21255                let matching_prefix = snippet
21256                    .prefix
21257                    .iter()
21258                    .find(|prefix| matched_strings.contains(*prefix))?;
21259                let start = as_offset - last_word.len();
21260                let start = snapshot.anchor_before(start);
21261                let range = start..buffer_position;
21262                let lsp_start = to_lsp(&start);
21263                let lsp_range = lsp::Range {
21264                    start: lsp_start,
21265                    end: lsp_end,
21266                };
21267                Some(Completion {
21268                    replace_range: range,
21269                    new_text: snippet.body.clone(),
21270                    source: CompletionSource::Lsp {
21271                        insert_range: None,
21272                        server_id: LanguageServerId(usize::MAX),
21273                        resolved: true,
21274                        lsp_completion: Box::new(lsp::CompletionItem {
21275                            label: snippet.prefix.first().unwrap().clone(),
21276                            kind: Some(CompletionItemKind::SNIPPET),
21277                            label_details: snippet.description.as_ref().map(|description| {
21278                                lsp::CompletionItemLabelDetails {
21279                                    detail: Some(description.clone()),
21280                                    description: None,
21281                                }
21282                            }),
21283                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21284                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21285                                lsp::InsertReplaceEdit {
21286                                    new_text: snippet.body.clone(),
21287                                    insert: lsp_range,
21288                                    replace: lsp_range,
21289                                },
21290                            )),
21291                            filter_text: Some(snippet.body.clone()),
21292                            sort_text: Some(char::MAX.to_string()),
21293                            ..lsp::CompletionItem::default()
21294                        }),
21295                        lsp_defaults: None,
21296                    },
21297                    label: CodeLabel {
21298                        text: matching_prefix.clone(),
21299                        runs: Vec::new(),
21300                        filter_range: 0..matching_prefix.len(),
21301                    },
21302                    icon_path: None,
21303                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21304                        single_line: snippet.name.clone().into(),
21305                        plain_text: snippet
21306                            .description
21307                            .clone()
21308                            .map(|description| description.into()),
21309                    }),
21310                    insert_text_mode: None,
21311                    confirm: None,
21312                })
21313            }))
21314        }
21315
21316        Ok(CompletionResponse {
21317            completions,
21318            is_incomplete,
21319        })
21320    })
21321}
21322
21323impl CompletionProvider for Entity<Project> {
21324    fn completions(
21325        &self,
21326        _excerpt_id: ExcerptId,
21327        buffer: &Entity<Buffer>,
21328        buffer_position: text::Anchor,
21329        options: CompletionContext,
21330        _window: &mut Window,
21331        cx: &mut Context<Editor>,
21332    ) -> Task<Result<Vec<CompletionResponse>>> {
21333        self.update(cx, |project, cx| {
21334            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21335            let project_completions = project.completions(buffer, buffer_position, options, cx);
21336            cx.background_spawn(async move {
21337                let mut responses = project_completions.await?;
21338                let snippets = snippets.await?;
21339                if !snippets.completions.is_empty() {
21340                    responses.push(snippets);
21341                }
21342                Ok(responses)
21343            })
21344        })
21345    }
21346
21347    fn resolve_completions(
21348        &self,
21349        buffer: Entity<Buffer>,
21350        completion_indices: Vec<usize>,
21351        completions: Rc<RefCell<Box<[Completion]>>>,
21352        cx: &mut Context<Editor>,
21353    ) -> Task<Result<bool>> {
21354        self.update(cx, |project, cx| {
21355            project.lsp_store().update(cx, |lsp_store, cx| {
21356                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21357            })
21358        })
21359    }
21360
21361    fn apply_additional_edits_for_completion(
21362        &self,
21363        buffer: Entity<Buffer>,
21364        completions: Rc<RefCell<Box<[Completion]>>>,
21365        completion_index: usize,
21366        push_to_history: bool,
21367        cx: &mut Context<Editor>,
21368    ) -> Task<Result<Option<language::Transaction>>> {
21369        self.update(cx, |project, cx| {
21370            project.lsp_store().update(cx, |lsp_store, cx| {
21371                lsp_store.apply_additional_edits_for_completion(
21372                    buffer,
21373                    completions,
21374                    completion_index,
21375                    push_to_history,
21376                    cx,
21377                )
21378            })
21379        })
21380    }
21381
21382    fn is_completion_trigger(
21383        &self,
21384        buffer: &Entity<Buffer>,
21385        position: language::Anchor,
21386        text: &str,
21387        trigger_in_words: bool,
21388        menu_is_open: bool,
21389        cx: &mut Context<Editor>,
21390    ) -> bool {
21391        let mut chars = text.chars();
21392        let char = if let Some(char) = chars.next() {
21393            char
21394        } else {
21395            return false;
21396        };
21397        if chars.next().is_some() {
21398            return false;
21399        }
21400
21401        let buffer = buffer.read(cx);
21402        let snapshot = buffer.snapshot();
21403        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21404            return false;
21405        }
21406        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21407        if trigger_in_words && classifier.is_word(char) {
21408            return true;
21409        }
21410
21411        buffer.completion_triggers().contains(text)
21412    }
21413}
21414
21415impl SemanticsProvider for Entity<Project> {
21416    fn hover(
21417        &self,
21418        buffer: &Entity<Buffer>,
21419        position: text::Anchor,
21420        cx: &mut App,
21421    ) -> Option<Task<Vec<project::Hover>>> {
21422        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21423    }
21424
21425    fn document_highlights(
21426        &self,
21427        buffer: &Entity<Buffer>,
21428        position: text::Anchor,
21429        cx: &mut App,
21430    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21431        Some(self.update(cx, |project, cx| {
21432            project.document_highlights(buffer, position, cx)
21433        }))
21434    }
21435
21436    fn definitions(
21437        &self,
21438        buffer: &Entity<Buffer>,
21439        position: text::Anchor,
21440        kind: GotoDefinitionKind,
21441        cx: &mut App,
21442    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21443        Some(self.update(cx, |project, cx| match kind {
21444            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21445            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21446            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21447            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21448        }))
21449    }
21450
21451    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21452        // TODO: make this work for remote projects
21453        self.update(cx, |project, cx| {
21454            if project
21455                .active_debug_session(cx)
21456                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21457            {
21458                return true;
21459            }
21460
21461            buffer.update(cx, |buffer, cx| {
21462                project.any_language_server_supports_inlay_hints(buffer, cx)
21463            })
21464        })
21465    }
21466
21467    fn inline_values(
21468        &self,
21469        buffer_handle: Entity<Buffer>,
21470
21471        range: Range<text::Anchor>,
21472        cx: &mut App,
21473    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21474        self.update(cx, |project, cx| {
21475            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21476
21477            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21478        })
21479    }
21480
21481    fn inlay_hints(
21482        &self,
21483        buffer_handle: Entity<Buffer>,
21484        range: Range<text::Anchor>,
21485        cx: &mut App,
21486    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21487        Some(self.update(cx, |project, cx| {
21488            project.inlay_hints(buffer_handle, range, cx)
21489        }))
21490    }
21491
21492    fn resolve_inlay_hint(
21493        &self,
21494        hint: InlayHint,
21495        buffer_handle: Entity<Buffer>,
21496        server_id: LanguageServerId,
21497        cx: &mut App,
21498    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21499        Some(self.update(cx, |project, cx| {
21500            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21501        }))
21502    }
21503
21504    fn range_for_rename(
21505        &self,
21506        buffer: &Entity<Buffer>,
21507        position: text::Anchor,
21508        cx: &mut App,
21509    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21510        Some(self.update(cx, |project, cx| {
21511            let buffer = buffer.clone();
21512            let task = project.prepare_rename(buffer.clone(), position, cx);
21513            cx.spawn(async move |_, cx| {
21514                Ok(match task.await? {
21515                    PrepareRenameResponse::Success(range) => Some(range),
21516                    PrepareRenameResponse::InvalidPosition => None,
21517                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21518                        // Fallback on using TreeSitter info to determine identifier range
21519                        buffer.read_with(cx, |buffer, _| {
21520                            let snapshot = buffer.snapshot();
21521                            let (range, kind) = snapshot.surrounding_word(position);
21522                            if kind != Some(CharKind::Word) {
21523                                return None;
21524                            }
21525                            Some(
21526                                snapshot.anchor_before(range.start)
21527                                    ..snapshot.anchor_after(range.end),
21528                            )
21529                        })?
21530                    }
21531                })
21532            })
21533        }))
21534    }
21535
21536    fn perform_rename(
21537        &self,
21538        buffer: &Entity<Buffer>,
21539        position: text::Anchor,
21540        new_name: String,
21541        cx: &mut App,
21542    ) -> Option<Task<Result<ProjectTransaction>>> {
21543        Some(self.update(cx, |project, cx| {
21544            project.perform_rename(buffer.clone(), position, new_name, cx)
21545        }))
21546    }
21547}
21548
21549fn inlay_hint_settings(
21550    location: Anchor,
21551    snapshot: &MultiBufferSnapshot,
21552    cx: &mut Context<Editor>,
21553) -> InlayHintSettings {
21554    let file = snapshot.file_at(location);
21555    let language = snapshot.language_at(location).map(|l| l.name());
21556    language_settings(language, file, cx).inlay_hints
21557}
21558
21559fn consume_contiguous_rows(
21560    contiguous_row_selections: &mut Vec<Selection<Point>>,
21561    selection: &Selection<Point>,
21562    display_map: &DisplaySnapshot,
21563    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21564) -> (MultiBufferRow, MultiBufferRow) {
21565    contiguous_row_selections.push(selection.clone());
21566    let start_row = MultiBufferRow(selection.start.row);
21567    let mut end_row = ending_row(selection, display_map);
21568
21569    while let Some(next_selection) = selections.peek() {
21570        if next_selection.start.row <= end_row.0 {
21571            end_row = ending_row(next_selection, display_map);
21572            contiguous_row_selections.push(selections.next().unwrap().clone());
21573        } else {
21574            break;
21575        }
21576    }
21577    (start_row, end_row)
21578}
21579
21580fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21581    if next_selection.end.column > 0 || next_selection.is_empty() {
21582        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21583    } else {
21584        MultiBufferRow(next_selection.end.row)
21585    }
21586}
21587
21588impl EditorSnapshot {
21589    pub fn remote_selections_in_range<'a>(
21590        &'a self,
21591        range: &'a Range<Anchor>,
21592        collaboration_hub: &dyn CollaborationHub,
21593        cx: &'a App,
21594    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21595        let participant_names = collaboration_hub.user_names(cx);
21596        let participant_indices = collaboration_hub.user_participant_indices(cx);
21597        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21598        let collaborators_by_replica_id = collaborators_by_peer_id
21599            .values()
21600            .map(|collaborator| (collaborator.replica_id, collaborator))
21601            .collect::<HashMap<_, _>>();
21602        self.buffer_snapshot
21603            .selections_in_range(range, false)
21604            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21605                if replica_id == AGENT_REPLICA_ID {
21606                    Some(RemoteSelection {
21607                        replica_id,
21608                        selection,
21609                        cursor_shape,
21610                        line_mode,
21611                        collaborator_id: CollaboratorId::Agent,
21612                        user_name: Some("Agent".into()),
21613                        color: cx.theme().players().agent(),
21614                    })
21615                } else {
21616                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21617                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21618                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21619                    Some(RemoteSelection {
21620                        replica_id,
21621                        selection,
21622                        cursor_shape,
21623                        line_mode,
21624                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21625                        user_name,
21626                        color: if let Some(index) = participant_index {
21627                            cx.theme().players().color_for_participant(index.0)
21628                        } else {
21629                            cx.theme().players().absent()
21630                        },
21631                    })
21632                }
21633            })
21634    }
21635
21636    pub fn hunks_for_ranges(
21637        &self,
21638        ranges: impl IntoIterator<Item = Range<Point>>,
21639    ) -> Vec<MultiBufferDiffHunk> {
21640        let mut hunks = Vec::new();
21641        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21642            HashMap::default();
21643        for query_range in ranges {
21644            let query_rows =
21645                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21646            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21647                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21648            ) {
21649                // Include deleted hunks that are adjacent to the query range, because
21650                // otherwise they would be missed.
21651                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21652                if hunk.status().is_deleted() {
21653                    intersects_range |= hunk.row_range.start == query_rows.end;
21654                    intersects_range |= hunk.row_range.end == query_rows.start;
21655                }
21656                if intersects_range {
21657                    if !processed_buffer_rows
21658                        .entry(hunk.buffer_id)
21659                        .or_default()
21660                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21661                    {
21662                        continue;
21663                    }
21664                    hunks.push(hunk);
21665                }
21666            }
21667        }
21668
21669        hunks
21670    }
21671
21672    fn display_diff_hunks_for_rows<'a>(
21673        &'a self,
21674        display_rows: Range<DisplayRow>,
21675        folded_buffers: &'a HashSet<BufferId>,
21676    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21677        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21678        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21679
21680        self.buffer_snapshot
21681            .diff_hunks_in_range(buffer_start..buffer_end)
21682            .filter_map(|hunk| {
21683                if folded_buffers.contains(&hunk.buffer_id) {
21684                    return None;
21685                }
21686
21687                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21688                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21689
21690                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21691                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21692
21693                let display_hunk = if hunk_display_start.column() != 0 {
21694                    DisplayDiffHunk::Folded {
21695                        display_row: hunk_display_start.row(),
21696                    }
21697                } else {
21698                    let mut end_row = hunk_display_end.row();
21699                    if hunk_display_end.column() > 0 {
21700                        end_row.0 += 1;
21701                    }
21702                    let is_created_file = hunk.is_created_file();
21703                    DisplayDiffHunk::Unfolded {
21704                        status: hunk.status(),
21705                        diff_base_byte_range: hunk.diff_base_byte_range,
21706                        display_row_range: hunk_display_start.row()..end_row,
21707                        multi_buffer_range: Anchor::range_in_buffer(
21708                            hunk.excerpt_id,
21709                            hunk.buffer_id,
21710                            hunk.buffer_range,
21711                        ),
21712                        is_created_file,
21713                    }
21714                };
21715
21716                Some(display_hunk)
21717            })
21718    }
21719
21720    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21721        self.display_snapshot.buffer_snapshot.language_at(position)
21722    }
21723
21724    pub fn is_focused(&self) -> bool {
21725        self.is_focused
21726    }
21727
21728    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21729        self.placeholder_text.as_ref()
21730    }
21731
21732    pub fn scroll_position(&self) -> gpui::Point<f32> {
21733        self.scroll_anchor.scroll_position(&self.display_snapshot)
21734    }
21735
21736    fn gutter_dimensions(
21737        &self,
21738        font_id: FontId,
21739        font_size: Pixels,
21740        max_line_number_width: Pixels,
21741        cx: &App,
21742    ) -> Option<GutterDimensions> {
21743        if !self.show_gutter {
21744            return None;
21745        }
21746
21747        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21748        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21749
21750        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21751            matches!(
21752                ProjectSettings::get_global(cx).git.git_gutter,
21753                Some(GitGutterSetting::TrackedFiles)
21754            )
21755        });
21756        let gutter_settings = EditorSettings::get_global(cx).gutter;
21757        let show_line_numbers = self
21758            .show_line_numbers
21759            .unwrap_or(gutter_settings.line_numbers);
21760        let line_gutter_width = if show_line_numbers {
21761            // Avoid flicker-like gutter resizes when the line number gains another digit by
21762            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21763            let min_width_for_number_on_gutter =
21764                ch_advance * gutter_settings.min_line_number_digits as f32;
21765            max_line_number_width.max(min_width_for_number_on_gutter)
21766        } else {
21767            0.0.into()
21768        };
21769
21770        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21771        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21772
21773        let git_blame_entries_width =
21774            self.git_blame_gutter_max_author_length
21775                .map(|max_author_length| {
21776                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21777                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21778
21779                    /// The number of characters to dedicate to gaps and margins.
21780                    const SPACING_WIDTH: usize = 4;
21781
21782                    let max_char_count = max_author_length.min(renderer.max_author_length())
21783                        + ::git::SHORT_SHA_LENGTH
21784                        + MAX_RELATIVE_TIMESTAMP.len()
21785                        + SPACING_WIDTH;
21786
21787                    ch_advance * max_char_count
21788                });
21789
21790        let is_singleton = self.buffer_snapshot.is_singleton();
21791
21792        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21793        left_padding += if !is_singleton {
21794            ch_width * 4.0
21795        } else if show_runnables || show_breakpoints {
21796            ch_width * 3.0
21797        } else if show_git_gutter && show_line_numbers {
21798            ch_width * 2.0
21799        } else if show_git_gutter || show_line_numbers {
21800            ch_width
21801        } else {
21802            px(0.)
21803        };
21804
21805        let shows_folds = is_singleton && gutter_settings.folds;
21806
21807        let right_padding = if shows_folds && show_line_numbers {
21808            ch_width * 4.0
21809        } else if shows_folds || (!is_singleton && show_line_numbers) {
21810            ch_width * 3.0
21811        } else if show_line_numbers {
21812            ch_width
21813        } else {
21814            px(0.)
21815        };
21816
21817        Some(GutterDimensions {
21818            left_padding,
21819            right_padding,
21820            width: line_gutter_width + left_padding + right_padding,
21821            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21822            git_blame_entries_width,
21823        })
21824    }
21825
21826    pub fn render_crease_toggle(
21827        &self,
21828        buffer_row: MultiBufferRow,
21829        row_contains_cursor: bool,
21830        editor: Entity<Editor>,
21831        window: &mut Window,
21832        cx: &mut App,
21833    ) -> Option<AnyElement> {
21834        let folded = self.is_line_folded(buffer_row);
21835        let mut is_foldable = false;
21836
21837        if let Some(crease) = self
21838            .crease_snapshot
21839            .query_row(buffer_row, &self.buffer_snapshot)
21840        {
21841            is_foldable = true;
21842            match crease {
21843                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21844                    if let Some(render_toggle) = render_toggle {
21845                        let toggle_callback =
21846                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21847                                if folded {
21848                                    editor.update(cx, |editor, cx| {
21849                                        editor.fold_at(buffer_row, window, cx)
21850                                    });
21851                                } else {
21852                                    editor.update(cx, |editor, cx| {
21853                                        editor.unfold_at(buffer_row, window, cx)
21854                                    });
21855                                }
21856                            });
21857                        return Some((render_toggle)(
21858                            buffer_row,
21859                            folded,
21860                            toggle_callback,
21861                            window,
21862                            cx,
21863                        ));
21864                    }
21865                }
21866            }
21867        }
21868
21869        is_foldable |= self.starts_indent(buffer_row);
21870
21871        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21872            Some(
21873                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21874                    .toggle_state(folded)
21875                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21876                        if folded {
21877                            this.unfold_at(buffer_row, window, cx);
21878                        } else {
21879                            this.fold_at(buffer_row, window, cx);
21880                        }
21881                    }))
21882                    .into_any_element(),
21883            )
21884        } else {
21885            None
21886        }
21887    }
21888
21889    pub fn render_crease_trailer(
21890        &self,
21891        buffer_row: MultiBufferRow,
21892        window: &mut Window,
21893        cx: &mut App,
21894    ) -> Option<AnyElement> {
21895        let folded = self.is_line_folded(buffer_row);
21896        if let Crease::Inline { render_trailer, .. } = self
21897            .crease_snapshot
21898            .query_row(buffer_row, &self.buffer_snapshot)?
21899        {
21900            let render_trailer = render_trailer.as_ref()?;
21901            Some(render_trailer(buffer_row, folded, window, cx))
21902        } else {
21903            None
21904        }
21905    }
21906}
21907
21908impl Deref for EditorSnapshot {
21909    type Target = DisplaySnapshot;
21910
21911    fn deref(&self) -> &Self::Target {
21912        &self.display_snapshot
21913    }
21914}
21915
21916#[derive(Clone, Debug, PartialEq, Eq)]
21917pub enum EditorEvent {
21918    InputIgnored {
21919        text: Arc<str>,
21920    },
21921    InputHandled {
21922        utf16_range_to_replace: Option<Range<isize>>,
21923        text: Arc<str>,
21924    },
21925    ExcerptsAdded {
21926        buffer: Entity<Buffer>,
21927        predecessor: ExcerptId,
21928        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21929    },
21930    ExcerptsRemoved {
21931        ids: Vec<ExcerptId>,
21932        removed_buffer_ids: Vec<BufferId>,
21933    },
21934    BufferFoldToggled {
21935        ids: Vec<ExcerptId>,
21936        folded: bool,
21937    },
21938    ExcerptsEdited {
21939        ids: Vec<ExcerptId>,
21940    },
21941    ExcerptsExpanded {
21942        ids: Vec<ExcerptId>,
21943    },
21944    BufferEdited,
21945    Edited {
21946        transaction_id: clock::Lamport,
21947    },
21948    Reparsed(BufferId),
21949    Focused,
21950    FocusedIn,
21951    Blurred,
21952    DirtyChanged,
21953    Saved,
21954    TitleChanged,
21955    DiffBaseChanged,
21956    SelectionsChanged {
21957        local: bool,
21958    },
21959    ScrollPositionChanged {
21960        local: bool,
21961        autoscroll: bool,
21962    },
21963    Closed,
21964    TransactionUndone {
21965        transaction_id: clock::Lamport,
21966    },
21967    TransactionBegun {
21968        transaction_id: clock::Lamport,
21969    },
21970    Reloaded,
21971    CursorShapeChanged,
21972    PushedToNavHistory {
21973        anchor: Anchor,
21974        is_deactivate: bool,
21975    },
21976}
21977
21978impl EventEmitter<EditorEvent> for Editor {}
21979
21980impl Focusable for Editor {
21981    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21982        self.focus_handle.clone()
21983    }
21984}
21985
21986impl Render for Editor {
21987    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21988        let settings = ThemeSettings::get_global(cx);
21989
21990        let mut text_style = match self.mode {
21991            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21992                color: cx.theme().colors().editor_foreground,
21993                font_family: settings.ui_font.family.clone(),
21994                font_features: settings.ui_font.features.clone(),
21995                font_fallbacks: settings.ui_font.fallbacks.clone(),
21996                font_size: rems(0.875).into(),
21997                font_weight: settings.ui_font.weight,
21998                line_height: relative(settings.buffer_line_height.value()),
21999                ..Default::default()
22000            },
22001            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22002                color: cx.theme().colors().editor_foreground,
22003                font_family: settings.buffer_font.family.clone(),
22004                font_features: settings.buffer_font.features.clone(),
22005                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22006                font_size: settings.buffer_font_size(cx).into(),
22007                font_weight: settings.buffer_font.weight,
22008                line_height: relative(settings.buffer_line_height.value()),
22009                ..Default::default()
22010            },
22011        };
22012        if let Some(text_style_refinement) = &self.text_style_refinement {
22013            text_style.refine(text_style_refinement)
22014        }
22015
22016        let background = match self.mode {
22017            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22018            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22019            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22020            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22021        };
22022
22023        EditorElement::new(
22024            &cx.entity(),
22025            EditorStyle {
22026                background,
22027                local_player: cx.theme().players().local(),
22028                text: text_style,
22029                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22030                syntax: cx.theme().syntax().clone(),
22031                status: cx.theme().status().clone(),
22032                inlay_hints_style: make_inlay_hints_style(cx),
22033                inline_completion_styles: make_suggestion_styles(cx),
22034                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22035                show_underlines: !self.mode.is_minimap(),
22036            },
22037        )
22038    }
22039}
22040
22041impl EntityInputHandler for Editor {
22042    fn text_for_range(
22043        &mut self,
22044        range_utf16: Range<usize>,
22045        adjusted_range: &mut Option<Range<usize>>,
22046        _: &mut Window,
22047        cx: &mut Context<Self>,
22048    ) -> Option<String> {
22049        let snapshot = self.buffer.read(cx).read(cx);
22050        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22051        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22052        if (start.0..end.0) != range_utf16 {
22053            adjusted_range.replace(start.0..end.0);
22054        }
22055        Some(snapshot.text_for_range(start..end).collect())
22056    }
22057
22058    fn selected_text_range(
22059        &mut self,
22060        ignore_disabled_input: bool,
22061        _: &mut Window,
22062        cx: &mut Context<Self>,
22063    ) -> Option<UTF16Selection> {
22064        // Prevent the IME menu from appearing when holding down an alphabetic key
22065        // while input is disabled.
22066        if !ignore_disabled_input && !self.input_enabled {
22067            return None;
22068        }
22069
22070        let selection = self.selections.newest::<OffsetUtf16>(cx);
22071        let range = selection.range();
22072
22073        Some(UTF16Selection {
22074            range: range.start.0..range.end.0,
22075            reversed: selection.reversed,
22076        })
22077    }
22078
22079    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22080        let snapshot = self.buffer.read(cx).read(cx);
22081        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22082        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22083    }
22084
22085    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22086        self.clear_highlights::<InputComposition>(cx);
22087        self.ime_transaction.take();
22088    }
22089
22090    fn replace_text_in_range(
22091        &mut self,
22092        range_utf16: Option<Range<usize>>,
22093        text: &str,
22094        window: &mut Window,
22095        cx: &mut Context<Self>,
22096    ) {
22097        if !self.input_enabled {
22098            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22099            return;
22100        }
22101
22102        self.transact(window, cx, |this, window, cx| {
22103            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22104                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22105                Some(this.selection_replacement_ranges(range_utf16, cx))
22106            } else {
22107                this.marked_text_ranges(cx)
22108            };
22109
22110            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22111                let newest_selection_id = this.selections.newest_anchor().id;
22112                this.selections
22113                    .all::<OffsetUtf16>(cx)
22114                    .iter()
22115                    .zip(ranges_to_replace.iter())
22116                    .find_map(|(selection, range)| {
22117                        if selection.id == newest_selection_id {
22118                            Some(
22119                                (range.start.0 as isize - selection.head().0 as isize)
22120                                    ..(range.end.0 as isize - selection.head().0 as isize),
22121                            )
22122                        } else {
22123                            None
22124                        }
22125                    })
22126            });
22127
22128            cx.emit(EditorEvent::InputHandled {
22129                utf16_range_to_replace: range_to_replace,
22130                text: text.into(),
22131            });
22132
22133            if let Some(new_selected_ranges) = new_selected_ranges {
22134                this.change_selections(None, window, cx, |selections| {
22135                    selections.select_ranges(new_selected_ranges)
22136                });
22137                this.backspace(&Default::default(), window, cx);
22138            }
22139
22140            this.handle_input(text, window, cx);
22141        });
22142
22143        if let Some(transaction) = self.ime_transaction {
22144            self.buffer.update(cx, |buffer, cx| {
22145                buffer.group_until_transaction(transaction, cx);
22146            });
22147        }
22148
22149        self.unmark_text(window, cx);
22150    }
22151
22152    fn replace_and_mark_text_in_range(
22153        &mut self,
22154        range_utf16: Option<Range<usize>>,
22155        text: &str,
22156        new_selected_range_utf16: Option<Range<usize>>,
22157        window: &mut Window,
22158        cx: &mut Context<Self>,
22159    ) {
22160        if !self.input_enabled {
22161            return;
22162        }
22163
22164        let transaction = self.transact(window, cx, |this, window, cx| {
22165            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22166                let snapshot = this.buffer.read(cx).read(cx);
22167                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22168                    for marked_range in &mut marked_ranges {
22169                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22170                        marked_range.start.0 += relative_range_utf16.start;
22171                        marked_range.start =
22172                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22173                        marked_range.end =
22174                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22175                    }
22176                }
22177                Some(marked_ranges)
22178            } else if let Some(range_utf16) = range_utf16 {
22179                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22180                Some(this.selection_replacement_ranges(range_utf16, cx))
22181            } else {
22182                None
22183            };
22184
22185            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22186                let newest_selection_id = this.selections.newest_anchor().id;
22187                this.selections
22188                    .all::<OffsetUtf16>(cx)
22189                    .iter()
22190                    .zip(ranges_to_replace.iter())
22191                    .find_map(|(selection, range)| {
22192                        if selection.id == newest_selection_id {
22193                            Some(
22194                                (range.start.0 as isize - selection.head().0 as isize)
22195                                    ..(range.end.0 as isize - selection.head().0 as isize),
22196                            )
22197                        } else {
22198                            None
22199                        }
22200                    })
22201            });
22202
22203            cx.emit(EditorEvent::InputHandled {
22204                utf16_range_to_replace: range_to_replace,
22205                text: text.into(),
22206            });
22207
22208            if let Some(ranges) = ranges_to_replace {
22209                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22210            }
22211
22212            let marked_ranges = {
22213                let snapshot = this.buffer.read(cx).read(cx);
22214                this.selections
22215                    .disjoint_anchors()
22216                    .iter()
22217                    .map(|selection| {
22218                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22219                    })
22220                    .collect::<Vec<_>>()
22221            };
22222
22223            if text.is_empty() {
22224                this.unmark_text(window, cx);
22225            } else {
22226                this.highlight_text::<InputComposition>(
22227                    marked_ranges.clone(),
22228                    HighlightStyle {
22229                        underline: Some(UnderlineStyle {
22230                            thickness: px(1.),
22231                            color: None,
22232                            wavy: false,
22233                        }),
22234                        ..Default::default()
22235                    },
22236                    cx,
22237                );
22238            }
22239
22240            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22241            let use_autoclose = this.use_autoclose;
22242            let use_auto_surround = this.use_auto_surround;
22243            this.set_use_autoclose(false);
22244            this.set_use_auto_surround(false);
22245            this.handle_input(text, window, cx);
22246            this.set_use_autoclose(use_autoclose);
22247            this.set_use_auto_surround(use_auto_surround);
22248
22249            if let Some(new_selected_range) = new_selected_range_utf16 {
22250                let snapshot = this.buffer.read(cx).read(cx);
22251                let new_selected_ranges = marked_ranges
22252                    .into_iter()
22253                    .map(|marked_range| {
22254                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22255                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22256                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22257                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22258                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22259                    })
22260                    .collect::<Vec<_>>();
22261
22262                drop(snapshot);
22263                this.change_selections(None, window, cx, |selections| {
22264                    selections.select_ranges(new_selected_ranges)
22265                });
22266            }
22267        });
22268
22269        self.ime_transaction = self.ime_transaction.or(transaction);
22270        if let Some(transaction) = self.ime_transaction {
22271            self.buffer.update(cx, |buffer, cx| {
22272                buffer.group_until_transaction(transaction, cx);
22273            });
22274        }
22275
22276        if self.text_highlights::<InputComposition>(cx).is_none() {
22277            self.ime_transaction.take();
22278        }
22279    }
22280
22281    fn bounds_for_range(
22282        &mut self,
22283        range_utf16: Range<usize>,
22284        element_bounds: gpui::Bounds<Pixels>,
22285        window: &mut Window,
22286        cx: &mut Context<Self>,
22287    ) -> Option<gpui::Bounds<Pixels>> {
22288        let text_layout_details = self.text_layout_details(window);
22289        let gpui::Size {
22290            width: em_width,
22291            height: line_height,
22292        } = self.character_size(window);
22293
22294        let snapshot = self.snapshot(window, cx);
22295        let scroll_position = snapshot.scroll_position();
22296        let scroll_left = scroll_position.x * em_width;
22297
22298        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22299        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22300            + self.gutter_dimensions.width
22301            + self.gutter_dimensions.margin;
22302        let y = line_height * (start.row().as_f32() - scroll_position.y);
22303
22304        Some(Bounds {
22305            origin: element_bounds.origin + point(x, y),
22306            size: size(em_width, line_height),
22307        })
22308    }
22309
22310    fn character_index_for_point(
22311        &mut self,
22312        point: gpui::Point<Pixels>,
22313        _window: &mut Window,
22314        _cx: &mut Context<Self>,
22315    ) -> Option<usize> {
22316        let position_map = self.last_position_map.as_ref()?;
22317        if !position_map.text_hitbox.contains(&point) {
22318            return None;
22319        }
22320        let display_point = position_map.point_for_position(point).previous_valid;
22321        let anchor = position_map
22322            .snapshot
22323            .display_point_to_anchor(display_point, Bias::Left);
22324        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22325        Some(utf16_offset.0)
22326    }
22327}
22328
22329trait SelectionExt {
22330    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22331    fn spanned_rows(
22332        &self,
22333        include_end_if_at_line_start: bool,
22334        map: &DisplaySnapshot,
22335    ) -> Range<MultiBufferRow>;
22336}
22337
22338impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22339    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22340        let start = self
22341            .start
22342            .to_point(&map.buffer_snapshot)
22343            .to_display_point(map);
22344        let end = self
22345            .end
22346            .to_point(&map.buffer_snapshot)
22347            .to_display_point(map);
22348        if self.reversed {
22349            end..start
22350        } else {
22351            start..end
22352        }
22353    }
22354
22355    fn spanned_rows(
22356        &self,
22357        include_end_if_at_line_start: bool,
22358        map: &DisplaySnapshot,
22359    ) -> Range<MultiBufferRow> {
22360        let start = self.start.to_point(&map.buffer_snapshot);
22361        let mut end = self.end.to_point(&map.buffer_snapshot);
22362        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22363            end.row -= 1;
22364        }
22365
22366        let buffer_start = map.prev_line_boundary(start).0;
22367        let buffer_end = map.next_line_boundary(end).0;
22368        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22369    }
22370}
22371
22372impl<T: InvalidationRegion> InvalidationStack<T> {
22373    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22374    where
22375        S: Clone + ToOffset,
22376    {
22377        while let Some(region) = self.last() {
22378            let all_selections_inside_invalidation_ranges =
22379                if selections.len() == region.ranges().len() {
22380                    selections
22381                        .iter()
22382                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22383                        .all(|(selection, invalidation_range)| {
22384                            let head = selection.head().to_offset(buffer);
22385                            invalidation_range.start <= head && invalidation_range.end >= head
22386                        })
22387                } else {
22388                    false
22389                };
22390
22391            if all_selections_inside_invalidation_ranges {
22392                break;
22393            } else {
22394                self.pop();
22395            }
22396        }
22397    }
22398}
22399
22400impl<T> Default for InvalidationStack<T> {
22401    fn default() -> Self {
22402        Self(Default::default())
22403    }
22404}
22405
22406impl<T> Deref for InvalidationStack<T> {
22407    type Target = Vec<T>;
22408
22409    fn deref(&self) -> &Self::Target {
22410        &self.0
22411    }
22412}
22413
22414impl<T> DerefMut for InvalidationStack<T> {
22415    fn deref_mut(&mut self) -> &mut Self::Target {
22416        &mut self.0
22417    }
22418}
22419
22420impl InvalidationRegion for SnippetState {
22421    fn ranges(&self) -> &[Range<Anchor>] {
22422        &self.ranges[self.active_index]
22423    }
22424}
22425
22426fn inline_completion_edit_text(
22427    current_snapshot: &BufferSnapshot,
22428    edits: &[(Range<Anchor>, String)],
22429    edit_preview: &EditPreview,
22430    include_deletions: bool,
22431    cx: &App,
22432) -> HighlightedText {
22433    let edits = edits
22434        .iter()
22435        .map(|(anchor, text)| {
22436            (
22437                anchor.start.text_anchor..anchor.end.text_anchor,
22438                text.clone(),
22439            )
22440        })
22441        .collect::<Vec<_>>();
22442
22443    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22444}
22445
22446pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22447    match severity {
22448        lsp::DiagnosticSeverity::ERROR => colors.error,
22449        lsp::DiagnosticSeverity::WARNING => colors.warning,
22450        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22451        lsp::DiagnosticSeverity::HINT => colors.info,
22452        _ => colors.ignored,
22453    }
22454}
22455
22456pub fn styled_runs_for_code_label<'a>(
22457    label: &'a CodeLabel,
22458    syntax_theme: &'a theme::SyntaxTheme,
22459) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22460    let fade_out = HighlightStyle {
22461        fade_out: Some(0.35),
22462        ..Default::default()
22463    };
22464
22465    let mut prev_end = label.filter_range.end;
22466    label
22467        .runs
22468        .iter()
22469        .enumerate()
22470        .flat_map(move |(ix, (range, highlight_id))| {
22471            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22472                style
22473            } else {
22474                return Default::default();
22475            };
22476            let mut muted_style = style;
22477            muted_style.highlight(fade_out);
22478
22479            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22480            if range.start >= label.filter_range.end {
22481                if range.start > prev_end {
22482                    runs.push((prev_end..range.start, fade_out));
22483                }
22484                runs.push((range.clone(), muted_style));
22485            } else if range.end <= label.filter_range.end {
22486                runs.push((range.clone(), style));
22487            } else {
22488                runs.push((range.start..label.filter_range.end, style));
22489                runs.push((label.filter_range.end..range.end, muted_style));
22490            }
22491            prev_end = cmp::max(prev_end, range.end);
22492
22493            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22494                runs.push((prev_end..label.text.len(), fade_out));
22495            }
22496
22497            runs
22498        })
22499}
22500
22501pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22502    let mut prev_index = 0;
22503    let mut prev_codepoint: Option<char> = None;
22504    text.char_indices()
22505        .chain([(text.len(), '\0')])
22506        .filter_map(move |(index, codepoint)| {
22507            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22508            let is_boundary = index == text.len()
22509                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22510                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22511            if is_boundary {
22512                let chunk = &text[prev_index..index];
22513                prev_index = index;
22514                Some(chunk)
22515            } else {
22516                None
22517            }
22518        })
22519}
22520
22521pub trait RangeToAnchorExt: Sized {
22522    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22523
22524    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22525        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22526        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22527    }
22528}
22529
22530impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22531    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22532        let start_offset = self.start.to_offset(snapshot);
22533        let end_offset = self.end.to_offset(snapshot);
22534        if start_offset == end_offset {
22535            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22536        } else {
22537            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22538        }
22539    }
22540}
22541
22542pub trait RowExt {
22543    fn as_f32(&self) -> f32;
22544
22545    fn next_row(&self) -> Self;
22546
22547    fn previous_row(&self) -> Self;
22548
22549    fn minus(&self, other: Self) -> u32;
22550}
22551
22552impl RowExt for DisplayRow {
22553    fn as_f32(&self) -> f32 {
22554        self.0 as f32
22555    }
22556
22557    fn next_row(&self) -> Self {
22558        Self(self.0 + 1)
22559    }
22560
22561    fn previous_row(&self) -> Self {
22562        Self(self.0.saturating_sub(1))
22563    }
22564
22565    fn minus(&self, other: Self) -> u32 {
22566        self.0 - other.0
22567    }
22568}
22569
22570impl RowExt for MultiBufferRow {
22571    fn as_f32(&self) -> f32 {
22572        self.0 as f32
22573    }
22574
22575    fn next_row(&self) -> Self {
22576        Self(self.0 + 1)
22577    }
22578
22579    fn previous_row(&self) -> Self {
22580        Self(self.0.saturating_sub(1))
22581    }
22582
22583    fn minus(&self, other: Self) -> u32 {
22584        self.0 - other.0
22585    }
22586}
22587
22588trait RowRangeExt {
22589    type Row;
22590
22591    fn len(&self) -> usize;
22592
22593    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22594}
22595
22596impl RowRangeExt for Range<MultiBufferRow> {
22597    type Row = MultiBufferRow;
22598
22599    fn len(&self) -> usize {
22600        (self.end.0 - self.start.0) as usize
22601    }
22602
22603    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22604        (self.start.0..self.end.0).map(MultiBufferRow)
22605    }
22606}
22607
22608impl RowRangeExt for Range<DisplayRow> {
22609    type Row = DisplayRow;
22610
22611    fn len(&self) -> usize {
22612        (self.end.0 - self.start.0) as usize
22613    }
22614
22615    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22616        (self.start.0..self.end.0).map(DisplayRow)
22617    }
22618}
22619
22620/// If select range has more than one line, we
22621/// just point the cursor to range.start.
22622fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22623    if range.start.row == range.end.row {
22624        range
22625    } else {
22626        range.start..range.start
22627    }
22628}
22629pub struct KillRing(ClipboardItem);
22630impl Global for KillRing {}
22631
22632const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22633
22634enum BreakpointPromptEditAction {
22635    Log,
22636    Condition,
22637    HitCondition,
22638}
22639
22640struct BreakpointPromptEditor {
22641    pub(crate) prompt: Entity<Editor>,
22642    editor: WeakEntity<Editor>,
22643    breakpoint_anchor: Anchor,
22644    breakpoint: Breakpoint,
22645    edit_action: BreakpointPromptEditAction,
22646    block_ids: HashSet<CustomBlockId>,
22647    editor_margins: Arc<Mutex<EditorMargins>>,
22648    _subscriptions: Vec<Subscription>,
22649}
22650
22651impl BreakpointPromptEditor {
22652    const MAX_LINES: u8 = 4;
22653
22654    fn new(
22655        editor: WeakEntity<Editor>,
22656        breakpoint_anchor: Anchor,
22657        breakpoint: Breakpoint,
22658        edit_action: BreakpointPromptEditAction,
22659        window: &mut Window,
22660        cx: &mut Context<Self>,
22661    ) -> Self {
22662        let base_text = match edit_action {
22663            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22664            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22665            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22666        }
22667        .map(|msg| msg.to_string())
22668        .unwrap_or_default();
22669
22670        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22671        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22672
22673        let prompt = cx.new(|cx| {
22674            let mut prompt = Editor::new(
22675                EditorMode::AutoHeight {
22676                    min_lines: 1,
22677                    max_lines: Self::MAX_LINES as usize,
22678                },
22679                buffer,
22680                None,
22681                window,
22682                cx,
22683            );
22684            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22685            prompt.set_show_cursor_when_unfocused(false, cx);
22686            prompt.set_placeholder_text(
22687                match edit_action {
22688                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22689                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22690                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22691                },
22692                cx,
22693            );
22694
22695            prompt
22696        });
22697
22698        Self {
22699            prompt,
22700            editor,
22701            breakpoint_anchor,
22702            breakpoint,
22703            edit_action,
22704            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22705            block_ids: Default::default(),
22706            _subscriptions: vec![],
22707        }
22708    }
22709
22710    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22711        self.block_ids.extend(block_ids)
22712    }
22713
22714    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22715        if let Some(editor) = self.editor.upgrade() {
22716            let message = self
22717                .prompt
22718                .read(cx)
22719                .buffer
22720                .read(cx)
22721                .as_singleton()
22722                .expect("A multi buffer in breakpoint prompt isn't possible")
22723                .read(cx)
22724                .as_rope()
22725                .to_string();
22726
22727            editor.update(cx, |editor, cx| {
22728                editor.edit_breakpoint_at_anchor(
22729                    self.breakpoint_anchor,
22730                    self.breakpoint.clone(),
22731                    match self.edit_action {
22732                        BreakpointPromptEditAction::Log => {
22733                            BreakpointEditAction::EditLogMessage(message.into())
22734                        }
22735                        BreakpointPromptEditAction::Condition => {
22736                            BreakpointEditAction::EditCondition(message.into())
22737                        }
22738                        BreakpointPromptEditAction::HitCondition => {
22739                            BreakpointEditAction::EditHitCondition(message.into())
22740                        }
22741                    },
22742                    cx,
22743                );
22744
22745                editor.remove_blocks(self.block_ids.clone(), None, cx);
22746                cx.focus_self(window);
22747            });
22748        }
22749    }
22750
22751    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22752        self.editor
22753            .update(cx, |editor, cx| {
22754                editor.remove_blocks(self.block_ids.clone(), None, cx);
22755                window.focus(&editor.focus_handle);
22756            })
22757            .log_err();
22758    }
22759
22760    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22761        let settings = ThemeSettings::get_global(cx);
22762        let text_style = TextStyle {
22763            color: if self.prompt.read(cx).read_only(cx) {
22764                cx.theme().colors().text_disabled
22765            } else {
22766                cx.theme().colors().text
22767            },
22768            font_family: settings.buffer_font.family.clone(),
22769            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22770            font_size: settings.buffer_font_size(cx).into(),
22771            font_weight: settings.buffer_font.weight,
22772            line_height: relative(settings.buffer_line_height.value()),
22773            ..Default::default()
22774        };
22775        EditorElement::new(
22776            &self.prompt,
22777            EditorStyle {
22778                background: cx.theme().colors().editor_background,
22779                local_player: cx.theme().players().local(),
22780                text: text_style,
22781                ..Default::default()
22782            },
22783        )
22784    }
22785}
22786
22787impl Render for BreakpointPromptEditor {
22788    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22789        let editor_margins = *self.editor_margins.lock();
22790        let gutter_dimensions = editor_margins.gutter;
22791        h_flex()
22792            .key_context("Editor")
22793            .bg(cx.theme().colors().editor_background)
22794            .border_y_1()
22795            .border_color(cx.theme().status().info_border)
22796            .size_full()
22797            .py(window.line_height() / 2.5)
22798            .on_action(cx.listener(Self::confirm))
22799            .on_action(cx.listener(Self::cancel))
22800            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22801            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22802    }
22803}
22804
22805impl Focusable for BreakpointPromptEditor {
22806    fn focus_handle(&self, cx: &App) -> FocusHandle {
22807        self.prompt.focus_handle(cx)
22808    }
22809}
22810
22811fn all_edits_insertions_or_deletions(
22812    edits: &Vec<(Range<Anchor>, String)>,
22813    snapshot: &MultiBufferSnapshot,
22814) -> bool {
22815    let mut all_insertions = true;
22816    let mut all_deletions = true;
22817
22818    for (range, new_text) in edits.iter() {
22819        let range_is_empty = range.to_offset(&snapshot).is_empty();
22820        let text_is_empty = new_text.is_empty();
22821
22822        if range_is_empty != text_is_empty {
22823            if range_is_empty {
22824                all_deletions = false;
22825            } else {
22826                all_insertions = false;
22827            }
22828        } else {
22829            return false;
22830        }
22831
22832        if !all_insertions && !all_deletions {
22833            return false;
22834        }
22835    }
22836    all_insertions || all_deletions
22837}
22838
22839struct MissingEditPredictionKeybindingTooltip;
22840
22841impl Render for MissingEditPredictionKeybindingTooltip {
22842    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22843        ui::tooltip_container(window, cx, |container, _, cx| {
22844            container
22845                .flex_shrink_0()
22846                .max_w_80()
22847                .min_h(rems_from_px(124.))
22848                .justify_between()
22849                .child(
22850                    v_flex()
22851                        .flex_1()
22852                        .text_ui_sm(cx)
22853                        .child(Label::new("Conflict with Accept Keybinding"))
22854                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22855                )
22856                .child(
22857                    h_flex()
22858                        .pb_1()
22859                        .gap_1()
22860                        .items_end()
22861                        .w_full()
22862                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22863                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22864                        }))
22865                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22866                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22867                        })),
22868                )
22869        })
22870    }
22871}
22872
22873#[derive(Debug, Clone, Copy, PartialEq)]
22874pub struct LineHighlight {
22875    pub background: Background,
22876    pub border: Option<gpui::Hsla>,
22877    pub include_gutter: bool,
22878    pub type_id: Option<TypeId>,
22879}
22880
22881fn render_diff_hunk_controls(
22882    row: u32,
22883    status: &DiffHunkStatus,
22884    hunk_range: Range<Anchor>,
22885    is_created_file: bool,
22886    line_height: Pixels,
22887    editor: &Entity<Editor>,
22888    _window: &mut Window,
22889    cx: &mut App,
22890) -> AnyElement {
22891    h_flex()
22892        .h(line_height)
22893        .mr_1()
22894        .gap_1()
22895        .px_0p5()
22896        .pb_1()
22897        .border_x_1()
22898        .border_b_1()
22899        .border_color(cx.theme().colors().border_variant)
22900        .rounded_b_lg()
22901        .bg(cx.theme().colors().editor_background)
22902        .gap_1()
22903        .block_mouse_except_scroll()
22904        .shadow_md()
22905        .child(if status.has_secondary_hunk() {
22906            Button::new(("stage", row as u64), "Stage")
22907                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22908                .tooltip({
22909                    let focus_handle = editor.focus_handle(cx);
22910                    move |window, cx| {
22911                        Tooltip::for_action_in(
22912                            "Stage Hunk",
22913                            &::git::ToggleStaged,
22914                            &focus_handle,
22915                            window,
22916                            cx,
22917                        )
22918                    }
22919                })
22920                .on_click({
22921                    let editor = editor.clone();
22922                    move |_event, _window, cx| {
22923                        editor.update(cx, |editor, cx| {
22924                            editor.stage_or_unstage_diff_hunks(
22925                                true,
22926                                vec![hunk_range.start..hunk_range.start],
22927                                cx,
22928                            );
22929                        });
22930                    }
22931                })
22932        } else {
22933            Button::new(("unstage", row as u64), "Unstage")
22934                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22935                .tooltip({
22936                    let focus_handle = editor.focus_handle(cx);
22937                    move |window, cx| {
22938                        Tooltip::for_action_in(
22939                            "Unstage Hunk",
22940                            &::git::ToggleStaged,
22941                            &focus_handle,
22942                            window,
22943                            cx,
22944                        )
22945                    }
22946                })
22947                .on_click({
22948                    let editor = editor.clone();
22949                    move |_event, _window, cx| {
22950                        editor.update(cx, |editor, cx| {
22951                            editor.stage_or_unstage_diff_hunks(
22952                                false,
22953                                vec![hunk_range.start..hunk_range.start],
22954                                cx,
22955                            );
22956                        });
22957                    }
22958                })
22959        })
22960        .child(
22961            Button::new(("restore", row as u64), "Restore")
22962                .tooltip({
22963                    let focus_handle = editor.focus_handle(cx);
22964                    move |window, cx| {
22965                        Tooltip::for_action_in(
22966                            "Restore Hunk",
22967                            &::git::Restore,
22968                            &focus_handle,
22969                            window,
22970                            cx,
22971                        )
22972                    }
22973                })
22974                .on_click({
22975                    let editor = editor.clone();
22976                    move |_event, window, cx| {
22977                        editor.update(cx, |editor, cx| {
22978                            let snapshot = editor.snapshot(window, cx);
22979                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22980                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22981                        });
22982                    }
22983                })
22984                .disabled(is_created_file),
22985        )
22986        .when(
22987            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22988            |el| {
22989                el.child(
22990                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22991                        .shape(IconButtonShape::Square)
22992                        .icon_size(IconSize::Small)
22993                        // .disabled(!has_multiple_hunks)
22994                        .tooltip({
22995                            let focus_handle = editor.focus_handle(cx);
22996                            move |window, cx| {
22997                                Tooltip::for_action_in(
22998                                    "Next Hunk",
22999                                    &GoToHunk,
23000                                    &focus_handle,
23001                                    window,
23002                                    cx,
23003                                )
23004                            }
23005                        })
23006                        .on_click({
23007                            let editor = editor.clone();
23008                            move |_event, window, cx| {
23009                                editor.update(cx, |editor, cx| {
23010                                    let snapshot = editor.snapshot(window, cx);
23011                                    let position =
23012                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23013                                    editor.go_to_hunk_before_or_after_position(
23014                                        &snapshot,
23015                                        position,
23016                                        Direction::Next,
23017                                        window,
23018                                        cx,
23019                                    );
23020                                    editor.expand_selected_diff_hunks(cx);
23021                                });
23022                            }
23023                        }),
23024                )
23025                .child(
23026                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23027                        .shape(IconButtonShape::Square)
23028                        .icon_size(IconSize::Small)
23029                        // .disabled(!has_multiple_hunks)
23030                        .tooltip({
23031                            let focus_handle = editor.focus_handle(cx);
23032                            move |window, cx| {
23033                                Tooltip::for_action_in(
23034                                    "Previous Hunk",
23035                                    &GoToPreviousHunk,
23036                                    &focus_handle,
23037                                    window,
23038                                    cx,
23039                                )
23040                            }
23041                        })
23042                        .on_click({
23043                            let editor = editor.clone();
23044                            move |_event, window, cx| {
23045                                editor.update(cx, |editor, cx| {
23046                                    let snapshot = editor.snapshot(window, cx);
23047                                    let point =
23048                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23049                                    editor.go_to_hunk_before_or_after_position(
23050                                        &snapshot,
23051                                        point,
23052                                        Direction::Prev,
23053                                        window,
23054                                        cx,
23055                                    );
23056                                    editor.expand_selected_diff_hunks(cx);
23057                                });
23058                            }
23059                        }),
23060                )
23061            },
23062        )
23063        .into_any_element()
23064}