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(..)
 1800                        | project::Event::LanguageServerRemoved(..) => {
 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(true, 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, 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.visible_excerpts(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 visible_excerpts(
 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                let actions = CodeActionContents::new(
 5945                    resolved_tasks,
 5946                    code_actions,
 5947                    debug_scenarios,
 5948                    task_context.unwrap_or_default(),
 5949                );
 5950
 5951                // Don't show the menu if there are no actions available
 5952                if actions.is_empty() {
 5953                    cx.notify();
 5954                    return Task::ready(Ok(()));
 5955                }
 5956
 5957                *editor.context_menu.borrow_mut() =
 5958                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5959                        buffer,
 5960                        actions,
 5961                        selected_item: Default::default(),
 5962                        scroll_handle: UniformListScrollHandle::default(),
 5963                        deployed_from,
 5964                    }));
 5965                cx.notify();
 5966                if spawn_straight_away {
 5967                    if let Some(task) = editor.confirm_code_action(
 5968                        &ConfirmCodeAction { item_ix: Some(0) },
 5969                        window,
 5970                        cx,
 5971                    ) {
 5972                        return task;
 5973                    }
 5974                }
 5975
 5976                Task::ready(Ok(()))
 5977            })
 5978        })
 5979        .detach_and_log_err(cx);
 5980    }
 5981
 5982    fn debug_scenarios(
 5983        &mut self,
 5984        resolved_tasks: &Option<ResolvedTasks>,
 5985        buffer: &Entity<Buffer>,
 5986        cx: &mut App,
 5987    ) -> Task<Vec<task::DebugScenario>> {
 5988        maybe!({
 5989            let project = self.project.as_ref()?;
 5990            let dap_store = project.read(cx).dap_store();
 5991            let mut scenarios = vec![];
 5992            let resolved_tasks = resolved_tasks.as_ref()?;
 5993            let buffer = buffer.read(cx);
 5994            let language = buffer.language()?;
 5995            let file = buffer.file();
 5996            let debug_adapter = language_settings(language.name().into(), file, cx)
 5997                .debuggers
 5998                .first()
 5999                .map(SharedString::from)
 6000                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6001
 6002            dap_store.update(cx, |dap_store, cx| {
 6003                for (_, task) in &resolved_tasks.templates {
 6004                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6005                        task.original_task().clone(),
 6006                        debug_adapter.clone().into(),
 6007                        task.display_label().to_owned().into(),
 6008                        cx,
 6009                    );
 6010                    scenarios.push(maybe_scenario);
 6011                }
 6012            });
 6013            Some(cx.background_spawn(async move {
 6014                let scenarios = futures::future::join_all(scenarios)
 6015                    .await
 6016                    .into_iter()
 6017                    .flatten()
 6018                    .collect::<Vec<_>>();
 6019                scenarios
 6020            }))
 6021        })
 6022        .unwrap_or_else(|| Task::ready(vec![]))
 6023    }
 6024
 6025    fn code_actions(
 6026        &mut self,
 6027        buffer_row: u32,
 6028        window: &mut Window,
 6029        cx: &mut Context<Self>,
 6030    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6031        let mut task = self.code_actions_task.take();
 6032        cx.spawn_in(window, async move |editor, cx| {
 6033            while let Some(prev_task) = task {
 6034                prev_task.await.log_err();
 6035                task = editor
 6036                    .update(cx, |this, _| this.code_actions_task.take())
 6037                    .ok()?;
 6038            }
 6039
 6040            editor
 6041                .update(cx, |editor, cx| {
 6042                    editor
 6043                        .available_code_actions
 6044                        .clone()
 6045                        .and_then(|(location, code_actions)| {
 6046                            let snapshot = location.buffer.read(cx).snapshot();
 6047                            let point_range = location.range.to_point(&snapshot);
 6048                            let point_range = point_range.start.row..=point_range.end.row;
 6049                            if point_range.contains(&buffer_row) {
 6050                                Some(code_actions)
 6051                            } else {
 6052                                None
 6053                            }
 6054                        })
 6055                })
 6056                .ok()
 6057                .flatten()
 6058        })
 6059    }
 6060
 6061    pub fn confirm_code_action(
 6062        &mut self,
 6063        action: &ConfirmCodeAction,
 6064        window: &mut Window,
 6065        cx: &mut Context<Self>,
 6066    ) -> Option<Task<Result<()>>> {
 6067        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6068
 6069        let actions_menu =
 6070            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6071                menu
 6072            } else {
 6073                return None;
 6074            };
 6075
 6076        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6077        let action = actions_menu.actions.get(action_ix)?;
 6078        let title = action.label();
 6079        let buffer = actions_menu.buffer;
 6080        let workspace = self.workspace()?;
 6081
 6082        match action {
 6083            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6084                workspace.update(cx, |workspace, cx| {
 6085                    workspace.schedule_resolved_task(
 6086                        task_source_kind,
 6087                        resolved_task,
 6088                        false,
 6089                        window,
 6090                        cx,
 6091                    );
 6092
 6093                    Some(Task::ready(Ok(())))
 6094                })
 6095            }
 6096            CodeActionsItem::CodeAction {
 6097                excerpt_id,
 6098                action,
 6099                provider,
 6100            } => {
 6101                let apply_code_action =
 6102                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6103                let workspace = workspace.downgrade();
 6104                Some(cx.spawn_in(window, async move |editor, cx| {
 6105                    let project_transaction = apply_code_action.await?;
 6106                    Self::open_project_transaction(
 6107                        &editor,
 6108                        workspace,
 6109                        project_transaction,
 6110                        title,
 6111                        cx,
 6112                    )
 6113                    .await
 6114                }))
 6115            }
 6116            CodeActionsItem::DebugScenario(scenario) => {
 6117                let context = actions_menu.actions.context.clone();
 6118
 6119                workspace.update(cx, |workspace, cx| {
 6120                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6121                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6122                });
 6123                Some(Task::ready(Ok(())))
 6124            }
 6125        }
 6126    }
 6127
 6128    pub async fn open_project_transaction(
 6129        this: &WeakEntity<Editor>,
 6130        workspace: WeakEntity<Workspace>,
 6131        transaction: ProjectTransaction,
 6132        title: String,
 6133        cx: &mut AsyncWindowContext,
 6134    ) -> Result<()> {
 6135        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6136        cx.update(|_, cx| {
 6137            entries.sort_unstable_by_key(|(buffer, _)| {
 6138                buffer.read(cx).file().map(|f| f.path().clone())
 6139            });
 6140        })?;
 6141
 6142        // If the project transaction's edits are all contained within this editor, then
 6143        // avoid opening a new editor to display them.
 6144
 6145        if let Some((buffer, transaction)) = entries.first() {
 6146            if entries.len() == 1 {
 6147                let excerpt = this.update(cx, |editor, cx| {
 6148                    editor
 6149                        .buffer()
 6150                        .read(cx)
 6151                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6152                })?;
 6153                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6154                    if excerpted_buffer == *buffer {
 6155                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6156                            let excerpt_range = excerpt_range.to_offset(buffer);
 6157                            buffer
 6158                                .edited_ranges_for_transaction::<usize>(transaction)
 6159                                .all(|range| {
 6160                                    excerpt_range.start <= range.start
 6161                                        && excerpt_range.end >= range.end
 6162                                })
 6163                        })?;
 6164
 6165                        if all_edits_within_excerpt {
 6166                            return Ok(());
 6167                        }
 6168                    }
 6169                }
 6170            }
 6171        } else {
 6172            return Ok(());
 6173        }
 6174
 6175        let mut ranges_to_highlight = Vec::new();
 6176        let excerpt_buffer = cx.new(|cx| {
 6177            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6178            for (buffer_handle, transaction) in &entries {
 6179                let edited_ranges = buffer_handle
 6180                    .read(cx)
 6181                    .edited_ranges_for_transaction::<Point>(transaction)
 6182                    .collect::<Vec<_>>();
 6183                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6184                    PathKey::for_buffer(buffer_handle, cx),
 6185                    buffer_handle.clone(),
 6186                    edited_ranges,
 6187                    DEFAULT_MULTIBUFFER_CONTEXT,
 6188                    cx,
 6189                );
 6190
 6191                ranges_to_highlight.extend(ranges);
 6192            }
 6193            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6194            multibuffer
 6195        })?;
 6196
 6197        workspace.update_in(cx, |workspace, window, cx| {
 6198            let project = workspace.project().clone();
 6199            let editor =
 6200                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6201            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6202            editor.update(cx, |editor, cx| {
 6203                editor.highlight_background::<Self>(
 6204                    &ranges_to_highlight,
 6205                    |theme| theme.colors().editor_highlighted_line_background,
 6206                    cx,
 6207                );
 6208            });
 6209        })?;
 6210
 6211        Ok(())
 6212    }
 6213
 6214    pub fn clear_code_action_providers(&mut self) {
 6215        self.code_action_providers.clear();
 6216        self.available_code_actions.take();
 6217    }
 6218
 6219    pub fn add_code_action_provider(
 6220        &mut self,
 6221        provider: Rc<dyn CodeActionProvider>,
 6222        window: &mut Window,
 6223        cx: &mut Context<Self>,
 6224    ) {
 6225        if self
 6226            .code_action_providers
 6227            .iter()
 6228            .any(|existing_provider| existing_provider.id() == provider.id())
 6229        {
 6230            return;
 6231        }
 6232
 6233        self.code_action_providers.push(provider);
 6234        self.refresh_code_actions(window, cx);
 6235    }
 6236
 6237    pub fn remove_code_action_provider(
 6238        &mut self,
 6239        id: Arc<str>,
 6240        window: &mut Window,
 6241        cx: &mut Context<Self>,
 6242    ) {
 6243        self.code_action_providers
 6244            .retain(|provider| provider.id() != id);
 6245        self.refresh_code_actions(window, cx);
 6246    }
 6247
 6248    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6249        !self.code_action_providers.is_empty()
 6250            && EditorSettings::get_global(cx).toolbar.code_actions
 6251    }
 6252
 6253    pub fn has_available_code_actions(&self) -> bool {
 6254        self.available_code_actions
 6255            .as_ref()
 6256            .is_some_and(|(_, actions)| !actions.is_empty())
 6257    }
 6258
 6259    fn render_inline_code_actions(
 6260        &self,
 6261        icon_size: ui::IconSize,
 6262        display_row: DisplayRow,
 6263        is_active: bool,
 6264        cx: &mut Context<Self>,
 6265    ) -> AnyElement {
 6266        let show_tooltip = !self.context_menu_visible();
 6267        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6268            .icon_size(icon_size)
 6269            .shape(ui::IconButtonShape::Square)
 6270            .style(ButtonStyle::Transparent)
 6271            .icon_color(ui::Color::Hidden)
 6272            .toggle_state(is_active)
 6273            .when(show_tooltip, |this| {
 6274                this.tooltip({
 6275                    let focus_handle = self.focus_handle.clone();
 6276                    move |window, cx| {
 6277                        Tooltip::for_action_in(
 6278                            "Toggle Code Actions",
 6279                            &ToggleCodeActions {
 6280                                deployed_from: None,
 6281                                quick_launch: false,
 6282                            },
 6283                            &focus_handle,
 6284                            window,
 6285                            cx,
 6286                        )
 6287                    }
 6288                })
 6289            })
 6290            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6291                window.focus(&editor.focus_handle(cx));
 6292                editor.toggle_code_actions(
 6293                    &crate::actions::ToggleCodeActions {
 6294                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6295                            display_row,
 6296                        )),
 6297                        quick_launch: false,
 6298                    },
 6299                    window,
 6300                    cx,
 6301                );
 6302            }))
 6303            .into_any_element()
 6304    }
 6305
 6306    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6307        &self.context_menu
 6308    }
 6309
 6310    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6311        let newest_selection = self.selections.newest_anchor().clone();
 6312        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6313        let buffer = self.buffer.read(cx);
 6314        if newest_selection.head().diff_base_anchor.is_some() {
 6315            return None;
 6316        }
 6317        let (start_buffer, start) =
 6318            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6319        let (end_buffer, end) =
 6320            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6321        if start_buffer != end_buffer {
 6322            return None;
 6323        }
 6324
 6325        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6326            cx.background_executor()
 6327                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6328                .await;
 6329
 6330            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6331                let providers = this.code_action_providers.clone();
 6332                let tasks = this
 6333                    .code_action_providers
 6334                    .iter()
 6335                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6336                    .collect::<Vec<_>>();
 6337                (providers, tasks)
 6338            })?;
 6339
 6340            let mut actions = Vec::new();
 6341            for (provider, provider_actions) in
 6342                providers.into_iter().zip(future::join_all(tasks).await)
 6343            {
 6344                if let Some(provider_actions) = provider_actions.log_err() {
 6345                    actions.extend(provider_actions.into_iter().map(|action| {
 6346                        AvailableCodeAction {
 6347                            excerpt_id: newest_selection.start.excerpt_id,
 6348                            action,
 6349                            provider: provider.clone(),
 6350                        }
 6351                    }));
 6352                }
 6353            }
 6354
 6355            this.update(cx, |this, cx| {
 6356                this.available_code_actions = if actions.is_empty() {
 6357                    None
 6358                } else {
 6359                    Some((
 6360                        Location {
 6361                            buffer: start_buffer,
 6362                            range: start..end,
 6363                        },
 6364                        actions.into(),
 6365                    ))
 6366                };
 6367                cx.notify();
 6368            })
 6369        }));
 6370        None
 6371    }
 6372
 6373    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6374        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6375            self.show_git_blame_inline = false;
 6376
 6377            self.show_git_blame_inline_delay_task =
 6378                Some(cx.spawn_in(window, async move |this, cx| {
 6379                    cx.background_executor().timer(delay).await;
 6380
 6381                    this.update(cx, |this, cx| {
 6382                        this.show_git_blame_inline = true;
 6383                        cx.notify();
 6384                    })
 6385                    .log_err();
 6386                }));
 6387        }
 6388    }
 6389
 6390    fn show_blame_popover(
 6391        &mut self,
 6392        blame_entry: &BlameEntry,
 6393        position: gpui::Point<Pixels>,
 6394        cx: &mut Context<Self>,
 6395    ) {
 6396        if let Some(state) = &mut self.inline_blame_popover {
 6397            state.hide_task.take();
 6398        } else {
 6399            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6400            let blame_entry = blame_entry.clone();
 6401            let show_task = cx.spawn(async move |editor, cx| {
 6402                cx.background_executor()
 6403                    .timer(std::time::Duration::from_millis(delay))
 6404                    .await;
 6405                editor
 6406                    .update(cx, |editor, cx| {
 6407                        editor.inline_blame_popover_show_task.take();
 6408                        let Some(blame) = editor.blame.as_ref() else {
 6409                            return;
 6410                        };
 6411                        let blame = blame.read(cx);
 6412                        let details = blame.details_for_entry(&blame_entry);
 6413                        let markdown = cx.new(|cx| {
 6414                            Markdown::new(
 6415                                details
 6416                                    .as_ref()
 6417                                    .map(|message| message.message.clone())
 6418                                    .unwrap_or_default(),
 6419                                None,
 6420                                None,
 6421                                cx,
 6422                            )
 6423                        });
 6424                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6425                            position,
 6426                            hide_task: None,
 6427                            popover_bounds: None,
 6428                            popover_state: InlineBlamePopoverState {
 6429                                scroll_handle: ScrollHandle::new(),
 6430                                commit_message: details,
 6431                                markdown,
 6432                            },
 6433                        });
 6434                        cx.notify();
 6435                    })
 6436                    .ok();
 6437            });
 6438            self.inline_blame_popover_show_task = Some(show_task);
 6439        }
 6440    }
 6441
 6442    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6443        self.inline_blame_popover_show_task.take();
 6444        if let Some(state) = &mut self.inline_blame_popover {
 6445            let hide_task = cx.spawn(async move |editor, cx| {
 6446                cx.background_executor()
 6447                    .timer(std::time::Duration::from_millis(100))
 6448                    .await;
 6449                editor
 6450                    .update(cx, |editor, cx| {
 6451                        editor.inline_blame_popover.take();
 6452                        cx.notify();
 6453                    })
 6454                    .ok();
 6455            });
 6456            state.hide_task = Some(hide_task);
 6457        }
 6458    }
 6459
 6460    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6461        if self.pending_rename.is_some() {
 6462            return None;
 6463        }
 6464
 6465        let provider = self.semantics_provider.clone()?;
 6466        let buffer = self.buffer.read(cx);
 6467        let newest_selection = self.selections.newest_anchor().clone();
 6468        let cursor_position = newest_selection.head();
 6469        let (cursor_buffer, cursor_buffer_position) =
 6470            buffer.text_anchor_for_position(cursor_position, cx)?;
 6471        let (tail_buffer, tail_buffer_position) =
 6472            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6473        if cursor_buffer != tail_buffer {
 6474            return None;
 6475        }
 6476
 6477        let snapshot = cursor_buffer.read(cx).snapshot();
 6478        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6479        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6480        if start_word_range != end_word_range {
 6481            self.document_highlights_task.take();
 6482            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6483            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6484            return None;
 6485        }
 6486
 6487        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6488        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6489            cx.background_executor()
 6490                .timer(Duration::from_millis(debounce))
 6491                .await;
 6492
 6493            let highlights = if let Some(highlights) = cx
 6494                .update(|cx| {
 6495                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6496                })
 6497                .ok()
 6498                .flatten()
 6499            {
 6500                highlights.await.log_err()
 6501            } else {
 6502                None
 6503            };
 6504
 6505            if let Some(highlights) = highlights {
 6506                this.update(cx, |this, cx| {
 6507                    if this.pending_rename.is_some() {
 6508                        return;
 6509                    }
 6510
 6511                    let buffer_id = cursor_position.buffer_id;
 6512                    let buffer = this.buffer.read(cx);
 6513                    if !buffer
 6514                        .text_anchor_for_position(cursor_position, cx)
 6515                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6516                    {
 6517                        return;
 6518                    }
 6519
 6520                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6521                    let mut write_ranges = Vec::new();
 6522                    let mut read_ranges = Vec::new();
 6523                    for highlight in highlights {
 6524                        for (excerpt_id, excerpt_range) in
 6525                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6526                        {
 6527                            let start = highlight
 6528                                .range
 6529                                .start
 6530                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6531                            let end = highlight
 6532                                .range
 6533                                .end
 6534                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6535                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6536                                continue;
 6537                            }
 6538
 6539                            let range = Anchor {
 6540                                buffer_id,
 6541                                excerpt_id,
 6542                                text_anchor: start,
 6543                                diff_base_anchor: None,
 6544                            }..Anchor {
 6545                                buffer_id,
 6546                                excerpt_id,
 6547                                text_anchor: end,
 6548                                diff_base_anchor: None,
 6549                            };
 6550                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6551                                write_ranges.push(range);
 6552                            } else {
 6553                                read_ranges.push(range);
 6554                            }
 6555                        }
 6556                    }
 6557
 6558                    this.highlight_background::<DocumentHighlightRead>(
 6559                        &read_ranges,
 6560                        |theme| theme.colors().editor_document_highlight_read_background,
 6561                        cx,
 6562                    );
 6563                    this.highlight_background::<DocumentHighlightWrite>(
 6564                        &write_ranges,
 6565                        |theme| theme.colors().editor_document_highlight_write_background,
 6566                        cx,
 6567                    );
 6568                    cx.notify();
 6569                })
 6570                .log_err();
 6571            }
 6572        }));
 6573        None
 6574    }
 6575
 6576    fn prepare_highlight_query_from_selection(
 6577        &mut self,
 6578        cx: &mut Context<Editor>,
 6579    ) -> Option<(String, Range<Anchor>)> {
 6580        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6581            return None;
 6582        }
 6583        if !EditorSettings::get_global(cx).selection_highlight {
 6584            return None;
 6585        }
 6586        if self.selections.count() != 1 || self.selections.line_mode {
 6587            return None;
 6588        }
 6589        let selection = self.selections.newest::<Point>(cx);
 6590        if selection.is_empty() || selection.start.row != selection.end.row {
 6591            return None;
 6592        }
 6593        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6594        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6595        let query = multi_buffer_snapshot
 6596            .text_for_range(selection_anchor_range.clone())
 6597            .collect::<String>();
 6598        if query.trim().is_empty() {
 6599            return None;
 6600        }
 6601        Some((query, selection_anchor_range))
 6602    }
 6603
 6604    fn update_selection_occurrence_highlights(
 6605        &mut self,
 6606        query_text: String,
 6607        query_range: Range<Anchor>,
 6608        multi_buffer_range_to_query: Range<Point>,
 6609        use_debounce: bool,
 6610        window: &mut Window,
 6611        cx: &mut Context<Editor>,
 6612    ) -> Task<()> {
 6613        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6614        cx.spawn_in(window, async move |editor, cx| {
 6615            if use_debounce {
 6616                cx.background_executor()
 6617                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6618                    .await;
 6619            }
 6620            let match_task = cx.background_spawn(async move {
 6621                let buffer_ranges = multi_buffer_snapshot
 6622                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6623                    .into_iter()
 6624                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6625                let mut match_ranges = Vec::new();
 6626                let Ok(regex) = project::search::SearchQuery::text(
 6627                    query_text.clone(),
 6628                    false,
 6629                    false,
 6630                    false,
 6631                    Default::default(),
 6632                    Default::default(),
 6633                    false,
 6634                    None,
 6635                ) else {
 6636                    return Vec::default();
 6637                };
 6638                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6639                    match_ranges.extend(
 6640                        regex
 6641                            .search(&buffer_snapshot, Some(search_range.clone()))
 6642                            .await
 6643                            .into_iter()
 6644                            .filter_map(|match_range| {
 6645                                let match_start = buffer_snapshot
 6646                                    .anchor_after(search_range.start + match_range.start);
 6647                                let match_end = buffer_snapshot
 6648                                    .anchor_before(search_range.start + match_range.end);
 6649                                let match_anchor_range = Anchor::range_in_buffer(
 6650                                    excerpt_id,
 6651                                    buffer_snapshot.remote_id(),
 6652                                    match_start..match_end,
 6653                                );
 6654                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6655                            }),
 6656                    );
 6657                }
 6658                match_ranges
 6659            });
 6660            let match_ranges = match_task.await;
 6661            editor
 6662                .update_in(cx, |editor, _, cx| {
 6663                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6664                    if !match_ranges.is_empty() {
 6665                        editor.highlight_background::<SelectedTextHighlight>(
 6666                            &match_ranges,
 6667                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6668                            cx,
 6669                        )
 6670                    }
 6671                })
 6672                .log_err();
 6673        })
 6674    }
 6675
 6676    fn refresh_selected_text_highlights(
 6677        &mut self,
 6678        on_buffer_edit: bool,
 6679        window: &mut Window,
 6680        cx: &mut Context<Editor>,
 6681    ) {
 6682        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6683        else {
 6684            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6685            self.quick_selection_highlight_task.take();
 6686            self.debounced_selection_highlight_task.take();
 6687            return;
 6688        };
 6689        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6690        if on_buffer_edit
 6691            || self
 6692                .quick_selection_highlight_task
 6693                .as_ref()
 6694                .map_or(true, |(prev_anchor_range, _)| {
 6695                    prev_anchor_range != &query_range
 6696                })
 6697        {
 6698            let multi_buffer_visible_start = self
 6699                .scroll_manager
 6700                .anchor()
 6701                .anchor
 6702                .to_point(&multi_buffer_snapshot);
 6703            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6704                multi_buffer_visible_start
 6705                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6706                Bias::Left,
 6707            );
 6708            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6709            self.quick_selection_highlight_task = Some((
 6710                query_range.clone(),
 6711                self.update_selection_occurrence_highlights(
 6712                    query_text.clone(),
 6713                    query_range.clone(),
 6714                    multi_buffer_visible_range,
 6715                    false,
 6716                    window,
 6717                    cx,
 6718                ),
 6719            ));
 6720        }
 6721        if on_buffer_edit
 6722            || self
 6723                .debounced_selection_highlight_task
 6724                .as_ref()
 6725                .map_or(true, |(prev_anchor_range, _)| {
 6726                    prev_anchor_range != &query_range
 6727                })
 6728        {
 6729            let multi_buffer_start = multi_buffer_snapshot
 6730                .anchor_before(0)
 6731                .to_point(&multi_buffer_snapshot);
 6732            let multi_buffer_end = multi_buffer_snapshot
 6733                .anchor_after(multi_buffer_snapshot.len())
 6734                .to_point(&multi_buffer_snapshot);
 6735            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6736            self.debounced_selection_highlight_task = Some((
 6737                query_range.clone(),
 6738                self.update_selection_occurrence_highlights(
 6739                    query_text,
 6740                    query_range,
 6741                    multi_buffer_full_range,
 6742                    true,
 6743                    window,
 6744                    cx,
 6745                ),
 6746            ));
 6747        }
 6748    }
 6749
 6750    pub fn refresh_inline_completion(
 6751        &mut self,
 6752        debounce: bool,
 6753        user_requested: bool,
 6754        window: &mut Window,
 6755        cx: &mut Context<Self>,
 6756    ) -> Option<()> {
 6757        let provider = self.edit_prediction_provider()?;
 6758        let cursor = self.selections.newest_anchor().head();
 6759        let (buffer, cursor_buffer_position) =
 6760            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6761
 6762        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6763            self.discard_inline_completion(false, cx);
 6764            return None;
 6765        }
 6766
 6767        if !user_requested
 6768            && (!self.should_show_edit_predictions()
 6769                || !self.is_focused(window)
 6770                || buffer.read(cx).is_empty())
 6771        {
 6772            self.discard_inline_completion(false, cx);
 6773            return None;
 6774        }
 6775
 6776        self.update_visible_inline_completion(window, cx);
 6777        provider.refresh(
 6778            self.project.clone(),
 6779            buffer,
 6780            cursor_buffer_position,
 6781            debounce,
 6782            cx,
 6783        );
 6784        Some(())
 6785    }
 6786
 6787    fn show_edit_predictions_in_menu(&self) -> bool {
 6788        match self.edit_prediction_settings {
 6789            EditPredictionSettings::Disabled => false,
 6790            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6791        }
 6792    }
 6793
 6794    pub fn edit_predictions_enabled(&self) -> bool {
 6795        match self.edit_prediction_settings {
 6796            EditPredictionSettings::Disabled => false,
 6797            EditPredictionSettings::Enabled { .. } => true,
 6798        }
 6799    }
 6800
 6801    fn edit_prediction_requires_modifier(&self) -> bool {
 6802        match self.edit_prediction_settings {
 6803            EditPredictionSettings::Disabled => false,
 6804            EditPredictionSettings::Enabled {
 6805                preview_requires_modifier,
 6806                ..
 6807            } => preview_requires_modifier,
 6808        }
 6809    }
 6810
 6811    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6812        if self.edit_prediction_provider.is_none() {
 6813            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6814        } else {
 6815            let selection = self.selections.newest_anchor();
 6816            let cursor = selection.head();
 6817
 6818            if let Some((buffer, cursor_buffer_position)) =
 6819                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6820            {
 6821                self.edit_prediction_settings =
 6822                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6823            }
 6824        }
 6825    }
 6826
 6827    fn edit_prediction_settings_at_position(
 6828        &self,
 6829        buffer: &Entity<Buffer>,
 6830        buffer_position: language::Anchor,
 6831        cx: &App,
 6832    ) -> EditPredictionSettings {
 6833        if !self.mode.is_full()
 6834            || !self.show_inline_completions_override.unwrap_or(true)
 6835            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6836        {
 6837            return EditPredictionSettings::Disabled;
 6838        }
 6839
 6840        let buffer = buffer.read(cx);
 6841
 6842        let file = buffer.file();
 6843
 6844        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6845            return EditPredictionSettings::Disabled;
 6846        };
 6847
 6848        let by_provider = matches!(
 6849            self.menu_inline_completions_policy,
 6850            MenuInlineCompletionsPolicy::ByProvider
 6851        );
 6852
 6853        let show_in_menu = by_provider
 6854            && self
 6855                .edit_prediction_provider
 6856                .as_ref()
 6857                .map_or(false, |provider| {
 6858                    provider.provider.show_completions_in_menu()
 6859                });
 6860
 6861        let preview_requires_modifier =
 6862            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6863
 6864        EditPredictionSettings::Enabled {
 6865            show_in_menu,
 6866            preview_requires_modifier,
 6867        }
 6868    }
 6869
 6870    fn should_show_edit_predictions(&self) -> bool {
 6871        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6872    }
 6873
 6874    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6875        matches!(
 6876            self.edit_prediction_preview,
 6877            EditPredictionPreview::Active { .. }
 6878        )
 6879    }
 6880
 6881    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6882        let cursor = self.selections.newest_anchor().head();
 6883        if let Some((buffer, cursor_position)) =
 6884            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6885        {
 6886            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6887        } else {
 6888            false
 6889        }
 6890    }
 6891
 6892    pub fn supports_minimap(&self, cx: &App) -> bool {
 6893        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6894    }
 6895
 6896    fn edit_predictions_enabled_in_buffer(
 6897        &self,
 6898        buffer: &Entity<Buffer>,
 6899        buffer_position: language::Anchor,
 6900        cx: &App,
 6901    ) -> bool {
 6902        maybe!({
 6903            if self.read_only(cx) {
 6904                return Some(false);
 6905            }
 6906            let provider = self.edit_prediction_provider()?;
 6907            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6908                return Some(false);
 6909            }
 6910            let buffer = buffer.read(cx);
 6911            let Some(file) = buffer.file() else {
 6912                return Some(true);
 6913            };
 6914            let settings = all_language_settings(Some(file), cx);
 6915            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6916        })
 6917        .unwrap_or(false)
 6918    }
 6919
 6920    fn cycle_inline_completion(
 6921        &mut self,
 6922        direction: Direction,
 6923        window: &mut Window,
 6924        cx: &mut Context<Self>,
 6925    ) -> Option<()> {
 6926        let provider = self.edit_prediction_provider()?;
 6927        let cursor = self.selections.newest_anchor().head();
 6928        let (buffer, cursor_buffer_position) =
 6929            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6930        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6931            return None;
 6932        }
 6933
 6934        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6935        self.update_visible_inline_completion(window, cx);
 6936
 6937        Some(())
 6938    }
 6939
 6940    pub fn show_inline_completion(
 6941        &mut self,
 6942        _: &ShowEditPrediction,
 6943        window: &mut Window,
 6944        cx: &mut Context<Self>,
 6945    ) {
 6946        if !self.has_active_inline_completion() {
 6947            self.refresh_inline_completion(false, true, window, cx);
 6948            return;
 6949        }
 6950
 6951        self.update_visible_inline_completion(window, cx);
 6952    }
 6953
 6954    pub fn display_cursor_names(
 6955        &mut self,
 6956        _: &DisplayCursorNames,
 6957        window: &mut Window,
 6958        cx: &mut Context<Self>,
 6959    ) {
 6960        self.show_cursor_names(window, cx);
 6961    }
 6962
 6963    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6964        self.show_cursor_names = true;
 6965        cx.notify();
 6966        cx.spawn_in(window, async move |this, cx| {
 6967            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6968            this.update(cx, |this, cx| {
 6969                this.show_cursor_names = false;
 6970                cx.notify()
 6971            })
 6972            .ok()
 6973        })
 6974        .detach();
 6975    }
 6976
 6977    pub fn next_edit_prediction(
 6978        &mut self,
 6979        _: &NextEditPrediction,
 6980        window: &mut Window,
 6981        cx: &mut Context<Self>,
 6982    ) {
 6983        if self.has_active_inline_completion() {
 6984            self.cycle_inline_completion(Direction::Next, window, cx);
 6985        } else {
 6986            let is_copilot_disabled = self
 6987                .refresh_inline_completion(false, true, window, cx)
 6988                .is_none();
 6989            if is_copilot_disabled {
 6990                cx.propagate();
 6991            }
 6992        }
 6993    }
 6994
 6995    pub fn previous_edit_prediction(
 6996        &mut self,
 6997        _: &PreviousEditPrediction,
 6998        window: &mut Window,
 6999        cx: &mut Context<Self>,
 7000    ) {
 7001        if self.has_active_inline_completion() {
 7002            self.cycle_inline_completion(Direction::Prev, window, cx);
 7003        } else {
 7004            let is_copilot_disabled = self
 7005                .refresh_inline_completion(false, true, window, cx)
 7006                .is_none();
 7007            if is_copilot_disabled {
 7008                cx.propagate();
 7009            }
 7010        }
 7011    }
 7012
 7013    pub fn accept_edit_prediction(
 7014        &mut self,
 7015        _: &AcceptEditPrediction,
 7016        window: &mut Window,
 7017        cx: &mut Context<Self>,
 7018    ) {
 7019        if self.show_edit_predictions_in_menu() {
 7020            self.hide_context_menu(window, cx);
 7021        }
 7022
 7023        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7024            return;
 7025        };
 7026
 7027        self.report_inline_completion_event(
 7028            active_inline_completion.completion_id.clone(),
 7029            true,
 7030            cx,
 7031        );
 7032
 7033        match &active_inline_completion.completion {
 7034            InlineCompletion::Move { target, .. } => {
 7035                let target = *target;
 7036
 7037                if let Some(position_map) = &self.last_position_map {
 7038                    if position_map
 7039                        .visible_row_range
 7040                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7041                        || !self.edit_prediction_requires_modifier()
 7042                    {
 7043                        self.unfold_ranges(&[target..target], true, false, cx);
 7044                        // Note that this is also done in vim's handler of the Tab action.
 7045                        self.change_selections(
 7046                            Some(Autoscroll::newest()),
 7047                            window,
 7048                            cx,
 7049                            |selections| {
 7050                                selections.select_anchor_ranges([target..target]);
 7051                            },
 7052                        );
 7053                        self.clear_row_highlights::<EditPredictionPreview>();
 7054
 7055                        self.edit_prediction_preview
 7056                            .set_previous_scroll_position(None);
 7057                    } else {
 7058                        self.edit_prediction_preview
 7059                            .set_previous_scroll_position(Some(
 7060                                position_map.snapshot.scroll_anchor,
 7061                            ));
 7062
 7063                        self.highlight_rows::<EditPredictionPreview>(
 7064                            target..target,
 7065                            cx.theme().colors().editor_highlighted_line_background,
 7066                            RowHighlightOptions {
 7067                                autoscroll: true,
 7068                                ..Default::default()
 7069                            },
 7070                            cx,
 7071                        );
 7072                        self.request_autoscroll(Autoscroll::fit(), cx);
 7073                    }
 7074                }
 7075            }
 7076            InlineCompletion::Edit { edits, .. } => {
 7077                if let Some(provider) = self.edit_prediction_provider() {
 7078                    provider.accept(cx);
 7079                }
 7080
 7081                // Store the transaction ID and selections before applying the edit
 7082                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7083
 7084                let snapshot = self.buffer.read(cx).snapshot(cx);
 7085                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7086
 7087                self.buffer.update(cx, |buffer, cx| {
 7088                    buffer.edit(edits.iter().cloned(), None, cx)
 7089                });
 7090
 7091                self.change_selections(None, window, cx, |s| {
 7092                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7093                });
 7094
 7095                let selections = self.selections.disjoint_anchors();
 7096                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7097                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7098                    if has_new_transaction {
 7099                        self.selection_history
 7100                            .insert_transaction(transaction_id_now, selections);
 7101                    }
 7102                }
 7103
 7104                self.update_visible_inline_completion(window, cx);
 7105                if self.active_inline_completion.is_none() {
 7106                    self.refresh_inline_completion(true, true, window, cx);
 7107                }
 7108
 7109                cx.notify();
 7110            }
 7111        }
 7112
 7113        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7114    }
 7115
 7116    pub fn accept_partial_inline_completion(
 7117        &mut self,
 7118        _: &AcceptPartialEditPrediction,
 7119        window: &mut Window,
 7120        cx: &mut Context<Self>,
 7121    ) {
 7122        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7123            return;
 7124        };
 7125        if self.selections.count() != 1 {
 7126            return;
 7127        }
 7128
 7129        self.report_inline_completion_event(
 7130            active_inline_completion.completion_id.clone(),
 7131            true,
 7132            cx,
 7133        );
 7134
 7135        match &active_inline_completion.completion {
 7136            InlineCompletion::Move { target, .. } => {
 7137                let target = *target;
 7138                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7139                    selections.select_anchor_ranges([target..target]);
 7140                });
 7141            }
 7142            InlineCompletion::Edit { edits, .. } => {
 7143                // Find an insertion that starts at the cursor position.
 7144                let snapshot = self.buffer.read(cx).snapshot(cx);
 7145                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7146                let insertion = edits.iter().find_map(|(range, text)| {
 7147                    let range = range.to_offset(&snapshot);
 7148                    if range.is_empty() && range.start == cursor_offset {
 7149                        Some(text)
 7150                    } else {
 7151                        None
 7152                    }
 7153                });
 7154
 7155                if let Some(text) = insertion {
 7156                    let mut partial_completion = text
 7157                        .chars()
 7158                        .by_ref()
 7159                        .take_while(|c| c.is_alphabetic())
 7160                        .collect::<String>();
 7161                    if partial_completion.is_empty() {
 7162                        partial_completion = text
 7163                            .chars()
 7164                            .by_ref()
 7165                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7166                            .collect::<String>();
 7167                    }
 7168
 7169                    cx.emit(EditorEvent::InputHandled {
 7170                        utf16_range_to_replace: None,
 7171                        text: partial_completion.clone().into(),
 7172                    });
 7173
 7174                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7175
 7176                    self.refresh_inline_completion(true, true, window, cx);
 7177                    cx.notify();
 7178                } else {
 7179                    self.accept_edit_prediction(&Default::default(), window, cx);
 7180                }
 7181            }
 7182        }
 7183    }
 7184
 7185    fn discard_inline_completion(
 7186        &mut self,
 7187        should_report_inline_completion_event: bool,
 7188        cx: &mut Context<Self>,
 7189    ) -> bool {
 7190        if should_report_inline_completion_event {
 7191            let completion_id = self
 7192                .active_inline_completion
 7193                .as_ref()
 7194                .and_then(|active_completion| active_completion.completion_id.clone());
 7195
 7196            self.report_inline_completion_event(completion_id, false, cx);
 7197        }
 7198
 7199        if let Some(provider) = self.edit_prediction_provider() {
 7200            provider.discard(cx);
 7201        }
 7202
 7203        self.take_active_inline_completion(cx)
 7204    }
 7205
 7206    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7207        let Some(provider) = self.edit_prediction_provider() else {
 7208            return;
 7209        };
 7210
 7211        let Some((_, buffer, _)) = self
 7212            .buffer
 7213            .read(cx)
 7214            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7215        else {
 7216            return;
 7217        };
 7218
 7219        let extension = buffer
 7220            .read(cx)
 7221            .file()
 7222            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7223
 7224        let event_type = match accepted {
 7225            true => "Edit Prediction Accepted",
 7226            false => "Edit Prediction Discarded",
 7227        };
 7228        telemetry::event!(
 7229            event_type,
 7230            provider = provider.name(),
 7231            prediction_id = id,
 7232            suggestion_accepted = accepted,
 7233            file_extension = extension,
 7234        );
 7235    }
 7236
 7237    pub fn has_active_inline_completion(&self) -> bool {
 7238        self.active_inline_completion.is_some()
 7239    }
 7240
 7241    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7242        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7243            return false;
 7244        };
 7245
 7246        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7247        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7248        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7249        true
 7250    }
 7251
 7252    /// Returns true when we're displaying the edit prediction popover below the cursor
 7253    /// like we are not previewing and the LSP autocomplete menu is visible
 7254    /// or we are in `when_holding_modifier` mode.
 7255    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7256        if self.edit_prediction_preview_is_active()
 7257            || !self.show_edit_predictions_in_menu()
 7258            || !self.edit_predictions_enabled()
 7259        {
 7260            return false;
 7261        }
 7262
 7263        if self.has_visible_completions_menu() {
 7264            return true;
 7265        }
 7266
 7267        has_completion && self.edit_prediction_requires_modifier()
 7268    }
 7269
 7270    fn handle_modifiers_changed(
 7271        &mut self,
 7272        modifiers: Modifiers,
 7273        position_map: &PositionMap,
 7274        window: &mut Window,
 7275        cx: &mut Context<Self>,
 7276    ) {
 7277        if self.show_edit_predictions_in_menu() {
 7278            self.update_edit_prediction_preview(&modifiers, window, cx);
 7279        }
 7280
 7281        self.update_selection_mode(&modifiers, position_map, window, cx);
 7282
 7283        let mouse_position = window.mouse_position();
 7284        if !position_map.text_hitbox.is_hovered(window) {
 7285            return;
 7286        }
 7287
 7288        self.update_hovered_link(
 7289            position_map.point_for_position(mouse_position),
 7290            &position_map.snapshot,
 7291            modifiers,
 7292            window,
 7293            cx,
 7294        )
 7295    }
 7296
 7297    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7298        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7299        if invert {
 7300            match multi_cursor_setting {
 7301                MultiCursorModifier::Alt => modifiers.alt,
 7302                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7303            }
 7304        } else {
 7305            match multi_cursor_setting {
 7306                MultiCursorModifier::Alt => modifiers.secondary(),
 7307                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7308            }
 7309        }
 7310    }
 7311
 7312    fn columnar_selection_mode(
 7313        modifiers: &Modifiers,
 7314        cx: &mut Context<Self>,
 7315    ) -> Option<ColumnarMode> {
 7316        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7317            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7318                Some(ColumnarMode::FromMouse)
 7319            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7320                Some(ColumnarMode::FromSelection)
 7321            } else {
 7322                None
 7323            }
 7324        } else {
 7325            None
 7326        }
 7327    }
 7328
 7329    fn update_selection_mode(
 7330        &mut self,
 7331        modifiers: &Modifiers,
 7332        position_map: &PositionMap,
 7333        window: &mut Window,
 7334        cx: &mut Context<Self>,
 7335    ) {
 7336        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7337            return;
 7338        };
 7339        if self.selections.pending.is_none() {
 7340            return;
 7341        }
 7342
 7343        let mouse_position = window.mouse_position();
 7344        let point_for_position = position_map.point_for_position(mouse_position);
 7345        let position = point_for_position.previous_valid;
 7346
 7347        self.select(
 7348            SelectPhase::BeginColumnar {
 7349                position,
 7350                reset: false,
 7351                mode,
 7352                goal_column: point_for_position.exact_unclipped.column(),
 7353            },
 7354            window,
 7355            cx,
 7356        );
 7357    }
 7358
 7359    fn update_edit_prediction_preview(
 7360        &mut self,
 7361        modifiers: &Modifiers,
 7362        window: &mut Window,
 7363        cx: &mut Context<Self>,
 7364    ) {
 7365        let mut modifiers_held = false;
 7366        if let Some(accept_keystroke) = self
 7367            .accept_edit_prediction_keybind(false, window, cx)
 7368            .keystroke()
 7369        {
 7370            modifiers_held = modifiers_held
 7371                || (&accept_keystroke.modifiers == modifiers
 7372                    && accept_keystroke.modifiers.modified());
 7373        };
 7374        if let Some(accept_partial_keystroke) = self
 7375            .accept_edit_prediction_keybind(true, window, cx)
 7376            .keystroke()
 7377        {
 7378            modifiers_held = modifiers_held
 7379                || (&accept_partial_keystroke.modifiers == modifiers
 7380                    && accept_partial_keystroke.modifiers.modified());
 7381        }
 7382
 7383        if modifiers_held {
 7384            if matches!(
 7385                self.edit_prediction_preview,
 7386                EditPredictionPreview::Inactive { .. }
 7387            ) {
 7388                self.edit_prediction_preview = EditPredictionPreview::Active {
 7389                    previous_scroll_position: None,
 7390                    since: Instant::now(),
 7391                };
 7392
 7393                self.update_visible_inline_completion(window, cx);
 7394                cx.notify();
 7395            }
 7396        } else if let EditPredictionPreview::Active {
 7397            previous_scroll_position,
 7398            since,
 7399        } = self.edit_prediction_preview
 7400        {
 7401            if let (Some(previous_scroll_position), Some(position_map)) =
 7402                (previous_scroll_position, self.last_position_map.as_ref())
 7403            {
 7404                self.set_scroll_position(
 7405                    previous_scroll_position
 7406                        .scroll_position(&position_map.snapshot.display_snapshot),
 7407                    window,
 7408                    cx,
 7409                );
 7410            }
 7411
 7412            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7413                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7414            };
 7415            self.clear_row_highlights::<EditPredictionPreview>();
 7416            self.update_visible_inline_completion(window, cx);
 7417            cx.notify();
 7418        }
 7419    }
 7420
 7421    fn update_visible_inline_completion(
 7422        &mut self,
 7423        _window: &mut Window,
 7424        cx: &mut Context<Self>,
 7425    ) -> Option<()> {
 7426        let selection = self.selections.newest_anchor();
 7427        let cursor = selection.head();
 7428        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7429        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7430        let excerpt_id = cursor.excerpt_id;
 7431
 7432        let show_in_menu = self.show_edit_predictions_in_menu();
 7433        let completions_menu_has_precedence = !show_in_menu
 7434            && (self.context_menu.borrow().is_some()
 7435                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7436
 7437        if completions_menu_has_precedence
 7438            || !offset_selection.is_empty()
 7439            || self
 7440                .active_inline_completion
 7441                .as_ref()
 7442                .map_or(false, |completion| {
 7443                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7444                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7445                    !invalidation_range.contains(&offset_selection.head())
 7446                })
 7447        {
 7448            self.discard_inline_completion(false, cx);
 7449            return None;
 7450        }
 7451
 7452        self.take_active_inline_completion(cx);
 7453        let Some(provider) = self.edit_prediction_provider() else {
 7454            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7455            return None;
 7456        };
 7457
 7458        let (buffer, cursor_buffer_position) =
 7459            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7460
 7461        self.edit_prediction_settings =
 7462            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7463
 7464        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7465
 7466        if self.edit_prediction_indent_conflict {
 7467            let cursor_point = cursor.to_point(&multibuffer);
 7468
 7469            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7470
 7471            if let Some((_, indent)) = indents.iter().next() {
 7472                if indent.len == cursor_point.column {
 7473                    self.edit_prediction_indent_conflict = false;
 7474                }
 7475            }
 7476        }
 7477
 7478        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7479        let edits = inline_completion
 7480            .edits
 7481            .into_iter()
 7482            .flat_map(|(range, new_text)| {
 7483                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7484                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7485                Some((start..end, new_text))
 7486            })
 7487            .collect::<Vec<_>>();
 7488        if edits.is_empty() {
 7489            return None;
 7490        }
 7491
 7492        let first_edit_start = edits.first().unwrap().0.start;
 7493        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7494        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7495
 7496        let last_edit_end = edits.last().unwrap().0.end;
 7497        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7498        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7499
 7500        let cursor_row = cursor.to_point(&multibuffer).row;
 7501
 7502        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7503
 7504        let mut inlay_ids = Vec::new();
 7505        let invalidation_row_range;
 7506        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7507            Some(cursor_row..edit_end_row)
 7508        } else if cursor_row > edit_end_row {
 7509            Some(edit_start_row..cursor_row)
 7510        } else {
 7511            None
 7512        };
 7513        let is_move =
 7514            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7515        let completion = if is_move {
 7516            invalidation_row_range =
 7517                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7518            let target = first_edit_start;
 7519            InlineCompletion::Move { target, snapshot }
 7520        } else {
 7521            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7522                && !self.inline_completions_hidden_for_vim_mode;
 7523
 7524            if show_completions_in_buffer {
 7525                if edits
 7526                    .iter()
 7527                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7528                {
 7529                    let mut inlays = Vec::new();
 7530                    for (range, new_text) in &edits {
 7531                        let inlay = Inlay::inline_completion(
 7532                            post_inc(&mut self.next_inlay_id),
 7533                            range.start,
 7534                            new_text.as_str(),
 7535                        );
 7536                        inlay_ids.push(inlay.id);
 7537                        inlays.push(inlay);
 7538                    }
 7539
 7540                    self.splice_inlays(&[], inlays, cx);
 7541                } else {
 7542                    let background_color = cx.theme().status().deleted_background;
 7543                    self.highlight_text::<InlineCompletionHighlight>(
 7544                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7545                        HighlightStyle {
 7546                            background_color: Some(background_color),
 7547                            ..Default::default()
 7548                        },
 7549                        cx,
 7550                    );
 7551                }
 7552            }
 7553
 7554            invalidation_row_range = edit_start_row..edit_end_row;
 7555
 7556            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7557                if provider.show_tab_accept_marker() {
 7558                    EditDisplayMode::TabAccept
 7559                } else {
 7560                    EditDisplayMode::Inline
 7561                }
 7562            } else {
 7563                EditDisplayMode::DiffPopover
 7564            };
 7565
 7566            InlineCompletion::Edit {
 7567                edits,
 7568                edit_preview: inline_completion.edit_preview,
 7569                display_mode,
 7570                snapshot,
 7571            }
 7572        };
 7573
 7574        let invalidation_range = multibuffer
 7575            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7576            ..multibuffer.anchor_after(Point::new(
 7577                invalidation_row_range.end,
 7578                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7579            ));
 7580
 7581        self.stale_inline_completion_in_menu = None;
 7582        self.active_inline_completion = Some(InlineCompletionState {
 7583            inlay_ids,
 7584            completion,
 7585            completion_id: inline_completion.id,
 7586            invalidation_range,
 7587        });
 7588
 7589        cx.notify();
 7590
 7591        Some(())
 7592    }
 7593
 7594    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7595        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7596    }
 7597
 7598    fn clear_tasks(&mut self) {
 7599        self.tasks.clear()
 7600    }
 7601
 7602    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7603        if self.tasks.insert(key, value).is_some() {
 7604            // This case should hopefully be rare, but just in case...
 7605            log::error!(
 7606                "multiple different run targets found on a single line, only the last target will be rendered"
 7607            )
 7608        }
 7609    }
 7610
 7611    /// Get all display points of breakpoints that will be rendered within editor
 7612    ///
 7613    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7614    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7615    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7616    fn active_breakpoints(
 7617        &self,
 7618        range: Range<DisplayRow>,
 7619        window: &mut Window,
 7620        cx: &mut Context<Self>,
 7621    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7622        let mut breakpoint_display_points = HashMap::default();
 7623
 7624        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7625            return breakpoint_display_points;
 7626        };
 7627
 7628        let snapshot = self.snapshot(window, cx);
 7629
 7630        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7631        let Some(project) = self.project.as_ref() else {
 7632            return breakpoint_display_points;
 7633        };
 7634
 7635        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7636            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7637
 7638        for (buffer_snapshot, range, excerpt_id) in
 7639            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7640        {
 7641            let Some(buffer) = project
 7642                .read(cx)
 7643                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7644            else {
 7645                continue;
 7646            };
 7647            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7648                &buffer,
 7649                Some(
 7650                    buffer_snapshot.anchor_before(range.start)
 7651                        ..buffer_snapshot.anchor_after(range.end),
 7652                ),
 7653                buffer_snapshot,
 7654                cx,
 7655            );
 7656            for (breakpoint, state) in breakpoints {
 7657                let multi_buffer_anchor =
 7658                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7659                let position = multi_buffer_anchor
 7660                    .to_point(&multi_buffer_snapshot)
 7661                    .to_display_point(&snapshot);
 7662
 7663                breakpoint_display_points.insert(
 7664                    position.row(),
 7665                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7666                );
 7667            }
 7668        }
 7669
 7670        breakpoint_display_points
 7671    }
 7672
 7673    fn breakpoint_context_menu(
 7674        &self,
 7675        anchor: Anchor,
 7676        window: &mut Window,
 7677        cx: &mut Context<Self>,
 7678    ) -> Entity<ui::ContextMenu> {
 7679        let weak_editor = cx.weak_entity();
 7680        let focus_handle = self.focus_handle(cx);
 7681
 7682        let row = self
 7683            .buffer
 7684            .read(cx)
 7685            .snapshot(cx)
 7686            .summary_for_anchor::<Point>(&anchor)
 7687            .row;
 7688
 7689        let breakpoint = self
 7690            .breakpoint_at_row(row, window, cx)
 7691            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7692
 7693        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7694            "Edit Log Breakpoint"
 7695        } else {
 7696            "Set Log Breakpoint"
 7697        };
 7698
 7699        let condition_breakpoint_msg = if breakpoint
 7700            .as_ref()
 7701            .is_some_and(|bp| bp.1.condition.is_some())
 7702        {
 7703            "Edit Condition Breakpoint"
 7704        } else {
 7705            "Set Condition Breakpoint"
 7706        };
 7707
 7708        let hit_condition_breakpoint_msg = if breakpoint
 7709            .as_ref()
 7710            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7711        {
 7712            "Edit Hit Condition Breakpoint"
 7713        } else {
 7714            "Set Hit Condition Breakpoint"
 7715        };
 7716
 7717        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7718            "Unset Breakpoint"
 7719        } else {
 7720            "Set Breakpoint"
 7721        };
 7722
 7723        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7724
 7725        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7726            BreakpointState::Enabled => Some("Disable"),
 7727            BreakpointState::Disabled => Some("Enable"),
 7728        });
 7729
 7730        let (anchor, breakpoint) =
 7731            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7732
 7733        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7734            menu.on_blur_subscription(Subscription::new(|| {}))
 7735                .context(focus_handle)
 7736                .when(run_to_cursor, |this| {
 7737                    let weak_editor = weak_editor.clone();
 7738                    this.entry("Run to cursor", None, move |window, cx| {
 7739                        weak_editor
 7740                            .update(cx, |editor, cx| {
 7741                                editor.change_selections(None, window, cx, |s| {
 7742                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7743                                });
 7744                            })
 7745                            .ok();
 7746
 7747                        window.dispatch_action(Box::new(RunToCursor), cx);
 7748                    })
 7749                    .separator()
 7750                })
 7751                .when_some(toggle_state_msg, |this, msg| {
 7752                    this.entry(msg, None, {
 7753                        let weak_editor = weak_editor.clone();
 7754                        let breakpoint = breakpoint.clone();
 7755                        move |_window, cx| {
 7756                            weak_editor
 7757                                .update(cx, |this, cx| {
 7758                                    this.edit_breakpoint_at_anchor(
 7759                                        anchor,
 7760                                        breakpoint.as_ref().clone(),
 7761                                        BreakpointEditAction::InvertState,
 7762                                        cx,
 7763                                    );
 7764                                })
 7765                                .log_err();
 7766                        }
 7767                    })
 7768                })
 7769                .entry(set_breakpoint_msg, None, {
 7770                    let weak_editor = weak_editor.clone();
 7771                    let breakpoint = breakpoint.clone();
 7772                    move |_window, cx| {
 7773                        weak_editor
 7774                            .update(cx, |this, cx| {
 7775                                this.edit_breakpoint_at_anchor(
 7776                                    anchor,
 7777                                    breakpoint.as_ref().clone(),
 7778                                    BreakpointEditAction::Toggle,
 7779                                    cx,
 7780                                );
 7781                            })
 7782                            .log_err();
 7783                    }
 7784                })
 7785                .entry(log_breakpoint_msg, None, {
 7786                    let breakpoint = breakpoint.clone();
 7787                    let weak_editor = weak_editor.clone();
 7788                    move |window, cx| {
 7789                        weak_editor
 7790                            .update(cx, |this, cx| {
 7791                                this.add_edit_breakpoint_block(
 7792                                    anchor,
 7793                                    breakpoint.as_ref(),
 7794                                    BreakpointPromptEditAction::Log,
 7795                                    window,
 7796                                    cx,
 7797                                );
 7798                            })
 7799                            .log_err();
 7800                    }
 7801                })
 7802                .entry(condition_breakpoint_msg, None, {
 7803                    let breakpoint = breakpoint.clone();
 7804                    let weak_editor = weak_editor.clone();
 7805                    move |window, cx| {
 7806                        weak_editor
 7807                            .update(cx, |this, cx| {
 7808                                this.add_edit_breakpoint_block(
 7809                                    anchor,
 7810                                    breakpoint.as_ref(),
 7811                                    BreakpointPromptEditAction::Condition,
 7812                                    window,
 7813                                    cx,
 7814                                );
 7815                            })
 7816                            .log_err();
 7817                    }
 7818                })
 7819                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7820                    weak_editor
 7821                        .update(cx, |this, cx| {
 7822                            this.add_edit_breakpoint_block(
 7823                                anchor,
 7824                                breakpoint.as_ref(),
 7825                                BreakpointPromptEditAction::HitCondition,
 7826                                window,
 7827                                cx,
 7828                            );
 7829                        })
 7830                        .log_err();
 7831                })
 7832        })
 7833    }
 7834
 7835    fn render_breakpoint(
 7836        &self,
 7837        position: Anchor,
 7838        row: DisplayRow,
 7839        breakpoint: &Breakpoint,
 7840        state: Option<BreakpointSessionState>,
 7841        cx: &mut Context<Self>,
 7842    ) -> IconButton {
 7843        let is_rejected = state.is_some_and(|s| !s.verified);
 7844        // Is it a breakpoint that shows up when hovering over gutter?
 7845        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7846            (false, false),
 7847            |PhantomBreakpointIndicator {
 7848                 is_active,
 7849                 display_row,
 7850                 collides_with_existing_breakpoint,
 7851             }| {
 7852                (
 7853                    is_active && display_row == row,
 7854                    collides_with_existing_breakpoint,
 7855                )
 7856            },
 7857        );
 7858
 7859        let (color, icon) = {
 7860            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7861                (false, false) => ui::IconName::DebugBreakpoint,
 7862                (true, false) => ui::IconName::DebugLogBreakpoint,
 7863                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7864                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7865            };
 7866
 7867            let color = if is_phantom {
 7868                Color::Hint
 7869            } else if is_rejected {
 7870                Color::Disabled
 7871            } else {
 7872                Color::Debugger
 7873            };
 7874
 7875            (color, icon)
 7876        };
 7877
 7878        let breakpoint = Arc::from(breakpoint.clone());
 7879
 7880        let alt_as_text = gpui::Keystroke {
 7881            modifiers: Modifiers::secondary_key(),
 7882            ..Default::default()
 7883        };
 7884        let primary_action_text = if breakpoint.is_disabled() {
 7885            "Enable breakpoint"
 7886        } else if is_phantom && !collides_with_existing {
 7887            "Set breakpoint"
 7888        } else {
 7889            "Unset breakpoint"
 7890        };
 7891        let focus_handle = self.focus_handle.clone();
 7892
 7893        let meta = if is_rejected {
 7894            SharedString::from("No executable code is associated with this line.")
 7895        } else if collides_with_existing && !breakpoint.is_disabled() {
 7896            SharedString::from(format!(
 7897                "{alt_as_text}-click to disable,\nright-click for more options."
 7898            ))
 7899        } else {
 7900            SharedString::from("Right-click for more options.")
 7901        };
 7902        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7903            .icon_size(IconSize::XSmall)
 7904            .size(ui::ButtonSize::None)
 7905            .when(is_rejected, |this| {
 7906                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7907            })
 7908            .icon_color(color)
 7909            .style(ButtonStyle::Transparent)
 7910            .on_click(cx.listener({
 7911                let breakpoint = breakpoint.clone();
 7912
 7913                move |editor, event: &ClickEvent, window, cx| {
 7914                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7915                        BreakpointEditAction::InvertState
 7916                    } else {
 7917                        BreakpointEditAction::Toggle
 7918                    };
 7919
 7920                    window.focus(&editor.focus_handle(cx));
 7921                    editor.edit_breakpoint_at_anchor(
 7922                        position,
 7923                        breakpoint.as_ref().clone(),
 7924                        edit_action,
 7925                        cx,
 7926                    );
 7927                }
 7928            }))
 7929            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7930                editor.set_breakpoint_context_menu(
 7931                    row,
 7932                    Some(position),
 7933                    event.down.position,
 7934                    window,
 7935                    cx,
 7936                );
 7937            }))
 7938            .tooltip(move |window, cx| {
 7939                Tooltip::with_meta_in(
 7940                    primary_action_text,
 7941                    Some(&ToggleBreakpoint),
 7942                    meta.clone(),
 7943                    &focus_handle,
 7944                    window,
 7945                    cx,
 7946                )
 7947            })
 7948    }
 7949
 7950    fn build_tasks_context(
 7951        project: &Entity<Project>,
 7952        buffer: &Entity<Buffer>,
 7953        buffer_row: u32,
 7954        tasks: &Arc<RunnableTasks>,
 7955        cx: &mut Context<Self>,
 7956    ) -> Task<Option<task::TaskContext>> {
 7957        let position = Point::new(buffer_row, tasks.column);
 7958        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7959        let location = Location {
 7960            buffer: buffer.clone(),
 7961            range: range_start..range_start,
 7962        };
 7963        // Fill in the environmental variables from the tree-sitter captures
 7964        let mut captured_task_variables = TaskVariables::default();
 7965        for (capture_name, value) in tasks.extra_variables.clone() {
 7966            captured_task_variables.insert(
 7967                task::VariableName::Custom(capture_name.into()),
 7968                value.clone(),
 7969            );
 7970        }
 7971        project.update(cx, |project, cx| {
 7972            project.task_store().update(cx, |task_store, cx| {
 7973                task_store.task_context_for_location(captured_task_variables, location, cx)
 7974            })
 7975        })
 7976    }
 7977
 7978    pub fn spawn_nearest_task(
 7979        &mut self,
 7980        action: &SpawnNearestTask,
 7981        window: &mut Window,
 7982        cx: &mut Context<Self>,
 7983    ) {
 7984        let Some((workspace, _)) = self.workspace.clone() else {
 7985            return;
 7986        };
 7987        let Some(project) = self.project.clone() else {
 7988            return;
 7989        };
 7990
 7991        // Try to find a closest, enclosing node using tree-sitter that has a
 7992        // task
 7993        let Some((buffer, buffer_row, tasks)) = self
 7994            .find_enclosing_node_task(cx)
 7995            // Or find the task that's closest in row-distance.
 7996            .or_else(|| self.find_closest_task(cx))
 7997        else {
 7998            return;
 7999        };
 8000
 8001        let reveal_strategy = action.reveal;
 8002        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8003        cx.spawn_in(window, async move |_, cx| {
 8004            let context = task_context.await?;
 8005            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8006
 8007            let resolved = &mut resolved_task.resolved;
 8008            resolved.reveal = reveal_strategy;
 8009
 8010            workspace
 8011                .update_in(cx, |workspace, window, cx| {
 8012                    workspace.schedule_resolved_task(
 8013                        task_source_kind,
 8014                        resolved_task,
 8015                        false,
 8016                        window,
 8017                        cx,
 8018                    );
 8019                })
 8020                .ok()
 8021        })
 8022        .detach();
 8023    }
 8024
 8025    fn find_closest_task(
 8026        &mut self,
 8027        cx: &mut Context<Self>,
 8028    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8029        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8030
 8031        let ((buffer_id, row), tasks) = self
 8032            .tasks
 8033            .iter()
 8034            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8035
 8036        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8037        let tasks = Arc::new(tasks.to_owned());
 8038        Some((buffer, *row, tasks))
 8039    }
 8040
 8041    fn find_enclosing_node_task(
 8042        &mut self,
 8043        cx: &mut Context<Self>,
 8044    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8045        let snapshot = self.buffer.read(cx).snapshot(cx);
 8046        let offset = self.selections.newest::<usize>(cx).head();
 8047        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8048        let buffer_id = excerpt.buffer().remote_id();
 8049
 8050        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8051        let mut cursor = layer.node().walk();
 8052
 8053        while cursor.goto_first_child_for_byte(offset).is_some() {
 8054            if cursor.node().end_byte() == offset {
 8055                cursor.goto_next_sibling();
 8056            }
 8057        }
 8058
 8059        // Ascend to the smallest ancestor that contains the range and has a task.
 8060        loop {
 8061            let node = cursor.node();
 8062            let node_range = node.byte_range();
 8063            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8064
 8065            // Check if this node contains our offset
 8066            if node_range.start <= offset && node_range.end >= offset {
 8067                // If it contains offset, check for task
 8068                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8069                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8070                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8071                }
 8072            }
 8073
 8074            if !cursor.goto_parent() {
 8075                break;
 8076            }
 8077        }
 8078        None
 8079    }
 8080
 8081    fn render_run_indicator(
 8082        &self,
 8083        _style: &EditorStyle,
 8084        is_active: bool,
 8085        row: DisplayRow,
 8086        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8087        cx: &mut Context<Self>,
 8088    ) -> IconButton {
 8089        let color = Color::Muted;
 8090        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8091
 8092        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8093            .shape(ui::IconButtonShape::Square)
 8094            .icon_size(IconSize::XSmall)
 8095            .icon_color(color)
 8096            .toggle_state(is_active)
 8097            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8098                let quick_launch = e.down.button == MouseButton::Left;
 8099                window.focus(&editor.focus_handle(cx));
 8100                editor.toggle_code_actions(
 8101                    &ToggleCodeActions {
 8102                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8103                        quick_launch,
 8104                    },
 8105                    window,
 8106                    cx,
 8107                );
 8108            }))
 8109            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8110                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8111            }))
 8112    }
 8113
 8114    pub fn context_menu_visible(&self) -> bool {
 8115        !self.edit_prediction_preview_is_active()
 8116            && self
 8117                .context_menu
 8118                .borrow()
 8119                .as_ref()
 8120                .map_or(false, |menu| menu.visible())
 8121    }
 8122
 8123    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8124        self.context_menu
 8125            .borrow()
 8126            .as_ref()
 8127            .map(|menu| menu.origin())
 8128    }
 8129
 8130    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8131        self.context_menu_options = Some(options);
 8132    }
 8133
 8134    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8135    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8136
 8137    fn render_edit_prediction_popover(
 8138        &mut self,
 8139        text_bounds: &Bounds<Pixels>,
 8140        content_origin: gpui::Point<Pixels>,
 8141        right_margin: Pixels,
 8142        editor_snapshot: &EditorSnapshot,
 8143        visible_row_range: Range<DisplayRow>,
 8144        scroll_top: f32,
 8145        scroll_bottom: f32,
 8146        line_layouts: &[LineWithInvisibles],
 8147        line_height: Pixels,
 8148        scroll_pixel_position: gpui::Point<Pixels>,
 8149        newest_selection_head: Option<DisplayPoint>,
 8150        editor_width: Pixels,
 8151        style: &EditorStyle,
 8152        window: &mut Window,
 8153        cx: &mut App,
 8154    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8155        if self.mode().is_minimap() {
 8156            return None;
 8157        }
 8158        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8159
 8160        if self.edit_prediction_visible_in_cursor_popover(true) {
 8161            return None;
 8162        }
 8163
 8164        match &active_inline_completion.completion {
 8165            InlineCompletion::Move { target, .. } => {
 8166                let target_display_point = target.to_display_point(editor_snapshot);
 8167
 8168                if self.edit_prediction_requires_modifier() {
 8169                    if !self.edit_prediction_preview_is_active() {
 8170                        return None;
 8171                    }
 8172
 8173                    self.render_edit_prediction_modifier_jump_popover(
 8174                        text_bounds,
 8175                        content_origin,
 8176                        visible_row_range,
 8177                        line_layouts,
 8178                        line_height,
 8179                        scroll_pixel_position,
 8180                        newest_selection_head,
 8181                        target_display_point,
 8182                        window,
 8183                        cx,
 8184                    )
 8185                } else {
 8186                    self.render_edit_prediction_eager_jump_popover(
 8187                        text_bounds,
 8188                        content_origin,
 8189                        editor_snapshot,
 8190                        visible_row_range,
 8191                        scroll_top,
 8192                        scroll_bottom,
 8193                        line_height,
 8194                        scroll_pixel_position,
 8195                        target_display_point,
 8196                        editor_width,
 8197                        window,
 8198                        cx,
 8199                    )
 8200                }
 8201            }
 8202            InlineCompletion::Edit {
 8203                display_mode: EditDisplayMode::Inline,
 8204                ..
 8205            } => None,
 8206            InlineCompletion::Edit {
 8207                display_mode: EditDisplayMode::TabAccept,
 8208                edits,
 8209                ..
 8210            } => {
 8211                let range = &edits.first()?.0;
 8212                let target_display_point = range.end.to_display_point(editor_snapshot);
 8213
 8214                self.render_edit_prediction_end_of_line_popover(
 8215                    "Accept",
 8216                    editor_snapshot,
 8217                    visible_row_range,
 8218                    target_display_point,
 8219                    line_height,
 8220                    scroll_pixel_position,
 8221                    content_origin,
 8222                    editor_width,
 8223                    window,
 8224                    cx,
 8225                )
 8226            }
 8227            InlineCompletion::Edit {
 8228                edits,
 8229                edit_preview,
 8230                display_mode: EditDisplayMode::DiffPopover,
 8231                snapshot,
 8232            } => self.render_edit_prediction_diff_popover(
 8233                text_bounds,
 8234                content_origin,
 8235                right_margin,
 8236                editor_snapshot,
 8237                visible_row_range,
 8238                line_layouts,
 8239                line_height,
 8240                scroll_pixel_position,
 8241                newest_selection_head,
 8242                editor_width,
 8243                style,
 8244                edits,
 8245                edit_preview,
 8246                snapshot,
 8247                window,
 8248                cx,
 8249            ),
 8250        }
 8251    }
 8252
 8253    fn render_edit_prediction_modifier_jump_popover(
 8254        &mut self,
 8255        text_bounds: &Bounds<Pixels>,
 8256        content_origin: gpui::Point<Pixels>,
 8257        visible_row_range: Range<DisplayRow>,
 8258        line_layouts: &[LineWithInvisibles],
 8259        line_height: Pixels,
 8260        scroll_pixel_position: gpui::Point<Pixels>,
 8261        newest_selection_head: Option<DisplayPoint>,
 8262        target_display_point: DisplayPoint,
 8263        window: &mut Window,
 8264        cx: &mut App,
 8265    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8266        let scrolled_content_origin =
 8267            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8268
 8269        const SCROLL_PADDING_Y: Pixels = px(12.);
 8270
 8271        if target_display_point.row() < visible_row_range.start {
 8272            return self.render_edit_prediction_scroll_popover(
 8273                |_| SCROLL_PADDING_Y,
 8274                IconName::ArrowUp,
 8275                visible_row_range,
 8276                line_layouts,
 8277                newest_selection_head,
 8278                scrolled_content_origin,
 8279                window,
 8280                cx,
 8281            );
 8282        } else if target_display_point.row() >= visible_row_range.end {
 8283            return self.render_edit_prediction_scroll_popover(
 8284                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8285                IconName::ArrowDown,
 8286                visible_row_range,
 8287                line_layouts,
 8288                newest_selection_head,
 8289                scrolled_content_origin,
 8290                window,
 8291                cx,
 8292            );
 8293        }
 8294
 8295        const POLE_WIDTH: Pixels = px(2.);
 8296
 8297        let line_layout =
 8298            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8299        let target_column = target_display_point.column() as usize;
 8300
 8301        let target_x = line_layout.x_for_index(target_column);
 8302        let target_y =
 8303            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8304
 8305        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8306
 8307        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8308        border_color.l += 0.001;
 8309
 8310        let mut element = v_flex()
 8311            .items_end()
 8312            .when(flag_on_right, |el| el.items_start())
 8313            .child(if flag_on_right {
 8314                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8315                    .rounded_bl(px(0.))
 8316                    .rounded_tl(px(0.))
 8317                    .border_l_2()
 8318                    .border_color(border_color)
 8319            } else {
 8320                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8321                    .rounded_br(px(0.))
 8322                    .rounded_tr(px(0.))
 8323                    .border_r_2()
 8324                    .border_color(border_color)
 8325            })
 8326            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8327            .into_any();
 8328
 8329        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8330
 8331        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8332            - point(
 8333                if flag_on_right {
 8334                    POLE_WIDTH
 8335                } else {
 8336                    size.width - POLE_WIDTH
 8337                },
 8338                size.height - line_height,
 8339            );
 8340
 8341        origin.x = origin.x.max(content_origin.x);
 8342
 8343        element.prepaint_at(origin, window, cx);
 8344
 8345        Some((element, origin))
 8346    }
 8347
 8348    fn render_edit_prediction_scroll_popover(
 8349        &mut self,
 8350        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8351        scroll_icon: IconName,
 8352        visible_row_range: Range<DisplayRow>,
 8353        line_layouts: &[LineWithInvisibles],
 8354        newest_selection_head: Option<DisplayPoint>,
 8355        scrolled_content_origin: gpui::Point<Pixels>,
 8356        window: &mut Window,
 8357        cx: &mut App,
 8358    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8359        let mut element = self
 8360            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8361            .into_any();
 8362
 8363        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8364
 8365        let cursor = newest_selection_head?;
 8366        let cursor_row_layout =
 8367            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8368        let cursor_column = cursor.column() as usize;
 8369
 8370        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8371
 8372        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8373
 8374        element.prepaint_at(origin, window, cx);
 8375        Some((element, origin))
 8376    }
 8377
 8378    fn render_edit_prediction_eager_jump_popover(
 8379        &mut self,
 8380        text_bounds: &Bounds<Pixels>,
 8381        content_origin: gpui::Point<Pixels>,
 8382        editor_snapshot: &EditorSnapshot,
 8383        visible_row_range: Range<DisplayRow>,
 8384        scroll_top: f32,
 8385        scroll_bottom: f32,
 8386        line_height: Pixels,
 8387        scroll_pixel_position: gpui::Point<Pixels>,
 8388        target_display_point: DisplayPoint,
 8389        editor_width: Pixels,
 8390        window: &mut Window,
 8391        cx: &mut App,
 8392    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8393        if target_display_point.row().as_f32() < scroll_top {
 8394            let mut element = self
 8395                .render_edit_prediction_line_popover(
 8396                    "Jump to Edit",
 8397                    Some(IconName::ArrowUp),
 8398                    window,
 8399                    cx,
 8400                )?
 8401                .into_any();
 8402
 8403            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8404            let offset = point(
 8405                (text_bounds.size.width - size.width) / 2.,
 8406                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8407            );
 8408
 8409            let origin = text_bounds.origin + offset;
 8410            element.prepaint_at(origin, window, cx);
 8411            Some((element, origin))
 8412        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8413            let mut element = self
 8414                .render_edit_prediction_line_popover(
 8415                    "Jump to Edit",
 8416                    Some(IconName::ArrowDown),
 8417                    window,
 8418                    cx,
 8419                )?
 8420                .into_any();
 8421
 8422            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8423            let offset = point(
 8424                (text_bounds.size.width - size.width) / 2.,
 8425                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8426            );
 8427
 8428            let origin = text_bounds.origin + offset;
 8429            element.prepaint_at(origin, window, cx);
 8430            Some((element, origin))
 8431        } else {
 8432            self.render_edit_prediction_end_of_line_popover(
 8433                "Jump to Edit",
 8434                editor_snapshot,
 8435                visible_row_range,
 8436                target_display_point,
 8437                line_height,
 8438                scroll_pixel_position,
 8439                content_origin,
 8440                editor_width,
 8441                window,
 8442                cx,
 8443            )
 8444        }
 8445    }
 8446
 8447    fn render_edit_prediction_end_of_line_popover(
 8448        self: &mut Editor,
 8449        label: &'static str,
 8450        editor_snapshot: &EditorSnapshot,
 8451        visible_row_range: Range<DisplayRow>,
 8452        target_display_point: DisplayPoint,
 8453        line_height: Pixels,
 8454        scroll_pixel_position: gpui::Point<Pixels>,
 8455        content_origin: gpui::Point<Pixels>,
 8456        editor_width: Pixels,
 8457        window: &mut Window,
 8458        cx: &mut App,
 8459    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8460        let target_line_end = DisplayPoint::new(
 8461            target_display_point.row(),
 8462            editor_snapshot.line_len(target_display_point.row()),
 8463        );
 8464
 8465        let mut element = self
 8466            .render_edit_prediction_line_popover(label, None, window, cx)?
 8467            .into_any();
 8468
 8469        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8470
 8471        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8472
 8473        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8474        let mut origin = start_point
 8475            + line_origin
 8476            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8477        origin.x = origin.x.max(content_origin.x);
 8478
 8479        let max_x = content_origin.x + editor_width - size.width;
 8480
 8481        if origin.x > max_x {
 8482            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8483
 8484            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8485                origin.y += offset;
 8486                IconName::ArrowUp
 8487            } else {
 8488                origin.y -= offset;
 8489                IconName::ArrowDown
 8490            };
 8491
 8492            element = self
 8493                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8494                .into_any();
 8495
 8496            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8497
 8498            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8499        }
 8500
 8501        element.prepaint_at(origin, window, cx);
 8502        Some((element, origin))
 8503    }
 8504
 8505    fn render_edit_prediction_diff_popover(
 8506        self: &Editor,
 8507        text_bounds: &Bounds<Pixels>,
 8508        content_origin: gpui::Point<Pixels>,
 8509        right_margin: Pixels,
 8510        editor_snapshot: &EditorSnapshot,
 8511        visible_row_range: Range<DisplayRow>,
 8512        line_layouts: &[LineWithInvisibles],
 8513        line_height: Pixels,
 8514        scroll_pixel_position: gpui::Point<Pixels>,
 8515        newest_selection_head: Option<DisplayPoint>,
 8516        editor_width: Pixels,
 8517        style: &EditorStyle,
 8518        edits: &Vec<(Range<Anchor>, String)>,
 8519        edit_preview: &Option<language::EditPreview>,
 8520        snapshot: &language::BufferSnapshot,
 8521        window: &mut Window,
 8522        cx: &mut App,
 8523    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8524        let edit_start = edits
 8525            .first()
 8526            .unwrap()
 8527            .0
 8528            .start
 8529            .to_display_point(editor_snapshot);
 8530        let edit_end = edits
 8531            .last()
 8532            .unwrap()
 8533            .0
 8534            .end
 8535            .to_display_point(editor_snapshot);
 8536
 8537        let is_visible = visible_row_range.contains(&edit_start.row())
 8538            || visible_row_range.contains(&edit_end.row());
 8539        if !is_visible {
 8540            return None;
 8541        }
 8542
 8543        let highlighted_edits =
 8544            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8545
 8546        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8547        let line_count = highlighted_edits.text.lines().count();
 8548
 8549        const BORDER_WIDTH: Pixels = px(1.);
 8550
 8551        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8552        let has_keybind = keybind.is_some();
 8553
 8554        let mut element = h_flex()
 8555            .items_start()
 8556            .child(
 8557                h_flex()
 8558                    .bg(cx.theme().colors().editor_background)
 8559                    .border(BORDER_WIDTH)
 8560                    .shadow_sm()
 8561                    .border_color(cx.theme().colors().border)
 8562                    .rounded_l_lg()
 8563                    .when(line_count > 1, |el| el.rounded_br_lg())
 8564                    .pr_1()
 8565                    .child(styled_text),
 8566            )
 8567            .child(
 8568                h_flex()
 8569                    .h(line_height + BORDER_WIDTH * 2.)
 8570                    .px_1p5()
 8571                    .gap_1()
 8572                    // Workaround: For some reason, there's a gap if we don't do this
 8573                    .ml(-BORDER_WIDTH)
 8574                    .shadow(vec![gpui::BoxShadow {
 8575                        color: gpui::black().opacity(0.05),
 8576                        offset: point(px(1.), px(1.)),
 8577                        blur_radius: px(2.),
 8578                        spread_radius: px(0.),
 8579                    }])
 8580                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8581                    .border(BORDER_WIDTH)
 8582                    .border_color(cx.theme().colors().border)
 8583                    .rounded_r_lg()
 8584                    .id("edit_prediction_diff_popover_keybind")
 8585                    .when(!has_keybind, |el| {
 8586                        let status_colors = cx.theme().status();
 8587
 8588                        el.bg(status_colors.error_background)
 8589                            .border_color(status_colors.error.opacity(0.6))
 8590                            .child(Icon::new(IconName::Info).color(Color::Error))
 8591                            .cursor_default()
 8592                            .hoverable_tooltip(move |_window, cx| {
 8593                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8594                            })
 8595                    })
 8596                    .children(keybind),
 8597            )
 8598            .into_any();
 8599
 8600        let longest_row =
 8601            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8602        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8603            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8604        } else {
 8605            layout_line(
 8606                longest_row,
 8607                editor_snapshot,
 8608                style,
 8609                editor_width,
 8610                |_| false,
 8611                window,
 8612                cx,
 8613            )
 8614            .width
 8615        };
 8616
 8617        let viewport_bounds =
 8618            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8619                right: -right_margin,
 8620                ..Default::default()
 8621            });
 8622
 8623        let x_after_longest =
 8624            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8625                - scroll_pixel_position.x;
 8626
 8627        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8628
 8629        // Fully visible if it can be displayed within the window (allow overlapping other
 8630        // panes). However, this is only allowed if the popover starts within text_bounds.
 8631        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8632            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8633
 8634        let mut origin = if can_position_to_the_right {
 8635            point(
 8636                x_after_longest,
 8637                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8638                    - scroll_pixel_position.y,
 8639            )
 8640        } else {
 8641            let cursor_row = newest_selection_head.map(|head| head.row());
 8642            let above_edit = edit_start
 8643                .row()
 8644                .0
 8645                .checked_sub(line_count as u32)
 8646                .map(DisplayRow);
 8647            let below_edit = Some(edit_end.row() + 1);
 8648            let above_cursor =
 8649                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8650            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8651
 8652            // Place the edit popover adjacent to the edit if there is a location
 8653            // available that is onscreen and does not obscure the cursor. Otherwise,
 8654            // place it adjacent to the cursor.
 8655            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8656                .into_iter()
 8657                .flatten()
 8658                .find(|&start_row| {
 8659                    let end_row = start_row + line_count as u32;
 8660                    visible_row_range.contains(&start_row)
 8661                        && visible_row_range.contains(&end_row)
 8662                        && cursor_row.map_or(true, |cursor_row| {
 8663                            !((start_row..end_row).contains(&cursor_row))
 8664                        })
 8665                })?;
 8666
 8667            content_origin
 8668                + point(
 8669                    -scroll_pixel_position.x,
 8670                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8671                )
 8672        };
 8673
 8674        origin.x -= BORDER_WIDTH;
 8675
 8676        window.defer_draw(element, origin, 1);
 8677
 8678        // Do not return an element, since it will already be drawn due to defer_draw.
 8679        None
 8680    }
 8681
 8682    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8683        px(30.)
 8684    }
 8685
 8686    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8687        if self.read_only(cx) {
 8688            cx.theme().players().read_only()
 8689        } else {
 8690            self.style.as_ref().unwrap().local_player
 8691        }
 8692    }
 8693
 8694    fn render_edit_prediction_accept_keybind(
 8695        &self,
 8696        window: &mut Window,
 8697        cx: &App,
 8698    ) -> Option<AnyElement> {
 8699        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8700        let accept_keystroke = accept_binding.keystroke()?;
 8701
 8702        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8703
 8704        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8705            Color::Accent
 8706        } else {
 8707            Color::Muted
 8708        };
 8709
 8710        h_flex()
 8711            .px_0p5()
 8712            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8713            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8714            .text_size(TextSize::XSmall.rems(cx))
 8715            .child(h_flex().children(ui::render_modifiers(
 8716                &accept_keystroke.modifiers,
 8717                PlatformStyle::platform(),
 8718                Some(modifiers_color),
 8719                Some(IconSize::XSmall.rems().into()),
 8720                true,
 8721            )))
 8722            .when(is_platform_style_mac, |parent| {
 8723                parent.child(accept_keystroke.key.clone())
 8724            })
 8725            .when(!is_platform_style_mac, |parent| {
 8726                parent.child(
 8727                    Key::new(
 8728                        util::capitalize(&accept_keystroke.key),
 8729                        Some(Color::Default),
 8730                    )
 8731                    .size(Some(IconSize::XSmall.rems().into())),
 8732                )
 8733            })
 8734            .into_any()
 8735            .into()
 8736    }
 8737
 8738    fn render_edit_prediction_line_popover(
 8739        &self,
 8740        label: impl Into<SharedString>,
 8741        icon: Option<IconName>,
 8742        window: &mut Window,
 8743        cx: &App,
 8744    ) -> Option<Stateful<Div>> {
 8745        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8746
 8747        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8748        let has_keybind = keybind.is_some();
 8749
 8750        let result = h_flex()
 8751            .id("ep-line-popover")
 8752            .py_0p5()
 8753            .pl_1()
 8754            .pr(padding_right)
 8755            .gap_1()
 8756            .rounded_md()
 8757            .border_1()
 8758            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8759            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8760            .shadow_sm()
 8761            .when(!has_keybind, |el| {
 8762                let status_colors = cx.theme().status();
 8763
 8764                el.bg(status_colors.error_background)
 8765                    .border_color(status_colors.error.opacity(0.6))
 8766                    .pl_2()
 8767                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8768                    .cursor_default()
 8769                    .hoverable_tooltip(move |_window, cx| {
 8770                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8771                    })
 8772            })
 8773            .children(keybind)
 8774            .child(
 8775                Label::new(label)
 8776                    .size(LabelSize::Small)
 8777                    .when(!has_keybind, |el| {
 8778                        el.color(cx.theme().status().error.into()).strikethrough()
 8779                    }),
 8780            )
 8781            .when(!has_keybind, |el| {
 8782                el.child(
 8783                    h_flex().ml_1().child(
 8784                        Icon::new(IconName::Info)
 8785                            .size(IconSize::Small)
 8786                            .color(cx.theme().status().error.into()),
 8787                    ),
 8788                )
 8789            })
 8790            .when_some(icon, |element, icon| {
 8791                element.child(
 8792                    div()
 8793                        .mt(px(1.5))
 8794                        .child(Icon::new(icon).size(IconSize::Small)),
 8795                )
 8796            });
 8797
 8798        Some(result)
 8799    }
 8800
 8801    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8802        let accent_color = cx.theme().colors().text_accent;
 8803        let editor_bg_color = cx.theme().colors().editor_background;
 8804        editor_bg_color.blend(accent_color.opacity(0.1))
 8805    }
 8806
 8807    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8808        let accent_color = cx.theme().colors().text_accent;
 8809        let editor_bg_color = cx.theme().colors().editor_background;
 8810        editor_bg_color.blend(accent_color.opacity(0.6))
 8811    }
 8812
 8813    fn render_edit_prediction_cursor_popover(
 8814        &self,
 8815        min_width: Pixels,
 8816        max_width: Pixels,
 8817        cursor_point: Point,
 8818        style: &EditorStyle,
 8819        accept_keystroke: Option<&gpui::Keystroke>,
 8820        _window: &Window,
 8821        cx: &mut Context<Editor>,
 8822    ) -> Option<AnyElement> {
 8823        let provider = self.edit_prediction_provider.as_ref()?;
 8824
 8825        if provider.provider.needs_terms_acceptance(cx) {
 8826            return Some(
 8827                h_flex()
 8828                    .min_w(min_width)
 8829                    .flex_1()
 8830                    .px_2()
 8831                    .py_1()
 8832                    .gap_3()
 8833                    .elevation_2(cx)
 8834                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8835                    .id("accept-terms")
 8836                    .cursor_pointer()
 8837                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8838                    .on_click(cx.listener(|this, _event, window, cx| {
 8839                        cx.stop_propagation();
 8840                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8841                        window.dispatch_action(
 8842                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8843                            cx,
 8844                        );
 8845                    }))
 8846                    .child(
 8847                        h_flex()
 8848                            .flex_1()
 8849                            .gap_2()
 8850                            .child(Icon::new(IconName::ZedPredict))
 8851                            .child(Label::new("Accept Terms of Service"))
 8852                            .child(div().w_full())
 8853                            .child(
 8854                                Icon::new(IconName::ArrowUpRight)
 8855                                    .color(Color::Muted)
 8856                                    .size(IconSize::Small),
 8857                            )
 8858                            .into_any_element(),
 8859                    )
 8860                    .into_any(),
 8861            );
 8862        }
 8863
 8864        let is_refreshing = provider.provider.is_refreshing(cx);
 8865
 8866        fn pending_completion_container() -> Div {
 8867            h_flex()
 8868                .h_full()
 8869                .flex_1()
 8870                .gap_2()
 8871                .child(Icon::new(IconName::ZedPredict))
 8872        }
 8873
 8874        let completion = match &self.active_inline_completion {
 8875            Some(prediction) => {
 8876                if !self.has_visible_completions_menu() {
 8877                    const RADIUS: Pixels = px(6.);
 8878                    const BORDER_WIDTH: Pixels = px(1.);
 8879
 8880                    return Some(
 8881                        h_flex()
 8882                            .elevation_2(cx)
 8883                            .border(BORDER_WIDTH)
 8884                            .border_color(cx.theme().colors().border)
 8885                            .when(accept_keystroke.is_none(), |el| {
 8886                                el.border_color(cx.theme().status().error)
 8887                            })
 8888                            .rounded(RADIUS)
 8889                            .rounded_tl(px(0.))
 8890                            .overflow_hidden()
 8891                            .child(div().px_1p5().child(match &prediction.completion {
 8892                                InlineCompletion::Move { target, snapshot } => {
 8893                                    use text::ToPoint as _;
 8894                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8895                                    {
 8896                                        Icon::new(IconName::ZedPredictDown)
 8897                                    } else {
 8898                                        Icon::new(IconName::ZedPredictUp)
 8899                                    }
 8900                                }
 8901                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8902                            }))
 8903                            .child(
 8904                                h_flex()
 8905                                    .gap_1()
 8906                                    .py_1()
 8907                                    .px_2()
 8908                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8909                                    .border_l_1()
 8910                                    .border_color(cx.theme().colors().border)
 8911                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8912                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8913                                        el.child(
 8914                                            Label::new("Hold")
 8915                                                .size(LabelSize::Small)
 8916                                                .when(accept_keystroke.is_none(), |el| {
 8917                                                    el.strikethrough()
 8918                                                })
 8919                                                .line_height_style(LineHeightStyle::UiLabel),
 8920                                        )
 8921                                    })
 8922                                    .id("edit_prediction_cursor_popover_keybind")
 8923                                    .when(accept_keystroke.is_none(), |el| {
 8924                                        let status_colors = cx.theme().status();
 8925
 8926                                        el.bg(status_colors.error_background)
 8927                                            .border_color(status_colors.error.opacity(0.6))
 8928                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8929                                            .cursor_default()
 8930                                            .hoverable_tooltip(move |_window, cx| {
 8931                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8932                                                    .into()
 8933                                            })
 8934                                    })
 8935                                    .when_some(
 8936                                        accept_keystroke.as_ref(),
 8937                                        |el, accept_keystroke| {
 8938                                            el.child(h_flex().children(ui::render_modifiers(
 8939                                                &accept_keystroke.modifiers,
 8940                                                PlatformStyle::platform(),
 8941                                                Some(Color::Default),
 8942                                                Some(IconSize::XSmall.rems().into()),
 8943                                                false,
 8944                                            )))
 8945                                        },
 8946                                    ),
 8947                            )
 8948                            .into_any(),
 8949                    );
 8950                }
 8951
 8952                self.render_edit_prediction_cursor_popover_preview(
 8953                    prediction,
 8954                    cursor_point,
 8955                    style,
 8956                    cx,
 8957                )?
 8958            }
 8959
 8960            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8961                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8962                    stale_completion,
 8963                    cursor_point,
 8964                    style,
 8965                    cx,
 8966                )?,
 8967
 8968                None => {
 8969                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8970                }
 8971            },
 8972
 8973            None => pending_completion_container().child(Label::new("No Prediction")),
 8974        };
 8975
 8976        let completion = if is_refreshing {
 8977            completion
 8978                .with_animation(
 8979                    "loading-completion",
 8980                    Animation::new(Duration::from_secs(2))
 8981                        .repeat()
 8982                        .with_easing(pulsating_between(0.4, 0.8)),
 8983                    |label, delta| label.opacity(delta),
 8984                )
 8985                .into_any_element()
 8986        } else {
 8987            completion.into_any_element()
 8988        };
 8989
 8990        let has_completion = self.active_inline_completion.is_some();
 8991
 8992        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8993        Some(
 8994            h_flex()
 8995                .min_w(min_width)
 8996                .max_w(max_width)
 8997                .flex_1()
 8998                .elevation_2(cx)
 8999                .border_color(cx.theme().colors().border)
 9000                .child(
 9001                    div()
 9002                        .flex_1()
 9003                        .py_1()
 9004                        .px_2()
 9005                        .overflow_hidden()
 9006                        .child(completion),
 9007                )
 9008                .when_some(accept_keystroke, |el, accept_keystroke| {
 9009                    if !accept_keystroke.modifiers.modified() {
 9010                        return el;
 9011                    }
 9012
 9013                    el.child(
 9014                        h_flex()
 9015                            .h_full()
 9016                            .border_l_1()
 9017                            .rounded_r_lg()
 9018                            .border_color(cx.theme().colors().border)
 9019                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9020                            .gap_1()
 9021                            .py_1()
 9022                            .px_2()
 9023                            .child(
 9024                                h_flex()
 9025                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9026                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9027                                    .child(h_flex().children(ui::render_modifiers(
 9028                                        &accept_keystroke.modifiers,
 9029                                        PlatformStyle::platform(),
 9030                                        Some(if !has_completion {
 9031                                            Color::Muted
 9032                                        } else {
 9033                                            Color::Default
 9034                                        }),
 9035                                        None,
 9036                                        false,
 9037                                    ))),
 9038                            )
 9039                            .child(Label::new("Preview").into_any_element())
 9040                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9041                    )
 9042                })
 9043                .into_any(),
 9044        )
 9045    }
 9046
 9047    fn render_edit_prediction_cursor_popover_preview(
 9048        &self,
 9049        completion: &InlineCompletionState,
 9050        cursor_point: Point,
 9051        style: &EditorStyle,
 9052        cx: &mut Context<Editor>,
 9053    ) -> Option<Div> {
 9054        use text::ToPoint as _;
 9055
 9056        fn render_relative_row_jump(
 9057            prefix: impl Into<String>,
 9058            current_row: u32,
 9059            target_row: u32,
 9060        ) -> Div {
 9061            let (row_diff, arrow) = if target_row < current_row {
 9062                (current_row - target_row, IconName::ArrowUp)
 9063            } else {
 9064                (target_row - current_row, IconName::ArrowDown)
 9065            };
 9066
 9067            h_flex()
 9068                .child(
 9069                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9070                        .color(Color::Muted)
 9071                        .size(LabelSize::Small),
 9072                )
 9073                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9074        }
 9075
 9076        match &completion.completion {
 9077            InlineCompletion::Move {
 9078                target, snapshot, ..
 9079            } => Some(
 9080                h_flex()
 9081                    .px_2()
 9082                    .gap_2()
 9083                    .flex_1()
 9084                    .child(
 9085                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9086                            Icon::new(IconName::ZedPredictDown)
 9087                        } else {
 9088                            Icon::new(IconName::ZedPredictUp)
 9089                        },
 9090                    )
 9091                    .child(Label::new("Jump to Edit")),
 9092            ),
 9093
 9094            InlineCompletion::Edit {
 9095                edits,
 9096                edit_preview,
 9097                snapshot,
 9098                display_mode: _,
 9099            } => {
 9100                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9101
 9102                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9103                    &snapshot,
 9104                    &edits,
 9105                    edit_preview.as_ref()?,
 9106                    true,
 9107                    cx,
 9108                )
 9109                .first_line_preview();
 9110
 9111                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9112                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9113
 9114                let preview = h_flex()
 9115                    .gap_1()
 9116                    .min_w_16()
 9117                    .child(styled_text)
 9118                    .when(has_more_lines, |parent| parent.child(""));
 9119
 9120                let left = if first_edit_row != cursor_point.row {
 9121                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9122                        .into_any_element()
 9123                } else {
 9124                    Icon::new(IconName::ZedPredict).into_any_element()
 9125                };
 9126
 9127                Some(
 9128                    h_flex()
 9129                        .h_full()
 9130                        .flex_1()
 9131                        .gap_2()
 9132                        .pr_1()
 9133                        .overflow_x_hidden()
 9134                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9135                        .child(left)
 9136                        .child(preview),
 9137                )
 9138            }
 9139        }
 9140    }
 9141
 9142    pub fn render_context_menu(
 9143        &self,
 9144        style: &EditorStyle,
 9145        max_height_in_lines: u32,
 9146        window: &mut Window,
 9147        cx: &mut Context<Editor>,
 9148    ) -> Option<AnyElement> {
 9149        let menu = self.context_menu.borrow();
 9150        let menu = menu.as_ref()?;
 9151        if !menu.visible() {
 9152            return None;
 9153        };
 9154        Some(menu.render(style, max_height_in_lines, window, cx))
 9155    }
 9156
 9157    fn render_context_menu_aside(
 9158        &mut self,
 9159        max_size: Size<Pixels>,
 9160        window: &mut Window,
 9161        cx: &mut Context<Editor>,
 9162    ) -> Option<AnyElement> {
 9163        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9164            if menu.visible() {
 9165                menu.render_aside(max_size, window, cx)
 9166            } else {
 9167                None
 9168            }
 9169        })
 9170    }
 9171
 9172    fn hide_context_menu(
 9173        &mut self,
 9174        window: &mut Window,
 9175        cx: &mut Context<Self>,
 9176    ) -> Option<CodeContextMenu> {
 9177        cx.notify();
 9178        self.completion_tasks.clear();
 9179        let context_menu = self.context_menu.borrow_mut().take();
 9180        self.stale_inline_completion_in_menu.take();
 9181        self.update_visible_inline_completion(window, cx);
 9182        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9183            if let Some(completion_provider) = &self.completion_provider {
 9184                completion_provider.selection_changed(None, window, cx);
 9185            }
 9186        }
 9187        context_menu
 9188    }
 9189
 9190    fn show_snippet_choices(
 9191        &mut self,
 9192        choices: &Vec<String>,
 9193        selection: Range<Anchor>,
 9194        cx: &mut Context<Self>,
 9195    ) {
 9196        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9197            (Some(a), Some(b)) if a == b => a,
 9198            _ => {
 9199                log::error!("expected anchor range to have matching buffer IDs");
 9200                return;
 9201            }
 9202        };
 9203        let multi_buffer = self.buffer().read(cx);
 9204        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9205            return;
 9206        };
 9207
 9208        let id = post_inc(&mut self.next_completion_id);
 9209        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9210        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9211            CompletionsMenu::new_snippet_choices(
 9212                id,
 9213                true,
 9214                choices,
 9215                selection,
 9216                buffer,
 9217                snippet_sort_order,
 9218            ),
 9219        ));
 9220    }
 9221
 9222    pub fn insert_snippet(
 9223        &mut self,
 9224        insertion_ranges: &[Range<usize>],
 9225        snippet: Snippet,
 9226        window: &mut Window,
 9227        cx: &mut Context<Self>,
 9228    ) -> Result<()> {
 9229        struct Tabstop<T> {
 9230            is_end_tabstop: bool,
 9231            ranges: Vec<Range<T>>,
 9232            choices: Option<Vec<String>>,
 9233        }
 9234
 9235        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9236            let snippet_text: Arc<str> = snippet.text.clone().into();
 9237            let edits = insertion_ranges
 9238                .iter()
 9239                .cloned()
 9240                .map(|range| (range, snippet_text.clone()));
 9241            let autoindent_mode = AutoindentMode::Block {
 9242                original_indent_columns: Vec::new(),
 9243            };
 9244            buffer.edit(edits, Some(autoindent_mode), cx);
 9245
 9246            let snapshot = &*buffer.read(cx);
 9247            let snippet = &snippet;
 9248            snippet
 9249                .tabstops
 9250                .iter()
 9251                .map(|tabstop| {
 9252                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9253                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9254                    });
 9255                    let mut tabstop_ranges = tabstop
 9256                        .ranges
 9257                        .iter()
 9258                        .flat_map(|tabstop_range| {
 9259                            let mut delta = 0_isize;
 9260                            insertion_ranges.iter().map(move |insertion_range| {
 9261                                let insertion_start = insertion_range.start as isize + delta;
 9262                                delta +=
 9263                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9264
 9265                                let start = ((insertion_start + tabstop_range.start) as usize)
 9266                                    .min(snapshot.len());
 9267                                let end = ((insertion_start + tabstop_range.end) as usize)
 9268                                    .min(snapshot.len());
 9269                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9270                            })
 9271                        })
 9272                        .collect::<Vec<_>>();
 9273                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9274
 9275                    Tabstop {
 9276                        is_end_tabstop,
 9277                        ranges: tabstop_ranges,
 9278                        choices: tabstop.choices.clone(),
 9279                    }
 9280                })
 9281                .collect::<Vec<_>>()
 9282        });
 9283        if let Some(tabstop) = tabstops.first() {
 9284            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9285                // Reverse order so that the first range is the newest created selection.
 9286                // Completions will use it and autoscroll will prioritize it.
 9287                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9288            });
 9289
 9290            if let Some(choices) = &tabstop.choices {
 9291                if let Some(selection) = tabstop.ranges.first() {
 9292                    self.show_snippet_choices(choices, selection.clone(), cx)
 9293                }
 9294            }
 9295
 9296            // If we're already at the last tabstop and it's at the end of the snippet,
 9297            // we're done, we don't need to keep the state around.
 9298            if !tabstop.is_end_tabstop {
 9299                let choices = tabstops
 9300                    .iter()
 9301                    .map(|tabstop| tabstop.choices.clone())
 9302                    .collect();
 9303
 9304                let ranges = tabstops
 9305                    .into_iter()
 9306                    .map(|tabstop| tabstop.ranges)
 9307                    .collect::<Vec<_>>();
 9308
 9309                self.snippet_stack.push(SnippetState {
 9310                    active_index: 0,
 9311                    ranges,
 9312                    choices,
 9313                });
 9314            }
 9315
 9316            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9317            if self.autoclose_regions.is_empty() {
 9318                let snapshot = self.buffer.read(cx).snapshot(cx);
 9319                for selection in &mut self.selections.all::<Point>(cx) {
 9320                    let selection_head = selection.head();
 9321                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9322                        continue;
 9323                    };
 9324
 9325                    let mut bracket_pair = None;
 9326                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9327                    let prev_chars = snapshot
 9328                        .reversed_chars_at(selection_head)
 9329                        .collect::<String>();
 9330                    for (pair, enabled) in scope.brackets() {
 9331                        if enabled
 9332                            && pair.close
 9333                            && prev_chars.starts_with(pair.start.as_str())
 9334                            && next_chars.starts_with(pair.end.as_str())
 9335                        {
 9336                            bracket_pair = Some(pair.clone());
 9337                            break;
 9338                        }
 9339                    }
 9340                    if let Some(pair) = bracket_pair {
 9341                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9342                        let autoclose_enabled =
 9343                            self.use_autoclose && snapshot_settings.use_autoclose;
 9344                        if autoclose_enabled {
 9345                            let start = snapshot.anchor_after(selection_head);
 9346                            let end = snapshot.anchor_after(selection_head);
 9347                            self.autoclose_regions.push(AutocloseRegion {
 9348                                selection_id: selection.id,
 9349                                range: start..end,
 9350                                pair,
 9351                            });
 9352                        }
 9353                    }
 9354                }
 9355            }
 9356        }
 9357        Ok(())
 9358    }
 9359
 9360    pub fn move_to_next_snippet_tabstop(
 9361        &mut self,
 9362        window: &mut Window,
 9363        cx: &mut Context<Self>,
 9364    ) -> bool {
 9365        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9366    }
 9367
 9368    pub fn move_to_prev_snippet_tabstop(
 9369        &mut self,
 9370        window: &mut Window,
 9371        cx: &mut Context<Self>,
 9372    ) -> bool {
 9373        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9374    }
 9375
 9376    pub fn move_to_snippet_tabstop(
 9377        &mut self,
 9378        bias: Bias,
 9379        window: &mut Window,
 9380        cx: &mut Context<Self>,
 9381    ) -> bool {
 9382        if let Some(mut snippet) = self.snippet_stack.pop() {
 9383            match bias {
 9384                Bias::Left => {
 9385                    if snippet.active_index > 0 {
 9386                        snippet.active_index -= 1;
 9387                    } else {
 9388                        self.snippet_stack.push(snippet);
 9389                        return false;
 9390                    }
 9391                }
 9392                Bias::Right => {
 9393                    if snippet.active_index + 1 < snippet.ranges.len() {
 9394                        snippet.active_index += 1;
 9395                    } else {
 9396                        self.snippet_stack.push(snippet);
 9397                        return false;
 9398                    }
 9399                }
 9400            }
 9401            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9402                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9403                    // Reverse order so that the first range is the newest created selection.
 9404                    // Completions will use it and autoscroll will prioritize it.
 9405                    s.select_ranges(current_ranges.iter().rev().cloned())
 9406                });
 9407
 9408                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9409                    if let Some(selection) = current_ranges.first() {
 9410                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9411                    }
 9412                }
 9413
 9414                // If snippet state is not at the last tabstop, push it back on the stack
 9415                if snippet.active_index + 1 < snippet.ranges.len() {
 9416                    self.snippet_stack.push(snippet);
 9417                }
 9418                return true;
 9419            }
 9420        }
 9421
 9422        false
 9423    }
 9424
 9425    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9426        self.transact(window, cx, |this, window, cx| {
 9427            this.select_all(&SelectAll, window, cx);
 9428            this.insert("", window, cx);
 9429        });
 9430    }
 9431
 9432    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9433        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9434        self.transact(window, cx, |this, window, cx| {
 9435            this.select_autoclose_pair(window, cx);
 9436            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9437            if !this.linked_edit_ranges.is_empty() {
 9438                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9439                let snapshot = this.buffer.read(cx).snapshot(cx);
 9440
 9441                for selection in selections.iter() {
 9442                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9443                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9444                    if selection_start.buffer_id != selection_end.buffer_id {
 9445                        continue;
 9446                    }
 9447                    if let Some(ranges) =
 9448                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9449                    {
 9450                        for (buffer, entries) in ranges {
 9451                            linked_ranges.entry(buffer).or_default().extend(entries);
 9452                        }
 9453                    }
 9454                }
 9455            }
 9456
 9457            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9458            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9459            for selection in &mut selections {
 9460                if selection.is_empty() {
 9461                    let old_head = selection.head();
 9462                    let mut new_head =
 9463                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9464                            .to_point(&display_map);
 9465                    if let Some((buffer, line_buffer_range)) = display_map
 9466                        .buffer_snapshot
 9467                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9468                    {
 9469                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9470                        let indent_len = match indent_size.kind {
 9471                            IndentKind::Space => {
 9472                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9473                            }
 9474                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9475                        };
 9476                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9477                            let indent_len = indent_len.get();
 9478                            new_head = cmp::min(
 9479                                new_head,
 9480                                MultiBufferPoint::new(
 9481                                    old_head.row,
 9482                                    ((old_head.column - 1) / indent_len) * indent_len,
 9483                                ),
 9484                            );
 9485                        }
 9486                    }
 9487
 9488                    selection.set_head(new_head, SelectionGoal::None);
 9489                }
 9490            }
 9491
 9492            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9493                s.select(selections)
 9494            });
 9495            this.insert("", window, cx);
 9496            let empty_str: Arc<str> = Arc::from("");
 9497            for (buffer, edits) in linked_ranges {
 9498                let snapshot = buffer.read(cx).snapshot();
 9499                use text::ToPoint as TP;
 9500
 9501                let edits = edits
 9502                    .into_iter()
 9503                    .map(|range| {
 9504                        let end_point = TP::to_point(&range.end, &snapshot);
 9505                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9506
 9507                        if end_point == start_point {
 9508                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9509                                .saturating_sub(1);
 9510                            start_point =
 9511                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9512                        };
 9513
 9514                        (start_point..end_point, empty_str.clone())
 9515                    })
 9516                    .sorted_by_key(|(range, _)| range.start)
 9517                    .collect::<Vec<_>>();
 9518                buffer.update(cx, |this, cx| {
 9519                    this.edit(edits, None, cx);
 9520                })
 9521            }
 9522            this.refresh_inline_completion(true, false, window, cx);
 9523            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9524        });
 9525    }
 9526
 9527    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9528        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9529        self.transact(window, cx, |this, window, cx| {
 9530            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9531                s.move_with(|map, selection| {
 9532                    if selection.is_empty() {
 9533                        let cursor = movement::right(map, selection.head());
 9534                        selection.end = cursor;
 9535                        selection.reversed = true;
 9536                        selection.goal = SelectionGoal::None;
 9537                    }
 9538                })
 9539            });
 9540            this.insert("", window, cx);
 9541            this.refresh_inline_completion(true, false, window, cx);
 9542        });
 9543    }
 9544
 9545    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9546        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9547        if self.move_to_prev_snippet_tabstop(window, cx) {
 9548            return;
 9549        }
 9550        self.outdent(&Outdent, window, cx);
 9551    }
 9552
 9553    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9554        if self.move_to_next_snippet_tabstop(window, cx) {
 9555            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9556            return;
 9557        }
 9558        if self.read_only(cx) {
 9559            return;
 9560        }
 9561        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9562        let mut selections = self.selections.all_adjusted(cx);
 9563        let buffer = self.buffer.read(cx);
 9564        let snapshot = buffer.snapshot(cx);
 9565        let rows_iter = selections.iter().map(|s| s.head().row);
 9566        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9567
 9568        let has_some_cursor_in_whitespace = selections
 9569            .iter()
 9570            .filter(|selection| selection.is_empty())
 9571            .any(|selection| {
 9572                let cursor = selection.head();
 9573                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9574                cursor.column < current_indent.len
 9575            });
 9576
 9577        let mut edits = Vec::new();
 9578        let mut prev_edited_row = 0;
 9579        let mut row_delta = 0;
 9580        for selection in &mut selections {
 9581            if selection.start.row != prev_edited_row {
 9582                row_delta = 0;
 9583            }
 9584            prev_edited_row = selection.end.row;
 9585
 9586            // If the selection is non-empty, then increase the indentation of the selected lines.
 9587            if !selection.is_empty() {
 9588                row_delta =
 9589                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9590                continue;
 9591            }
 9592
 9593            let cursor = selection.head();
 9594            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9595            if let Some(suggested_indent) =
 9596                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9597            {
 9598                // Don't do anything if already at suggested indent
 9599                // and there is any other cursor which is not
 9600                if has_some_cursor_in_whitespace
 9601                    && cursor.column == current_indent.len
 9602                    && current_indent.len == suggested_indent.len
 9603                {
 9604                    continue;
 9605                }
 9606
 9607                // Adjust line and move cursor to suggested indent
 9608                // if cursor is not at suggested indent
 9609                if cursor.column < suggested_indent.len
 9610                    && cursor.column <= current_indent.len
 9611                    && current_indent.len <= suggested_indent.len
 9612                {
 9613                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9614                    selection.end = selection.start;
 9615                    if row_delta == 0 {
 9616                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9617                            cursor.row,
 9618                            current_indent,
 9619                            suggested_indent,
 9620                        ));
 9621                        row_delta = suggested_indent.len - current_indent.len;
 9622                    }
 9623                    continue;
 9624                }
 9625
 9626                // If current indent is more than suggested indent
 9627                // only move cursor to current indent and skip indent
 9628                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9629                    selection.start = Point::new(cursor.row, current_indent.len);
 9630                    selection.end = selection.start;
 9631                    continue;
 9632                }
 9633            }
 9634
 9635            // Otherwise, insert a hard or soft tab.
 9636            let settings = buffer.language_settings_at(cursor, cx);
 9637            let tab_size = if settings.hard_tabs {
 9638                IndentSize::tab()
 9639            } else {
 9640                let tab_size = settings.tab_size.get();
 9641                let indent_remainder = snapshot
 9642                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9643                    .flat_map(str::chars)
 9644                    .fold(row_delta % tab_size, |counter: u32, c| {
 9645                        if c == '\t' {
 9646                            0
 9647                        } else {
 9648                            (counter + 1) % tab_size
 9649                        }
 9650                    });
 9651
 9652                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9653                IndentSize::spaces(chars_to_next_tab_stop)
 9654            };
 9655            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9656            selection.end = selection.start;
 9657            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9658            row_delta += tab_size.len;
 9659        }
 9660
 9661        self.transact(window, cx, |this, window, cx| {
 9662            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9663            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9664                s.select(selections)
 9665            });
 9666            this.refresh_inline_completion(true, false, window, cx);
 9667        });
 9668    }
 9669
 9670    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9671        if self.read_only(cx) {
 9672            return;
 9673        }
 9674        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9675        let mut selections = self.selections.all::<Point>(cx);
 9676        let mut prev_edited_row = 0;
 9677        let mut row_delta = 0;
 9678        let mut edits = Vec::new();
 9679        let buffer = self.buffer.read(cx);
 9680        let snapshot = buffer.snapshot(cx);
 9681        for selection in &mut selections {
 9682            if selection.start.row != prev_edited_row {
 9683                row_delta = 0;
 9684            }
 9685            prev_edited_row = selection.end.row;
 9686
 9687            row_delta =
 9688                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9689        }
 9690
 9691        self.transact(window, cx, |this, window, cx| {
 9692            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9693            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9694                s.select(selections)
 9695            });
 9696        });
 9697    }
 9698
 9699    fn indent_selection(
 9700        buffer: &MultiBuffer,
 9701        snapshot: &MultiBufferSnapshot,
 9702        selection: &mut Selection<Point>,
 9703        edits: &mut Vec<(Range<Point>, String)>,
 9704        delta_for_start_row: u32,
 9705        cx: &App,
 9706    ) -> u32 {
 9707        let settings = buffer.language_settings_at(selection.start, cx);
 9708        let tab_size = settings.tab_size.get();
 9709        let indent_kind = if settings.hard_tabs {
 9710            IndentKind::Tab
 9711        } else {
 9712            IndentKind::Space
 9713        };
 9714        let mut start_row = selection.start.row;
 9715        let mut end_row = selection.end.row + 1;
 9716
 9717        // If a selection ends at the beginning of a line, don't indent
 9718        // that last line.
 9719        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9720            end_row -= 1;
 9721        }
 9722
 9723        // Avoid re-indenting a row that has already been indented by a
 9724        // previous selection, but still update this selection's column
 9725        // to reflect that indentation.
 9726        if delta_for_start_row > 0 {
 9727            start_row += 1;
 9728            selection.start.column += delta_for_start_row;
 9729            if selection.end.row == selection.start.row {
 9730                selection.end.column += delta_for_start_row;
 9731            }
 9732        }
 9733
 9734        let mut delta_for_end_row = 0;
 9735        let has_multiple_rows = start_row + 1 != end_row;
 9736        for row in start_row..end_row {
 9737            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9738            let indent_delta = match (current_indent.kind, indent_kind) {
 9739                (IndentKind::Space, IndentKind::Space) => {
 9740                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9741                    IndentSize::spaces(columns_to_next_tab_stop)
 9742                }
 9743                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9744                (_, IndentKind::Tab) => IndentSize::tab(),
 9745            };
 9746
 9747            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9748                0
 9749            } else {
 9750                selection.start.column
 9751            };
 9752            let row_start = Point::new(row, start);
 9753            edits.push((
 9754                row_start..row_start,
 9755                indent_delta.chars().collect::<String>(),
 9756            ));
 9757
 9758            // Update this selection's endpoints to reflect the indentation.
 9759            if row == selection.start.row {
 9760                selection.start.column += indent_delta.len;
 9761            }
 9762            if row == selection.end.row {
 9763                selection.end.column += indent_delta.len;
 9764                delta_for_end_row = indent_delta.len;
 9765            }
 9766        }
 9767
 9768        if selection.start.row == selection.end.row {
 9769            delta_for_start_row + delta_for_end_row
 9770        } else {
 9771            delta_for_end_row
 9772        }
 9773    }
 9774
 9775    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9776        if self.read_only(cx) {
 9777            return;
 9778        }
 9779        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9780        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9781        let selections = self.selections.all::<Point>(cx);
 9782        let mut deletion_ranges = Vec::new();
 9783        let mut last_outdent = None;
 9784        {
 9785            let buffer = self.buffer.read(cx);
 9786            let snapshot = buffer.snapshot(cx);
 9787            for selection in &selections {
 9788                let settings = buffer.language_settings_at(selection.start, cx);
 9789                let tab_size = settings.tab_size.get();
 9790                let mut rows = selection.spanned_rows(false, &display_map);
 9791
 9792                // Avoid re-outdenting a row that has already been outdented by a
 9793                // previous selection.
 9794                if let Some(last_row) = last_outdent {
 9795                    if last_row == rows.start {
 9796                        rows.start = rows.start.next_row();
 9797                    }
 9798                }
 9799                let has_multiple_rows = rows.len() > 1;
 9800                for row in rows.iter_rows() {
 9801                    let indent_size = snapshot.indent_size_for_line(row);
 9802                    if indent_size.len > 0 {
 9803                        let deletion_len = match indent_size.kind {
 9804                            IndentKind::Space => {
 9805                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9806                                if columns_to_prev_tab_stop == 0 {
 9807                                    tab_size
 9808                                } else {
 9809                                    columns_to_prev_tab_stop
 9810                                }
 9811                            }
 9812                            IndentKind::Tab => 1,
 9813                        };
 9814                        let start = if has_multiple_rows
 9815                            || deletion_len > selection.start.column
 9816                            || indent_size.len < selection.start.column
 9817                        {
 9818                            0
 9819                        } else {
 9820                            selection.start.column - deletion_len
 9821                        };
 9822                        deletion_ranges.push(
 9823                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9824                        );
 9825                        last_outdent = Some(row);
 9826                    }
 9827                }
 9828            }
 9829        }
 9830
 9831        self.transact(window, cx, |this, window, cx| {
 9832            this.buffer.update(cx, |buffer, cx| {
 9833                let empty_str: Arc<str> = Arc::default();
 9834                buffer.edit(
 9835                    deletion_ranges
 9836                        .into_iter()
 9837                        .map(|range| (range, empty_str.clone())),
 9838                    None,
 9839                    cx,
 9840                );
 9841            });
 9842            let selections = this.selections.all::<usize>(cx);
 9843            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9844                s.select(selections)
 9845            });
 9846        });
 9847    }
 9848
 9849    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9850        if self.read_only(cx) {
 9851            return;
 9852        }
 9853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9854        let selections = self
 9855            .selections
 9856            .all::<usize>(cx)
 9857            .into_iter()
 9858            .map(|s| s.range());
 9859
 9860        self.transact(window, cx, |this, window, cx| {
 9861            this.buffer.update(cx, |buffer, cx| {
 9862                buffer.autoindent_ranges(selections, cx);
 9863            });
 9864            let selections = this.selections.all::<usize>(cx);
 9865            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9866                s.select(selections)
 9867            });
 9868        });
 9869    }
 9870
 9871    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9872        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9873        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9874        let selections = self.selections.all::<Point>(cx);
 9875
 9876        let mut new_cursors = Vec::new();
 9877        let mut edit_ranges = Vec::new();
 9878        let mut selections = selections.iter().peekable();
 9879        while let Some(selection) = selections.next() {
 9880            let mut rows = selection.spanned_rows(false, &display_map);
 9881            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9882
 9883            // Accumulate contiguous regions of rows that we want to delete.
 9884            while let Some(next_selection) = selections.peek() {
 9885                let next_rows = next_selection.spanned_rows(false, &display_map);
 9886                if next_rows.start <= rows.end {
 9887                    rows.end = next_rows.end;
 9888                    selections.next().unwrap();
 9889                } else {
 9890                    break;
 9891                }
 9892            }
 9893
 9894            let buffer = &display_map.buffer_snapshot;
 9895            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9896            let edit_end;
 9897            let cursor_buffer_row;
 9898            if buffer.max_point().row >= rows.end.0 {
 9899                // If there's a line after the range, delete the \n from the end of the row range
 9900                // and position the cursor on the next line.
 9901                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9902                cursor_buffer_row = rows.end;
 9903            } else {
 9904                // If there isn't a line after the range, delete the \n from the line before the
 9905                // start of the row range and position the cursor there.
 9906                edit_start = edit_start.saturating_sub(1);
 9907                edit_end = buffer.len();
 9908                cursor_buffer_row = rows.start.previous_row();
 9909            }
 9910
 9911            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9912            *cursor.column_mut() =
 9913                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9914
 9915            new_cursors.push((
 9916                selection.id,
 9917                buffer.anchor_after(cursor.to_point(&display_map)),
 9918            ));
 9919            edit_ranges.push(edit_start..edit_end);
 9920        }
 9921
 9922        self.transact(window, cx, |this, window, cx| {
 9923            let buffer = this.buffer.update(cx, |buffer, cx| {
 9924                let empty_str: Arc<str> = Arc::default();
 9925                buffer.edit(
 9926                    edit_ranges
 9927                        .into_iter()
 9928                        .map(|range| (range, empty_str.clone())),
 9929                    None,
 9930                    cx,
 9931                );
 9932                buffer.snapshot(cx)
 9933            });
 9934            let new_selections = new_cursors
 9935                .into_iter()
 9936                .map(|(id, cursor)| {
 9937                    let cursor = cursor.to_point(&buffer);
 9938                    Selection {
 9939                        id,
 9940                        start: cursor,
 9941                        end: cursor,
 9942                        reversed: false,
 9943                        goal: SelectionGoal::None,
 9944                    }
 9945                })
 9946                .collect();
 9947
 9948            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9949                s.select(new_selections);
 9950            });
 9951        });
 9952    }
 9953
 9954    pub fn join_lines_impl(
 9955        &mut self,
 9956        insert_whitespace: bool,
 9957        window: &mut Window,
 9958        cx: &mut Context<Self>,
 9959    ) {
 9960        if self.read_only(cx) {
 9961            return;
 9962        }
 9963        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9964        for selection in self.selections.all::<Point>(cx) {
 9965            let start = MultiBufferRow(selection.start.row);
 9966            // Treat single line selections as if they include the next line. Otherwise this action
 9967            // would do nothing for single line selections individual cursors.
 9968            let end = if selection.start.row == selection.end.row {
 9969                MultiBufferRow(selection.start.row + 1)
 9970            } else {
 9971                MultiBufferRow(selection.end.row)
 9972            };
 9973
 9974            if let Some(last_row_range) = row_ranges.last_mut() {
 9975                if start <= last_row_range.end {
 9976                    last_row_range.end = end;
 9977                    continue;
 9978                }
 9979            }
 9980            row_ranges.push(start..end);
 9981        }
 9982
 9983        let snapshot = self.buffer.read(cx).snapshot(cx);
 9984        let mut cursor_positions = Vec::new();
 9985        for row_range in &row_ranges {
 9986            let anchor = snapshot.anchor_before(Point::new(
 9987                row_range.end.previous_row().0,
 9988                snapshot.line_len(row_range.end.previous_row()),
 9989            ));
 9990            cursor_positions.push(anchor..anchor);
 9991        }
 9992
 9993        self.transact(window, cx, |this, window, cx| {
 9994            for row_range in row_ranges.into_iter().rev() {
 9995                for row in row_range.iter_rows().rev() {
 9996                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9997                    let next_line_row = row.next_row();
 9998                    let indent = snapshot.indent_size_for_line(next_line_row);
 9999                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10000
10001                    let replace =
10002                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10003                            " "
10004                        } else {
10005                            ""
10006                        };
10007
10008                    this.buffer.update(cx, |buffer, cx| {
10009                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10010                    });
10011                }
10012            }
10013
10014            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10015                s.select_anchor_ranges(cursor_positions)
10016            });
10017        });
10018    }
10019
10020    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10021        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10022        self.join_lines_impl(true, window, cx);
10023    }
10024
10025    pub fn sort_lines_case_sensitive(
10026        &mut self,
10027        _: &SortLinesCaseSensitive,
10028        window: &mut Window,
10029        cx: &mut Context<Self>,
10030    ) {
10031        self.manipulate_lines(window, cx, |lines| lines.sort())
10032    }
10033
10034    pub fn sort_lines_case_insensitive(
10035        &mut self,
10036        _: &SortLinesCaseInsensitive,
10037        window: &mut Window,
10038        cx: &mut Context<Self>,
10039    ) {
10040        self.manipulate_lines(window, cx, |lines| {
10041            lines.sort_by_key(|line| line.to_lowercase())
10042        })
10043    }
10044
10045    pub fn unique_lines_case_insensitive(
10046        &mut self,
10047        _: &UniqueLinesCaseInsensitive,
10048        window: &mut Window,
10049        cx: &mut Context<Self>,
10050    ) {
10051        self.manipulate_lines(window, cx, |lines| {
10052            let mut seen = HashSet::default();
10053            lines.retain(|line| seen.insert(line.to_lowercase()));
10054        })
10055    }
10056
10057    pub fn unique_lines_case_sensitive(
10058        &mut self,
10059        _: &UniqueLinesCaseSensitive,
10060        window: &mut Window,
10061        cx: &mut Context<Self>,
10062    ) {
10063        self.manipulate_lines(window, cx, |lines| {
10064            let mut seen = HashSet::default();
10065            lines.retain(|line| seen.insert(*line));
10066        })
10067    }
10068
10069    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10070        let Some(project) = self.project.clone() else {
10071            return;
10072        };
10073        self.reload(project, window, cx)
10074            .detach_and_notify_err(window, cx);
10075    }
10076
10077    pub fn restore_file(
10078        &mut self,
10079        _: &::git::RestoreFile,
10080        window: &mut Window,
10081        cx: &mut Context<Self>,
10082    ) {
10083        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10084        let mut buffer_ids = HashSet::default();
10085        let snapshot = self.buffer().read(cx).snapshot(cx);
10086        for selection in self.selections.all::<usize>(cx) {
10087            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10088        }
10089
10090        let buffer = self.buffer().read(cx);
10091        let ranges = buffer_ids
10092            .into_iter()
10093            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10094            .collect::<Vec<_>>();
10095
10096        self.restore_hunks_in_ranges(ranges, window, cx);
10097    }
10098
10099    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10100        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10101        let selections = self
10102            .selections
10103            .all(cx)
10104            .into_iter()
10105            .map(|s| s.range())
10106            .collect();
10107        self.restore_hunks_in_ranges(selections, window, cx);
10108    }
10109
10110    pub fn restore_hunks_in_ranges(
10111        &mut self,
10112        ranges: Vec<Range<Point>>,
10113        window: &mut Window,
10114        cx: &mut Context<Editor>,
10115    ) {
10116        let mut revert_changes = HashMap::default();
10117        let chunk_by = self
10118            .snapshot(window, cx)
10119            .hunks_for_ranges(ranges)
10120            .into_iter()
10121            .chunk_by(|hunk| hunk.buffer_id);
10122        for (buffer_id, hunks) in &chunk_by {
10123            let hunks = hunks.collect::<Vec<_>>();
10124            for hunk in &hunks {
10125                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10126            }
10127            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10128        }
10129        drop(chunk_by);
10130        if !revert_changes.is_empty() {
10131            self.transact(window, cx, |editor, window, cx| {
10132                editor.restore(revert_changes, window, cx);
10133            });
10134        }
10135    }
10136
10137    pub fn open_active_item_in_terminal(
10138        &mut self,
10139        _: &OpenInTerminal,
10140        window: &mut Window,
10141        cx: &mut Context<Self>,
10142    ) {
10143        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10144            let project_path = buffer.read(cx).project_path(cx)?;
10145            let project = self.project.as_ref()?.read(cx);
10146            let entry = project.entry_for_path(&project_path, cx)?;
10147            let parent = match &entry.canonical_path {
10148                Some(canonical_path) => canonical_path.to_path_buf(),
10149                None => project.absolute_path(&project_path, cx)?,
10150            }
10151            .parent()?
10152            .to_path_buf();
10153            Some(parent)
10154        }) {
10155            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10156        }
10157    }
10158
10159    fn set_breakpoint_context_menu(
10160        &mut self,
10161        display_row: DisplayRow,
10162        position: Option<Anchor>,
10163        clicked_point: gpui::Point<Pixels>,
10164        window: &mut Window,
10165        cx: &mut Context<Self>,
10166    ) {
10167        let source = self
10168            .buffer
10169            .read(cx)
10170            .snapshot(cx)
10171            .anchor_before(Point::new(display_row.0, 0u32));
10172
10173        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10174
10175        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10176            self,
10177            source,
10178            clicked_point,
10179            context_menu,
10180            window,
10181            cx,
10182        );
10183    }
10184
10185    fn add_edit_breakpoint_block(
10186        &mut self,
10187        anchor: Anchor,
10188        breakpoint: &Breakpoint,
10189        edit_action: BreakpointPromptEditAction,
10190        window: &mut Window,
10191        cx: &mut Context<Self>,
10192    ) {
10193        let weak_editor = cx.weak_entity();
10194        let bp_prompt = cx.new(|cx| {
10195            BreakpointPromptEditor::new(
10196                weak_editor,
10197                anchor,
10198                breakpoint.clone(),
10199                edit_action,
10200                window,
10201                cx,
10202            )
10203        });
10204
10205        let height = bp_prompt.update(cx, |this, cx| {
10206            this.prompt
10207                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10208        });
10209        let cloned_prompt = bp_prompt.clone();
10210        let blocks = vec![BlockProperties {
10211            style: BlockStyle::Sticky,
10212            placement: BlockPlacement::Above(anchor),
10213            height: Some(height),
10214            render: Arc::new(move |cx| {
10215                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10216                cloned_prompt.clone().into_any_element()
10217            }),
10218            priority: 0,
10219            render_in_minimap: true,
10220        }];
10221
10222        let focus_handle = bp_prompt.focus_handle(cx);
10223        window.focus(&focus_handle);
10224
10225        let block_ids = self.insert_blocks(blocks, None, cx);
10226        bp_prompt.update(cx, |prompt, _| {
10227            prompt.add_block_ids(block_ids);
10228        });
10229    }
10230
10231    pub(crate) fn breakpoint_at_row(
10232        &self,
10233        row: u32,
10234        window: &mut Window,
10235        cx: &mut Context<Self>,
10236    ) -> Option<(Anchor, Breakpoint)> {
10237        let snapshot = self.snapshot(window, cx);
10238        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10239
10240        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10241    }
10242
10243    pub(crate) fn breakpoint_at_anchor(
10244        &self,
10245        breakpoint_position: Anchor,
10246        snapshot: &EditorSnapshot,
10247        cx: &mut Context<Self>,
10248    ) -> Option<(Anchor, Breakpoint)> {
10249        let project = self.project.clone()?;
10250
10251        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10252            snapshot
10253                .buffer_snapshot
10254                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10255        })?;
10256
10257        let enclosing_excerpt = breakpoint_position.excerpt_id;
10258        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10259        let buffer_snapshot = buffer.read(cx).snapshot();
10260
10261        let row = buffer_snapshot
10262            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10263            .row;
10264
10265        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10266        let anchor_end = snapshot
10267            .buffer_snapshot
10268            .anchor_after(Point::new(row, line_len));
10269
10270        let bp = self
10271            .breakpoint_store
10272            .as_ref()?
10273            .read_with(cx, |breakpoint_store, cx| {
10274                breakpoint_store
10275                    .breakpoints(
10276                        &buffer,
10277                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10278                        &buffer_snapshot,
10279                        cx,
10280                    )
10281                    .next()
10282                    .and_then(|(bp, _)| {
10283                        let breakpoint_row = buffer_snapshot
10284                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10285                            .row;
10286
10287                        if breakpoint_row == row {
10288                            snapshot
10289                                .buffer_snapshot
10290                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10291                                .map(|position| (position, bp.bp.clone()))
10292                        } else {
10293                            None
10294                        }
10295                    })
10296            });
10297        bp
10298    }
10299
10300    pub fn edit_log_breakpoint(
10301        &mut self,
10302        _: &EditLogBreakpoint,
10303        window: &mut Window,
10304        cx: &mut Context<Self>,
10305    ) {
10306        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10307            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10308                message: None,
10309                state: BreakpointState::Enabled,
10310                condition: None,
10311                hit_condition: None,
10312            });
10313
10314            self.add_edit_breakpoint_block(
10315                anchor,
10316                &breakpoint,
10317                BreakpointPromptEditAction::Log,
10318                window,
10319                cx,
10320            );
10321        }
10322    }
10323
10324    fn breakpoints_at_cursors(
10325        &self,
10326        window: &mut Window,
10327        cx: &mut Context<Self>,
10328    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10329        let snapshot = self.snapshot(window, cx);
10330        let cursors = self
10331            .selections
10332            .disjoint_anchors()
10333            .into_iter()
10334            .map(|selection| {
10335                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10336
10337                let breakpoint_position = self
10338                    .breakpoint_at_row(cursor_position.row, window, cx)
10339                    .map(|bp| bp.0)
10340                    .unwrap_or_else(|| {
10341                        snapshot
10342                            .display_snapshot
10343                            .buffer_snapshot
10344                            .anchor_after(Point::new(cursor_position.row, 0))
10345                    });
10346
10347                let breakpoint = self
10348                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10349                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10350
10351                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10352            })
10353            // 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.
10354            .collect::<HashMap<Anchor, _>>();
10355
10356        cursors.into_iter().collect()
10357    }
10358
10359    pub fn enable_breakpoint(
10360        &mut self,
10361        _: &crate::actions::EnableBreakpoint,
10362        window: &mut Window,
10363        cx: &mut Context<Self>,
10364    ) {
10365        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10366            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10367                continue;
10368            };
10369            self.edit_breakpoint_at_anchor(
10370                anchor,
10371                breakpoint,
10372                BreakpointEditAction::InvertState,
10373                cx,
10374            );
10375        }
10376    }
10377
10378    pub fn disable_breakpoint(
10379        &mut self,
10380        _: &crate::actions::DisableBreakpoint,
10381        window: &mut Window,
10382        cx: &mut Context<Self>,
10383    ) {
10384        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10385            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10386                continue;
10387            };
10388            self.edit_breakpoint_at_anchor(
10389                anchor,
10390                breakpoint,
10391                BreakpointEditAction::InvertState,
10392                cx,
10393            );
10394        }
10395    }
10396
10397    pub fn toggle_breakpoint(
10398        &mut self,
10399        _: &crate::actions::ToggleBreakpoint,
10400        window: &mut Window,
10401        cx: &mut Context<Self>,
10402    ) {
10403        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10404            if let Some(breakpoint) = breakpoint {
10405                self.edit_breakpoint_at_anchor(
10406                    anchor,
10407                    breakpoint,
10408                    BreakpointEditAction::Toggle,
10409                    cx,
10410                );
10411            } else {
10412                self.edit_breakpoint_at_anchor(
10413                    anchor,
10414                    Breakpoint::new_standard(),
10415                    BreakpointEditAction::Toggle,
10416                    cx,
10417                );
10418            }
10419        }
10420    }
10421
10422    pub fn edit_breakpoint_at_anchor(
10423        &mut self,
10424        breakpoint_position: Anchor,
10425        breakpoint: Breakpoint,
10426        edit_action: BreakpointEditAction,
10427        cx: &mut Context<Self>,
10428    ) {
10429        let Some(breakpoint_store) = &self.breakpoint_store else {
10430            return;
10431        };
10432
10433        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10434            if breakpoint_position == Anchor::min() {
10435                self.buffer()
10436                    .read(cx)
10437                    .excerpt_buffer_ids()
10438                    .into_iter()
10439                    .next()
10440            } else {
10441                None
10442            }
10443        }) else {
10444            return;
10445        };
10446
10447        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10448            return;
10449        };
10450
10451        breakpoint_store.update(cx, |breakpoint_store, cx| {
10452            breakpoint_store.toggle_breakpoint(
10453                buffer,
10454                BreakpointWithPosition {
10455                    position: breakpoint_position.text_anchor,
10456                    bp: breakpoint,
10457                },
10458                edit_action,
10459                cx,
10460            );
10461        });
10462
10463        cx.notify();
10464    }
10465
10466    #[cfg(any(test, feature = "test-support"))]
10467    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10468        self.breakpoint_store.clone()
10469    }
10470
10471    pub fn prepare_restore_change(
10472        &self,
10473        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10474        hunk: &MultiBufferDiffHunk,
10475        cx: &mut App,
10476    ) -> Option<()> {
10477        if hunk.is_created_file() {
10478            return None;
10479        }
10480        let buffer = self.buffer.read(cx);
10481        let diff = buffer.diff_for(hunk.buffer_id)?;
10482        let buffer = buffer.buffer(hunk.buffer_id)?;
10483        let buffer = buffer.read(cx);
10484        let original_text = diff
10485            .read(cx)
10486            .base_text()
10487            .as_rope()
10488            .slice(hunk.diff_base_byte_range.clone());
10489        let buffer_snapshot = buffer.snapshot();
10490        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10491        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10492            probe
10493                .0
10494                .start
10495                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10496                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10497        }) {
10498            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10499            Some(())
10500        } else {
10501            None
10502        }
10503    }
10504
10505    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10506        self.manipulate_lines(window, cx, |lines| lines.reverse())
10507    }
10508
10509    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10510        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10511    }
10512
10513    fn manipulate_lines<Fn>(
10514        &mut self,
10515        window: &mut Window,
10516        cx: &mut Context<Self>,
10517        mut callback: Fn,
10518    ) where
10519        Fn: FnMut(&mut Vec<&str>),
10520    {
10521        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10522
10523        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10524        let buffer = self.buffer.read(cx).snapshot(cx);
10525
10526        let mut edits = Vec::new();
10527
10528        let selections = self.selections.all::<Point>(cx);
10529        let mut selections = selections.iter().peekable();
10530        let mut contiguous_row_selections = Vec::new();
10531        let mut new_selections = Vec::new();
10532        let mut added_lines = 0;
10533        let mut removed_lines = 0;
10534
10535        while let Some(selection) = selections.next() {
10536            let (start_row, end_row) = consume_contiguous_rows(
10537                &mut contiguous_row_selections,
10538                selection,
10539                &display_map,
10540                &mut selections,
10541            );
10542
10543            let start_point = Point::new(start_row.0, 0);
10544            let end_point = Point::new(
10545                end_row.previous_row().0,
10546                buffer.line_len(end_row.previous_row()),
10547            );
10548            let text = buffer
10549                .text_for_range(start_point..end_point)
10550                .collect::<String>();
10551
10552            let mut lines = text.split('\n').collect_vec();
10553
10554            let lines_before = lines.len();
10555            callback(&mut lines);
10556            let lines_after = lines.len();
10557
10558            edits.push((start_point..end_point, lines.join("\n")));
10559
10560            // Selections must change based on added and removed line count
10561            let start_row =
10562                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10563            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10564            new_selections.push(Selection {
10565                id: selection.id,
10566                start: start_row,
10567                end: end_row,
10568                goal: SelectionGoal::None,
10569                reversed: selection.reversed,
10570            });
10571
10572            if lines_after > lines_before {
10573                added_lines += lines_after - lines_before;
10574            } else if lines_before > lines_after {
10575                removed_lines += lines_before - lines_after;
10576            }
10577        }
10578
10579        self.transact(window, cx, |this, window, cx| {
10580            let buffer = this.buffer.update(cx, |buffer, cx| {
10581                buffer.edit(edits, None, cx);
10582                buffer.snapshot(cx)
10583            });
10584
10585            // Recalculate offsets on newly edited buffer
10586            let new_selections = new_selections
10587                .iter()
10588                .map(|s| {
10589                    let start_point = Point::new(s.start.0, 0);
10590                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10591                    Selection {
10592                        id: s.id,
10593                        start: buffer.point_to_offset(start_point),
10594                        end: buffer.point_to_offset(end_point),
10595                        goal: s.goal,
10596                        reversed: s.reversed,
10597                    }
10598                })
10599                .collect();
10600
10601            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10602                s.select(new_selections);
10603            });
10604
10605            this.request_autoscroll(Autoscroll::fit(), cx);
10606        });
10607    }
10608
10609    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10610        self.manipulate_text(window, cx, |text| {
10611            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10612            if has_upper_case_characters {
10613                text.to_lowercase()
10614            } else {
10615                text.to_uppercase()
10616            }
10617        })
10618    }
10619
10620    pub fn convert_to_upper_case(
10621        &mut self,
10622        _: &ConvertToUpperCase,
10623        window: &mut Window,
10624        cx: &mut Context<Self>,
10625    ) {
10626        self.manipulate_text(window, cx, |text| text.to_uppercase())
10627    }
10628
10629    pub fn convert_to_lower_case(
10630        &mut self,
10631        _: &ConvertToLowerCase,
10632        window: &mut Window,
10633        cx: &mut Context<Self>,
10634    ) {
10635        self.manipulate_text(window, cx, |text| text.to_lowercase())
10636    }
10637
10638    pub fn convert_to_title_case(
10639        &mut self,
10640        _: &ConvertToTitleCase,
10641        window: &mut Window,
10642        cx: &mut Context<Self>,
10643    ) {
10644        self.manipulate_text(window, cx, |text| {
10645            text.split('\n')
10646                .map(|line| line.to_case(Case::Title))
10647                .join("\n")
10648        })
10649    }
10650
10651    pub fn convert_to_snake_case(
10652        &mut self,
10653        _: &ConvertToSnakeCase,
10654        window: &mut Window,
10655        cx: &mut Context<Self>,
10656    ) {
10657        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10658    }
10659
10660    pub fn convert_to_kebab_case(
10661        &mut self,
10662        _: &ConvertToKebabCase,
10663        window: &mut Window,
10664        cx: &mut Context<Self>,
10665    ) {
10666        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10667    }
10668
10669    pub fn convert_to_upper_camel_case(
10670        &mut self,
10671        _: &ConvertToUpperCamelCase,
10672        window: &mut Window,
10673        cx: &mut Context<Self>,
10674    ) {
10675        self.manipulate_text(window, cx, |text| {
10676            text.split('\n')
10677                .map(|line| line.to_case(Case::UpperCamel))
10678                .join("\n")
10679        })
10680    }
10681
10682    pub fn convert_to_lower_camel_case(
10683        &mut self,
10684        _: &ConvertToLowerCamelCase,
10685        window: &mut Window,
10686        cx: &mut Context<Self>,
10687    ) {
10688        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10689    }
10690
10691    pub fn convert_to_opposite_case(
10692        &mut self,
10693        _: &ConvertToOppositeCase,
10694        window: &mut Window,
10695        cx: &mut Context<Self>,
10696    ) {
10697        self.manipulate_text(window, cx, |text| {
10698            text.chars()
10699                .fold(String::with_capacity(text.len()), |mut t, c| {
10700                    if c.is_uppercase() {
10701                        t.extend(c.to_lowercase());
10702                    } else {
10703                        t.extend(c.to_uppercase());
10704                    }
10705                    t
10706                })
10707        })
10708    }
10709
10710    pub fn convert_to_rot13(
10711        &mut self,
10712        _: &ConvertToRot13,
10713        window: &mut Window,
10714        cx: &mut Context<Self>,
10715    ) {
10716        self.manipulate_text(window, cx, |text| {
10717            text.chars()
10718                .map(|c| match c {
10719                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10720                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10721                    _ => c,
10722                })
10723                .collect()
10724        })
10725    }
10726
10727    pub fn convert_to_rot47(
10728        &mut self,
10729        _: &ConvertToRot47,
10730        window: &mut Window,
10731        cx: &mut Context<Self>,
10732    ) {
10733        self.manipulate_text(window, cx, |text| {
10734            text.chars()
10735                .map(|c| {
10736                    let code_point = c as u32;
10737                    if code_point >= 33 && code_point <= 126 {
10738                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10739                    }
10740                    c
10741                })
10742                .collect()
10743        })
10744    }
10745
10746    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10747    where
10748        Fn: FnMut(&str) -> String,
10749    {
10750        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10751        let buffer = self.buffer.read(cx).snapshot(cx);
10752
10753        let mut new_selections = Vec::new();
10754        let mut edits = Vec::new();
10755        let mut selection_adjustment = 0i32;
10756
10757        for selection in self.selections.all::<usize>(cx) {
10758            let selection_is_empty = selection.is_empty();
10759
10760            let (start, end) = if selection_is_empty {
10761                let word_range = movement::surrounding_word(
10762                    &display_map,
10763                    selection.start.to_display_point(&display_map),
10764                );
10765                let start = word_range.start.to_offset(&display_map, Bias::Left);
10766                let end = word_range.end.to_offset(&display_map, Bias::Left);
10767                (start, end)
10768            } else {
10769                (selection.start, selection.end)
10770            };
10771
10772            let text = buffer.text_for_range(start..end).collect::<String>();
10773            let old_length = text.len() as i32;
10774            let text = callback(&text);
10775
10776            new_selections.push(Selection {
10777                start: (start as i32 - selection_adjustment) as usize,
10778                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10779                goal: SelectionGoal::None,
10780                ..selection
10781            });
10782
10783            selection_adjustment += old_length - text.len() as i32;
10784
10785            edits.push((start..end, text));
10786        }
10787
10788        self.transact(window, cx, |this, window, cx| {
10789            this.buffer.update(cx, |buffer, cx| {
10790                buffer.edit(edits, None, cx);
10791            });
10792
10793            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10794                s.select(new_selections);
10795            });
10796
10797            this.request_autoscroll(Autoscroll::fit(), cx);
10798        });
10799    }
10800
10801    pub fn move_selection_on_drop(
10802        &mut self,
10803        selection: &Selection<Anchor>,
10804        target: DisplayPoint,
10805        is_cut: bool,
10806        window: &mut Window,
10807        cx: &mut Context<Self>,
10808    ) {
10809        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10810        let buffer = &display_map.buffer_snapshot;
10811        let mut edits = Vec::new();
10812        let insert_point = display_map
10813            .clip_point(target, Bias::Left)
10814            .to_point(&display_map);
10815        let text = buffer
10816            .text_for_range(selection.start..selection.end)
10817            .collect::<String>();
10818        if is_cut {
10819            edits.push(((selection.start..selection.end), String::new()));
10820        }
10821        let insert_anchor = buffer.anchor_before(insert_point);
10822        edits.push(((insert_anchor..insert_anchor), text));
10823        let last_edit_start = insert_anchor.bias_left(buffer);
10824        let last_edit_end = insert_anchor.bias_right(buffer);
10825        self.transact(window, cx, |this, window, cx| {
10826            this.buffer.update(cx, |buffer, cx| {
10827                buffer.edit(edits, None, cx);
10828            });
10829            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10830                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10831            });
10832        });
10833    }
10834
10835    pub fn clear_selection_drag_state(&mut self) {
10836        self.selection_drag_state = SelectionDragState::None;
10837    }
10838
10839    pub fn duplicate(
10840        &mut self,
10841        upwards: bool,
10842        whole_lines: bool,
10843        window: &mut Window,
10844        cx: &mut Context<Self>,
10845    ) {
10846        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10847
10848        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10849        let buffer = &display_map.buffer_snapshot;
10850        let selections = self.selections.all::<Point>(cx);
10851
10852        let mut edits = Vec::new();
10853        let mut selections_iter = selections.iter().peekable();
10854        while let Some(selection) = selections_iter.next() {
10855            let mut rows = selection.spanned_rows(false, &display_map);
10856            // duplicate line-wise
10857            if whole_lines || selection.start == selection.end {
10858                // Avoid duplicating the same lines twice.
10859                while let Some(next_selection) = selections_iter.peek() {
10860                    let next_rows = next_selection.spanned_rows(false, &display_map);
10861                    if next_rows.start < rows.end {
10862                        rows.end = next_rows.end;
10863                        selections_iter.next().unwrap();
10864                    } else {
10865                        break;
10866                    }
10867                }
10868
10869                // Copy the text from the selected row region and splice it either at the start
10870                // or end of the region.
10871                let start = Point::new(rows.start.0, 0);
10872                let end = Point::new(
10873                    rows.end.previous_row().0,
10874                    buffer.line_len(rows.end.previous_row()),
10875                );
10876                let text = buffer
10877                    .text_for_range(start..end)
10878                    .chain(Some("\n"))
10879                    .collect::<String>();
10880                let insert_location = if upwards {
10881                    Point::new(rows.end.0, 0)
10882                } else {
10883                    start
10884                };
10885                edits.push((insert_location..insert_location, text));
10886            } else {
10887                // duplicate character-wise
10888                let start = selection.start;
10889                let end = selection.end;
10890                let text = buffer.text_for_range(start..end).collect::<String>();
10891                edits.push((selection.end..selection.end, text));
10892            }
10893        }
10894
10895        self.transact(window, cx, |this, _, cx| {
10896            this.buffer.update(cx, |buffer, cx| {
10897                buffer.edit(edits, None, cx);
10898            });
10899
10900            this.request_autoscroll(Autoscroll::fit(), cx);
10901        });
10902    }
10903
10904    pub fn duplicate_line_up(
10905        &mut self,
10906        _: &DuplicateLineUp,
10907        window: &mut Window,
10908        cx: &mut Context<Self>,
10909    ) {
10910        self.duplicate(true, true, window, cx);
10911    }
10912
10913    pub fn duplicate_line_down(
10914        &mut self,
10915        _: &DuplicateLineDown,
10916        window: &mut Window,
10917        cx: &mut Context<Self>,
10918    ) {
10919        self.duplicate(false, true, window, cx);
10920    }
10921
10922    pub fn duplicate_selection(
10923        &mut self,
10924        _: &DuplicateSelection,
10925        window: &mut Window,
10926        cx: &mut Context<Self>,
10927    ) {
10928        self.duplicate(false, false, window, cx);
10929    }
10930
10931    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10933
10934        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10935        let buffer = self.buffer.read(cx).snapshot(cx);
10936
10937        let mut edits = Vec::new();
10938        let mut unfold_ranges = Vec::new();
10939        let mut refold_creases = Vec::new();
10940
10941        let selections = self.selections.all::<Point>(cx);
10942        let mut selections = selections.iter().peekable();
10943        let mut contiguous_row_selections = Vec::new();
10944        let mut new_selections = Vec::new();
10945
10946        while let Some(selection) = selections.next() {
10947            // Find all the selections that span a contiguous row range
10948            let (start_row, end_row) = consume_contiguous_rows(
10949                &mut contiguous_row_selections,
10950                selection,
10951                &display_map,
10952                &mut selections,
10953            );
10954
10955            // Move the text spanned by the row range to be before the line preceding the row range
10956            if start_row.0 > 0 {
10957                let range_to_move = Point::new(
10958                    start_row.previous_row().0,
10959                    buffer.line_len(start_row.previous_row()),
10960                )
10961                    ..Point::new(
10962                        end_row.previous_row().0,
10963                        buffer.line_len(end_row.previous_row()),
10964                    );
10965                let insertion_point = display_map
10966                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10967                    .0;
10968
10969                // Don't move lines across excerpts
10970                if buffer
10971                    .excerpt_containing(insertion_point..range_to_move.end)
10972                    .is_some()
10973                {
10974                    let text = buffer
10975                        .text_for_range(range_to_move.clone())
10976                        .flat_map(|s| s.chars())
10977                        .skip(1)
10978                        .chain(['\n'])
10979                        .collect::<String>();
10980
10981                    edits.push((
10982                        buffer.anchor_after(range_to_move.start)
10983                            ..buffer.anchor_before(range_to_move.end),
10984                        String::new(),
10985                    ));
10986                    let insertion_anchor = buffer.anchor_after(insertion_point);
10987                    edits.push((insertion_anchor..insertion_anchor, text));
10988
10989                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10990
10991                    // Move selections up
10992                    new_selections.extend(contiguous_row_selections.drain(..).map(
10993                        |mut selection| {
10994                            selection.start.row -= row_delta;
10995                            selection.end.row -= row_delta;
10996                            selection
10997                        },
10998                    ));
10999
11000                    // Move folds up
11001                    unfold_ranges.push(range_to_move.clone());
11002                    for fold in display_map.folds_in_range(
11003                        buffer.anchor_before(range_to_move.start)
11004                            ..buffer.anchor_after(range_to_move.end),
11005                    ) {
11006                        let mut start = fold.range.start.to_point(&buffer);
11007                        let mut end = fold.range.end.to_point(&buffer);
11008                        start.row -= row_delta;
11009                        end.row -= row_delta;
11010                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11011                    }
11012                }
11013            }
11014
11015            // If we didn't move line(s), preserve the existing selections
11016            new_selections.append(&mut contiguous_row_selections);
11017        }
11018
11019        self.transact(window, cx, |this, window, cx| {
11020            this.unfold_ranges(&unfold_ranges, true, true, cx);
11021            this.buffer.update(cx, |buffer, cx| {
11022                for (range, text) in edits {
11023                    buffer.edit([(range, text)], None, cx);
11024                }
11025            });
11026            this.fold_creases(refold_creases, true, window, cx);
11027            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11028                s.select(new_selections);
11029            })
11030        });
11031    }
11032
11033    pub fn move_line_down(
11034        &mut self,
11035        _: &MoveLineDown,
11036        window: &mut Window,
11037        cx: &mut Context<Self>,
11038    ) {
11039        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11040
11041        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11042        let buffer = self.buffer.read(cx).snapshot(cx);
11043
11044        let mut edits = Vec::new();
11045        let mut unfold_ranges = Vec::new();
11046        let mut refold_creases = Vec::new();
11047
11048        let selections = self.selections.all::<Point>(cx);
11049        let mut selections = selections.iter().peekable();
11050        let mut contiguous_row_selections = Vec::new();
11051        let mut new_selections = Vec::new();
11052
11053        while let Some(selection) = selections.next() {
11054            // Find all the selections that span a contiguous row range
11055            let (start_row, end_row) = consume_contiguous_rows(
11056                &mut contiguous_row_selections,
11057                selection,
11058                &display_map,
11059                &mut selections,
11060            );
11061
11062            // Move the text spanned by the row range to be after the last line of the row range
11063            if end_row.0 <= buffer.max_point().row {
11064                let range_to_move =
11065                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11066                let insertion_point = display_map
11067                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11068                    .0;
11069
11070                // Don't move lines across excerpt boundaries
11071                if buffer
11072                    .excerpt_containing(range_to_move.start..insertion_point)
11073                    .is_some()
11074                {
11075                    let mut text = String::from("\n");
11076                    text.extend(buffer.text_for_range(range_to_move.clone()));
11077                    text.pop(); // Drop trailing newline
11078                    edits.push((
11079                        buffer.anchor_after(range_to_move.start)
11080                            ..buffer.anchor_before(range_to_move.end),
11081                        String::new(),
11082                    ));
11083                    let insertion_anchor = buffer.anchor_after(insertion_point);
11084                    edits.push((insertion_anchor..insertion_anchor, text));
11085
11086                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11087
11088                    // Move selections down
11089                    new_selections.extend(contiguous_row_selections.drain(..).map(
11090                        |mut selection| {
11091                            selection.start.row += row_delta;
11092                            selection.end.row += row_delta;
11093                            selection
11094                        },
11095                    ));
11096
11097                    // Move folds down
11098                    unfold_ranges.push(range_to_move.clone());
11099                    for fold in display_map.folds_in_range(
11100                        buffer.anchor_before(range_to_move.start)
11101                            ..buffer.anchor_after(range_to_move.end),
11102                    ) {
11103                        let mut start = fold.range.start.to_point(&buffer);
11104                        let mut end = fold.range.end.to_point(&buffer);
11105                        start.row += row_delta;
11106                        end.row += row_delta;
11107                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11108                    }
11109                }
11110            }
11111
11112            // If we didn't move line(s), preserve the existing selections
11113            new_selections.append(&mut contiguous_row_selections);
11114        }
11115
11116        self.transact(window, cx, |this, window, cx| {
11117            this.unfold_ranges(&unfold_ranges, true, true, cx);
11118            this.buffer.update(cx, |buffer, cx| {
11119                for (range, text) in edits {
11120                    buffer.edit([(range, text)], None, cx);
11121                }
11122            });
11123            this.fold_creases(refold_creases, true, window, cx);
11124            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11125                s.select(new_selections)
11126            });
11127        });
11128    }
11129
11130    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11131        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11132        let text_layout_details = &self.text_layout_details(window);
11133        self.transact(window, cx, |this, window, cx| {
11134            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11135                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11136                s.move_with(|display_map, selection| {
11137                    if !selection.is_empty() {
11138                        return;
11139                    }
11140
11141                    let mut head = selection.head();
11142                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11143                    if head.column() == display_map.line_len(head.row()) {
11144                        transpose_offset = display_map
11145                            .buffer_snapshot
11146                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11147                    }
11148
11149                    if transpose_offset == 0 {
11150                        return;
11151                    }
11152
11153                    *head.column_mut() += 1;
11154                    head = display_map.clip_point(head, Bias::Right);
11155                    let goal = SelectionGoal::HorizontalPosition(
11156                        display_map
11157                            .x_for_display_point(head, text_layout_details)
11158                            .into(),
11159                    );
11160                    selection.collapse_to(head, goal);
11161
11162                    let transpose_start = display_map
11163                        .buffer_snapshot
11164                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11165                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11166                        let transpose_end = display_map
11167                            .buffer_snapshot
11168                            .clip_offset(transpose_offset + 1, Bias::Right);
11169                        if let Some(ch) =
11170                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11171                        {
11172                            edits.push((transpose_start..transpose_offset, String::new()));
11173                            edits.push((transpose_end..transpose_end, ch.to_string()));
11174                        }
11175                    }
11176                });
11177                edits
11178            });
11179            this.buffer
11180                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11181            let selections = this.selections.all::<usize>(cx);
11182            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11183                s.select(selections);
11184            });
11185        });
11186    }
11187
11188    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11189        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11190        self.rewrap_impl(RewrapOptions::default(), cx)
11191    }
11192
11193    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11194        let buffer = self.buffer.read(cx).snapshot(cx);
11195        let selections = self.selections.all::<Point>(cx);
11196
11197        // Shrink and split selections to respect paragraph boundaries.
11198        let ranges = selections.into_iter().flat_map(|selection| {
11199            let language_settings = buffer.language_settings_at(selection.head(), cx);
11200            let language_scope = buffer.language_scope_at(selection.head());
11201
11202            let Some(start_row) = (selection.start.row..=selection.end.row)
11203                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11204            else {
11205                return vec![];
11206            };
11207            let Some(end_row) = (selection.start.row..=selection.end.row)
11208                .rev()
11209                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11210            else {
11211                return vec![];
11212            };
11213
11214            let mut row = start_row;
11215            let mut ranges = Vec::new();
11216            while let Some(blank_row) =
11217                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11218            {
11219                let next_paragraph_start = (blank_row + 1..=end_row)
11220                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11221                    .unwrap();
11222                ranges.push((
11223                    language_settings.clone(),
11224                    language_scope.clone(),
11225                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11226                ));
11227                row = next_paragraph_start;
11228            }
11229            ranges.push((
11230                language_settings.clone(),
11231                language_scope.clone(),
11232                Point::new(row, 0)..Point::new(end_row, 0),
11233            ));
11234
11235            ranges
11236        });
11237
11238        let mut edits = Vec::new();
11239        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11240
11241        for (language_settings, language_scope, range) in ranges {
11242            let mut start_row = range.start.row;
11243            let mut end_row = range.end.row;
11244
11245            // Skip selections that overlap with a range that has already been rewrapped.
11246            let selection_range = start_row..end_row;
11247            if rewrapped_row_ranges
11248                .iter()
11249                .any(|range| range.overlaps(&selection_range))
11250            {
11251                continue;
11252            }
11253
11254            let tab_size = language_settings.tab_size;
11255
11256            // Since not all lines in the selection may be at the same indent
11257            // level, choose the indent size that is the most common between all
11258            // of the lines.
11259            //
11260            // If there is a tie, we use the deepest indent.
11261            let (indent_size, indent_end) = {
11262                let mut indent_size_occurrences = HashMap::default();
11263                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11264
11265                for row in start_row..=end_row {
11266                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11267                    rows_by_indent_size.entry(indent).or_default().push(row);
11268                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11269                }
11270
11271                let indent_size = indent_size_occurrences
11272                    .into_iter()
11273                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11274                    .map(|(indent, _)| indent)
11275                    .unwrap_or_default();
11276                let row = rows_by_indent_size[&indent_size][0];
11277                let indent_end = Point::new(row, indent_size.len);
11278
11279                (indent_size, indent_end)
11280            };
11281
11282            let mut line_prefix = indent_size.chars().collect::<String>();
11283
11284            let mut inside_comment = false;
11285            if let Some(comment_prefix) = language_scope.and_then(|language| {
11286                language
11287                    .line_comment_prefixes()
11288                    .iter()
11289                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11290                    .cloned()
11291            }) {
11292                line_prefix.push_str(&comment_prefix);
11293                inside_comment = true;
11294            }
11295
11296            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11297                RewrapBehavior::InComments => inside_comment,
11298                RewrapBehavior::InSelections => !range.is_empty(),
11299                RewrapBehavior::Anywhere => true,
11300            };
11301
11302            let should_rewrap = options.override_language_settings
11303                || allow_rewrap_based_on_language
11304                || self.hard_wrap.is_some();
11305            if !should_rewrap {
11306                continue;
11307            }
11308
11309            if range.is_empty() {
11310                'expand_upwards: while start_row > 0 {
11311                    let prev_row = start_row - 1;
11312                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11313                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11314                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11315                    {
11316                        start_row = prev_row;
11317                    } else {
11318                        break 'expand_upwards;
11319                    }
11320                }
11321
11322                'expand_downwards: while end_row < buffer.max_point().row {
11323                    let next_row = end_row + 1;
11324                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11325                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11326                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11327                    {
11328                        end_row = next_row;
11329                    } else {
11330                        break 'expand_downwards;
11331                    }
11332                }
11333            }
11334
11335            let start = Point::new(start_row, 0);
11336            let start_offset = start.to_offset(&buffer);
11337            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11338            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11339            let Some(lines_without_prefixes) = selection_text
11340                .lines()
11341                .map(|line| {
11342                    line.strip_prefix(&line_prefix)
11343                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11344                        .with_context(|| {
11345                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11346                        })
11347                })
11348                .collect::<Result<Vec<_>, _>>()
11349                .log_err()
11350            else {
11351                continue;
11352            };
11353
11354            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11355                buffer
11356                    .language_settings_at(Point::new(start_row, 0), cx)
11357                    .preferred_line_length as usize
11358            });
11359            let wrapped_text = wrap_with_prefix(
11360                line_prefix,
11361                lines_without_prefixes.join("\n"),
11362                wrap_column,
11363                tab_size,
11364                options.preserve_existing_whitespace,
11365            );
11366
11367            // TODO: should always use char-based diff while still supporting cursor behavior that
11368            // matches vim.
11369            let mut diff_options = DiffOptions::default();
11370            if options.override_language_settings {
11371                diff_options.max_word_diff_len = 0;
11372                diff_options.max_word_diff_line_count = 0;
11373            } else {
11374                diff_options.max_word_diff_len = usize::MAX;
11375                diff_options.max_word_diff_line_count = usize::MAX;
11376            }
11377
11378            for (old_range, new_text) in
11379                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11380            {
11381                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11382                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11383                edits.push((edit_start..edit_end, new_text));
11384            }
11385
11386            rewrapped_row_ranges.push(start_row..=end_row);
11387        }
11388
11389        self.buffer
11390            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11391    }
11392
11393    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11394        let mut text = String::new();
11395        let buffer = self.buffer.read(cx).snapshot(cx);
11396        let mut selections = self.selections.all::<Point>(cx);
11397        let mut clipboard_selections = Vec::with_capacity(selections.len());
11398        {
11399            let max_point = buffer.max_point();
11400            let mut is_first = true;
11401            for selection in &mut selections {
11402                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11403                if is_entire_line {
11404                    selection.start = Point::new(selection.start.row, 0);
11405                    if !selection.is_empty() && selection.end.column == 0 {
11406                        selection.end = cmp::min(max_point, selection.end);
11407                    } else {
11408                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11409                    }
11410                    selection.goal = SelectionGoal::None;
11411                }
11412                if is_first {
11413                    is_first = false;
11414                } else {
11415                    text += "\n";
11416                }
11417                let mut len = 0;
11418                for chunk in buffer.text_for_range(selection.start..selection.end) {
11419                    text.push_str(chunk);
11420                    len += chunk.len();
11421                }
11422                clipboard_selections.push(ClipboardSelection {
11423                    len,
11424                    is_entire_line,
11425                    first_line_indent: buffer
11426                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11427                        .len,
11428                });
11429            }
11430        }
11431
11432        self.transact(window, cx, |this, window, cx| {
11433            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11434                s.select(selections);
11435            });
11436            this.insert("", window, cx);
11437        });
11438        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11439    }
11440
11441    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11442        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11443        let item = self.cut_common(window, cx);
11444        cx.write_to_clipboard(item);
11445    }
11446
11447    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11448        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11449        self.change_selections(None, window, cx, |s| {
11450            s.move_with(|snapshot, sel| {
11451                if sel.is_empty() {
11452                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11453                }
11454            });
11455        });
11456        let item = self.cut_common(window, cx);
11457        cx.set_global(KillRing(item))
11458    }
11459
11460    pub fn kill_ring_yank(
11461        &mut self,
11462        _: &KillRingYank,
11463        window: &mut Window,
11464        cx: &mut Context<Self>,
11465    ) {
11466        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11467        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11468            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11469                (kill_ring.text().to_string(), kill_ring.metadata_json())
11470            } else {
11471                return;
11472            }
11473        } else {
11474            return;
11475        };
11476        self.do_paste(&text, metadata, false, window, cx);
11477    }
11478
11479    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11480        self.do_copy(true, cx);
11481    }
11482
11483    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11484        self.do_copy(false, cx);
11485    }
11486
11487    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11488        let selections = self.selections.all::<Point>(cx);
11489        let buffer = self.buffer.read(cx).read(cx);
11490        let mut text = String::new();
11491
11492        let mut clipboard_selections = Vec::with_capacity(selections.len());
11493        {
11494            let max_point = buffer.max_point();
11495            let mut is_first = true;
11496            for selection in &selections {
11497                let mut start = selection.start;
11498                let mut end = selection.end;
11499                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11500                if is_entire_line {
11501                    start = Point::new(start.row, 0);
11502                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11503                }
11504
11505                let mut trimmed_selections = Vec::new();
11506                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11507                    let row = MultiBufferRow(start.row);
11508                    let first_indent = buffer.indent_size_for_line(row);
11509                    if first_indent.len == 0 || start.column > first_indent.len {
11510                        trimmed_selections.push(start..end);
11511                    } else {
11512                        trimmed_selections.push(
11513                            Point::new(row.0, first_indent.len)
11514                                ..Point::new(row.0, buffer.line_len(row)),
11515                        );
11516                        for row in start.row + 1..=end.row {
11517                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11518                            if row == end.row {
11519                                line_len = end.column;
11520                            }
11521                            if line_len == 0 {
11522                                trimmed_selections
11523                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11524                                continue;
11525                            }
11526                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11527                            if row_indent_size.len >= first_indent.len {
11528                                trimmed_selections.push(
11529                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11530                                );
11531                            } else {
11532                                trimmed_selections.clear();
11533                                trimmed_selections.push(start..end);
11534                                break;
11535                            }
11536                        }
11537                    }
11538                } else {
11539                    trimmed_selections.push(start..end);
11540                }
11541
11542                for trimmed_range in trimmed_selections {
11543                    if is_first {
11544                        is_first = false;
11545                    } else {
11546                        text += "\n";
11547                    }
11548                    let mut len = 0;
11549                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11550                        text.push_str(chunk);
11551                        len += chunk.len();
11552                    }
11553                    clipboard_selections.push(ClipboardSelection {
11554                        len,
11555                        is_entire_line,
11556                        first_line_indent: buffer
11557                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11558                            .len,
11559                    });
11560                }
11561            }
11562        }
11563
11564        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11565            text,
11566            clipboard_selections,
11567        ));
11568    }
11569
11570    pub fn do_paste(
11571        &mut self,
11572        text: &String,
11573        clipboard_selections: Option<Vec<ClipboardSelection>>,
11574        handle_entire_lines: bool,
11575        window: &mut Window,
11576        cx: &mut Context<Self>,
11577    ) {
11578        if self.read_only(cx) {
11579            return;
11580        }
11581
11582        let clipboard_text = Cow::Borrowed(text);
11583
11584        self.transact(window, cx, |this, window, cx| {
11585            if let Some(mut clipboard_selections) = clipboard_selections {
11586                let old_selections = this.selections.all::<usize>(cx);
11587                let all_selections_were_entire_line =
11588                    clipboard_selections.iter().all(|s| s.is_entire_line);
11589                let first_selection_indent_column =
11590                    clipboard_selections.first().map(|s| s.first_line_indent);
11591                if clipboard_selections.len() != old_selections.len() {
11592                    clipboard_selections.drain(..);
11593                }
11594                let cursor_offset = this.selections.last::<usize>(cx).head();
11595                let mut auto_indent_on_paste = true;
11596
11597                this.buffer.update(cx, |buffer, cx| {
11598                    let snapshot = buffer.read(cx);
11599                    auto_indent_on_paste = snapshot
11600                        .language_settings_at(cursor_offset, cx)
11601                        .auto_indent_on_paste;
11602
11603                    let mut start_offset = 0;
11604                    let mut edits = Vec::new();
11605                    let mut original_indent_columns = Vec::new();
11606                    for (ix, selection) in old_selections.iter().enumerate() {
11607                        let to_insert;
11608                        let entire_line;
11609                        let original_indent_column;
11610                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11611                            let end_offset = start_offset + clipboard_selection.len;
11612                            to_insert = &clipboard_text[start_offset..end_offset];
11613                            entire_line = clipboard_selection.is_entire_line;
11614                            start_offset = end_offset + 1;
11615                            original_indent_column = Some(clipboard_selection.first_line_indent);
11616                        } else {
11617                            to_insert = clipboard_text.as_str();
11618                            entire_line = all_selections_were_entire_line;
11619                            original_indent_column = first_selection_indent_column
11620                        }
11621
11622                        // If the corresponding selection was empty when this slice of the
11623                        // clipboard text was written, then the entire line containing the
11624                        // selection was copied. If this selection is also currently empty,
11625                        // then paste the line before the current line of the buffer.
11626                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11627                            let column = selection.start.to_point(&snapshot).column as usize;
11628                            let line_start = selection.start - column;
11629                            line_start..line_start
11630                        } else {
11631                            selection.range()
11632                        };
11633
11634                        edits.push((range, to_insert));
11635                        original_indent_columns.push(original_indent_column);
11636                    }
11637                    drop(snapshot);
11638
11639                    buffer.edit(
11640                        edits,
11641                        if auto_indent_on_paste {
11642                            Some(AutoindentMode::Block {
11643                                original_indent_columns,
11644                            })
11645                        } else {
11646                            None
11647                        },
11648                        cx,
11649                    );
11650                });
11651
11652                let selections = this.selections.all::<usize>(cx);
11653                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11654                    s.select(selections)
11655                });
11656            } else {
11657                this.insert(&clipboard_text, window, cx);
11658            }
11659        });
11660    }
11661
11662    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11663        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11664        if let Some(item) = cx.read_from_clipboard() {
11665            let entries = item.entries();
11666
11667            match entries.first() {
11668                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11669                // of all the pasted entries.
11670                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11671                    .do_paste(
11672                        clipboard_string.text(),
11673                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11674                        true,
11675                        window,
11676                        cx,
11677                    ),
11678                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11679            }
11680        }
11681    }
11682
11683    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11684        if self.read_only(cx) {
11685            return;
11686        }
11687
11688        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11689
11690        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11691            if let Some((selections, _)) =
11692                self.selection_history.transaction(transaction_id).cloned()
11693            {
11694                self.change_selections(None, window, cx, |s| {
11695                    s.select_anchors(selections.to_vec());
11696                });
11697            } else {
11698                log::error!(
11699                    "No entry in selection_history found for undo. \
11700                     This may correspond to a bug where undo does not update the selection. \
11701                     If this is occurring, please add details to \
11702                     https://github.com/zed-industries/zed/issues/22692"
11703                );
11704            }
11705            self.request_autoscroll(Autoscroll::fit(), cx);
11706            self.unmark_text(window, cx);
11707            self.refresh_inline_completion(true, false, window, cx);
11708            cx.emit(EditorEvent::Edited { transaction_id });
11709            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11710        }
11711    }
11712
11713    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11714        if self.read_only(cx) {
11715            return;
11716        }
11717
11718        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11719
11720        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11721            if let Some((_, Some(selections))) =
11722                self.selection_history.transaction(transaction_id).cloned()
11723            {
11724                self.change_selections(None, window, cx, |s| {
11725                    s.select_anchors(selections.to_vec());
11726                });
11727            } else {
11728                log::error!(
11729                    "No entry in selection_history found for redo. \
11730                     This may correspond to a bug where undo does not update the selection. \
11731                     If this is occurring, please add details to \
11732                     https://github.com/zed-industries/zed/issues/22692"
11733                );
11734            }
11735            self.request_autoscroll(Autoscroll::fit(), cx);
11736            self.unmark_text(window, cx);
11737            self.refresh_inline_completion(true, false, window, cx);
11738            cx.emit(EditorEvent::Edited { transaction_id });
11739        }
11740    }
11741
11742    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11743        self.buffer
11744            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11745    }
11746
11747    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11748        self.buffer
11749            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11750    }
11751
11752    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11753        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11754        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11755            s.move_with(|map, selection| {
11756                let cursor = if selection.is_empty() {
11757                    movement::left(map, selection.start)
11758                } else {
11759                    selection.start
11760                };
11761                selection.collapse_to(cursor, SelectionGoal::None);
11762            });
11763        })
11764    }
11765
11766    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11767        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11768        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11769            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11770        })
11771    }
11772
11773    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11774        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11775        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11776            s.move_with(|map, selection| {
11777                let cursor = if selection.is_empty() {
11778                    movement::right(map, selection.end)
11779                } else {
11780                    selection.end
11781                };
11782                selection.collapse_to(cursor, SelectionGoal::None)
11783            });
11784        })
11785    }
11786
11787    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11788        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11789        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11790            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11791        })
11792    }
11793
11794    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11795        if self.take_rename(true, window, cx).is_some() {
11796            return;
11797        }
11798
11799        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11800            cx.propagate();
11801            return;
11802        }
11803
11804        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11805
11806        let text_layout_details = &self.text_layout_details(window);
11807        let selection_count = self.selections.count();
11808        let first_selection = self.selections.first_anchor();
11809
11810        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11811            s.move_with(|map, selection| {
11812                if !selection.is_empty() {
11813                    selection.goal = SelectionGoal::None;
11814                }
11815                let (cursor, goal) = movement::up(
11816                    map,
11817                    selection.start,
11818                    selection.goal,
11819                    false,
11820                    text_layout_details,
11821                );
11822                selection.collapse_to(cursor, goal);
11823            });
11824        });
11825
11826        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11827        {
11828            cx.propagate();
11829        }
11830    }
11831
11832    pub fn move_up_by_lines(
11833        &mut self,
11834        action: &MoveUpByLines,
11835        window: &mut Window,
11836        cx: &mut Context<Self>,
11837    ) {
11838        if self.take_rename(true, window, cx).is_some() {
11839            return;
11840        }
11841
11842        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11843            cx.propagate();
11844            return;
11845        }
11846
11847        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11848
11849        let text_layout_details = &self.text_layout_details(window);
11850
11851        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11852            s.move_with(|map, selection| {
11853                if !selection.is_empty() {
11854                    selection.goal = SelectionGoal::None;
11855                }
11856                let (cursor, goal) = movement::up_by_rows(
11857                    map,
11858                    selection.start,
11859                    action.lines,
11860                    selection.goal,
11861                    false,
11862                    text_layout_details,
11863                );
11864                selection.collapse_to(cursor, goal);
11865            });
11866        })
11867    }
11868
11869    pub fn move_down_by_lines(
11870        &mut self,
11871        action: &MoveDownByLines,
11872        window: &mut Window,
11873        cx: &mut Context<Self>,
11874    ) {
11875        if self.take_rename(true, window, cx).is_some() {
11876            return;
11877        }
11878
11879        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11880            cx.propagate();
11881            return;
11882        }
11883
11884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11885
11886        let text_layout_details = &self.text_layout_details(window);
11887
11888        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11889            s.move_with(|map, selection| {
11890                if !selection.is_empty() {
11891                    selection.goal = SelectionGoal::None;
11892                }
11893                let (cursor, goal) = movement::down_by_rows(
11894                    map,
11895                    selection.start,
11896                    action.lines,
11897                    selection.goal,
11898                    false,
11899                    text_layout_details,
11900                );
11901                selection.collapse_to(cursor, goal);
11902            });
11903        })
11904    }
11905
11906    pub fn select_down_by_lines(
11907        &mut self,
11908        action: &SelectDownByLines,
11909        window: &mut Window,
11910        cx: &mut Context<Self>,
11911    ) {
11912        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11913        let text_layout_details = &self.text_layout_details(window);
11914        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11915            s.move_heads_with(|map, head, goal| {
11916                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11917            })
11918        })
11919    }
11920
11921    pub fn select_up_by_lines(
11922        &mut self,
11923        action: &SelectUpByLines,
11924        window: &mut Window,
11925        cx: &mut Context<Self>,
11926    ) {
11927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11928        let text_layout_details = &self.text_layout_details(window);
11929        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11930            s.move_heads_with(|map, head, goal| {
11931                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11932            })
11933        })
11934    }
11935
11936    pub fn select_page_up(
11937        &mut self,
11938        _: &SelectPageUp,
11939        window: &mut Window,
11940        cx: &mut Context<Self>,
11941    ) {
11942        let Some(row_count) = self.visible_row_count() else {
11943            return;
11944        };
11945
11946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11947
11948        let text_layout_details = &self.text_layout_details(window);
11949
11950        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11951            s.move_heads_with(|map, head, goal| {
11952                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11953            })
11954        })
11955    }
11956
11957    pub fn move_page_up(
11958        &mut self,
11959        action: &MovePageUp,
11960        window: &mut Window,
11961        cx: &mut Context<Self>,
11962    ) {
11963        if self.take_rename(true, window, cx).is_some() {
11964            return;
11965        }
11966
11967        if self
11968            .context_menu
11969            .borrow_mut()
11970            .as_mut()
11971            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11972            .unwrap_or(false)
11973        {
11974            return;
11975        }
11976
11977        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11978            cx.propagate();
11979            return;
11980        }
11981
11982        let Some(row_count) = self.visible_row_count() else {
11983            return;
11984        };
11985
11986        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11987
11988        let autoscroll = if action.center_cursor {
11989            Autoscroll::center()
11990        } else {
11991            Autoscroll::fit()
11992        };
11993
11994        let text_layout_details = &self.text_layout_details(window);
11995
11996        self.change_selections(Some(autoscroll), window, cx, |s| {
11997            s.move_with(|map, selection| {
11998                if !selection.is_empty() {
11999                    selection.goal = SelectionGoal::None;
12000                }
12001                let (cursor, goal) = movement::up_by_rows(
12002                    map,
12003                    selection.end,
12004                    row_count,
12005                    selection.goal,
12006                    false,
12007                    text_layout_details,
12008                );
12009                selection.collapse_to(cursor, goal);
12010            });
12011        });
12012    }
12013
12014    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12016        let text_layout_details = &self.text_layout_details(window);
12017        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12018            s.move_heads_with(|map, head, goal| {
12019                movement::up(map, head, goal, false, text_layout_details)
12020            })
12021        })
12022    }
12023
12024    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12025        self.take_rename(true, window, cx);
12026
12027        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12028            cx.propagate();
12029            return;
12030        }
12031
12032        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12033
12034        let text_layout_details = &self.text_layout_details(window);
12035        let selection_count = self.selections.count();
12036        let first_selection = self.selections.first_anchor();
12037
12038        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12039            s.move_with(|map, selection| {
12040                if !selection.is_empty() {
12041                    selection.goal = SelectionGoal::None;
12042                }
12043                let (cursor, goal) = movement::down(
12044                    map,
12045                    selection.end,
12046                    selection.goal,
12047                    false,
12048                    text_layout_details,
12049                );
12050                selection.collapse_to(cursor, goal);
12051            });
12052        });
12053
12054        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12055        {
12056            cx.propagate();
12057        }
12058    }
12059
12060    pub fn select_page_down(
12061        &mut self,
12062        _: &SelectPageDown,
12063        window: &mut Window,
12064        cx: &mut Context<Self>,
12065    ) {
12066        let Some(row_count) = self.visible_row_count() else {
12067            return;
12068        };
12069
12070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12071
12072        let text_layout_details = &self.text_layout_details(window);
12073
12074        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12075            s.move_heads_with(|map, head, goal| {
12076                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12077            })
12078        })
12079    }
12080
12081    pub fn move_page_down(
12082        &mut self,
12083        action: &MovePageDown,
12084        window: &mut Window,
12085        cx: &mut Context<Self>,
12086    ) {
12087        if self.take_rename(true, window, cx).is_some() {
12088            return;
12089        }
12090
12091        if self
12092            .context_menu
12093            .borrow_mut()
12094            .as_mut()
12095            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12096            .unwrap_or(false)
12097        {
12098            return;
12099        }
12100
12101        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12102            cx.propagate();
12103            return;
12104        }
12105
12106        let Some(row_count) = self.visible_row_count() else {
12107            return;
12108        };
12109
12110        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12111
12112        let autoscroll = if action.center_cursor {
12113            Autoscroll::center()
12114        } else {
12115            Autoscroll::fit()
12116        };
12117
12118        let text_layout_details = &self.text_layout_details(window);
12119        self.change_selections(Some(autoscroll), window, cx, |s| {
12120            s.move_with(|map, selection| {
12121                if !selection.is_empty() {
12122                    selection.goal = SelectionGoal::None;
12123                }
12124                let (cursor, goal) = movement::down_by_rows(
12125                    map,
12126                    selection.end,
12127                    row_count,
12128                    selection.goal,
12129                    false,
12130                    text_layout_details,
12131                );
12132                selection.collapse_to(cursor, goal);
12133            });
12134        });
12135    }
12136
12137    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12138        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12139        let text_layout_details = &self.text_layout_details(window);
12140        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12141            s.move_heads_with(|map, head, goal| {
12142                movement::down(map, head, goal, false, text_layout_details)
12143            })
12144        });
12145    }
12146
12147    pub fn context_menu_first(
12148        &mut self,
12149        _: &ContextMenuFirst,
12150        window: &mut Window,
12151        cx: &mut Context<Self>,
12152    ) {
12153        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12154            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12155        }
12156    }
12157
12158    pub fn context_menu_prev(
12159        &mut self,
12160        _: &ContextMenuPrevious,
12161        window: &mut Window,
12162        cx: &mut Context<Self>,
12163    ) {
12164        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12165            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12166        }
12167    }
12168
12169    pub fn context_menu_next(
12170        &mut self,
12171        _: &ContextMenuNext,
12172        window: &mut Window,
12173        cx: &mut Context<Self>,
12174    ) {
12175        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12176            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12177        }
12178    }
12179
12180    pub fn context_menu_last(
12181        &mut self,
12182        _: &ContextMenuLast,
12183        window: &mut Window,
12184        cx: &mut Context<Self>,
12185    ) {
12186        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12187            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12188        }
12189    }
12190
12191    pub fn move_to_previous_word_start(
12192        &mut self,
12193        _: &MoveToPreviousWordStart,
12194        window: &mut Window,
12195        cx: &mut Context<Self>,
12196    ) {
12197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12198        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12199            s.move_cursors_with(|map, head, _| {
12200                (
12201                    movement::previous_word_start(map, head),
12202                    SelectionGoal::None,
12203                )
12204            });
12205        })
12206    }
12207
12208    pub fn move_to_previous_subword_start(
12209        &mut self,
12210        _: &MoveToPreviousSubwordStart,
12211        window: &mut Window,
12212        cx: &mut Context<Self>,
12213    ) {
12214        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12215        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12216            s.move_cursors_with(|map, head, _| {
12217                (
12218                    movement::previous_subword_start(map, head),
12219                    SelectionGoal::None,
12220                )
12221            });
12222        })
12223    }
12224
12225    pub fn select_to_previous_word_start(
12226        &mut self,
12227        _: &SelectToPreviousWordStart,
12228        window: &mut Window,
12229        cx: &mut Context<Self>,
12230    ) {
12231        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12232        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12233            s.move_heads_with(|map, head, _| {
12234                (
12235                    movement::previous_word_start(map, head),
12236                    SelectionGoal::None,
12237                )
12238            });
12239        })
12240    }
12241
12242    pub fn select_to_previous_subword_start(
12243        &mut self,
12244        _: &SelectToPreviousSubwordStart,
12245        window: &mut Window,
12246        cx: &mut Context<Self>,
12247    ) {
12248        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12249        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12250            s.move_heads_with(|map, head, _| {
12251                (
12252                    movement::previous_subword_start(map, head),
12253                    SelectionGoal::None,
12254                )
12255            });
12256        })
12257    }
12258
12259    pub fn delete_to_previous_word_start(
12260        &mut self,
12261        action: &DeleteToPreviousWordStart,
12262        window: &mut Window,
12263        cx: &mut Context<Self>,
12264    ) {
12265        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12266        self.transact(window, cx, |this, window, cx| {
12267            this.select_autoclose_pair(window, cx);
12268            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12269                s.move_with(|map, selection| {
12270                    if selection.is_empty() {
12271                        let cursor = if action.ignore_newlines {
12272                            movement::previous_word_start(map, selection.head())
12273                        } else {
12274                            movement::previous_word_start_or_newline(map, selection.head())
12275                        };
12276                        selection.set_head(cursor, SelectionGoal::None);
12277                    }
12278                });
12279            });
12280            this.insert("", window, cx);
12281        });
12282    }
12283
12284    pub fn delete_to_previous_subword_start(
12285        &mut self,
12286        _: &DeleteToPreviousSubwordStart,
12287        window: &mut Window,
12288        cx: &mut Context<Self>,
12289    ) {
12290        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12291        self.transact(window, cx, |this, window, cx| {
12292            this.select_autoclose_pair(window, cx);
12293            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12294                s.move_with(|map, selection| {
12295                    if selection.is_empty() {
12296                        let cursor = movement::previous_subword_start(map, selection.head());
12297                        selection.set_head(cursor, SelectionGoal::None);
12298                    }
12299                });
12300            });
12301            this.insert("", window, cx);
12302        });
12303    }
12304
12305    pub fn move_to_next_word_end(
12306        &mut self,
12307        _: &MoveToNextWordEnd,
12308        window: &mut Window,
12309        cx: &mut Context<Self>,
12310    ) {
12311        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12312        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12313            s.move_cursors_with(|map, head, _| {
12314                (movement::next_word_end(map, head), SelectionGoal::None)
12315            });
12316        })
12317    }
12318
12319    pub fn move_to_next_subword_end(
12320        &mut self,
12321        _: &MoveToNextSubwordEnd,
12322        window: &mut Window,
12323        cx: &mut Context<Self>,
12324    ) {
12325        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12326        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12327            s.move_cursors_with(|map, head, _| {
12328                (movement::next_subword_end(map, head), SelectionGoal::None)
12329            });
12330        })
12331    }
12332
12333    pub fn select_to_next_word_end(
12334        &mut self,
12335        _: &SelectToNextWordEnd,
12336        window: &mut Window,
12337        cx: &mut Context<Self>,
12338    ) {
12339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12340        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12341            s.move_heads_with(|map, head, _| {
12342                (movement::next_word_end(map, head), SelectionGoal::None)
12343            });
12344        })
12345    }
12346
12347    pub fn select_to_next_subword_end(
12348        &mut self,
12349        _: &SelectToNextSubwordEnd,
12350        window: &mut Window,
12351        cx: &mut Context<Self>,
12352    ) {
12353        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12354        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12355            s.move_heads_with(|map, head, _| {
12356                (movement::next_subword_end(map, head), SelectionGoal::None)
12357            });
12358        })
12359    }
12360
12361    pub fn delete_to_next_word_end(
12362        &mut self,
12363        action: &DeleteToNextWordEnd,
12364        window: &mut Window,
12365        cx: &mut Context<Self>,
12366    ) {
12367        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12368        self.transact(window, cx, |this, window, cx| {
12369            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12370                s.move_with(|map, selection| {
12371                    if selection.is_empty() {
12372                        let cursor = if action.ignore_newlines {
12373                            movement::next_word_end(map, selection.head())
12374                        } else {
12375                            movement::next_word_end_or_newline(map, selection.head())
12376                        };
12377                        selection.set_head(cursor, SelectionGoal::None);
12378                    }
12379                });
12380            });
12381            this.insert("", window, cx);
12382        });
12383    }
12384
12385    pub fn delete_to_next_subword_end(
12386        &mut self,
12387        _: &DeleteToNextSubwordEnd,
12388        window: &mut Window,
12389        cx: &mut Context<Self>,
12390    ) {
12391        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12392        self.transact(window, cx, |this, window, cx| {
12393            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12394                s.move_with(|map, selection| {
12395                    if selection.is_empty() {
12396                        let cursor = movement::next_subword_end(map, selection.head());
12397                        selection.set_head(cursor, SelectionGoal::None);
12398                    }
12399                });
12400            });
12401            this.insert("", window, cx);
12402        });
12403    }
12404
12405    pub fn move_to_beginning_of_line(
12406        &mut self,
12407        action: &MoveToBeginningOfLine,
12408        window: &mut Window,
12409        cx: &mut Context<Self>,
12410    ) {
12411        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12412        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12413            s.move_cursors_with(|map, head, _| {
12414                (
12415                    movement::indented_line_beginning(
12416                        map,
12417                        head,
12418                        action.stop_at_soft_wraps,
12419                        action.stop_at_indent,
12420                    ),
12421                    SelectionGoal::None,
12422                )
12423            });
12424        })
12425    }
12426
12427    pub fn select_to_beginning_of_line(
12428        &mut self,
12429        action: &SelectToBeginningOfLine,
12430        window: &mut Window,
12431        cx: &mut Context<Self>,
12432    ) {
12433        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12434        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12435            s.move_heads_with(|map, head, _| {
12436                (
12437                    movement::indented_line_beginning(
12438                        map,
12439                        head,
12440                        action.stop_at_soft_wraps,
12441                        action.stop_at_indent,
12442                    ),
12443                    SelectionGoal::None,
12444                )
12445            });
12446        });
12447    }
12448
12449    pub fn delete_to_beginning_of_line(
12450        &mut self,
12451        action: &DeleteToBeginningOfLine,
12452        window: &mut Window,
12453        cx: &mut Context<Self>,
12454    ) {
12455        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12456        self.transact(window, cx, |this, window, cx| {
12457            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12458                s.move_with(|_, selection| {
12459                    selection.reversed = true;
12460                });
12461            });
12462
12463            this.select_to_beginning_of_line(
12464                &SelectToBeginningOfLine {
12465                    stop_at_soft_wraps: false,
12466                    stop_at_indent: action.stop_at_indent,
12467                },
12468                window,
12469                cx,
12470            );
12471            this.backspace(&Backspace, window, cx);
12472        });
12473    }
12474
12475    pub fn move_to_end_of_line(
12476        &mut self,
12477        action: &MoveToEndOfLine,
12478        window: &mut Window,
12479        cx: &mut Context<Self>,
12480    ) {
12481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12482        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12483            s.move_cursors_with(|map, head, _| {
12484                (
12485                    movement::line_end(map, head, action.stop_at_soft_wraps),
12486                    SelectionGoal::None,
12487                )
12488            });
12489        })
12490    }
12491
12492    pub fn select_to_end_of_line(
12493        &mut self,
12494        action: &SelectToEndOfLine,
12495        window: &mut Window,
12496        cx: &mut Context<Self>,
12497    ) {
12498        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12499        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12500            s.move_heads_with(|map, head, _| {
12501                (
12502                    movement::line_end(map, head, action.stop_at_soft_wraps),
12503                    SelectionGoal::None,
12504                )
12505            });
12506        })
12507    }
12508
12509    pub fn delete_to_end_of_line(
12510        &mut self,
12511        _: &DeleteToEndOfLine,
12512        window: &mut Window,
12513        cx: &mut Context<Self>,
12514    ) {
12515        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12516        self.transact(window, cx, |this, window, cx| {
12517            this.select_to_end_of_line(
12518                &SelectToEndOfLine {
12519                    stop_at_soft_wraps: false,
12520                },
12521                window,
12522                cx,
12523            );
12524            this.delete(&Delete, window, cx);
12525        });
12526    }
12527
12528    pub fn cut_to_end_of_line(
12529        &mut self,
12530        _: &CutToEndOfLine,
12531        window: &mut Window,
12532        cx: &mut Context<Self>,
12533    ) {
12534        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12535        self.transact(window, cx, |this, window, cx| {
12536            this.select_to_end_of_line(
12537                &SelectToEndOfLine {
12538                    stop_at_soft_wraps: false,
12539                },
12540                window,
12541                cx,
12542            );
12543            this.cut(&Cut, window, cx);
12544        });
12545    }
12546
12547    pub fn move_to_start_of_paragraph(
12548        &mut self,
12549        _: &MoveToStartOfParagraph,
12550        window: &mut Window,
12551        cx: &mut Context<Self>,
12552    ) {
12553        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12554            cx.propagate();
12555            return;
12556        }
12557        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12558        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12559            s.move_with(|map, selection| {
12560                selection.collapse_to(
12561                    movement::start_of_paragraph(map, selection.head(), 1),
12562                    SelectionGoal::None,
12563                )
12564            });
12565        })
12566    }
12567
12568    pub fn move_to_end_of_paragraph(
12569        &mut self,
12570        _: &MoveToEndOfParagraph,
12571        window: &mut Window,
12572        cx: &mut Context<Self>,
12573    ) {
12574        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12575            cx.propagate();
12576            return;
12577        }
12578        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12579        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12580            s.move_with(|map, selection| {
12581                selection.collapse_to(
12582                    movement::end_of_paragraph(map, selection.head(), 1),
12583                    SelectionGoal::None,
12584                )
12585            });
12586        })
12587    }
12588
12589    pub fn select_to_start_of_paragraph(
12590        &mut self,
12591        _: &SelectToStartOfParagraph,
12592        window: &mut Window,
12593        cx: &mut Context<Self>,
12594    ) {
12595        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12596            cx.propagate();
12597            return;
12598        }
12599        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12600        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12601            s.move_heads_with(|map, head, _| {
12602                (
12603                    movement::start_of_paragraph(map, head, 1),
12604                    SelectionGoal::None,
12605                )
12606            });
12607        })
12608    }
12609
12610    pub fn select_to_end_of_paragraph(
12611        &mut self,
12612        _: &SelectToEndOfParagraph,
12613        window: &mut Window,
12614        cx: &mut Context<Self>,
12615    ) {
12616        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12617            cx.propagate();
12618            return;
12619        }
12620        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12621        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12622            s.move_heads_with(|map, head, _| {
12623                (
12624                    movement::end_of_paragraph(map, head, 1),
12625                    SelectionGoal::None,
12626                )
12627            });
12628        })
12629    }
12630
12631    pub fn move_to_start_of_excerpt(
12632        &mut self,
12633        _: &MoveToStartOfExcerpt,
12634        window: &mut Window,
12635        cx: &mut Context<Self>,
12636    ) {
12637        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12638            cx.propagate();
12639            return;
12640        }
12641        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12642        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12643            s.move_with(|map, selection| {
12644                selection.collapse_to(
12645                    movement::start_of_excerpt(
12646                        map,
12647                        selection.head(),
12648                        workspace::searchable::Direction::Prev,
12649                    ),
12650                    SelectionGoal::None,
12651                )
12652            });
12653        })
12654    }
12655
12656    pub fn move_to_start_of_next_excerpt(
12657        &mut self,
12658        _: &MoveToStartOfNextExcerpt,
12659        window: &mut Window,
12660        cx: &mut Context<Self>,
12661    ) {
12662        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12663            cx.propagate();
12664            return;
12665        }
12666
12667        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12668            s.move_with(|map, selection| {
12669                selection.collapse_to(
12670                    movement::start_of_excerpt(
12671                        map,
12672                        selection.head(),
12673                        workspace::searchable::Direction::Next,
12674                    ),
12675                    SelectionGoal::None,
12676                )
12677            });
12678        })
12679    }
12680
12681    pub fn move_to_end_of_excerpt(
12682        &mut self,
12683        _: &MoveToEndOfExcerpt,
12684        window: &mut Window,
12685        cx: &mut Context<Self>,
12686    ) {
12687        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12688            cx.propagate();
12689            return;
12690        }
12691        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12692        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12693            s.move_with(|map, selection| {
12694                selection.collapse_to(
12695                    movement::end_of_excerpt(
12696                        map,
12697                        selection.head(),
12698                        workspace::searchable::Direction::Next,
12699                    ),
12700                    SelectionGoal::None,
12701                )
12702            });
12703        })
12704    }
12705
12706    pub fn move_to_end_of_previous_excerpt(
12707        &mut self,
12708        _: &MoveToEndOfPreviousExcerpt,
12709        window: &mut Window,
12710        cx: &mut Context<Self>,
12711    ) {
12712        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12713            cx.propagate();
12714            return;
12715        }
12716        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12717        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12718            s.move_with(|map, selection| {
12719                selection.collapse_to(
12720                    movement::end_of_excerpt(
12721                        map,
12722                        selection.head(),
12723                        workspace::searchable::Direction::Prev,
12724                    ),
12725                    SelectionGoal::None,
12726                )
12727            });
12728        })
12729    }
12730
12731    pub fn select_to_start_of_excerpt(
12732        &mut self,
12733        _: &SelectToStartOfExcerpt,
12734        window: &mut Window,
12735        cx: &mut Context<Self>,
12736    ) {
12737        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12738            cx.propagate();
12739            return;
12740        }
12741        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12742        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12743            s.move_heads_with(|map, head, _| {
12744                (
12745                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12746                    SelectionGoal::None,
12747                )
12748            });
12749        })
12750    }
12751
12752    pub fn select_to_start_of_next_excerpt(
12753        &mut self,
12754        _: &SelectToStartOfNextExcerpt,
12755        window: &mut Window,
12756        cx: &mut Context<Self>,
12757    ) {
12758        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12759            cx.propagate();
12760            return;
12761        }
12762        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12763        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12764            s.move_heads_with(|map, head, _| {
12765                (
12766                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12767                    SelectionGoal::None,
12768                )
12769            });
12770        })
12771    }
12772
12773    pub fn select_to_end_of_excerpt(
12774        &mut self,
12775        _: &SelectToEndOfExcerpt,
12776        window: &mut Window,
12777        cx: &mut Context<Self>,
12778    ) {
12779        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12780            cx.propagate();
12781            return;
12782        }
12783        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12784        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12785            s.move_heads_with(|map, head, _| {
12786                (
12787                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12788                    SelectionGoal::None,
12789                )
12790            });
12791        })
12792    }
12793
12794    pub fn select_to_end_of_previous_excerpt(
12795        &mut self,
12796        _: &SelectToEndOfPreviousExcerpt,
12797        window: &mut Window,
12798        cx: &mut Context<Self>,
12799    ) {
12800        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12801            cx.propagate();
12802            return;
12803        }
12804        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12805        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12806            s.move_heads_with(|map, head, _| {
12807                (
12808                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12809                    SelectionGoal::None,
12810                )
12811            });
12812        })
12813    }
12814
12815    pub fn move_to_beginning(
12816        &mut self,
12817        _: &MoveToBeginning,
12818        window: &mut Window,
12819        cx: &mut Context<Self>,
12820    ) {
12821        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12822            cx.propagate();
12823            return;
12824        }
12825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12826        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12827            s.select_ranges(vec![0..0]);
12828        });
12829    }
12830
12831    pub fn select_to_beginning(
12832        &mut self,
12833        _: &SelectToBeginning,
12834        window: &mut Window,
12835        cx: &mut Context<Self>,
12836    ) {
12837        let mut selection = self.selections.last::<Point>(cx);
12838        selection.set_head(Point::zero(), SelectionGoal::None);
12839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12840        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12841            s.select(vec![selection]);
12842        });
12843    }
12844
12845    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12846        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12847            cx.propagate();
12848            return;
12849        }
12850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12851        let cursor = self.buffer.read(cx).read(cx).len();
12852        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12853            s.select_ranges(vec![cursor..cursor])
12854        });
12855    }
12856
12857    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12858        self.nav_history = nav_history;
12859    }
12860
12861    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12862        self.nav_history.as_ref()
12863    }
12864
12865    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12866        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12867    }
12868
12869    fn push_to_nav_history(
12870        &mut self,
12871        cursor_anchor: Anchor,
12872        new_position: Option<Point>,
12873        is_deactivate: bool,
12874        cx: &mut Context<Self>,
12875    ) {
12876        if let Some(nav_history) = self.nav_history.as_mut() {
12877            let buffer = self.buffer.read(cx).read(cx);
12878            let cursor_position = cursor_anchor.to_point(&buffer);
12879            let scroll_state = self.scroll_manager.anchor();
12880            let scroll_top_row = scroll_state.top_row(&buffer);
12881            drop(buffer);
12882
12883            if let Some(new_position) = new_position {
12884                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12885                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12886                    return;
12887                }
12888            }
12889
12890            nav_history.push(
12891                Some(NavigationData {
12892                    cursor_anchor,
12893                    cursor_position,
12894                    scroll_anchor: scroll_state,
12895                    scroll_top_row,
12896                }),
12897                cx,
12898            );
12899            cx.emit(EditorEvent::PushedToNavHistory {
12900                anchor: cursor_anchor,
12901                is_deactivate,
12902            })
12903        }
12904    }
12905
12906    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12907        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12908        let buffer = self.buffer.read(cx).snapshot(cx);
12909        let mut selection = self.selections.first::<usize>(cx);
12910        selection.set_head(buffer.len(), SelectionGoal::None);
12911        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12912            s.select(vec![selection]);
12913        });
12914    }
12915
12916    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12917        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12918        let end = self.buffer.read(cx).read(cx).len();
12919        self.change_selections(None, window, cx, |s| {
12920            s.select_ranges(vec![0..end]);
12921        });
12922    }
12923
12924    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12926        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12927        let mut selections = self.selections.all::<Point>(cx);
12928        let max_point = display_map.buffer_snapshot.max_point();
12929        for selection in &mut selections {
12930            let rows = selection.spanned_rows(true, &display_map);
12931            selection.start = Point::new(rows.start.0, 0);
12932            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12933            selection.reversed = false;
12934        }
12935        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12936            s.select(selections);
12937        });
12938    }
12939
12940    pub fn split_selection_into_lines(
12941        &mut self,
12942        _: &SplitSelectionIntoLines,
12943        window: &mut Window,
12944        cx: &mut Context<Self>,
12945    ) {
12946        let selections = self
12947            .selections
12948            .all::<Point>(cx)
12949            .into_iter()
12950            .map(|selection| selection.start..selection.end)
12951            .collect::<Vec<_>>();
12952        self.unfold_ranges(&selections, true, true, cx);
12953
12954        let mut new_selection_ranges = Vec::new();
12955        {
12956            let buffer = self.buffer.read(cx).read(cx);
12957            for selection in selections {
12958                for row in selection.start.row..selection.end.row {
12959                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12960                    new_selection_ranges.push(cursor..cursor);
12961                }
12962
12963                let is_multiline_selection = selection.start.row != selection.end.row;
12964                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12965                // so this action feels more ergonomic when paired with other selection operations
12966                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12967                if !should_skip_last {
12968                    new_selection_ranges.push(selection.end..selection.end);
12969                }
12970            }
12971        }
12972        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12973            s.select_ranges(new_selection_ranges);
12974        });
12975    }
12976
12977    pub fn add_selection_above(
12978        &mut self,
12979        _: &AddSelectionAbove,
12980        window: &mut Window,
12981        cx: &mut Context<Self>,
12982    ) {
12983        self.add_selection(true, window, cx);
12984    }
12985
12986    pub fn add_selection_below(
12987        &mut self,
12988        _: &AddSelectionBelow,
12989        window: &mut Window,
12990        cx: &mut Context<Self>,
12991    ) {
12992        self.add_selection(false, window, cx);
12993    }
12994
12995    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12996        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12997
12998        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12999        let all_selections = self.selections.all::<Point>(cx);
13000        let text_layout_details = self.text_layout_details(window);
13001
13002        let (mut columnar_selections, new_selections_to_columnarize) = {
13003            if let Some(state) = self.add_selections_state.as_ref() {
13004                let columnar_selection_ids: HashSet<_> = state
13005                    .groups
13006                    .iter()
13007                    .flat_map(|group| group.stack.iter())
13008                    .copied()
13009                    .collect();
13010
13011                all_selections
13012                    .into_iter()
13013                    .partition(|s| columnar_selection_ids.contains(&s.id))
13014            } else {
13015                (Vec::new(), all_selections)
13016            }
13017        };
13018
13019        let mut state = self
13020            .add_selections_state
13021            .take()
13022            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13023
13024        for selection in new_selections_to_columnarize {
13025            let range = selection.display_range(&display_map).sorted();
13026            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13027            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13028            let positions = start_x.min(end_x)..start_x.max(end_x);
13029            let mut stack = Vec::new();
13030            for row in range.start.row().0..=range.end.row().0 {
13031                if let Some(selection) = self.selections.build_columnar_selection(
13032                    &display_map,
13033                    DisplayRow(row),
13034                    &positions,
13035                    selection.reversed,
13036                    &text_layout_details,
13037                ) {
13038                    stack.push(selection.id);
13039                    columnar_selections.push(selection);
13040                }
13041            }
13042            if !stack.is_empty() {
13043                if above {
13044                    stack.reverse();
13045                }
13046                state.groups.push(AddSelectionsGroup { above, stack });
13047            }
13048        }
13049
13050        let mut final_selections = Vec::new();
13051        let end_row = if above {
13052            DisplayRow(0)
13053        } else {
13054            display_map.max_point().row()
13055        };
13056
13057        let mut last_added_item_per_group = HashMap::default();
13058        for group in state.groups.iter_mut() {
13059            if let Some(last_id) = group.stack.last() {
13060                last_added_item_per_group.insert(*last_id, group);
13061            }
13062        }
13063
13064        for selection in columnar_selections {
13065            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13066                if above == group.above {
13067                    let range = selection.display_range(&display_map).sorted();
13068                    debug_assert_eq!(range.start.row(), range.end.row());
13069                    let mut row = range.start.row();
13070                    let positions =
13071                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13072                            px(start)..px(end)
13073                        } else {
13074                            let start_x =
13075                                display_map.x_for_display_point(range.start, &text_layout_details);
13076                            let end_x =
13077                                display_map.x_for_display_point(range.end, &text_layout_details);
13078                            start_x.min(end_x)..start_x.max(end_x)
13079                        };
13080
13081                    let mut maybe_new_selection = None;
13082                    while row != end_row {
13083                        if above {
13084                            row.0 -= 1;
13085                        } else {
13086                            row.0 += 1;
13087                        }
13088                        if let Some(new_selection) = self.selections.build_columnar_selection(
13089                            &display_map,
13090                            row,
13091                            &positions,
13092                            selection.reversed,
13093                            &text_layout_details,
13094                        ) {
13095                            maybe_new_selection = Some(new_selection);
13096                            break;
13097                        }
13098                    }
13099
13100                    if let Some(new_selection) = maybe_new_selection {
13101                        group.stack.push(new_selection.id);
13102                        if above {
13103                            final_selections.push(new_selection);
13104                            final_selections.push(selection);
13105                        } else {
13106                            final_selections.push(selection);
13107                            final_selections.push(new_selection);
13108                        }
13109                    } else {
13110                        final_selections.push(selection);
13111                    }
13112                } else {
13113                    group.stack.pop();
13114                }
13115            } else {
13116                final_selections.push(selection);
13117            }
13118        }
13119
13120        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13121            s.select(final_selections);
13122        });
13123
13124        let final_selection_ids: HashSet<_> = self
13125            .selections
13126            .all::<Point>(cx)
13127            .iter()
13128            .map(|s| s.id)
13129            .collect();
13130        state.groups.retain_mut(|group| {
13131            // selections might get merged above so we remove invalid items from stacks
13132            group.stack.retain(|id| final_selection_ids.contains(id));
13133
13134            // single selection in stack can be treated as initial state
13135            group.stack.len() > 1
13136        });
13137
13138        if !state.groups.is_empty() {
13139            self.add_selections_state = Some(state);
13140        }
13141    }
13142
13143    fn select_match_ranges(
13144        &mut self,
13145        range: Range<usize>,
13146        reversed: bool,
13147        replace_newest: bool,
13148        auto_scroll: Option<Autoscroll>,
13149        window: &mut Window,
13150        cx: &mut Context<Editor>,
13151    ) {
13152        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13153        self.change_selections(auto_scroll, window, cx, |s| {
13154            if replace_newest {
13155                s.delete(s.newest_anchor().id);
13156            }
13157            if reversed {
13158                s.insert_range(range.end..range.start);
13159            } else {
13160                s.insert_range(range);
13161            }
13162        });
13163    }
13164
13165    pub fn select_next_match_internal(
13166        &mut self,
13167        display_map: &DisplaySnapshot,
13168        replace_newest: bool,
13169        autoscroll: Option<Autoscroll>,
13170        window: &mut Window,
13171        cx: &mut Context<Self>,
13172    ) -> Result<()> {
13173        let buffer = &display_map.buffer_snapshot;
13174        let mut selections = self.selections.all::<usize>(cx);
13175        if let Some(mut select_next_state) = self.select_next_state.take() {
13176            let query = &select_next_state.query;
13177            if !select_next_state.done {
13178                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13179                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13180                let mut next_selected_range = None;
13181
13182                let bytes_after_last_selection =
13183                    buffer.bytes_in_range(last_selection.end..buffer.len());
13184                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13185                let query_matches = query
13186                    .stream_find_iter(bytes_after_last_selection)
13187                    .map(|result| (last_selection.end, result))
13188                    .chain(
13189                        query
13190                            .stream_find_iter(bytes_before_first_selection)
13191                            .map(|result| (0, result)),
13192                    );
13193
13194                for (start_offset, query_match) in query_matches {
13195                    let query_match = query_match.unwrap(); // can only fail due to I/O
13196                    let offset_range =
13197                        start_offset + query_match.start()..start_offset + query_match.end();
13198                    let display_range = offset_range.start.to_display_point(display_map)
13199                        ..offset_range.end.to_display_point(display_map);
13200
13201                    if !select_next_state.wordwise
13202                        || (!movement::is_inside_word(display_map, display_range.start)
13203                            && !movement::is_inside_word(display_map, display_range.end))
13204                    {
13205                        // TODO: This is n^2, because we might check all the selections
13206                        if !selections
13207                            .iter()
13208                            .any(|selection| selection.range().overlaps(&offset_range))
13209                        {
13210                            next_selected_range = Some(offset_range);
13211                            break;
13212                        }
13213                    }
13214                }
13215
13216                if let Some(next_selected_range) = next_selected_range {
13217                    self.select_match_ranges(
13218                        next_selected_range,
13219                        last_selection.reversed,
13220                        replace_newest,
13221                        autoscroll,
13222                        window,
13223                        cx,
13224                    );
13225                } else {
13226                    select_next_state.done = true;
13227                }
13228            }
13229
13230            self.select_next_state = Some(select_next_state);
13231        } else {
13232            let mut only_carets = true;
13233            let mut same_text_selected = true;
13234            let mut selected_text = None;
13235
13236            let mut selections_iter = selections.iter().peekable();
13237            while let Some(selection) = selections_iter.next() {
13238                if selection.start != selection.end {
13239                    only_carets = false;
13240                }
13241
13242                if same_text_selected {
13243                    if selected_text.is_none() {
13244                        selected_text =
13245                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13246                    }
13247
13248                    if let Some(next_selection) = selections_iter.peek() {
13249                        if next_selection.range().len() == selection.range().len() {
13250                            let next_selected_text = buffer
13251                                .text_for_range(next_selection.range())
13252                                .collect::<String>();
13253                            if Some(next_selected_text) != selected_text {
13254                                same_text_selected = false;
13255                                selected_text = None;
13256                            }
13257                        } else {
13258                            same_text_selected = false;
13259                            selected_text = None;
13260                        }
13261                    }
13262                }
13263            }
13264
13265            if only_carets {
13266                for selection in &mut selections {
13267                    let word_range = movement::surrounding_word(
13268                        display_map,
13269                        selection.start.to_display_point(display_map),
13270                    );
13271                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13272                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13273                    selection.goal = SelectionGoal::None;
13274                    selection.reversed = false;
13275                    self.select_match_ranges(
13276                        selection.start..selection.end,
13277                        selection.reversed,
13278                        replace_newest,
13279                        autoscroll,
13280                        window,
13281                        cx,
13282                    );
13283                }
13284
13285                if selections.len() == 1 {
13286                    let selection = selections
13287                        .last()
13288                        .expect("ensured that there's only one selection");
13289                    let query = buffer
13290                        .text_for_range(selection.start..selection.end)
13291                        .collect::<String>();
13292                    let is_empty = query.is_empty();
13293                    let select_state = SelectNextState {
13294                        query: AhoCorasick::new(&[query])?,
13295                        wordwise: true,
13296                        done: is_empty,
13297                    };
13298                    self.select_next_state = Some(select_state);
13299                } else {
13300                    self.select_next_state = None;
13301                }
13302            } else if let Some(selected_text) = selected_text {
13303                self.select_next_state = Some(SelectNextState {
13304                    query: AhoCorasick::new(&[selected_text])?,
13305                    wordwise: false,
13306                    done: false,
13307                });
13308                self.select_next_match_internal(
13309                    display_map,
13310                    replace_newest,
13311                    autoscroll,
13312                    window,
13313                    cx,
13314                )?;
13315            }
13316        }
13317        Ok(())
13318    }
13319
13320    pub fn select_all_matches(
13321        &mut self,
13322        _action: &SelectAllMatches,
13323        window: &mut Window,
13324        cx: &mut Context<Self>,
13325    ) -> Result<()> {
13326        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13327
13328        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13329
13330        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13331        let Some(select_next_state) = self.select_next_state.as_mut() else {
13332            return Ok(());
13333        };
13334        if select_next_state.done {
13335            return Ok(());
13336        }
13337
13338        let mut new_selections = Vec::new();
13339
13340        let reversed = self.selections.oldest::<usize>(cx).reversed;
13341        let buffer = &display_map.buffer_snapshot;
13342        let query_matches = select_next_state
13343            .query
13344            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13345
13346        for query_match in query_matches.into_iter() {
13347            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13348            let offset_range = if reversed {
13349                query_match.end()..query_match.start()
13350            } else {
13351                query_match.start()..query_match.end()
13352            };
13353            let display_range = offset_range.start.to_display_point(&display_map)
13354                ..offset_range.end.to_display_point(&display_map);
13355
13356            if !select_next_state.wordwise
13357                || (!movement::is_inside_word(&display_map, display_range.start)
13358                    && !movement::is_inside_word(&display_map, display_range.end))
13359            {
13360                new_selections.push(offset_range.start..offset_range.end);
13361            }
13362        }
13363
13364        select_next_state.done = true;
13365        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13366        self.change_selections(None, window, cx, |selections| {
13367            selections.select_ranges(new_selections)
13368        });
13369
13370        Ok(())
13371    }
13372
13373    pub fn select_next(
13374        &mut self,
13375        action: &SelectNext,
13376        window: &mut Window,
13377        cx: &mut Context<Self>,
13378    ) -> Result<()> {
13379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13380        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13381        self.select_next_match_internal(
13382            &display_map,
13383            action.replace_newest,
13384            Some(Autoscroll::newest()),
13385            window,
13386            cx,
13387        )?;
13388        Ok(())
13389    }
13390
13391    pub fn select_previous(
13392        &mut self,
13393        action: &SelectPrevious,
13394        window: &mut Window,
13395        cx: &mut Context<Self>,
13396    ) -> Result<()> {
13397        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13398        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13399        let buffer = &display_map.buffer_snapshot;
13400        let mut selections = self.selections.all::<usize>(cx);
13401        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13402            let query = &select_prev_state.query;
13403            if !select_prev_state.done {
13404                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13405                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13406                let mut next_selected_range = None;
13407                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13408                let bytes_before_last_selection =
13409                    buffer.reversed_bytes_in_range(0..last_selection.start);
13410                let bytes_after_first_selection =
13411                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13412                let query_matches = query
13413                    .stream_find_iter(bytes_before_last_selection)
13414                    .map(|result| (last_selection.start, result))
13415                    .chain(
13416                        query
13417                            .stream_find_iter(bytes_after_first_selection)
13418                            .map(|result| (buffer.len(), result)),
13419                    );
13420                for (end_offset, query_match) in query_matches {
13421                    let query_match = query_match.unwrap(); // can only fail due to I/O
13422                    let offset_range =
13423                        end_offset - query_match.end()..end_offset - query_match.start();
13424                    let display_range = offset_range.start.to_display_point(&display_map)
13425                        ..offset_range.end.to_display_point(&display_map);
13426
13427                    if !select_prev_state.wordwise
13428                        || (!movement::is_inside_word(&display_map, display_range.start)
13429                            && !movement::is_inside_word(&display_map, display_range.end))
13430                    {
13431                        next_selected_range = Some(offset_range);
13432                        break;
13433                    }
13434                }
13435
13436                if let Some(next_selected_range) = next_selected_range {
13437                    self.select_match_ranges(
13438                        next_selected_range,
13439                        last_selection.reversed,
13440                        action.replace_newest,
13441                        Some(Autoscroll::newest()),
13442                        window,
13443                        cx,
13444                    );
13445                } else {
13446                    select_prev_state.done = true;
13447                }
13448            }
13449
13450            self.select_prev_state = Some(select_prev_state);
13451        } else {
13452            let mut only_carets = true;
13453            let mut same_text_selected = true;
13454            let mut selected_text = None;
13455
13456            let mut selections_iter = selections.iter().peekable();
13457            while let Some(selection) = selections_iter.next() {
13458                if selection.start != selection.end {
13459                    only_carets = false;
13460                }
13461
13462                if same_text_selected {
13463                    if selected_text.is_none() {
13464                        selected_text =
13465                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13466                    }
13467
13468                    if let Some(next_selection) = selections_iter.peek() {
13469                        if next_selection.range().len() == selection.range().len() {
13470                            let next_selected_text = buffer
13471                                .text_for_range(next_selection.range())
13472                                .collect::<String>();
13473                            if Some(next_selected_text) != selected_text {
13474                                same_text_selected = false;
13475                                selected_text = None;
13476                            }
13477                        } else {
13478                            same_text_selected = false;
13479                            selected_text = None;
13480                        }
13481                    }
13482                }
13483            }
13484
13485            if only_carets {
13486                for selection in &mut selections {
13487                    let word_range = movement::surrounding_word(
13488                        &display_map,
13489                        selection.start.to_display_point(&display_map),
13490                    );
13491                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13492                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13493                    selection.goal = SelectionGoal::None;
13494                    selection.reversed = false;
13495                    self.select_match_ranges(
13496                        selection.start..selection.end,
13497                        selection.reversed,
13498                        action.replace_newest,
13499                        Some(Autoscroll::newest()),
13500                        window,
13501                        cx,
13502                    );
13503                }
13504                if selections.len() == 1 {
13505                    let selection = selections
13506                        .last()
13507                        .expect("ensured that there's only one selection");
13508                    let query = buffer
13509                        .text_for_range(selection.start..selection.end)
13510                        .collect::<String>();
13511                    let is_empty = query.is_empty();
13512                    let select_state = SelectNextState {
13513                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13514                        wordwise: true,
13515                        done: is_empty,
13516                    };
13517                    self.select_prev_state = Some(select_state);
13518                } else {
13519                    self.select_prev_state = None;
13520                }
13521            } else if let Some(selected_text) = selected_text {
13522                self.select_prev_state = Some(SelectNextState {
13523                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13524                    wordwise: false,
13525                    done: false,
13526                });
13527                self.select_previous(action, window, cx)?;
13528            }
13529        }
13530        Ok(())
13531    }
13532
13533    pub fn find_next_match(
13534        &mut self,
13535        _: &FindNextMatch,
13536        window: &mut Window,
13537        cx: &mut Context<Self>,
13538    ) -> Result<()> {
13539        let selections = self.selections.disjoint_anchors();
13540        match selections.first() {
13541            Some(first) if selections.len() >= 2 => {
13542                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13543                    s.select_ranges([first.range()]);
13544                });
13545            }
13546            _ => self.select_next(
13547                &SelectNext {
13548                    replace_newest: true,
13549                },
13550                window,
13551                cx,
13552            )?,
13553        }
13554        Ok(())
13555    }
13556
13557    pub fn find_previous_match(
13558        &mut self,
13559        _: &FindPreviousMatch,
13560        window: &mut Window,
13561        cx: &mut Context<Self>,
13562    ) -> Result<()> {
13563        let selections = self.selections.disjoint_anchors();
13564        match selections.last() {
13565            Some(last) if selections.len() >= 2 => {
13566                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13567                    s.select_ranges([last.range()]);
13568                });
13569            }
13570            _ => self.select_previous(
13571                &SelectPrevious {
13572                    replace_newest: true,
13573                },
13574                window,
13575                cx,
13576            )?,
13577        }
13578        Ok(())
13579    }
13580
13581    pub fn toggle_comments(
13582        &mut self,
13583        action: &ToggleComments,
13584        window: &mut Window,
13585        cx: &mut Context<Self>,
13586    ) {
13587        if self.read_only(cx) {
13588            return;
13589        }
13590        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13591        let text_layout_details = &self.text_layout_details(window);
13592        self.transact(window, cx, |this, window, cx| {
13593            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13594            let mut edits = Vec::new();
13595            let mut selection_edit_ranges = Vec::new();
13596            let mut last_toggled_row = None;
13597            let snapshot = this.buffer.read(cx).read(cx);
13598            let empty_str: Arc<str> = Arc::default();
13599            let mut suffixes_inserted = Vec::new();
13600            let ignore_indent = action.ignore_indent;
13601
13602            fn comment_prefix_range(
13603                snapshot: &MultiBufferSnapshot,
13604                row: MultiBufferRow,
13605                comment_prefix: &str,
13606                comment_prefix_whitespace: &str,
13607                ignore_indent: bool,
13608            ) -> Range<Point> {
13609                let indent_size = if ignore_indent {
13610                    0
13611                } else {
13612                    snapshot.indent_size_for_line(row).len
13613                };
13614
13615                let start = Point::new(row.0, indent_size);
13616
13617                let mut line_bytes = snapshot
13618                    .bytes_in_range(start..snapshot.max_point())
13619                    .flatten()
13620                    .copied();
13621
13622                // If this line currently begins with the line comment prefix, then record
13623                // the range containing the prefix.
13624                if line_bytes
13625                    .by_ref()
13626                    .take(comment_prefix.len())
13627                    .eq(comment_prefix.bytes())
13628                {
13629                    // Include any whitespace that matches the comment prefix.
13630                    let matching_whitespace_len = line_bytes
13631                        .zip(comment_prefix_whitespace.bytes())
13632                        .take_while(|(a, b)| a == b)
13633                        .count() as u32;
13634                    let end = Point::new(
13635                        start.row,
13636                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13637                    );
13638                    start..end
13639                } else {
13640                    start..start
13641                }
13642            }
13643
13644            fn comment_suffix_range(
13645                snapshot: &MultiBufferSnapshot,
13646                row: MultiBufferRow,
13647                comment_suffix: &str,
13648                comment_suffix_has_leading_space: bool,
13649            ) -> Range<Point> {
13650                let end = Point::new(row.0, snapshot.line_len(row));
13651                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13652
13653                let mut line_end_bytes = snapshot
13654                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13655                    .flatten()
13656                    .copied();
13657
13658                let leading_space_len = if suffix_start_column > 0
13659                    && line_end_bytes.next() == Some(b' ')
13660                    && comment_suffix_has_leading_space
13661                {
13662                    1
13663                } else {
13664                    0
13665                };
13666
13667                // If this line currently begins with the line comment prefix, then record
13668                // the range containing the prefix.
13669                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13670                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13671                    start..end
13672                } else {
13673                    end..end
13674                }
13675            }
13676
13677            // TODO: Handle selections that cross excerpts
13678            for selection in &mut selections {
13679                let start_column = snapshot
13680                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13681                    .len;
13682                let language = if let Some(language) =
13683                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13684                {
13685                    language
13686                } else {
13687                    continue;
13688                };
13689
13690                selection_edit_ranges.clear();
13691
13692                // If multiple selections contain a given row, avoid processing that
13693                // row more than once.
13694                let mut start_row = MultiBufferRow(selection.start.row);
13695                if last_toggled_row == Some(start_row) {
13696                    start_row = start_row.next_row();
13697                }
13698                let end_row =
13699                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13700                        MultiBufferRow(selection.end.row - 1)
13701                    } else {
13702                        MultiBufferRow(selection.end.row)
13703                    };
13704                last_toggled_row = Some(end_row);
13705
13706                if start_row > end_row {
13707                    continue;
13708                }
13709
13710                // If the language has line comments, toggle those.
13711                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13712
13713                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13714                if ignore_indent {
13715                    full_comment_prefixes = full_comment_prefixes
13716                        .into_iter()
13717                        .map(|s| Arc::from(s.trim_end()))
13718                        .collect();
13719                }
13720
13721                if !full_comment_prefixes.is_empty() {
13722                    let first_prefix = full_comment_prefixes
13723                        .first()
13724                        .expect("prefixes is non-empty");
13725                    let prefix_trimmed_lengths = full_comment_prefixes
13726                        .iter()
13727                        .map(|p| p.trim_end_matches(' ').len())
13728                        .collect::<SmallVec<[usize; 4]>>();
13729
13730                    let mut all_selection_lines_are_comments = true;
13731
13732                    for row in start_row.0..=end_row.0 {
13733                        let row = MultiBufferRow(row);
13734                        if start_row < end_row && snapshot.is_line_blank(row) {
13735                            continue;
13736                        }
13737
13738                        let prefix_range = full_comment_prefixes
13739                            .iter()
13740                            .zip(prefix_trimmed_lengths.iter().copied())
13741                            .map(|(prefix, trimmed_prefix_len)| {
13742                                comment_prefix_range(
13743                                    snapshot.deref(),
13744                                    row,
13745                                    &prefix[..trimmed_prefix_len],
13746                                    &prefix[trimmed_prefix_len..],
13747                                    ignore_indent,
13748                                )
13749                            })
13750                            .max_by_key(|range| range.end.column - range.start.column)
13751                            .expect("prefixes is non-empty");
13752
13753                        if prefix_range.is_empty() {
13754                            all_selection_lines_are_comments = false;
13755                        }
13756
13757                        selection_edit_ranges.push(prefix_range);
13758                    }
13759
13760                    if all_selection_lines_are_comments {
13761                        edits.extend(
13762                            selection_edit_ranges
13763                                .iter()
13764                                .cloned()
13765                                .map(|range| (range, empty_str.clone())),
13766                        );
13767                    } else {
13768                        let min_column = selection_edit_ranges
13769                            .iter()
13770                            .map(|range| range.start.column)
13771                            .min()
13772                            .unwrap_or(0);
13773                        edits.extend(selection_edit_ranges.iter().map(|range| {
13774                            let position = Point::new(range.start.row, min_column);
13775                            (position..position, first_prefix.clone())
13776                        }));
13777                    }
13778                } else if let Some((full_comment_prefix, comment_suffix)) =
13779                    language.block_comment_delimiters()
13780                {
13781                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13782                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13783                    let prefix_range = comment_prefix_range(
13784                        snapshot.deref(),
13785                        start_row,
13786                        comment_prefix,
13787                        comment_prefix_whitespace,
13788                        ignore_indent,
13789                    );
13790                    let suffix_range = comment_suffix_range(
13791                        snapshot.deref(),
13792                        end_row,
13793                        comment_suffix.trim_start_matches(' '),
13794                        comment_suffix.starts_with(' '),
13795                    );
13796
13797                    if prefix_range.is_empty() || suffix_range.is_empty() {
13798                        edits.push((
13799                            prefix_range.start..prefix_range.start,
13800                            full_comment_prefix.clone(),
13801                        ));
13802                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13803                        suffixes_inserted.push((end_row, comment_suffix.len()));
13804                    } else {
13805                        edits.push((prefix_range, empty_str.clone()));
13806                        edits.push((suffix_range, empty_str.clone()));
13807                    }
13808                } else {
13809                    continue;
13810                }
13811            }
13812
13813            drop(snapshot);
13814            this.buffer.update(cx, |buffer, cx| {
13815                buffer.edit(edits, None, cx);
13816            });
13817
13818            // Adjust selections so that they end before any comment suffixes that
13819            // were inserted.
13820            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13821            let mut selections = this.selections.all::<Point>(cx);
13822            let snapshot = this.buffer.read(cx).read(cx);
13823            for selection in &mut selections {
13824                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13825                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13826                        Ordering::Less => {
13827                            suffixes_inserted.next();
13828                            continue;
13829                        }
13830                        Ordering::Greater => break,
13831                        Ordering::Equal => {
13832                            if selection.end.column == snapshot.line_len(row) {
13833                                if selection.is_empty() {
13834                                    selection.start.column -= suffix_len as u32;
13835                                }
13836                                selection.end.column -= suffix_len as u32;
13837                            }
13838                            break;
13839                        }
13840                    }
13841                }
13842            }
13843
13844            drop(snapshot);
13845            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13846                s.select(selections)
13847            });
13848
13849            let selections = this.selections.all::<Point>(cx);
13850            let selections_on_single_row = selections.windows(2).all(|selections| {
13851                selections[0].start.row == selections[1].start.row
13852                    && selections[0].end.row == selections[1].end.row
13853                    && selections[0].start.row == selections[0].end.row
13854            });
13855            let selections_selecting = selections
13856                .iter()
13857                .any(|selection| selection.start != selection.end);
13858            let advance_downwards = action.advance_downwards
13859                && selections_on_single_row
13860                && !selections_selecting
13861                && !matches!(this.mode, EditorMode::SingleLine { .. });
13862
13863            if advance_downwards {
13864                let snapshot = this.buffer.read(cx).snapshot(cx);
13865
13866                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13867                    s.move_cursors_with(|display_snapshot, display_point, _| {
13868                        let mut point = display_point.to_point(display_snapshot);
13869                        point.row += 1;
13870                        point = snapshot.clip_point(point, Bias::Left);
13871                        let display_point = point.to_display_point(display_snapshot);
13872                        let goal = SelectionGoal::HorizontalPosition(
13873                            display_snapshot
13874                                .x_for_display_point(display_point, text_layout_details)
13875                                .into(),
13876                        );
13877                        (display_point, goal)
13878                    })
13879                });
13880            }
13881        });
13882    }
13883
13884    pub fn select_enclosing_symbol(
13885        &mut self,
13886        _: &SelectEnclosingSymbol,
13887        window: &mut Window,
13888        cx: &mut Context<Self>,
13889    ) {
13890        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13891
13892        let buffer = self.buffer.read(cx).snapshot(cx);
13893        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13894
13895        fn update_selection(
13896            selection: &Selection<usize>,
13897            buffer_snap: &MultiBufferSnapshot,
13898        ) -> Option<Selection<usize>> {
13899            let cursor = selection.head();
13900            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13901            for symbol in symbols.iter().rev() {
13902                let start = symbol.range.start.to_offset(buffer_snap);
13903                let end = symbol.range.end.to_offset(buffer_snap);
13904                let new_range = start..end;
13905                if start < selection.start || end > selection.end {
13906                    return Some(Selection {
13907                        id: selection.id,
13908                        start: new_range.start,
13909                        end: new_range.end,
13910                        goal: SelectionGoal::None,
13911                        reversed: selection.reversed,
13912                    });
13913                }
13914            }
13915            None
13916        }
13917
13918        let mut selected_larger_symbol = false;
13919        let new_selections = old_selections
13920            .iter()
13921            .map(|selection| match update_selection(selection, &buffer) {
13922                Some(new_selection) => {
13923                    if new_selection.range() != selection.range() {
13924                        selected_larger_symbol = true;
13925                    }
13926                    new_selection
13927                }
13928                None => selection.clone(),
13929            })
13930            .collect::<Vec<_>>();
13931
13932        if selected_larger_symbol {
13933            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13934                s.select(new_selections);
13935            });
13936        }
13937    }
13938
13939    pub fn select_larger_syntax_node(
13940        &mut self,
13941        _: &SelectLargerSyntaxNode,
13942        window: &mut Window,
13943        cx: &mut Context<Self>,
13944    ) {
13945        let Some(visible_row_count) = self.visible_row_count() else {
13946            return;
13947        };
13948        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13949        if old_selections.is_empty() {
13950            return;
13951        }
13952
13953        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13954
13955        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13956        let buffer = self.buffer.read(cx).snapshot(cx);
13957
13958        let mut selected_larger_node = false;
13959        let mut new_selections = old_selections
13960            .iter()
13961            .map(|selection| {
13962                let old_range = selection.start..selection.end;
13963
13964                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13965                    // manually select word at selection
13966                    if ["string_content", "inline"].contains(&node.kind()) {
13967                        let word_range = {
13968                            let display_point = buffer
13969                                .offset_to_point(old_range.start)
13970                                .to_display_point(&display_map);
13971                            let Range { start, end } =
13972                                movement::surrounding_word(&display_map, display_point);
13973                            start.to_point(&display_map).to_offset(&buffer)
13974                                ..end.to_point(&display_map).to_offset(&buffer)
13975                        };
13976                        // ignore if word is already selected
13977                        if !word_range.is_empty() && old_range != word_range {
13978                            let last_word_range = {
13979                                let display_point = buffer
13980                                    .offset_to_point(old_range.end)
13981                                    .to_display_point(&display_map);
13982                                let Range { start, end } =
13983                                    movement::surrounding_word(&display_map, display_point);
13984                                start.to_point(&display_map).to_offset(&buffer)
13985                                    ..end.to_point(&display_map).to_offset(&buffer)
13986                            };
13987                            // only select word if start and end point belongs to same word
13988                            if word_range == last_word_range {
13989                                selected_larger_node = true;
13990                                return Selection {
13991                                    id: selection.id,
13992                                    start: word_range.start,
13993                                    end: word_range.end,
13994                                    goal: SelectionGoal::None,
13995                                    reversed: selection.reversed,
13996                                };
13997                            }
13998                        }
13999                    }
14000                }
14001
14002                let mut new_range = old_range.clone();
14003                while let Some((_node, containing_range)) =
14004                    buffer.syntax_ancestor(new_range.clone())
14005                {
14006                    new_range = match containing_range {
14007                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14008                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14009                    };
14010                    if !display_map.intersects_fold(new_range.start)
14011                        && !display_map.intersects_fold(new_range.end)
14012                    {
14013                        break;
14014                    }
14015                }
14016
14017                selected_larger_node |= new_range != old_range;
14018                Selection {
14019                    id: selection.id,
14020                    start: new_range.start,
14021                    end: new_range.end,
14022                    goal: SelectionGoal::None,
14023                    reversed: selection.reversed,
14024                }
14025            })
14026            .collect::<Vec<_>>();
14027
14028        if !selected_larger_node {
14029            return; // don't put this call in the history
14030        }
14031
14032        // scroll based on transformation done to the last selection created by the user
14033        let (last_old, last_new) = old_selections
14034            .last()
14035            .zip(new_selections.last().cloned())
14036            .expect("old_selections isn't empty");
14037
14038        // revert selection
14039        let is_selection_reversed = {
14040            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14041            new_selections.last_mut().expect("checked above").reversed =
14042                should_newest_selection_be_reversed;
14043            should_newest_selection_be_reversed
14044        };
14045
14046        if selected_larger_node {
14047            self.select_syntax_node_history.disable_clearing = true;
14048            self.change_selections(None, window, cx, |s| {
14049                s.select(new_selections.clone());
14050            });
14051            self.select_syntax_node_history.disable_clearing = false;
14052        }
14053
14054        let start_row = last_new.start.to_display_point(&display_map).row().0;
14055        let end_row = last_new.end.to_display_point(&display_map).row().0;
14056        let selection_height = end_row - start_row + 1;
14057        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14058
14059        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14060        let scroll_behavior = if fits_on_the_screen {
14061            self.request_autoscroll(Autoscroll::fit(), cx);
14062            SelectSyntaxNodeScrollBehavior::FitSelection
14063        } else if is_selection_reversed {
14064            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14065            SelectSyntaxNodeScrollBehavior::CursorTop
14066        } else {
14067            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14068            SelectSyntaxNodeScrollBehavior::CursorBottom
14069        };
14070
14071        self.select_syntax_node_history.push((
14072            old_selections,
14073            scroll_behavior,
14074            is_selection_reversed,
14075        ));
14076    }
14077
14078    pub fn select_smaller_syntax_node(
14079        &mut self,
14080        _: &SelectSmallerSyntaxNode,
14081        window: &mut Window,
14082        cx: &mut Context<Self>,
14083    ) {
14084        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14085
14086        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14087            self.select_syntax_node_history.pop()
14088        {
14089            if let Some(selection) = selections.last_mut() {
14090                selection.reversed = is_selection_reversed;
14091            }
14092
14093            self.select_syntax_node_history.disable_clearing = true;
14094            self.change_selections(None, window, cx, |s| {
14095                s.select(selections.to_vec());
14096            });
14097            self.select_syntax_node_history.disable_clearing = false;
14098
14099            match scroll_behavior {
14100                SelectSyntaxNodeScrollBehavior::CursorTop => {
14101                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14102                }
14103                SelectSyntaxNodeScrollBehavior::FitSelection => {
14104                    self.request_autoscroll(Autoscroll::fit(), cx);
14105                }
14106                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14107                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14108                }
14109            }
14110        }
14111    }
14112
14113    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14114        if !EditorSettings::get_global(cx).gutter.runnables {
14115            self.clear_tasks();
14116            return Task::ready(());
14117        }
14118        let project = self.project.as_ref().map(Entity::downgrade);
14119        let task_sources = self.lsp_task_sources(cx);
14120        let multi_buffer = self.buffer.downgrade();
14121        cx.spawn_in(window, async move |editor, cx| {
14122            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14123            let Some(project) = project.and_then(|p| p.upgrade()) else {
14124                return;
14125            };
14126            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14127                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14128            }) else {
14129                return;
14130            };
14131
14132            let hide_runnables = project
14133                .update(cx, |project, cx| {
14134                    // Do not display any test indicators in non-dev server remote projects.
14135                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14136                })
14137                .unwrap_or(true);
14138            if hide_runnables {
14139                return;
14140            }
14141            let new_rows =
14142                cx.background_spawn({
14143                    let snapshot = display_snapshot.clone();
14144                    async move {
14145                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14146                    }
14147                })
14148                    .await;
14149            let Ok(lsp_tasks) =
14150                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14151            else {
14152                return;
14153            };
14154            let lsp_tasks = lsp_tasks.await;
14155
14156            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14157                lsp_tasks
14158                    .into_iter()
14159                    .flat_map(|(kind, tasks)| {
14160                        tasks.into_iter().filter_map(move |(location, task)| {
14161                            Some((kind.clone(), location?, task))
14162                        })
14163                    })
14164                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14165                        let buffer = location.target.buffer;
14166                        let buffer_snapshot = buffer.read(cx).snapshot();
14167                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14168                            |(excerpt_id, snapshot, _)| {
14169                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14170                                    display_snapshot
14171                                        .buffer_snapshot
14172                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14173                                } else {
14174                                    None
14175                                }
14176                            },
14177                        );
14178                        if let Some(offset) = offset {
14179                            let task_buffer_range =
14180                                location.target.range.to_point(&buffer_snapshot);
14181                            let context_buffer_range =
14182                                task_buffer_range.to_offset(&buffer_snapshot);
14183                            let context_range = BufferOffset(context_buffer_range.start)
14184                                ..BufferOffset(context_buffer_range.end);
14185
14186                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14187                                .or_insert_with(|| RunnableTasks {
14188                                    templates: Vec::new(),
14189                                    offset,
14190                                    column: task_buffer_range.start.column,
14191                                    extra_variables: HashMap::default(),
14192                                    context_range,
14193                                })
14194                                .templates
14195                                .push((kind, task.original_task().clone()));
14196                        }
14197
14198                        acc
14199                    })
14200            }) else {
14201                return;
14202            };
14203
14204            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14205                buffer.language_settings(cx).tasks.prefer_lsp
14206            }) else {
14207                return;
14208            };
14209
14210            let rows = Self::runnable_rows(
14211                project,
14212                display_snapshot,
14213                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14214                new_rows,
14215                cx.clone(),
14216            )
14217            .await;
14218            editor
14219                .update(cx, |editor, _| {
14220                    editor.clear_tasks();
14221                    for (key, mut value) in rows {
14222                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14223                            value.templates.extend(lsp_tasks.templates);
14224                        }
14225
14226                        editor.insert_tasks(key, value);
14227                    }
14228                    for (key, value) in lsp_tasks_by_rows {
14229                        editor.insert_tasks(key, value);
14230                    }
14231                })
14232                .ok();
14233        })
14234    }
14235    fn fetch_runnable_ranges(
14236        snapshot: &DisplaySnapshot,
14237        range: Range<Anchor>,
14238    ) -> Vec<language::RunnableRange> {
14239        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14240    }
14241
14242    fn runnable_rows(
14243        project: Entity<Project>,
14244        snapshot: DisplaySnapshot,
14245        prefer_lsp: bool,
14246        runnable_ranges: Vec<RunnableRange>,
14247        cx: AsyncWindowContext,
14248    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14249        cx.spawn(async move |cx| {
14250            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14251            for mut runnable in runnable_ranges {
14252                let Some(tasks) = cx
14253                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14254                    .ok()
14255                else {
14256                    continue;
14257                };
14258                let mut tasks = tasks.await;
14259
14260                if prefer_lsp {
14261                    tasks.retain(|(task_kind, _)| {
14262                        !matches!(task_kind, TaskSourceKind::Language { .. })
14263                    });
14264                }
14265                if tasks.is_empty() {
14266                    continue;
14267                }
14268
14269                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14270                let Some(row) = snapshot
14271                    .buffer_snapshot
14272                    .buffer_line_for_row(MultiBufferRow(point.row))
14273                    .map(|(_, range)| range.start.row)
14274                else {
14275                    continue;
14276                };
14277
14278                let context_range =
14279                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14280                runnable_rows.push((
14281                    (runnable.buffer_id, row),
14282                    RunnableTasks {
14283                        templates: tasks,
14284                        offset: snapshot
14285                            .buffer_snapshot
14286                            .anchor_before(runnable.run_range.start),
14287                        context_range,
14288                        column: point.column,
14289                        extra_variables: runnable.extra_captures,
14290                    },
14291                ));
14292            }
14293            runnable_rows
14294        })
14295    }
14296
14297    fn templates_with_tags(
14298        project: &Entity<Project>,
14299        runnable: &mut Runnable,
14300        cx: &mut App,
14301    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14302        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14303            let (worktree_id, file) = project
14304                .buffer_for_id(runnable.buffer, cx)
14305                .and_then(|buffer| buffer.read(cx).file())
14306                .map(|file| (file.worktree_id(cx), file.clone()))
14307                .unzip();
14308
14309            (
14310                project.task_store().read(cx).task_inventory().cloned(),
14311                worktree_id,
14312                file,
14313            )
14314        });
14315
14316        let tags = mem::take(&mut runnable.tags);
14317        let language = runnable.language.clone();
14318        cx.spawn(async move |cx| {
14319            let mut templates_with_tags = Vec::new();
14320            if let Some(inventory) = inventory {
14321                for RunnableTag(tag) in tags {
14322                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14323                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14324                    }) else {
14325                        return templates_with_tags;
14326                    };
14327                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14328                        move |(_, template)| {
14329                            template.tags.iter().any(|source_tag| source_tag == &tag)
14330                        },
14331                    ));
14332                }
14333            }
14334            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14335
14336            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14337                // Strongest source wins; if we have worktree tag binding, prefer that to
14338                // global and language bindings;
14339                // if we have a global binding, prefer that to language binding.
14340                let first_mismatch = templates_with_tags
14341                    .iter()
14342                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14343                if let Some(index) = first_mismatch {
14344                    templates_with_tags.truncate(index);
14345                }
14346            }
14347
14348            templates_with_tags
14349        })
14350    }
14351
14352    pub fn move_to_enclosing_bracket(
14353        &mut self,
14354        _: &MoveToEnclosingBracket,
14355        window: &mut Window,
14356        cx: &mut Context<Self>,
14357    ) {
14358        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14359        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14360            s.move_offsets_with(|snapshot, selection| {
14361                let Some(enclosing_bracket_ranges) =
14362                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14363                else {
14364                    return;
14365                };
14366
14367                let mut best_length = usize::MAX;
14368                let mut best_inside = false;
14369                let mut best_in_bracket_range = false;
14370                let mut best_destination = None;
14371                for (open, close) in enclosing_bracket_ranges {
14372                    let close = close.to_inclusive();
14373                    let length = close.end() - open.start;
14374                    let inside = selection.start >= open.end && selection.end <= *close.start();
14375                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14376                        || close.contains(&selection.head());
14377
14378                    // If best is next to a bracket and current isn't, skip
14379                    if !in_bracket_range && best_in_bracket_range {
14380                        continue;
14381                    }
14382
14383                    // Prefer smaller lengths unless best is inside and current isn't
14384                    if length > best_length && (best_inside || !inside) {
14385                        continue;
14386                    }
14387
14388                    best_length = length;
14389                    best_inside = inside;
14390                    best_in_bracket_range = in_bracket_range;
14391                    best_destination = Some(
14392                        if close.contains(&selection.start) && close.contains(&selection.end) {
14393                            if inside { open.end } else { open.start }
14394                        } else if inside {
14395                            *close.start()
14396                        } else {
14397                            *close.end()
14398                        },
14399                    );
14400                }
14401
14402                if let Some(destination) = best_destination {
14403                    selection.collapse_to(destination, SelectionGoal::None);
14404                }
14405            })
14406        });
14407    }
14408
14409    pub fn undo_selection(
14410        &mut self,
14411        _: &UndoSelection,
14412        window: &mut Window,
14413        cx: &mut Context<Self>,
14414    ) {
14415        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14416        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14417            self.selection_history.mode = SelectionHistoryMode::Undoing;
14418            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14419                this.end_selection(window, cx);
14420                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14421                    s.select_anchors(entry.selections.to_vec())
14422                });
14423            });
14424            self.selection_history.mode = SelectionHistoryMode::Normal;
14425
14426            self.select_next_state = entry.select_next_state;
14427            self.select_prev_state = entry.select_prev_state;
14428            self.add_selections_state = entry.add_selections_state;
14429        }
14430    }
14431
14432    pub fn redo_selection(
14433        &mut self,
14434        _: &RedoSelection,
14435        window: &mut Window,
14436        cx: &mut Context<Self>,
14437    ) {
14438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14439        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14440            self.selection_history.mode = SelectionHistoryMode::Redoing;
14441            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14442                this.end_selection(window, cx);
14443                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14444                    s.select_anchors(entry.selections.to_vec())
14445                });
14446            });
14447            self.selection_history.mode = SelectionHistoryMode::Normal;
14448
14449            self.select_next_state = entry.select_next_state;
14450            self.select_prev_state = entry.select_prev_state;
14451            self.add_selections_state = entry.add_selections_state;
14452        }
14453    }
14454
14455    pub fn expand_excerpts(
14456        &mut self,
14457        action: &ExpandExcerpts,
14458        _: &mut Window,
14459        cx: &mut Context<Self>,
14460    ) {
14461        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14462    }
14463
14464    pub fn expand_excerpts_down(
14465        &mut self,
14466        action: &ExpandExcerptsDown,
14467        _: &mut Window,
14468        cx: &mut Context<Self>,
14469    ) {
14470        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14471    }
14472
14473    pub fn expand_excerpts_up(
14474        &mut self,
14475        action: &ExpandExcerptsUp,
14476        _: &mut Window,
14477        cx: &mut Context<Self>,
14478    ) {
14479        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14480    }
14481
14482    pub fn expand_excerpts_for_direction(
14483        &mut self,
14484        lines: u32,
14485        direction: ExpandExcerptDirection,
14486
14487        cx: &mut Context<Self>,
14488    ) {
14489        let selections = self.selections.disjoint_anchors();
14490
14491        let lines = if lines == 0 {
14492            EditorSettings::get_global(cx).expand_excerpt_lines
14493        } else {
14494            lines
14495        };
14496
14497        self.buffer.update(cx, |buffer, cx| {
14498            let snapshot = buffer.snapshot(cx);
14499            let mut excerpt_ids = selections
14500                .iter()
14501                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14502                .collect::<Vec<_>>();
14503            excerpt_ids.sort();
14504            excerpt_ids.dedup();
14505            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14506        })
14507    }
14508
14509    pub fn expand_excerpt(
14510        &mut self,
14511        excerpt: ExcerptId,
14512        direction: ExpandExcerptDirection,
14513        window: &mut Window,
14514        cx: &mut Context<Self>,
14515    ) {
14516        let current_scroll_position = self.scroll_position(cx);
14517        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14518        let mut should_scroll_up = false;
14519
14520        if direction == ExpandExcerptDirection::Down {
14521            let multi_buffer = self.buffer.read(cx);
14522            let snapshot = multi_buffer.snapshot(cx);
14523            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14524                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14525                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14526                        let buffer_snapshot = buffer.read(cx).snapshot();
14527                        let excerpt_end_row =
14528                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14529                        let last_row = buffer_snapshot.max_point().row;
14530                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14531                        should_scroll_up = lines_below >= lines_to_expand;
14532                    }
14533                }
14534            }
14535        }
14536
14537        self.buffer.update(cx, |buffer, cx| {
14538            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14539        });
14540
14541        if should_scroll_up {
14542            let new_scroll_position =
14543                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14544            self.set_scroll_position(new_scroll_position, window, cx);
14545        }
14546    }
14547
14548    pub fn go_to_singleton_buffer_point(
14549        &mut self,
14550        point: Point,
14551        window: &mut Window,
14552        cx: &mut Context<Self>,
14553    ) {
14554        self.go_to_singleton_buffer_range(point..point, window, cx);
14555    }
14556
14557    pub fn go_to_singleton_buffer_range(
14558        &mut self,
14559        range: Range<Point>,
14560        window: &mut Window,
14561        cx: &mut Context<Self>,
14562    ) {
14563        let multibuffer = self.buffer().read(cx);
14564        let Some(buffer) = multibuffer.as_singleton() else {
14565            return;
14566        };
14567        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14568            return;
14569        };
14570        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14571            return;
14572        };
14573        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14574            s.select_anchor_ranges([start..end])
14575        });
14576    }
14577
14578    pub fn go_to_diagnostic(
14579        &mut self,
14580        _: &GoToDiagnostic,
14581        window: &mut Window,
14582        cx: &mut Context<Self>,
14583    ) {
14584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14585        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14586    }
14587
14588    pub fn go_to_prev_diagnostic(
14589        &mut self,
14590        _: &GoToPreviousDiagnostic,
14591        window: &mut Window,
14592        cx: &mut Context<Self>,
14593    ) {
14594        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14595        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14596    }
14597
14598    pub fn go_to_diagnostic_impl(
14599        &mut self,
14600        direction: Direction,
14601        window: &mut Window,
14602        cx: &mut Context<Self>,
14603    ) {
14604        let buffer = self.buffer.read(cx).snapshot(cx);
14605        let selection = self.selections.newest::<usize>(cx);
14606
14607        let mut active_group_id = None;
14608        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14609            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14610                active_group_id = Some(active_group.group_id);
14611            }
14612        }
14613
14614        fn filtered(
14615            snapshot: EditorSnapshot,
14616            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14617        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14618            diagnostics
14619                .filter(|entry| entry.range.start != entry.range.end)
14620                .filter(|entry| !entry.diagnostic.is_unnecessary)
14621                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14622        }
14623
14624        let snapshot = self.snapshot(window, cx);
14625        let before = filtered(
14626            snapshot.clone(),
14627            buffer
14628                .diagnostics_in_range(0..selection.start)
14629                .filter(|entry| entry.range.start <= selection.start),
14630        );
14631        let after = filtered(
14632            snapshot,
14633            buffer
14634                .diagnostics_in_range(selection.start..buffer.len())
14635                .filter(|entry| entry.range.start >= selection.start),
14636        );
14637
14638        let mut found: Option<DiagnosticEntry<usize>> = None;
14639        if direction == Direction::Prev {
14640            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14641            {
14642                for diagnostic in prev_diagnostics.into_iter().rev() {
14643                    if diagnostic.range.start != selection.start
14644                        || active_group_id
14645                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14646                    {
14647                        found = Some(diagnostic);
14648                        break 'outer;
14649                    }
14650                }
14651            }
14652        } else {
14653            for diagnostic in after.chain(before) {
14654                if diagnostic.range.start != selection.start
14655                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14656                {
14657                    found = Some(diagnostic);
14658                    break;
14659                }
14660            }
14661        }
14662        let Some(next_diagnostic) = found else {
14663            return;
14664        };
14665
14666        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14667            return;
14668        };
14669        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14670            s.select_ranges(vec![
14671                next_diagnostic.range.start..next_diagnostic.range.start,
14672            ])
14673        });
14674        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14675        self.refresh_inline_completion(false, true, window, cx);
14676    }
14677
14678    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14680        let snapshot = self.snapshot(window, cx);
14681        let selection = self.selections.newest::<Point>(cx);
14682        self.go_to_hunk_before_or_after_position(
14683            &snapshot,
14684            selection.head(),
14685            Direction::Next,
14686            window,
14687            cx,
14688        );
14689    }
14690
14691    pub fn go_to_hunk_before_or_after_position(
14692        &mut self,
14693        snapshot: &EditorSnapshot,
14694        position: Point,
14695        direction: Direction,
14696        window: &mut Window,
14697        cx: &mut Context<Editor>,
14698    ) {
14699        let row = if direction == Direction::Next {
14700            self.hunk_after_position(snapshot, position)
14701                .map(|hunk| hunk.row_range.start)
14702        } else {
14703            self.hunk_before_position(snapshot, position)
14704        };
14705
14706        if let Some(row) = row {
14707            let destination = Point::new(row.0, 0);
14708            let autoscroll = Autoscroll::center();
14709
14710            self.unfold_ranges(&[destination..destination], false, false, cx);
14711            self.change_selections(Some(autoscroll), window, cx, |s| {
14712                s.select_ranges([destination..destination]);
14713            });
14714        }
14715    }
14716
14717    fn hunk_after_position(
14718        &mut self,
14719        snapshot: &EditorSnapshot,
14720        position: Point,
14721    ) -> Option<MultiBufferDiffHunk> {
14722        snapshot
14723            .buffer_snapshot
14724            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14725            .find(|hunk| hunk.row_range.start.0 > position.row)
14726            .or_else(|| {
14727                snapshot
14728                    .buffer_snapshot
14729                    .diff_hunks_in_range(Point::zero()..position)
14730                    .find(|hunk| hunk.row_range.end.0 < position.row)
14731            })
14732    }
14733
14734    fn go_to_prev_hunk(
14735        &mut self,
14736        _: &GoToPreviousHunk,
14737        window: &mut Window,
14738        cx: &mut Context<Self>,
14739    ) {
14740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14741        let snapshot = self.snapshot(window, cx);
14742        let selection = self.selections.newest::<Point>(cx);
14743        self.go_to_hunk_before_or_after_position(
14744            &snapshot,
14745            selection.head(),
14746            Direction::Prev,
14747            window,
14748            cx,
14749        );
14750    }
14751
14752    fn hunk_before_position(
14753        &mut self,
14754        snapshot: &EditorSnapshot,
14755        position: Point,
14756    ) -> Option<MultiBufferRow> {
14757        snapshot
14758            .buffer_snapshot
14759            .diff_hunk_before(position)
14760            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14761    }
14762
14763    fn go_to_next_change(
14764        &mut self,
14765        _: &GoToNextChange,
14766        window: &mut Window,
14767        cx: &mut Context<Self>,
14768    ) {
14769        if let Some(selections) = self
14770            .change_list
14771            .next_change(1, Direction::Next)
14772            .map(|s| s.to_vec())
14773        {
14774            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14775                let map = s.display_map();
14776                s.select_display_ranges(selections.iter().map(|a| {
14777                    let point = a.to_display_point(&map);
14778                    point..point
14779                }))
14780            })
14781        }
14782    }
14783
14784    fn go_to_previous_change(
14785        &mut self,
14786        _: &GoToPreviousChange,
14787        window: &mut Window,
14788        cx: &mut Context<Self>,
14789    ) {
14790        if let Some(selections) = self
14791            .change_list
14792            .next_change(1, Direction::Prev)
14793            .map(|s| s.to_vec())
14794        {
14795            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14796                let map = s.display_map();
14797                s.select_display_ranges(selections.iter().map(|a| {
14798                    let point = a.to_display_point(&map);
14799                    point..point
14800                }))
14801            })
14802        }
14803    }
14804
14805    fn go_to_line<T: 'static>(
14806        &mut self,
14807        position: Anchor,
14808        highlight_color: Option<Hsla>,
14809        window: &mut Window,
14810        cx: &mut Context<Self>,
14811    ) {
14812        let snapshot = self.snapshot(window, cx).display_snapshot;
14813        let position = position.to_point(&snapshot.buffer_snapshot);
14814        let start = snapshot
14815            .buffer_snapshot
14816            .clip_point(Point::new(position.row, 0), Bias::Left);
14817        let end = start + Point::new(1, 0);
14818        let start = snapshot.buffer_snapshot.anchor_before(start);
14819        let end = snapshot.buffer_snapshot.anchor_before(end);
14820
14821        self.highlight_rows::<T>(
14822            start..end,
14823            highlight_color
14824                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14825            Default::default(),
14826            cx,
14827        );
14828
14829        if self.buffer.read(cx).is_singleton() {
14830            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14831        }
14832    }
14833
14834    pub fn go_to_definition(
14835        &mut self,
14836        _: &GoToDefinition,
14837        window: &mut Window,
14838        cx: &mut Context<Self>,
14839    ) -> Task<Result<Navigated>> {
14840        let definition =
14841            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14842        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14843        cx.spawn_in(window, async move |editor, cx| {
14844            if definition.await? == Navigated::Yes {
14845                return Ok(Navigated::Yes);
14846            }
14847            match fallback_strategy {
14848                GoToDefinitionFallback::None => Ok(Navigated::No),
14849                GoToDefinitionFallback::FindAllReferences => {
14850                    match editor.update_in(cx, |editor, window, cx| {
14851                        editor.find_all_references(&FindAllReferences, window, cx)
14852                    })? {
14853                        Some(references) => references.await,
14854                        None => Ok(Navigated::No),
14855                    }
14856                }
14857            }
14858        })
14859    }
14860
14861    pub fn go_to_declaration(
14862        &mut self,
14863        _: &GoToDeclaration,
14864        window: &mut Window,
14865        cx: &mut Context<Self>,
14866    ) -> Task<Result<Navigated>> {
14867        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14868    }
14869
14870    pub fn go_to_declaration_split(
14871        &mut self,
14872        _: &GoToDeclaration,
14873        window: &mut Window,
14874        cx: &mut Context<Self>,
14875    ) -> Task<Result<Navigated>> {
14876        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14877    }
14878
14879    pub fn go_to_implementation(
14880        &mut self,
14881        _: &GoToImplementation,
14882        window: &mut Window,
14883        cx: &mut Context<Self>,
14884    ) -> Task<Result<Navigated>> {
14885        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14886    }
14887
14888    pub fn go_to_implementation_split(
14889        &mut self,
14890        _: &GoToImplementationSplit,
14891        window: &mut Window,
14892        cx: &mut Context<Self>,
14893    ) -> Task<Result<Navigated>> {
14894        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14895    }
14896
14897    pub fn go_to_type_definition(
14898        &mut self,
14899        _: &GoToTypeDefinition,
14900        window: &mut Window,
14901        cx: &mut Context<Self>,
14902    ) -> Task<Result<Navigated>> {
14903        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14904    }
14905
14906    pub fn go_to_definition_split(
14907        &mut self,
14908        _: &GoToDefinitionSplit,
14909        window: &mut Window,
14910        cx: &mut Context<Self>,
14911    ) -> Task<Result<Navigated>> {
14912        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14913    }
14914
14915    pub fn go_to_type_definition_split(
14916        &mut self,
14917        _: &GoToTypeDefinitionSplit,
14918        window: &mut Window,
14919        cx: &mut Context<Self>,
14920    ) -> Task<Result<Navigated>> {
14921        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14922    }
14923
14924    fn go_to_definition_of_kind(
14925        &mut self,
14926        kind: GotoDefinitionKind,
14927        split: bool,
14928        window: &mut Window,
14929        cx: &mut Context<Self>,
14930    ) -> Task<Result<Navigated>> {
14931        let Some(provider) = self.semantics_provider.clone() else {
14932            return Task::ready(Ok(Navigated::No));
14933        };
14934        let head = self.selections.newest::<usize>(cx).head();
14935        let buffer = self.buffer.read(cx);
14936        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14937            text_anchor
14938        } else {
14939            return Task::ready(Ok(Navigated::No));
14940        };
14941
14942        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14943            return Task::ready(Ok(Navigated::No));
14944        };
14945
14946        cx.spawn_in(window, async move |editor, cx| {
14947            let definitions = definitions.await?;
14948            let navigated = editor
14949                .update_in(cx, |editor, window, cx| {
14950                    editor.navigate_to_hover_links(
14951                        Some(kind),
14952                        definitions
14953                            .into_iter()
14954                            .filter(|location| {
14955                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14956                            })
14957                            .map(HoverLink::Text)
14958                            .collect::<Vec<_>>(),
14959                        split,
14960                        window,
14961                        cx,
14962                    )
14963                })?
14964                .await?;
14965            anyhow::Ok(navigated)
14966        })
14967    }
14968
14969    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14970        let selection = self.selections.newest_anchor();
14971        let head = selection.head();
14972        let tail = selection.tail();
14973
14974        let Some((buffer, start_position)) =
14975            self.buffer.read(cx).text_anchor_for_position(head, cx)
14976        else {
14977            return;
14978        };
14979
14980        let end_position = if head != tail {
14981            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14982                return;
14983            };
14984            Some(pos)
14985        } else {
14986            None
14987        };
14988
14989        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14990            let url = if let Some(end_pos) = end_position {
14991                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14992            } else {
14993                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14994            };
14995
14996            if let Some(url) = url {
14997                editor.update(cx, |_, cx| {
14998                    cx.open_url(&url);
14999                })
15000            } else {
15001                Ok(())
15002            }
15003        });
15004
15005        url_finder.detach();
15006    }
15007
15008    pub fn open_selected_filename(
15009        &mut self,
15010        _: &OpenSelectedFilename,
15011        window: &mut Window,
15012        cx: &mut Context<Self>,
15013    ) {
15014        let Some(workspace) = self.workspace() else {
15015            return;
15016        };
15017
15018        let position = self.selections.newest_anchor().head();
15019
15020        let Some((buffer, buffer_position)) =
15021            self.buffer.read(cx).text_anchor_for_position(position, cx)
15022        else {
15023            return;
15024        };
15025
15026        let project = self.project.clone();
15027
15028        cx.spawn_in(window, async move |_, cx| {
15029            let result = find_file(&buffer, project, buffer_position, cx).await;
15030
15031            if let Some((_, path)) = result {
15032                workspace
15033                    .update_in(cx, |workspace, window, cx| {
15034                        workspace.open_resolved_path(path, window, cx)
15035                    })?
15036                    .await?;
15037            }
15038            anyhow::Ok(())
15039        })
15040        .detach();
15041    }
15042
15043    pub(crate) fn navigate_to_hover_links(
15044        &mut self,
15045        kind: Option<GotoDefinitionKind>,
15046        mut definitions: Vec<HoverLink>,
15047        split: bool,
15048        window: &mut Window,
15049        cx: &mut Context<Editor>,
15050    ) -> Task<Result<Navigated>> {
15051        // If there is one definition, just open it directly
15052        if definitions.len() == 1 {
15053            let definition = definitions.pop().unwrap();
15054
15055            enum TargetTaskResult {
15056                Location(Option<Location>),
15057                AlreadyNavigated,
15058            }
15059
15060            let target_task = match definition {
15061                HoverLink::Text(link) => {
15062                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15063                }
15064                HoverLink::InlayHint(lsp_location, server_id) => {
15065                    let computation =
15066                        self.compute_target_location(lsp_location, server_id, window, cx);
15067                    cx.background_spawn(async move {
15068                        let location = computation.await?;
15069                        Ok(TargetTaskResult::Location(location))
15070                    })
15071                }
15072                HoverLink::Url(url) => {
15073                    cx.open_url(&url);
15074                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15075                }
15076                HoverLink::File(path) => {
15077                    if let Some(workspace) = self.workspace() {
15078                        cx.spawn_in(window, async move |_, cx| {
15079                            workspace
15080                                .update_in(cx, |workspace, window, cx| {
15081                                    workspace.open_resolved_path(path, window, cx)
15082                                })?
15083                                .await
15084                                .map(|_| TargetTaskResult::AlreadyNavigated)
15085                        })
15086                    } else {
15087                        Task::ready(Ok(TargetTaskResult::Location(None)))
15088                    }
15089                }
15090            };
15091            cx.spawn_in(window, async move |editor, cx| {
15092                let target = match target_task.await.context("target resolution task")? {
15093                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15094                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15095                    TargetTaskResult::Location(Some(target)) => target,
15096                };
15097
15098                editor.update_in(cx, |editor, window, cx| {
15099                    let Some(workspace) = editor.workspace() else {
15100                        return Navigated::No;
15101                    };
15102                    let pane = workspace.read(cx).active_pane().clone();
15103
15104                    let range = target.range.to_point(target.buffer.read(cx));
15105                    let range = editor.range_for_match(&range);
15106                    let range = collapse_multiline_range(range);
15107
15108                    if !split
15109                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15110                    {
15111                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15112                    } else {
15113                        window.defer(cx, move |window, cx| {
15114                            let target_editor: Entity<Self> =
15115                                workspace.update(cx, |workspace, cx| {
15116                                    let pane = if split {
15117                                        workspace.adjacent_pane(window, cx)
15118                                    } else {
15119                                        workspace.active_pane().clone()
15120                                    };
15121
15122                                    workspace.open_project_item(
15123                                        pane,
15124                                        target.buffer.clone(),
15125                                        true,
15126                                        true,
15127                                        window,
15128                                        cx,
15129                                    )
15130                                });
15131                            target_editor.update(cx, |target_editor, cx| {
15132                                // When selecting a definition in a different buffer, disable the nav history
15133                                // to avoid creating a history entry at the previous cursor location.
15134                                pane.update(cx, |pane, _| pane.disable_history());
15135                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15136                                pane.update(cx, |pane, _| pane.enable_history());
15137                            });
15138                        });
15139                    }
15140                    Navigated::Yes
15141                })
15142            })
15143        } else if !definitions.is_empty() {
15144            cx.spawn_in(window, async move |editor, cx| {
15145                let (title, location_tasks, workspace) = editor
15146                    .update_in(cx, |editor, window, cx| {
15147                        let tab_kind = match kind {
15148                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15149                            _ => "Definitions",
15150                        };
15151                        let title = definitions
15152                            .iter()
15153                            .find_map(|definition| match definition {
15154                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15155                                    let buffer = origin.buffer.read(cx);
15156                                    format!(
15157                                        "{} for {}",
15158                                        tab_kind,
15159                                        buffer
15160                                            .text_for_range(origin.range.clone())
15161                                            .collect::<String>()
15162                                    )
15163                                }),
15164                                HoverLink::InlayHint(_, _) => None,
15165                                HoverLink::Url(_) => None,
15166                                HoverLink::File(_) => None,
15167                            })
15168                            .unwrap_or(tab_kind.to_string());
15169                        let location_tasks = definitions
15170                            .into_iter()
15171                            .map(|definition| match definition {
15172                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15173                                HoverLink::InlayHint(lsp_location, server_id) => editor
15174                                    .compute_target_location(lsp_location, server_id, window, cx),
15175                                HoverLink::Url(_) => Task::ready(Ok(None)),
15176                                HoverLink::File(_) => Task::ready(Ok(None)),
15177                            })
15178                            .collect::<Vec<_>>();
15179                        (title, location_tasks, editor.workspace().clone())
15180                    })
15181                    .context("location tasks preparation")?;
15182
15183                let locations: Vec<Location> = future::join_all(location_tasks)
15184                    .await
15185                    .into_iter()
15186                    .filter_map(|location| location.transpose())
15187                    .collect::<Result<_>>()
15188                    .context("location tasks")?;
15189
15190                if locations.is_empty() {
15191                    return Ok(Navigated::No);
15192                }
15193
15194                let Some(workspace) = workspace else {
15195                    return Ok(Navigated::No);
15196                };
15197
15198                let opened = workspace
15199                    .update_in(cx, |workspace, window, cx| {
15200                        Self::open_locations_in_multibuffer(
15201                            workspace,
15202                            locations,
15203                            title,
15204                            split,
15205                            MultibufferSelectionMode::First,
15206                            window,
15207                            cx,
15208                        )
15209                    })
15210                    .ok();
15211
15212                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15213            })
15214        } else {
15215            Task::ready(Ok(Navigated::No))
15216        }
15217    }
15218
15219    fn compute_target_location(
15220        &self,
15221        lsp_location: lsp::Location,
15222        server_id: LanguageServerId,
15223        window: &mut Window,
15224        cx: &mut Context<Self>,
15225    ) -> Task<anyhow::Result<Option<Location>>> {
15226        let Some(project) = self.project.clone() else {
15227            return Task::ready(Ok(None));
15228        };
15229
15230        cx.spawn_in(window, async move |editor, cx| {
15231            let location_task = editor.update(cx, |_, cx| {
15232                project.update(cx, |project, cx| {
15233                    let language_server_name = project
15234                        .language_server_statuses(cx)
15235                        .find(|(id, _)| server_id == *id)
15236                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15237                    language_server_name.map(|language_server_name| {
15238                        project.open_local_buffer_via_lsp(
15239                            lsp_location.uri.clone(),
15240                            server_id,
15241                            language_server_name,
15242                            cx,
15243                        )
15244                    })
15245                })
15246            })?;
15247            let location = match location_task {
15248                Some(task) => Some({
15249                    let target_buffer_handle = task.await.context("open local buffer")?;
15250                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15251                        let target_start = target_buffer
15252                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15253                        let target_end = target_buffer
15254                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15255                        target_buffer.anchor_after(target_start)
15256                            ..target_buffer.anchor_before(target_end)
15257                    })?;
15258                    Location {
15259                        buffer: target_buffer_handle,
15260                        range,
15261                    }
15262                }),
15263                None => None,
15264            };
15265            Ok(location)
15266        })
15267    }
15268
15269    pub fn find_all_references(
15270        &mut self,
15271        _: &FindAllReferences,
15272        window: &mut Window,
15273        cx: &mut Context<Self>,
15274    ) -> Option<Task<Result<Navigated>>> {
15275        let selection = self.selections.newest::<usize>(cx);
15276        let multi_buffer = self.buffer.read(cx);
15277        let head = selection.head();
15278
15279        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15280        let head_anchor = multi_buffer_snapshot.anchor_at(
15281            head,
15282            if head < selection.tail() {
15283                Bias::Right
15284            } else {
15285                Bias::Left
15286            },
15287        );
15288
15289        match self
15290            .find_all_references_task_sources
15291            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15292        {
15293            Ok(_) => {
15294                log::info!(
15295                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15296                );
15297                return None;
15298            }
15299            Err(i) => {
15300                self.find_all_references_task_sources.insert(i, head_anchor);
15301            }
15302        }
15303
15304        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15305        let workspace = self.workspace()?;
15306        let project = workspace.read(cx).project().clone();
15307        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15308        Some(cx.spawn_in(window, async move |editor, cx| {
15309            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15310                if let Ok(i) = editor
15311                    .find_all_references_task_sources
15312                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15313                {
15314                    editor.find_all_references_task_sources.remove(i);
15315                }
15316            });
15317
15318            let locations = references.await?;
15319            if locations.is_empty() {
15320                return anyhow::Ok(Navigated::No);
15321            }
15322
15323            workspace.update_in(cx, |workspace, window, cx| {
15324                let title = locations
15325                    .first()
15326                    .as_ref()
15327                    .map(|location| {
15328                        let buffer = location.buffer.read(cx);
15329                        format!(
15330                            "References to `{}`",
15331                            buffer
15332                                .text_for_range(location.range.clone())
15333                                .collect::<String>()
15334                        )
15335                    })
15336                    .unwrap();
15337                Self::open_locations_in_multibuffer(
15338                    workspace,
15339                    locations,
15340                    title,
15341                    false,
15342                    MultibufferSelectionMode::First,
15343                    window,
15344                    cx,
15345                );
15346                Navigated::Yes
15347            })
15348        }))
15349    }
15350
15351    /// Opens a multibuffer with the given project locations in it
15352    pub fn open_locations_in_multibuffer(
15353        workspace: &mut Workspace,
15354        mut locations: Vec<Location>,
15355        title: String,
15356        split: bool,
15357        multibuffer_selection_mode: MultibufferSelectionMode,
15358        window: &mut Window,
15359        cx: &mut Context<Workspace>,
15360    ) {
15361        if locations.is_empty() {
15362            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15363            return;
15364        }
15365
15366        // If there are multiple definitions, open them in a multibuffer
15367        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15368        let mut locations = locations.into_iter().peekable();
15369        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15370        let capability = workspace.project().read(cx).capability();
15371
15372        let excerpt_buffer = cx.new(|cx| {
15373            let mut multibuffer = MultiBuffer::new(capability);
15374            while let Some(location) = locations.next() {
15375                let buffer = location.buffer.read(cx);
15376                let mut ranges_for_buffer = Vec::new();
15377                let range = location.range.to_point(buffer);
15378                ranges_for_buffer.push(range.clone());
15379
15380                while let Some(next_location) = locations.peek() {
15381                    if next_location.buffer == location.buffer {
15382                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15383                        locations.next();
15384                    } else {
15385                        break;
15386                    }
15387                }
15388
15389                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15390                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15391                    PathKey::for_buffer(&location.buffer, cx),
15392                    location.buffer.clone(),
15393                    ranges_for_buffer,
15394                    DEFAULT_MULTIBUFFER_CONTEXT,
15395                    cx,
15396                );
15397                ranges.extend(new_ranges)
15398            }
15399
15400            multibuffer.with_title(title)
15401        });
15402
15403        let editor = cx.new(|cx| {
15404            Editor::for_multibuffer(
15405                excerpt_buffer,
15406                Some(workspace.project().clone()),
15407                window,
15408                cx,
15409            )
15410        });
15411        editor.update(cx, |editor, cx| {
15412            match multibuffer_selection_mode {
15413                MultibufferSelectionMode::First => {
15414                    if let Some(first_range) = ranges.first() {
15415                        editor.change_selections(None, window, cx, |selections| {
15416                            selections.clear_disjoint();
15417                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15418                        });
15419                    }
15420                    editor.highlight_background::<Self>(
15421                        &ranges,
15422                        |theme| theme.colors().editor_highlighted_line_background,
15423                        cx,
15424                    );
15425                }
15426                MultibufferSelectionMode::All => {
15427                    editor.change_selections(None, window, cx, |selections| {
15428                        selections.clear_disjoint();
15429                        selections.select_anchor_ranges(ranges);
15430                    });
15431                }
15432            }
15433            editor.register_buffers_with_language_servers(cx);
15434        });
15435
15436        let item = Box::new(editor);
15437        let item_id = item.item_id();
15438
15439        if split {
15440            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15441        } else {
15442            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15443                let (preview_item_id, preview_item_idx) =
15444                    workspace.active_pane().read_with(cx, |pane, _| {
15445                        (pane.preview_item_id(), pane.preview_item_idx())
15446                    });
15447
15448                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15449
15450                if let Some(preview_item_id) = preview_item_id {
15451                    workspace.active_pane().update(cx, |pane, cx| {
15452                        pane.remove_item(preview_item_id, false, false, window, cx);
15453                    });
15454                }
15455            } else {
15456                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15457            }
15458        }
15459        workspace.active_pane().update(cx, |pane, cx| {
15460            pane.set_preview_item_id(Some(item_id), cx);
15461        });
15462    }
15463
15464    pub fn rename(
15465        &mut self,
15466        _: &Rename,
15467        window: &mut Window,
15468        cx: &mut Context<Self>,
15469    ) -> Option<Task<Result<()>>> {
15470        use language::ToOffset as _;
15471
15472        let provider = self.semantics_provider.clone()?;
15473        let selection = self.selections.newest_anchor().clone();
15474        let (cursor_buffer, cursor_buffer_position) = self
15475            .buffer
15476            .read(cx)
15477            .text_anchor_for_position(selection.head(), cx)?;
15478        let (tail_buffer, cursor_buffer_position_end) = self
15479            .buffer
15480            .read(cx)
15481            .text_anchor_for_position(selection.tail(), cx)?;
15482        if tail_buffer != cursor_buffer {
15483            return None;
15484        }
15485
15486        let snapshot = cursor_buffer.read(cx).snapshot();
15487        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15488        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15489        let prepare_rename = provider
15490            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15491            .unwrap_or_else(|| Task::ready(Ok(None)));
15492        drop(snapshot);
15493
15494        Some(cx.spawn_in(window, async move |this, cx| {
15495            let rename_range = if let Some(range) = prepare_rename.await? {
15496                Some(range)
15497            } else {
15498                this.update(cx, |this, cx| {
15499                    let buffer = this.buffer.read(cx).snapshot(cx);
15500                    let mut buffer_highlights = this
15501                        .document_highlights_for_position(selection.head(), &buffer)
15502                        .filter(|highlight| {
15503                            highlight.start.excerpt_id == selection.head().excerpt_id
15504                                && highlight.end.excerpt_id == selection.head().excerpt_id
15505                        });
15506                    buffer_highlights
15507                        .next()
15508                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15509                })?
15510            };
15511            if let Some(rename_range) = rename_range {
15512                this.update_in(cx, |this, window, cx| {
15513                    let snapshot = cursor_buffer.read(cx).snapshot();
15514                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15515                    let cursor_offset_in_rename_range =
15516                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15517                    let cursor_offset_in_rename_range_end =
15518                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15519
15520                    this.take_rename(false, window, cx);
15521                    let buffer = this.buffer.read(cx).read(cx);
15522                    let cursor_offset = selection.head().to_offset(&buffer);
15523                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15524                    let rename_end = rename_start + rename_buffer_range.len();
15525                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15526                    let mut old_highlight_id = None;
15527                    let old_name: Arc<str> = buffer
15528                        .chunks(rename_start..rename_end, true)
15529                        .map(|chunk| {
15530                            if old_highlight_id.is_none() {
15531                                old_highlight_id = chunk.syntax_highlight_id;
15532                            }
15533                            chunk.text
15534                        })
15535                        .collect::<String>()
15536                        .into();
15537
15538                    drop(buffer);
15539
15540                    // Position the selection in the rename editor so that it matches the current selection.
15541                    this.show_local_selections = false;
15542                    let rename_editor = cx.new(|cx| {
15543                        let mut editor = Editor::single_line(window, cx);
15544                        editor.buffer.update(cx, |buffer, cx| {
15545                            buffer.edit([(0..0, old_name.clone())], None, cx)
15546                        });
15547                        let rename_selection_range = match cursor_offset_in_rename_range
15548                            .cmp(&cursor_offset_in_rename_range_end)
15549                        {
15550                            Ordering::Equal => {
15551                                editor.select_all(&SelectAll, window, cx);
15552                                return editor;
15553                            }
15554                            Ordering::Less => {
15555                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15556                            }
15557                            Ordering::Greater => {
15558                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15559                            }
15560                        };
15561                        if rename_selection_range.end > old_name.len() {
15562                            editor.select_all(&SelectAll, window, cx);
15563                        } else {
15564                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15565                                s.select_ranges([rename_selection_range]);
15566                            });
15567                        }
15568                        editor
15569                    });
15570                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15571                        if e == &EditorEvent::Focused {
15572                            cx.emit(EditorEvent::FocusedIn)
15573                        }
15574                    })
15575                    .detach();
15576
15577                    let write_highlights =
15578                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15579                    let read_highlights =
15580                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15581                    let ranges = write_highlights
15582                        .iter()
15583                        .flat_map(|(_, ranges)| ranges.iter())
15584                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15585                        .cloned()
15586                        .collect();
15587
15588                    this.highlight_text::<Rename>(
15589                        ranges,
15590                        HighlightStyle {
15591                            fade_out: Some(0.6),
15592                            ..Default::default()
15593                        },
15594                        cx,
15595                    );
15596                    let rename_focus_handle = rename_editor.focus_handle(cx);
15597                    window.focus(&rename_focus_handle);
15598                    let block_id = this.insert_blocks(
15599                        [BlockProperties {
15600                            style: BlockStyle::Flex,
15601                            placement: BlockPlacement::Below(range.start),
15602                            height: Some(1),
15603                            render: Arc::new({
15604                                let rename_editor = rename_editor.clone();
15605                                move |cx: &mut BlockContext| {
15606                                    let mut text_style = cx.editor_style.text.clone();
15607                                    if let Some(highlight_style) = old_highlight_id
15608                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15609                                    {
15610                                        text_style = text_style.highlight(highlight_style);
15611                                    }
15612                                    div()
15613                                        .block_mouse_except_scroll()
15614                                        .pl(cx.anchor_x)
15615                                        .child(EditorElement::new(
15616                                            &rename_editor,
15617                                            EditorStyle {
15618                                                background: cx.theme().system().transparent,
15619                                                local_player: cx.editor_style.local_player,
15620                                                text: text_style,
15621                                                scrollbar_width: cx.editor_style.scrollbar_width,
15622                                                syntax: cx.editor_style.syntax.clone(),
15623                                                status: cx.editor_style.status.clone(),
15624                                                inlay_hints_style: HighlightStyle {
15625                                                    font_weight: Some(FontWeight::BOLD),
15626                                                    ..make_inlay_hints_style(cx.app)
15627                                                },
15628                                                inline_completion_styles: make_suggestion_styles(
15629                                                    cx.app,
15630                                                ),
15631                                                ..EditorStyle::default()
15632                                            },
15633                                        ))
15634                                        .into_any_element()
15635                                }
15636                            }),
15637                            priority: 0,
15638                            render_in_minimap: true,
15639                        }],
15640                        Some(Autoscroll::fit()),
15641                        cx,
15642                    )[0];
15643                    this.pending_rename = Some(RenameState {
15644                        range,
15645                        old_name,
15646                        editor: rename_editor,
15647                        block_id,
15648                    });
15649                })?;
15650            }
15651
15652            Ok(())
15653        }))
15654    }
15655
15656    pub fn confirm_rename(
15657        &mut self,
15658        _: &ConfirmRename,
15659        window: &mut Window,
15660        cx: &mut Context<Self>,
15661    ) -> Option<Task<Result<()>>> {
15662        let rename = self.take_rename(false, window, cx)?;
15663        let workspace = self.workspace()?.downgrade();
15664        let (buffer, start) = self
15665            .buffer
15666            .read(cx)
15667            .text_anchor_for_position(rename.range.start, cx)?;
15668        let (end_buffer, _) = self
15669            .buffer
15670            .read(cx)
15671            .text_anchor_for_position(rename.range.end, cx)?;
15672        if buffer != end_buffer {
15673            return None;
15674        }
15675
15676        let old_name = rename.old_name;
15677        let new_name = rename.editor.read(cx).text(cx);
15678
15679        let rename = self.semantics_provider.as_ref()?.perform_rename(
15680            &buffer,
15681            start,
15682            new_name.clone(),
15683            cx,
15684        )?;
15685
15686        Some(cx.spawn_in(window, async move |editor, cx| {
15687            let project_transaction = rename.await?;
15688            Self::open_project_transaction(
15689                &editor,
15690                workspace,
15691                project_transaction,
15692                format!("Rename: {}{}", old_name, new_name),
15693                cx,
15694            )
15695            .await?;
15696
15697            editor.update(cx, |editor, cx| {
15698                editor.refresh_document_highlights(cx);
15699            })?;
15700            Ok(())
15701        }))
15702    }
15703
15704    fn take_rename(
15705        &mut self,
15706        moving_cursor: bool,
15707        window: &mut Window,
15708        cx: &mut Context<Self>,
15709    ) -> Option<RenameState> {
15710        let rename = self.pending_rename.take()?;
15711        if rename.editor.focus_handle(cx).is_focused(window) {
15712            window.focus(&self.focus_handle);
15713        }
15714
15715        self.remove_blocks(
15716            [rename.block_id].into_iter().collect(),
15717            Some(Autoscroll::fit()),
15718            cx,
15719        );
15720        self.clear_highlights::<Rename>(cx);
15721        self.show_local_selections = true;
15722
15723        if moving_cursor {
15724            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15725                editor.selections.newest::<usize>(cx).head()
15726            });
15727
15728            // Update the selection to match the position of the selection inside
15729            // the rename editor.
15730            let snapshot = self.buffer.read(cx).read(cx);
15731            let rename_range = rename.range.to_offset(&snapshot);
15732            let cursor_in_editor = snapshot
15733                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15734                .min(rename_range.end);
15735            drop(snapshot);
15736
15737            self.change_selections(None, window, cx, |s| {
15738                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15739            });
15740        } else {
15741            self.refresh_document_highlights(cx);
15742        }
15743
15744        Some(rename)
15745    }
15746
15747    pub fn pending_rename(&self) -> Option<&RenameState> {
15748        self.pending_rename.as_ref()
15749    }
15750
15751    fn format(
15752        &mut self,
15753        _: &Format,
15754        window: &mut Window,
15755        cx: &mut Context<Self>,
15756    ) -> Option<Task<Result<()>>> {
15757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15758
15759        let project = match &self.project {
15760            Some(project) => project.clone(),
15761            None => return None,
15762        };
15763
15764        Some(self.perform_format(
15765            project,
15766            FormatTrigger::Manual,
15767            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15768            window,
15769            cx,
15770        ))
15771    }
15772
15773    fn format_selections(
15774        &mut self,
15775        _: &FormatSelections,
15776        window: &mut Window,
15777        cx: &mut Context<Self>,
15778    ) -> Option<Task<Result<()>>> {
15779        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15780
15781        let project = match &self.project {
15782            Some(project) => project.clone(),
15783            None => return None,
15784        };
15785
15786        let ranges = self
15787            .selections
15788            .all_adjusted(cx)
15789            .into_iter()
15790            .map(|selection| selection.range())
15791            .collect_vec();
15792
15793        Some(self.perform_format(
15794            project,
15795            FormatTrigger::Manual,
15796            FormatTarget::Ranges(ranges),
15797            window,
15798            cx,
15799        ))
15800    }
15801
15802    fn perform_format(
15803        &mut self,
15804        project: Entity<Project>,
15805        trigger: FormatTrigger,
15806        target: FormatTarget,
15807        window: &mut Window,
15808        cx: &mut Context<Self>,
15809    ) -> Task<Result<()>> {
15810        let buffer = self.buffer.clone();
15811        let (buffers, target) = match target {
15812            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15813            FormatTarget::Ranges(selection_ranges) => {
15814                let multi_buffer = buffer.read(cx);
15815                let snapshot = multi_buffer.read(cx);
15816                let mut buffers = HashSet::default();
15817                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15818                    BTreeMap::new();
15819                for selection_range in selection_ranges {
15820                    for (buffer, buffer_range, _) in
15821                        snapshot.range_to_buffer_ranges(selection_range)
15822                    {
15823                        let buffer_id = buffer.remote_id();
15824                        let start = buffer.anchor_before(buffer_range.start);
15825                        let end = buffer.anchor_after(buffer_range.end);
15826                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15827                        buffer_id_to_ranges
15828                            .entry(buffer_id)
15829                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15830                            .or_insert_with(|| vec![start..end]);
15831                    }
15832                }
15833                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15834            }
15835        };
15836
15837        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15838        let selections_prev = transaction_id_prev
15839            .and_then(|transaction_id_prev| {
15840                // default to selections as they were after the last edit, if we have them,
15841                // instead of how they are now.
15842                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15843                // will take you back to where you made the last edit, instead of staying where you scrolled
15844                self.selection_history
15845                    .transaction(transaction_id_prev)
15846                    .map(|t| t.0.clone())
15847            })
15848            .unwrap_or_else(|| {
15849                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15850                self.selections.disjoint_anchors()
15851            });
15852
15853        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15854        let format = project.update(cx, |project, cx| {
15855            project.format(buffers, target, true, trigger, cx)
15856        });
15857
15858        cx.spawn_in(window, async move |editor, cx| {
15859            let transaction = futures::select_biased! {
15860                transaction = format.log_err().fuse() => transaction,
15861                () = timeout => {
15862                    log::warn!("timed out waiting for formatting");
15863                    None
15864                }
15865            };
15866
15867            buffer
15868                .update(cx, |buffer, cx| {
15869                    if let Some(transaction) = transaction {
15870                        if !buffer.is_singleton() {
15871                            buffer.push_transaction(&transaction.0, cx);
15872                        }
15873                    }
15874                    cx.notify();
15875                })
15876                .ok();
15877
15878            if let Some(transaction_id_now) =
15879                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15880            {
15881                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15882                if has_new_transaction {
15883                    _ = editor.update(cx, |editor, _| {
15884                        editor
15885                            .selection_history
15886                            .insert_transaction(transaction_id_now, selections_prev);
15887                    });
15888                }
15889            }
15890
15891            Ok(())
15892        })
15893    }
15894
15895    fn organize_imports(
15896        &mut self,
15897        _: &OrganizeImports,
15898        window: &mut Window,
15899        cx: &mut Context<Self>,
15900    ) -> Option<Task<Result<()>>> {
15901        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15902        let project = match &self.project {
15903            Some(project) => project.clone(),
15904            None => return None,
15905        };
15906        Some(self.perform_code_action_kind(
15907            project,
15908            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15909            window,
15910            cx,
15911        ))
15912    }
15913
15914    fn perform_code_action_kind(
15915        &mut self,
15916        project: Entity<Project>,
15917        kind: CodeActionKind,
15918        window: &mut Window,
15919        cx: &mut Context<Self>,
15920    ) -> Task<Result<()>> {
15921        let buffer = self.buffer.clone();
15922        let buffers = buffer.read(cx).all_buffers();
15923        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15924        let apply_action = project.update(cx, |project, cx| {
15925            project.apply_code_action_kind(buffers, kind, true, cx)
15926        });
15927        cx.spawn_in(window, async move |_, cx| {
15928            let transaction = futures::select_biased! {
15929                () = timeout => {
15930                    log::warn!("timed out waiting for executing code action");
15931                    None
15932                }
15933                transaction = apply_action.log_err().fuse() => transaction,
15934            };
15935            buffer
15936                .update(cx, |buffer, cx| {
15937                    // check if we need this
15938                    if let Some(transaction) = transaction {
15939                        if !buffer.is_singleton() {
15940                            buffer.push_transaction(&transaction.0, cx);
15941                        }
15942                    }
15943                    cx.notify();
15944                })
15945                .ok();
15946            Ok(())
15947        })
15948    }
15949
15950    fn restart_language_server(
15951        &mut self,
15952        _: &RestartLanguageServer,
15953        _: &mut Window,
15954        cx: &mut Context<Self>,
15955    ) {
15956        if let Some(project) = self.project.clone() {
15957            self.buffer.update(cx, |multi_buffer, cx| {
15958                project.update(cx, |project, cx| {
15959                    project.restart_language_servers_for_buffers(
15960                        multi_buffer.all_buffers().into_iter().collect(),
15961                        cx,
15962                    );
15963                });
15964            })
15965        }
15966    }
15967
15968    fn stop_language_server(
15969        &mut self,
15970        _: &StopLanguageServer,
15971        _: &mut Window,
15972        cx: &mut Context<Self>,
15973    ) {
15974        if let Some(project) = self.project.clone() {
15975            self.buffer.update(cx, |multi_buffer, cx| {
15976                project.update(cx, |project, cx| {
15977                    project.stop_language_servers_for_buffers(
15978                        multi_buffer.all_buffers().into_iter().collect(),
15979                        cx,
15980                    );
15981                    cx.emit(project::Event::RefreshInlayHints);
15982                });
15983            });
15984        }
15985    }
15986
15987    fn cancel_language_server_work(
15988        workspace: &mut Workspace,
15989        _: &actions::CancelLanguageServerWork,
15990        _: &mut Window,
15991        cx: &mut Context<Workspace>,
15992    ) {
15993        let project = workspace.project();
15994        let buffers = workspace
15995            .active_item(cx)
15996            .and_then(|item| item.act_as::<Editor>(cx))
15997            .map_or(HashSet::default(), |editor| {
15998                editor.read(cx).buffer.read(cx).all_buffers()
15999            });
16000        project.update(cx, |project, cx| {
16001            project.cancel_language_server_work_for_buffers(buffers, cx);
16002        });
16003    }
16004
16005    fn show_character_palette(
16006        &mut self,
16007        _: &ShowCharacterPalette,
16008        window: &mut Window,
16009        _: &mut Context<Self>,
16010    ) {
16011        window.show_character_palette();
16012    }
16013
16014    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16015        if self.mode.is_minimap() {
16016            return;
16017        }
16018
16019        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16020            let buffer = self.buffer.read(cx).snapshot(cx);
16021            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16022            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16023            let is_valid = buffer
16024                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16025                .any(|entry| {
16026                    entry.diagnostic.is_primary
16027                        && !entry.range.is_empty()
16028                        && entry.range.start == primary_range_start
16029                        && entry.diagnostic.message == active_diagnostics.active_message
16030                });
16031
16032            if !is_valid {
16033                self.dismiss_diagnostics(cx);
16034            }
16035        }
16036    }
16037
16038    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16039        match &self.active_diagnostics {
16040            ActiveDiagnostic::Group(group) => Some(group),
16041            _ => None,
16042        }
16043    }
16044
16045    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16046        self.dismiss_diagnostics(cx);
16047        self.active_diagnostics = ActiveDiagnostic::All;
16048    }
16049
16050    fn activate_diagnostics(
16051        &mut self,
16052        buffer_id: BufferId,
16053        diagnostic: DiagnosticEntry<usize>,
16054        window: &mut Window,
16055        cx: &mut Context<Self>,
16056    ) {
16057        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16058            return;
16059        }
16060        self.dismiss_diagnostics(cx);
16061        let snapshot = self.snapshot(window, cx);
16062        let buffer = self.buffer.read(cx).snapshot(cx);
16063        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16064            return;
16065        };
16066
16067        let diagnostic_group = buffer
16068            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16069            .collect::<Vec<_>>();
16070
16071        let blocks =
16072            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16073
16074        let blocks = self.display_map.update(cx, |display_map, cx| {
16075            display_map.insert_blocks(blocks, cx).into_iter().collect()
16076        });
16077        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16078            active_range: buffer.anchor_before(diagnostic.range.start)
16079                ..buffer.anchor_after(diagnostic.range.end),
16080            active_message: diagnostic.diagnostic.message.clone(),
16081            group_id: diagnostic.diagnostic.group_id,
16082            blocks,
16083        });
16084        cx.notify();
16085    }
16086
16087    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16088        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16089            return;
16090        };
16091
16092        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16093        if let ActiveDiagnostic::Group(group) = prev {
16094            self.display_map.update(cx, |display_map, cx| {
16095                display_map.remove_blocks(group.blocks, cx);
16096            });
16097            cx.notify();
16098        }
16099    }
16100
16101    /// Disable inline diagnostics rendering for this editor.
16102    pub fn disable_inline_diagnostics(&mut self) {
16103        self.inline_diagnostics_enabled = false;
16104        self.inline_diagnostics_update = Task::ready(());
16105        self.inline_diagnostics.clear();
16106    }
16107
16108    pub fn diagnostics_enabled(&self) -> bool {
16109        self.mode.is_full()
16110    }
16111
16112    pub fn inline_diagnostics_enabled(&self) -> bool {
16113        self.diagnostics_enabled() && self.inline_diagnostics_enabled
16114    }
16115
16116    pub fn show_inline_diagnostics(&self) -> bool {
16117        self.show_inline_diagnostics
16118    }
16119
16120    pub fn toggle_inline_diagnostics(
16121        &mut self,
16122        _: &ToggleInlineDiagnostics,
16123        window: &mut Window,
16124        cx: &mut Context<Editor>,
16125    ) {
16126        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16127        self.refresh_inline_diagnostics(false, window, cx);
16128    }
16129
16130    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16131        self.diagnostics_max_severity = severity;
16132        self.display_map.update(cx, |display_map, _| {
16133            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16134        });
16135    }
16136
16137    pub fn toggle_diagnostics(
16138        &mut self,
16139        _: &ToggleDiagnostics,
16140        window: &mut Window,
16141        cx: &mut Context<Editor>,
16142    ) {
16143        if !self.diagnostics_enabled() {
16144            return;
16145        }
16146
16147        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16148            EditorSettings::get_global(cx)
16149                .diagnostics_max_severity
16150                .filter(|severity| severity != &DiagnosticSeverity::Off)
16151                .unwrap_or(DiagnosticSeverity::Hint)
16152        } else {
16153            DiagnosticSeverity::Off
16154        };
16155        self.set_max_diagnostics_severity(new_severity, cx);
16156        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16157            self.active_diagnostics = ActiveDiagnostic::None;
16158            self.inline_diagnostics_update = Task::ready(());
16159            self.inline_diagnostics.clear();
16160        } else {
16161            self.refresh_inline_diagnostics(false, window, cx);
16162        }
16163
16164        cx.notify();
16165    }
16166
16167    pub fn toggle_minimap(
16168        &mut self,
16169        _: &ToggleMinimap,
16170        window: &mut Window,
16171        cx: &mut Context<Editor>,
16172    ) {
16173        if self.supports_minimap(cx) {
16174            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16175        }
16176    }
16177
16178    fn refresh_inline_diagnostics(
16179        &mut self,
16180        debounce: bool,
16181        window: &mut Window,
16182        cx: &mut Context<Self>,
16183    ) {
16184        let max_severity = ProjectSettings::get_global(cx)
16185            .diagnostics
16186            .inline
16187            .max_severity
16188            .unwrap_or(self.diagnostics_max_severity);
16189
16190        if !self.inline_diagnostics_enabled()
16191            || !self.show_inline_diagnostics
16192            || max_severity == DiagnosticSeverity::Off
16193        {
16194            self.inline_diagnostics_update = Task::ready(());
16195            self.inline_diagnostics.clear();
16196            return;
16197        }
16198
16199        let debounce_ms = ProjectSettings::get_global(cx)
16200            .diagnostics
16201            .inline
16202            .update_debounce_ms;
16203        let debounce = if debounce && debounce_ms > 0 {
16204            Some(Duration::from_millis(debounce_ms))
16205        } else {
16206            None
16207        };
16208        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16209            if let Some(debounce) = debounce {
16210                cx.background_executor().timer(debounce).await;
16211            }
16212            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16213                editor
16214                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16215                    .ok()
16216            }) else {
16217                return;
16218            };
16219
16220            let new_inline_diagnostics = cx
16221                .background_spawn(async move {
16222                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16223                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16224                        let message = diagnostic_entry
16225                            .diagnostic
16226                            .message
16227                            .split_once('\n')
16228                            .map(|(line, _)| line)
16229                            .map(SharedString::new)
16230                            .unwrap_or_else(|| {
16231                                SharedString::from(diagnostic_entry.diagnostic.message)
16232                            });
16233                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16234                        let (Ok(i) | Err(i)) = inline_diagnostics
16235                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16236                        inline_diagnostics.insert(
16237                            i,
16238                            (
16239                                start_anchor,
16240                                InlineDiagnostic {
16241                                    message,
16242                                    group_id: diagnostic_entry.diagnostic.group_id,
16243                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16244                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16245                                    severity: diagnostic_entry.diagnostic.severity,
16246                                },
16247                            ),
16248                        );
16249                    }
16250                    inline_diagnostics
16251                })
16252                .await;
16253
16254            editor
16255                .update(cx, |editor, cx| {
16256                    editor.inline_diagnostics = new_inline_diagnostics;
16257                    cx.notify();
16258                })
16259                .ok();
16260        });
16261    }
16262
16263    fn pull_diagnostics(
16264        &mut self,
16265        buffer_id: Option<BufferId>,
16266        window: &Window,
16267        cx: &mut Context<Self>,
16268    ) -> Option<()> {
16269        if !self.mode().is_full() {
16270            return None;
16271        }
16272        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16273            .diagnostics
16274            .lsp_pull_diagnostics;
16275        if !pull_diagnostics_settings.enabled {
16276            return None;
16277        }
16278        let project = self.project.as_ref()?.downgrade();
16279        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16280        let mut buffers = self.buffer.read(cx).all_buffers();
16281        if let Some(buffer_id) = buffer_id {
16282            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16283        }
16284
16285        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16286            cx.background_executor().timer(debounce).await;
16287
16288            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16289                buffers
16290                    .into_iter()
16291                    .filter_map(|buffer| {
16292                        project
16293                            .update(cx, |project, cx| {
16294                                project.lsp_store().update(cx, |lsp_store, cx| {
16295                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16296                                })
16297                            })
16298                            .ok()
16299                    })
16300                    .collect::<FuturesUnordered<_>>()
16301            }) else {
16302                return;
16303            };
16304
16305            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16306                match pull_task {
16307                    Ok(()) => {
16308                        if editor
16309                            .update_in(cx, |editor, window, cx| {
16310                                editor.update_diagnostics_state(window, cx);
16311                            })
16312                            .is_err()
16313                        {
16314                            return;
16315                        }
16316                    }
16317                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16318                }
16319            }
16320        });
16321
16322        Some(())
16323    }
16324
16325    pub fn set_selections_from_remote(
16326        &mut self,
16327        selections: Vec<Selection<Anchor>>,
16328        pending_selection: Option<Selection<Anchor>>,
16329        window: &mut Window,
16330        cx: &mut Context<Self>,
16331    ) {
16332        let old_cursor_position = self.selections.newest_anchor().head();
16333        self.selections.change_with(cx, |s| {
16334            s.select_anchors(selections);
16335            if let Some(pending_selection) = pending_selection {
16336                s.set_pending(pending_selection, SelectMode::Character);
16337            } else {
16338                s.clear_pending();
16339            }
16340        });
16341        self.selections_did_change(
16342            false,
16343            &old_cursor_position,
16344            SelectionEffects::default(),
16345            window,
16346            cx,
16347        );
16348    }
16349
16350    pub fn transact(
16351        &mut self,
16352        window: &mut Window,
16353        cx: &mut Context<Self>,
16354        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16355    ) -> Option<TransactionId> {
16356        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16357            this.start_transaction_at(Instant::now(), window, cx);
16358            update(this, window, cx);
16359            this.end_transaction_at(Instant::now(), cx)
16360        })
16361    }
16362
16363    pub fn start_transaction_at(
16364        &mut self,
16365        now: Instant,
16366        window: &mut Window,
16367        cx: &mut Context<Self>,
16368    ) {
16369        self.end_selection(window, cx);
16370        if let Some(tx_id) = self
16371            .buffer
16372            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16373        {
16374            self.selection_history
16375                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16376            cx.emit(EditorEvent::TransactionBegun {
16377                transaction_id: tx_id,
16378            })
16379        }
16380    }
16381
16382    pub fn end_transaction_at(
16383        &mut self,
16384        now: Instant,
16385        cx: &mut Context<Self>,
16386    ) -> Option<TransactionId> {
16387        if let Some(transaction_id) = self
16388            .buffer
16389            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16390        {
16391            if let Some((_, end_selections)) =
16392                self.selection_history.transaction_mut(transaction_id)
16393            {
16394                *end_selections = Some(self.selections.disjoint_anchors());
16395            } else {
16396                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16397            }
16398
16399            cx.emit(EditorEvent::Edited { transaction_id });
16400            Some(transaction_id)
16401        } else {
16402            None
16403        }
16404    }
16405
16406    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16407        if self.selection_mark_mode {
16408            self.change_selections(None, window, cx, |s| {
16409                s.move_with(|_, sel| {
16410                    sel.collapse_to(sel.head(), SelectionGoal::None);
16411                });
16412            })
16413        }
16414        self.selection_mark_mode = true;
16415        cx.notify();
16416    }
16417
16418    pub fn swap_selection_ends(
16419        &mut self,
16420        _: &actions::SwapSelectionEnds,
16421        window: &mut Window,
16422        cx: &mut Context<Self>,
16423    ) {
16424        self.change_selections(None, window, cx, |s| {
16425            s.move_with(|_, sel| {
16426                if sel.start != sel.end {
16427                    sel.reversed = !sel.reversed
16428                }
16429            });
16430        });
16431        self.request_autoscroll(Autoscroll::newest(), cx);
16432        cx.notify();
16433    }
16434
16435    pub fn toggle_fold(
16436        &mut self,
16437        _: &actions::ToggleFold,
16438        window: &mut Window,
16439        cx: &mut Context<Self>,
16440    ) {
16441        if self.is_singleton(cx) {
16442            let selection = self.selections.newest::<Point>(cx);
16443
16444            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16445            let range = if selection.is_empty() {
16446                let point = selection.head().to_display_point(&display_map);
16447                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16448                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16449                    .to_point(&display_map);
16450                start..end
16451            } else {
16452                selection.range()
16453            };
16454            if display_map.folds_in_range(range).next().is_some() {
16455                self.unfold_lines(&Default::default(), window, cx)
16456            } else {
16457                self.fold(&Default::default(), window, cx)
16458            }
16459        } else {
16460            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16461            let buffer_ids: HashSet<_> = self
16462                .selections
16463                .disjoint_anchor_ranges()
16464                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16465                .collect();
16466
16467            let should_unfold = buffer_ids
16468                .iter()
16469                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16470
16471            for buffer_id in buffer_ids {
16472                if should_unfold {
16473                    self.unfold_buffer(buffer_id, cx);
16474                } else {
16475                    self.fold_buffer(buffer_id, cx);
16476                }
16477            }
16478        }
16479    }
16480
16481    pub fn toggle_fold_recursive(
16482        &mut self,
16483        _: &actions::ToggleFoldRecursive,
16484        window: &mut Window,
16485        cx: &mut Context<Self>,
16486    ) {
16487        let selection = self.selections.newest::<Point>(cx);
16488
16489        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16490        let range = if selection.is_empty() {
16491            let point = selection.head().to_display_point(&display_map);
16492            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16493            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16494                .to_point(&display_map);
16495            start..end
16496        } else {
16497            selection.range()
16498        };
16499        if display_map.folds_in_range(range).next().is_some() {
16500            self.unfold_recursive(&Default::default(), window, cx)
16501        } else {
16502            self.fold_recursive(&Default::default(), window, cx)
16503        }
16504    }
16505
16506    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16507        if self.is_singleton(cx) {
16508            let mut to_fold = Vec::new();
16509            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16510            let selections = self.selections.all_adjusted(cx);
16511
16512            for selection in selections {
16513                let range = selection.range().sorted();
16514                let buffer_start_row = range.start.row;
16515
16516                if range.start.row != range.end.row {
16517                    let mut found = false;
16518                    let mut row = range.start.row;
16519                    while row <= range.end.row {
16520                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16521                        {
16522                            found = true;
16523                            row = crease.range().end.row + 1;
16524                            to_fold.push(crease);
16525                        } else {
16526                            row += 1
16527                        }
16528                    }
16529                    if found {
16530                        continue;
16531                    }
16532                }
16533
16534                for row in (0..=range.start.row).rev() {
16535                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16536                        if crease.range().end.row >= buffer_start_row {
16537                            to_fold.push(crease);
16538                            if row <= range.start.row {
16539                                break;
16540                            }
16541                        }
16542                    }
16543                }
16544            }
16545
16546            self.fold_creases(to_fold, true, window, cx);
16547        } else {
16548            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16549            let buffer_ids = self
16550                .selections
16551                .disjoint_anchor_ranges()
16552                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16553                .collect::<HashSet<_>>();
16554            for buffer_id in buffer_ids {
16555                self.fold_buffer(buffer_id, cx);
16556            }
16557        }
16558    }
16559
16560    fn fold_at_level(
16561        &mut self,
16562        fold_at: &FoldAtLevel,
16563        window: &mut Window,
16564        cx: &mut Context<Self>,
16565    ) {
16566        if !self.buffer.read(cx).is_singleton() {
16567            return;
16568        }
16569
16570        let fold_at_level = fold_at.0;
16571        let snapshot = self.buffer.read(cx).snapshot(cx);
16572        let mut to_fold = Vec::new();
16573        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16574
16575        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16576            while start_row < end_row {
16577                match self
16578                    .snapshot(window, cx)
16579                    .crease_for_buffer_row(MultiBufferRow(start_row))
16580                {
16581                    Some(crease) => {
16582                        let nested_start_row = crease.range().start.row + 1;
16583                        let nested_end_row = crease.range().end.row;
16584
16585                        if current_level < fold_at_level {
16586                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16587                        } else if current_level == fold_at_level {
16588                            to_fold.push(crease);
16589                        }
16590
16591                        start_row = nested_end_row + 1;
16592                    }
16593                    None => start_row += 1,
16594                }
16595            }
16596        }
16597
16598        self.fold_creases(to_fold, true, window, cx);
16599    }
16600
16601    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16602        if self.buffer.read(cx).is_singleton() {
16603            let mut fold_ranges = Vec::new();
16604            let snapshot = self.buffer.read(cx).snapshot(cx);
16605
16606            for row in 0..snapshot.max_row().0 {
16607                if let Some(foldable_range) = self
16608                    .snapshot(window, cx)
16609                    .crease_for_buffer_row(MultiBufferRow(row))
16610                {
16611                    fold_ranges.push(foldable_range);
16612                }
16613            }
16614
16615            self.fold_creases(fold_ranges, true, window, cx);
16616        } else {
16617            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16618                editor
16619                    .update_in(cx, |editor, _, cx| {
16620                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16621                            editor.fold_buffer(buffer_id, cx);
16622                        }
16623                    })
16624                    .ok();
16625            });
16626        }
16627    }
16628
16629    pub fn fold_function_bodies(
16630        &mut self,
16631        _: &actions::FoldFunctionBodies,
16632        window: &mut Window,
16633        cx: &mut Context<Self>,
16634    ) {
16635        let snapshot = self.buffer.read(cx).snapshot(cx);
16636
16637        let ranges = snapshot
16638            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16639            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16640            .collect::<Vec<_>>();
16641
16642        let creases = ranges
16643            .into_iter()
16644            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16645            .collect();
16646
16647        self.fold_creases(creases, true, window, cx);
16648    }
16649
16650    pub fn fold_recursive(
16651        &mut self,
16652        _: &actions::FoldRecursive,
16653        window: &mut Window,
16654        cx: &mut Context<Self>,
16655    ) {
16656        let mut to_fold = Vec::new();
16657        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16658        let selections = self.selections.all_adjusted(cx);
16659
16660        for selection in selections {
16661            let range = selection.range().sorted();
16662            let buffer_start_row = range.start.row;
16663
16664            if range.start.row != range.end.row {
16665                let mut found = false;
16666                for row in range.start.row..=range.end.row {
16667                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16668                        found = true;
16669                        to_fold.push(crease);
16670                    }
16671                }
16672                if found {
16673                    continue;
16674                }
16675            }
16676
16677            for row in (0..=range.start.row).rev() {
16678                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16679                    if crease.range().end.row >= buffer_start_row {
16680                        to_fold.push(crease);
16681                    } else {
16682                        break;
16683                    }
16684                }
16685            }
16686        }
16687
16688        self.fold_creases(to_fold, true, window, cx);
16689    }
16690
16691    pub fn fold_at(
16692        &mut self,
16693        buffer_row: MultiBufferRow,
16694        window: &mut Window,
16695        cx: &mut Context<Self>,
16696    ) {
16697        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16698
16699        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16700            let autoscroll = self
16701                .selections
16702                .all::<Point>(cx)
16703                .iter()
16704                .any(|selection| crease.range().overlaps(&selection.range()));
16705
16706            self.fold_creases(vec![crease], autoscroll, window, cx);
16707        }
16708    }
16709
16710    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16711        if self.is_singleton(cx) {
16712            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16713            let buffer = &display_map.buffer_snapshot;
16714            let selections = self.selections.all::<Point>(cx);
16715            let ranges = selections
16716                .iter()
16717                .map(|s| {
16718                    let range = s.display_range(&display_map).sorted();
16719                    let mut start = range.start.to_point(&display_map);
16720                    let mut end = range.end.to_point(&display_map);
16721                    start.column = 0;
16722                    end.column = buffer.line_len(MultiBufferRow(end.row));
16723                    start..end
16724                })
16725                .collect::<Vec<_>>();
16726
16727            self.unfold_ranges(&ranges, true, true, cx);
16728        } else {
16729            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16730            let buffer_ids = self
16731                .selections
16732                .disjoint_anchor_ranges()
16733                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16734                .collect::<HashSet<_>>();
16735            for buffer_id in buffer_ids {
16736                self.unfold_buffer(buffer_id, cx);
16737            }
16738        }
16739    }
16740
16741    pub fn unfold_recursive(
16742        &mut self,
16743        _: &UnfoldRecursive,
16744        _window: &mut Window,
16745        cx: &mut Context<Self>,
16746    ) {
16747        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16748        let selections = self.selections.all::<Point>(cx);
16749        let ranges = selections
16750            .iter()
16751            .map(|s| {
16752                let mut range = s.display_range(&display_map).sorted();
16753                *range.start.column_mut() = 0;
16754                *range.end.column_mut() = display_map.line_len(range.end.row());
16755                let start = range.start.to_point(&display_map);
16756                let end = range.end.to_point(&display_map);
16757                start..end
16758            })
16759            .collect::<Vec<_>>();
16760
16761        self.unfold_ranges(&ranges, true, true, cx);
16762    }
16763
16764    pub fn unfold_at(
16765        &mut self,
16766        buffer_row: MultiBufferRow,
16767        _window: &mut Window,
16768        cx: &mut Context<Self>,
16769    ) {
16770        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16771
16772        let intersection_range = Point::new(buffer_row.0, 0)
16773            ..Point::new(
16774                buffer_row.0,
16775                display_map.buffer_snapshot.line_len(buffer_row),
16776            );
16777
16778        let autoscroll = self
16779            .selections
16780            .all::<Point>(cx)
16781            .iter()
16782            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16783
16784        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16785    }
16786
16787    pub fn unfold_all(
16788        &mut self,
16789        _: &actions::UnfoldAll,
16790        _window: &mut Window,
16791        cx: &mut Context<Self>,
16792    ) {
16793        if self.buffer.read(cx).is_singleton() {
16794            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16795            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16796        } else {
16797            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16798                editor
16799                    .update(cx, |editor, cx| {
16800                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16801                            editor.unfold_buffer(buffer_id, cx);
16802                        }
16803                    })
16804                    .ok();
16805            });
16806        }
16807    }
16808
16809    pub fn fold_selected_ranges(
16810        &mut self,
16811        _: &FoldSelectedRanges,
16812        window: &mut Window,
16813        cx: &mut Context<Self>,
16814    ) {
16815        let selections = self.selections.all_adjusted(cx);
16816        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16817        let ranges = selections
16818            .into_iter()
16819            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16820            .collect::<Vec<_>>();
16821        self.fold_creases(ranges, true, window, cx);
16822    }
16823
16824    pub fn fold_ranges<T: ToOffset + Clone>(
16825        &mut self,
16826        ranges: Vec<Range<T>>,
16827        auto_scroll: bool,
16828        window: &mut Window,
16829        cx: &mut Context<Self>,
16830    ) {
16831        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16832        let ranges = ranges
16833            .into_iter()
16834            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16835            .collect::<Vec<_>>();
16836        self.fold_creases(ranges, auto_scroll, window, cx);
16837    }
16838
16839    pub fn fold_creases<T: ToOffset + Clone>(
16840        &mut self,
16841        creases: Vec<Crease<T>>,
16842        auto_scroll: bool,
16843        _window: &mut Window,
16844        cx: &mut Context<Self>,
16845    ) {
16846        if creases.is_empty() {
16847            return;
16848        }
16849
16850        let mut buffers_affected = HashSet::default();
16851        let multi_buffer = self.buffer().read(cx);
16852        for crease in &creases {
16853            if let Some((_, buffer, _)) =
16854                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16855            {
16856                buffers_affected.insert(buffer.read(cx).remote_id());
16857            };
16858        }
16859
16860        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16861
16862        if auto_scroll {
16863            self.request_autoscroll(Autoscroll::fit(), cx);
16864        }
16865
16866        cx.notify();
16867
16868        self.scrollbar_marker_state.dirty = true;
16869        self.folds_did_change(cx);
16870    }
16871
16872    /// Removes any folds whose ranges intersect any of the given ranges.
16873    pub fn unfold_ranges<T: ToOffset + Clone>(
16874        &mut self,
16875        ranges: &[Range<T>],
16876        inclusive: bool,
16877        auto_scroll: bool,
16878        cx: &mut Context<Self>,
16879    ) {
16880        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16881            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16882        });
16883        self.folds_did_change(cx);
16884    }
16885
16886    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16887        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16888            return;
16889        }
16890        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16891        self.display_map.update(cx, |display_map, cx| {
16892            display_map.fold_buffers([buffer_id], cx)
16893        });
16894        cx.emit(EditorEvent::BufferFoldToggled {
16895            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16896            folded: true,
16897        });
16898        cx.notify();
16899    }
16900
16901    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16902        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16903            return;
16904        }
16905        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16906        self.display_map.update(cx, |display_map, cx| {
16907            display_map.unfold_buffers([buffer_id], cx);
16908        });
16909        cx.emit(EditorEvent::BufferFoldToggled {
16910            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16911            folded: false,
16912        });
16913        cx.notify();
16914    }
16915
16916    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16917        self.display_map.read(cx).is_buffer_folded(buffer)
16918    }
16919
16920    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16921        self.display_map.read(cx).folded_buffers()
16922    }
16923
16924    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16925        self.display_map.update(cx, |display_map, cx| {
16926            display_map.disable_header_for_buffer(buffer_id, cx);
16927        });
16928        cx.notify();
16929    }
16930
16931    /// Removes any folds with the given ranges.
16932    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16933        &mut self,
16934        ranges: &[Range<T>],
16935        type_id: TypeId,
16936        auto_scroll: bool,
16937        cx: &mut Context<Self>,
16938    ) {
16939        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16940            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16941        });
16942        self.folds_did_change(cx);
16943    }
16944
16945    fn remove_folds_with<T: ToOffset + Clone>(
16946        &mut self,
16947        ranges: &[Range<T>],
16948        auto_scroll: bool,
16949        cx: &mut Context<Self>,
16950        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16951    ) {
16952        if ranges.is_empty() {
16953            return;
16954        }
16955
16956        let mut buffers_affected = HashSet::default();
16957        let multi_buffer = self.buffer().read(cx);
16958        for range in ranges {
16959            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16960                buffers_affected.insert(buffer.read(cx).remote_id());
16961            };
16962        }
16963
16964        self.display_map.update(cx, update);
16965
16966        if auto_scroll {
16967            self.request_autoscroll(Autoscroll::fit(), cx);
16968        }
16969
16970        cx.notify();
16971        self.scrollbar_marker_state.dirty = true;
16972        self.active_indent_guides_state.dirty = true;
16973    }
16974
16975    pub fn update_fold_widths(
16976        &mut self,
16977        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16978        cx: &mut Context<Self>,
16979    ) -> bool {
16980        self.display_map
16981            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16982    }
16983
16984    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16985        self.display_map.read(cx).fold_placeholder.clone()
16986    }
16987
16988    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16989        self.buffer.update(cx, |buffer, cx| {
16990            buffer.set_all_diff_hunks_expanded(cx);
16991        });
16992    }
16993
16994    pub fn expand_all_diff_hunks(
16995        &mut self,
16996        _: &ExpandAllDiffHunks,
16997        _window: &mut Window,
16998        cx: &mut Context<Self>,
16999    ) {
17000        self.buffer.update(cx, |buffer, cx| {
17001            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17002        });
17003    }
17004
17005    pub fn toggle_selected_diff_hunks(
17006        &mut self,
17007        _: &ToggleSelectedDiffHunks,
17008        _window: &mut Window,
17009        cx: &mut Context<Self>,
17010    ) {
17011        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17012        self.toggle_diff_hunks_in_ranges(ranges, cx);
17013    }
17014
17015    pub fn diff_hunks_in_ranges<'a>(
17016        &'a self,
17017        ranges: &'a [Range<Anchor>],
17018        buffer: &'a MultiBufferSnapshot,
17019    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17020        ranges.iter().flat_map(move |range| {
17021            let end_excerpt_id = range.end.excerpt_id;
17022            let range = range.to_point(buffer);
17023            let mut peek_end = range.end;
17024            if range.end.row < buffer.max_row().0 {
17025                peek_end = Point::new(range.end.row + 1, 0);
17026            }
17027            buffer
17028                .diff_hunks_in_range(range.start..peek_end)
17029                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17030        })
17031    }
17032
17033    pub fn has_stageable_diff_hunks_in_ranges(
17034        &self,
17035        ranges: &[Range<Anchor>],
17036        snapshot: &MultiBufferSnapshot,
17037    ) -> bool {
17038        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17039        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17040    }
17041
17042    pub fn toggle_staged_selected_diff_hunks(
17043        &mut self,
17044        _: &::git::ToggleStaged,
17045        _: &mut Window,
17046        cx: &mut Context<Self>,
17047    ) {
17048        let snapshot = self.buffer.read(cx).snapshot(cx);
17049        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17050        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17051        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17052    }
17053
17054    pub fn set_render_diff_hunk_controls(
17055        &mut self,
17056        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17057        cx: &mut Context<Self>,
17058    ) {
17059        self.render_diff_hunk_controls = render_diff_hunk_controls;
17060        cx.notify();
17061    }
17062
17063    pub fn stage_and_next(
17064        &mut self,
17065        _: &::git::StageAndNext,
17066        window: &mut Window,
17067        cx: &mut Context<Self>,
17068    ) {
17069        self.do_stage_or_unstage_and_next(true, window, cx);
17070    }
17071
17072    pub fn unstage_and_next(
17073        &mut self,
17074        _: &::git::UnstageAndNext,
17075        window: &mut Window,
17076        cx: &mut Context<Self>,
17077    ) {
17078        self.do_stage_or_unstage_and_next(false, window, cx);
17079    }
17080
17081    pub fn stage_or_unstage_diff_hunks(
17082        &mut self,
17083        stage: bool,
17084        ranges: Vec<Range<Anchor>>,
17085        cx: &mut Context<Self>,
17086    ) {
17087        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17088        cx.spawn(async move |this, cx| {
17089            task.await?;
17090            this.update(cx, |this, cx| {
17091                let snapshot = this.buffer.read(cx).snapshot(cx);
17092                let chunk_by = this
17093                    .diff_hunks_in_ranges(&ranges, &snapshot)
17094                    .chunk_by(|hunk| hunk.buffer_id);
17095                for (buffer_id, hunks) in &chunk_by {
17096                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17097                }
17098            })
17099        })
17100        .detach_and_log_err(cx);
17101    }
17102
17103    fn save_buffers_for_ranges_if_needed(
17104        &mut self,
17105        ranges: &[Range<Anchor>],
17106        cx: &mut Context<Editor>,
17107    ) -> Task<Result<()>> {
17108        let multibuffer = self.buffer.read(cx);
17109        let snapshot = multibuffer.read(cx);
17110        let buffer_ids: HashSet<_> = ranges
17111            .iter()
17112            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17113            .collect();
17114        drop(snapshot);
17115
17116        let mut buffers = HashSet::default();
17117        for buffer_id in buffer_ids {
17118            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17119                let buffer = buffer_entity.read(cx);
17120                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17121                {
17122                    buffers.insert(buffer_entity);
17123                }
17124            }
17125        }
17126
17127        if let Some(project) = &self.project {
17128            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17129        } else {
17130            Task::ready(Ok(()))
17131        }
17132    }
17133
17134    fn do_stage_or_unstage_and_next(
17135        &mut self,
17136        stage: bool,
17137        window: &mut Window,
17138        cx: &mut Context<Self>,
17139    ) {
17140        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17141
17142        if ranges.iter().any(|range| range.start != range.end) {
17143            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17144            return;
17145        }
17146
17147        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17148        let snapshot = self.snapshot(window, cx);
17149        let position = self.selections.newest::<Point>(cx).head();
17150        let mut row = snapshot
17151            .buffer_snapshot
17152            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17153            .find(|hunk| hunk.row_range.start.0 > position.row)
17154            .map(|hunk| hunk.row_range.start);
17155
17156        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17157        // Outside of the project diff editor, wrap around to the beginning.
17158        if !all_diff_hunks_expanded {
17159            row = row.or_else(|| {
17160                snapshot
17161                    .buffer_snapshot
17162                    .diff_hunks_in_range(Point::zero()..position)
17163                    .find(|hunk| hunk.row_range.end.0 < position.row)
17164                    .map(|hunk| hunk.row_range.start)
17165            });
17166        }
17167
17168        if let Some(row) = row {
17169            let destination = Point::new(row.0, 0);
17170            let autoscroll = Autoscroll::center();
17171
17172            self.unfold_ranges(&[destination..destination], false, false, cx);
17173            self.change_selections(Some(autoscroll), window, cx, |s| {
17174                s.select_ranges([destination..destination]);
17175            });
17176        }
17177    }
17178
17179    fn do_stage_or_unstage(
17180        &self,
17181        stage: bool,
17182        buffer_id: BufferId,
17183        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17184        cx: &mut App,
17185    ) -> Option<()> {
17186        let project = self.project.as_ref()?;
17187        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17188        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17189        let buffer_snapshot = buffer.read(cx).snapshot();
17190        let file_exists = buffer_snapshot
17191            .file()
17192            .is_some_and(|file| file.disk_state().exists());
17193        diff.update(cx, |diff, cx| {
17194            diff.stage_or_unstage_hunks(
17195                stage,
17196                &hunks
17197                    .map(|hunk| buffer_diff::DiffHunk {
17198                        buffer_range: hunk.buffer_range,
17199                        diff_base_byte_range: hunk.diff_base_byte_range,
17200                        secondary_status: hunk.secondary_status,
17201                        range: Point::zero()..Point::zero(), // unused
17202                    })
17203                    .collect::<Vec<_>>(),
17204                &buffer_snapshot,
17205                file_exists,
17206                cx,
17207            )
17208        });
17209        None
17210    }
17211
17212    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17213        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17214        self.buffer
17215            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17216    }
17217
17218    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17219        self.buffer.update(cx, |buffer, cx| {
17220            let ranges = vec![Anchor::min()..Anchor::max()];
17221            if !buffer.all_diff_hunks_expanded()
17222                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17223            {
17224                buffer.collapse_diff_hunks(ranges, cx);
17225                true
17226            } else {
17227                false
17228            }
17229        })
17230    }
17231
17232    fn toggle_diff_hunks_in_ranges(
17233        &mut self,
17234        ranges: Vec<Range<Anchor>>,
17235        cx: &mut Context<Editor>,
17236    ) {
17237        self.buffer.update(cx, |buffer, cx| {
17238            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17239            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17240        })
17241    }
17242
17243    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17244        self.buffer.update(cx, |buffer, cx| {
17245            let snapshot = buffer.snapshot(cx);
17246            let excerpt_id = range.end.excerpt_id;
17247            let point_range = range.to_point(&snapshot);
17248            let expand = !buffer.single_hunk_is_expanded(range, cx);
17249            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17250        })
17251    }
17252
17253    pub(crate) fn apply_all_diff_hunks(
17254        &mut self,
17255        _: &ApplyAllDiffHunks,
17256        window: &mut Window,
17257        cx: &mut Context<Self>,
17258    ) {
17259        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17260
17261        let buffers = self.buffer.read(cx).all_buffers();
17262        for branch_buffer in buffers {
17263            branch_buffer.update(cx, |branch_buffer, cx| {
17264                branch_buffer.merge_into_base(Vec::new(), cx);
17265            });
17266        }
17267
17268        if let Some(project) = self.project.clone() {
17269            self.save(
17270                SaveOptions {
17271                    format: true,
17272                    autosave: false,
17273                },
17274                project,
17275                window,
17276                cx,
17277            )
17278            .detach_and_log_err(cx);
17279        }
17280    }
17281
17282    pub(crate) fn apply_selected_diff_hunks(
17283        &mut self,
17284        _: &ApplyDiffHunk,
17285        window: &mut Window,
17286        cx: &mut Context<Self>,
17287    ) {
17288        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17289        let snapshot = self.snapshot(window, cx);
17290        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17291        let mut ranges_by_buffer = HashMap::default();
17292        self.transact(window, cx, |editor, _window, cx| {
17293            for hunk in hunks {
17294                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17295                    ranges_by_buffer
17296                        .entry(buffer.clone())
17297                        .or_insert_with(Vec::new)
17298                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17299                }
17300            }
17301
17302            for (buffer, ranges) in ranges_by_buffer {
17303                buffer.update(cx, |buffer, cx| {
17304                    buffer.merge_into_base(ranges, cx);
17305                });
17306            }
17307        });
17308
17309        if let Some(project) = self.project.clone() {
17310            self.save(
17311                SaveOptions {
17312                    format: true,
17313                    autosave: false,
17314                },
17315                project,
17316                window,
17317                cx,
17318            )
17319            .detach_and_log_err(cx);
17320        }
17321    }
17322
17323    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17324        if hovered != self.gutter_hovered {
17325            self.gutter_hovered = hovered;
17326            cx.notify();
17327        }
17328    }
17329
17330    pub fn insert_blocks(
17331        &mut self,
17332        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17333        autoscroll: Option<Autoscroll>,
17334        cx: &mut Context<Self>,
17335    ) -> Vec<CustomBlockId> {
17336        let blocks = self
17337            .display_map
17338            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17339        if let Some(autoscroll) = autoscroll {
17340            self.request_autoscroll(autoscroll, cx);
17341        }
17342        cx.notify();
17343        blocks
17344    }
17345
17346    pub fn resize_blocks(
17347        &mut self,
17348        heights: HashMap<CustomBlockId, u32>,
17349        autoscroll: Option<Autoscroll>,
17350        cx: &mut Context<Self>,
17351    ) {
17352        self.display_map
17353            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17354        if let Some(autoscroll) = autoscroll {
17355            self.request_autoscroll(autoscroll, cx);
17356        }
17357        cx.notify();
17358    }
17359
17360    pub fn replace_blocks(
17361        &mut self,
17362        renderers: HashMap<CustomBlockId, RenderBlock>,
17363        autoscroll: Option<Autoscroll>,
17364        cx: &mut Context<Self>,
17365    ) {
17366        self.display_map
17367            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17368        if let Some(autoscroll) = autoscroll {
17369            self.request_autoscroll(autoscroll, cx);
17370        }
17371        cx.notify();
17372    }
17373
17374    pub fn remove_blocks(
17375        &mut self,
17376        block_ids: HashSet<CustomBlockId>,
17377        autoscroll: Option<Autoscroll>,
17378        cx: &mut Context<Self>,
17379    ) {
17380        self.display_map.update(cx, |display_map, cx| {
17381            display_map.remove_blocks(block_ids, cx)
17382        });
17383        if let Some(autoscroll) = autoscroll {
17384            self.request_autoscroll(autoscroll, cx);
17385        }
17386        cx.notify();
17387    }
17388
17389    pub fn row_for_block(
17390        &self,
17391        block_id: CustomBlockId,
17392        cx: &mut Context<Self>,
17393    ) -> Option<DisplayRow> {
17394        self.display_map
17395            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17396    }
17397
17398    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17399        self.focused_block = Some(focused_block);
17400    }
17401
17402    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17403        self.focused_block.take()
17404    }
17405
17406    pub fn insert_creases(
17407        &mut self,
17408        creases: impl IntoIterator<Item = Crease<Anchor>>,
17409        cx: &mut Context<Self>,
17410    ) -> Vec<CreaseId> {
17411        self.display_map
17412            .update(cx, |map, cx| map.insert_creases(creases, cx))
17413    }
17414
17415    pub fn remove_creases(
17416        &mut self,
17417        ids: impl IntoIterator<Item = CreaseId>,
17418        cx: &mut Context<Self>,
17419    ) -> Vec<(CreaseId, Range<Anchor>)> {
17420        self.display_map
17421            .update(cx, |map, cx| map.remove_creases(ids, cx))
17422    }
17423
17424    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17425        self.display_map
17426            .update(cx, |map, cx| map.snapshot(cx))
17427            .longest_row()
17428    }
17429
17430    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17431        self.display_map
17432            .update(cx, |map, cx| map.snapshot(cx))
17433            .max_point()
17434    }
17435
17436    pub fn text(&self, cx: &App) -> String {
17437        self.buffer.read(cx).read(cx).text()
17438    }
17439
17440    pub fn is_empty(&self, cx: &App) -> bool {
17441        self.buffer.read(cx).read(cx).is_empty()
17442    }
17443
17444    pub fn text_option(&self, cx: &App) -> Option<String> {
17445        let text = self.text(cx);
17446        let text = text.trim();
17447
17448        if text.is_empty() {
17449            return None;
17450        }
17451
17452        Some(text.to_string())
17453    }
17454
17455    pub fn set_text(
17456        &mut self,
17457        text: impl Into<Arc<str>>,
17458        window: &mut Window,
17459        cx: &mut Context<Self>,
17460    ) {
17461        self.transact(window, cx, |this, _, cx| {
17462            this.buffer
17463                .read(cx)
17464                .as_singleton()
17465                .expect("you can only call set_text on editors for singleton buffers")
17466                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17467        });
17468    }
17469
17470    pub fn display_text(&self, cx: &mut App) -> String {
17471        self.display_map
17472            .update(cx, |map, cx| map.snapshot(cx))
17473            .text()
17474    }
17475
17476    fn create_minimap(
17477        &self,
17478        minimap_settings: MinimapSettings,
17479        window: &mut Window,
17480        cx: &mut Context<Self>,
17481    ) -> Option<Entity<Self>> {
17482        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17483            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17484    }
17485
17486    fn initialize_new_minimap(
17487        &self,
17488        minimap_settings: MinimapSettings,
17489        window: &mut Window,
17490        cx: &mut Context<Self>,
17491    ) -> Entity<Self> {
17492        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17493
17494        let mut minimap = Editor::new_internal(
17495            EditorMode::Minimap {
17496                parent: cx.weak_entity(),
17497            },
17498            self.buffer.clone(),
17499            self.project.clone(),
17500            Some(self.display_map.clone()),
17501            window,
17502            cx,
17503        );
17504        minimap.scroll_manager.clone_state(&self.scroll_manager);
17505        minimap.set_text_style_refinement(TextStyleRefinement {
17506            font_size: Some(MINIMAP_FONT_SIZE),
17507            font_weight: Some(MINIMAP_FONT_WEIGHT),
17508            ..Default::default()
17509        });
17510        minimap.update_minimap_configuration(minimap_settings, cx);
17511        cx.new(|_| minimap)
17512    }
17513
17514    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17515        let current_line_highlight = minimap_settings
17516            .current_line_highlight
17517            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17518        self.set_current_line_highlight(Some(current_line_highlight));
17519    }
17520
17521    pub fn minimap(&self) -> Option<&Entity<Self>> {
17522        self.minimap
17523            .as_ref()
17524            .filter(|_| self.minimap_visibility.visible())
17525    }
17526
17527    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17528        let mut wrap_guides = smallvec![];
17529
17530        if self.show_wrap_guides == Some(false) {
17531            return wrap_guides;
17532        }
17533
17534        let settings = self.buffer.read(cx).language_settings(cx);
17535        if settings.show_wrap_guides {
17536            match self.soft_wrap_mode(cx) {
17537                SoftWrap::Column(soft_wrap) => {
17538                    wrap_guides.push((soft_wrap as usize, true));
17539                }
17540                SoftWrap::Bounded(soft_wrap) => {
17541                    wrap_guides.push((soft_wrap as usize, true));
17542                }
17543                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17544            }
17545            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17546        }
17547
17548        wrap_guides
17549    }
17550
17551    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17552        let settings = self.buffer.read(cx).language_settings(cx);
17553        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17554        match mode {
17555            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17556                SoftWrap::None
17557            }
17558            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17559            language_settings::SoftWrap::PreferredLineLength => {
17560                SoftWrap::Column(settings.preferred_line_length)
17561            }
17562            language_settings::SoftWrap::Bounded => {
17563                SoftWrap::Bounded(settings.preferred_line_length)
17564            }
17565        }
17566    }
17567
17568    pub fn set_soft_wrap_mode(
17569        &mut self,
17570        mode: language_settings::SoftWrap,
17571
17572        cx: &mut Context<Self>,
17573    ) {
17574        self.soft_wrap_mode_override = Some(mode);
17575        cx.notify();
17576    }
17577
17578    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17579        self.hard_wrap = hard_wrap;
17580        cx.notify();
17581    }
17582
17583    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17584        self.text_style_refinement = Some(style);
17585    }
17586
17587    /// called by the Element so we know what style we were most recently rendered with.
17588    pub(crate) fn set_style(
17589        &mut self,
17590        style: EditorStyle,
17591        window: &mut Window,
17592        cx: &mut Context<Self>,
17593    ) {
17594        // We intentionally do not inform the display map about the minimap style
17595        // so that wrapping is not recalculated and stays consistent for the editor
17596        // and its linked minimap.
17597        if !self.mode.is_minimap() {
17598            let rem_size = window.rem_size();
17599            self.display_map.update(cx, |map, cx| {
17600                map.set_font(
17601                    style.text.font(),
17602                    style.text.font_size.to_pixels(rem_size),
17603                    cx,
17604                )
17605            });
17606        }
17607        self.style = Some(style);
17608    }
17609
17610    pub fn style(&self) -> Option<&EditorStyle> {
17611        self.style.as_ref()
17612    }
17613
17614    // Called by the element. This method is not designed to be called outside of the editor
17615    // element's layout code because it does not notify when rewrapping is computed synchronously.
17616    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17617        self.display_map
17618            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17619    }
17620
17621    pub fn set_soft_wrap(&mut self) {
17622        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17623    }
17624
17625    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17626        if self.soft_wrap_mode_override.is_some() {
17627            self.soft_wrap_mode_override.take();
17628        } else {
17629            let soft_wrap = match self.soft_wrap_mode(cx) {
17630                SoftWrap::GitDiff => return,
17631                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17632                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17633                    language_settings::SoftWrap::None
17634                }
17635            };
17636            self.soft_wrap_mode_override = Some(soft_wrap);
17637        }
17638        cx.notify();
17639    }
17640
17641    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17642        let Some(workspace) = self.workspace() else {
17643            return;
17644        };
17645        let fs = workspace.read(cx).app_state().fs.clone();
17646        let current_show = TabBarSettings::get_global(cx).show;
17647        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17648            setting.show = Some(!current_show);
17649        });
17650    }
17651
17652    pub fn toggle_indent_guides(
17653        &mut self,
17654        _: &ToggleIndentGuides,
17655        _: &mut Window,
17656        cx: &mut Context<Self>,
17657    ) {
17658        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17659            self.buffer
17660                .read(cx)
17661                .language_settings(cx)
17662                .indent_guides
17663                .enabled
17664        });
17665        self.show_indent_guides = Some(!currently_enabled);
17666        cx.notify();
17667    }
17668
17669    fn should_show_indent_guides(&self) -> Option<bool> {
17670        self.show_indent_guides
17671    }
17672
17673    pub fn toggle_line_numbers(
17674        &mut self,
17675        _: &ToggleLineNumbers,
17676        _: &mut Window,
17677        cx: &mut Context<Self>,
17678    ) {
17679        let mut editor_settings = EditorSettings::get_global(cx).clone();
17680        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17681        EditorSettings::override_global(editor_settings, cx);
17682    }
17683
17684    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17685        if let Some(show_line_numbers) = self.show_line_numbers {
17686            return show_line_numbers;
17687        }
17688        EditorSettings::get_global(cx).gutter.line_numbers
17689    }
17690
17691    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17692        self.use_relative_line_numbers
17693            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17694    }
17695
17696    pub fn toggle_relative_line_numbers(
17697        &mut self,
17698        _: &ToggleRelativeLineNumbers,
17699        _: &mut Window,
17700        cx: &mut Context<Self>,
17701    ) {
17702        let is_relative = self.should_use_relative_line_numbers(cx);
17703        self.set_relative_line_number(Some(!is_relative), cx)
17704    }
17705
17706    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17707        self.use_relative_line_numbers = is_relative;
17708        cx.notify();
17709    }
17710
17711    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17712        self.show_gutter = show_gutter;
17713        cx.notify();
17714    }
17715
17716    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17717        self.show_scrollbars = ScrollbarAxes {
17718            horizontal: show,
17719            vertical: show,
17720        };
17721        cx.notify();
17722    }
17723
17724    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17725        self.show_scrollbars.vertical = show;
17726        cx.notify();
17727    }
17728
17729    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17730        self.show_scrollbars.horizontal = show;
17731        cx.notify();
17732    }
17733
17734    pub fn set_minimap_visibility(
17735        &mut self,
17736        minimap_visibility: MinimapVisibility,
17737        window: &mut Window,
17738        cx: &mut Context<Self>,
17739    ) {
17740        if self.minimap_visibility != minimap_visibility {
17741            if minimap_visibility.visible() && self.minimap.is_none() {
17742                let minimap_settings = EditorSettings::get_global(cx).minimap;
17743                self.minimap =
17744                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17745            }
17746            self.minimap_visibility = minimap_visibility;
17747            cx.notify();
17748        }
17749    }
17750
17751    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17752        self.set_show_scrollbars(false, cx);
17753        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17754    }
17755
17756    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17757        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17758    }
17759
17760    /// Normally the text in full mode and auto height editors is padded on the
17761    /// left side by roughly half a character width for improved hit testing.
17762    ///
17763    /// Use this method to disable this for cases where this is not wanted (e.g.
17764    /// if you want to align the editor text with some other text above or below)
17765    /// or if you want to add this padding to single-line editors.
17766    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17767        self.offset_content = offset_content;
17768        cx.notify();
17769    }
17770
17771    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17772        self.show_line_numbers = Some(show_line_numbers);
17773        cx.notify();
17774    }
17775
17776    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17777        self.disable_expand_excerpt_buttons = true;
17778        cx.notify();
17779    }
17780
17781    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17782        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17783        cx.notify();
17784    }
17785
17786    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17787        self.show_code_actions = Some(show_code_actions);
17788        cx.notify();
17789    }
17790
17791    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17792        self.show_runnables = Some(show_runnables);
17793        cx.notify();
17794    }
17795
17796    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17797        self.show_breakpoints = Some(show_breakpoints);
17798        cx.notify();
17799    }
17800
17801    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17802        if self.display_map.read(cx).masked != masked {
17803            self.display_map.update(cx, |map, _| map.masked = masked);
17804        }
17805        cx.notify()
17806    }
17807
17808    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17809        self.show_wrap_guides = Some(show_wrap_guides);
17810        cx.notify();
17811    }
17812
17813    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17814        self.show_indent_guides = Some(show_indent_guides);
17815        cx.notify();
17816    }
17817
17818    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17819        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17820            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17821                if let Some(dir) = file.abs_path(cx).parent() {
17822                    return Some(dir.to_owned());
17823                }
17824            }
17825
17826            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17827                return Some(project_path.path.to_path_buf());
17828            }
17829        }
17830
17831        None
17832    }
17833
17834    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17835        self.active_excerpt(cx)?
17836            .1
17837            .read(cx)
17838            .file()
17839            .and_then(|f| f.as_local())
17840    }
17841
17842    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17843        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17844            let buffer = buffer.read(cx);
17845            if let Some(project_path) = buffer.project_path(cx) {
17846                let project = self.project.as_ref()?.read(cx);
17847                project.absolute_path(&project_path, cx)
17848            } else {
17849                buffer
17850                    .file()
17851                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17852            }
17853        })
17854    }
17855
17856    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17857        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17858            let project_path = buffer.read(cx).project_path(cx)?;
17859            let project = self.project.as_ref()?.read(cx);
17860            let entry = project.entry_for_path(&project_path, cx)?;
17861            let path = entry.path.to_path_buf();
17862            Some(path)
17863        })
17864    }
17865
17866    pub fn reveal_in_finder(
17867        &mut self,
17868        _: &RevealInFileManager,
17869        _window: &mut Window,
17870        cx: &mut Context<Self>,
17871    ) {
17872        if let Some(target) = self.target_file(cx) {
17873            cx.reveal_path(&target.abs_path(cx));
17874        }
17875    }
17876
17877    pub fn copy_path(
17878        &mut self,
17879        _: &zed_actions::workspace::CopyPath,
17880        _window: &mut Window,
17881        cx: &mut Context<Self>,
17882    ) {
17883        if let Some(path) = self.target_file_abs_path(cx) {
17884            if let Some(path) = path.to_str() {
17885                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17886            }
17887        }
17888    }
17889
17890    pub fn copy_relative_path(
17891        &mut self,
17892        _: &zed_actions::workspace::CopyRelativePath,
17893        _window: &mut Window,
17894        cx: &mut Context<Self>,
17895    ) {
17896        if let Some(path) = self.target_file_path(cx) {
17897            if let Some(path) = path.to_str() {
17898                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17899            }
17900        }
17901    }
17902
17903    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17904        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17905            buffer.read(cx).project_path(cx)
17906        } else {
17907            None
17908        }
17909    }
17910
17911    // Returns true if the editor handled a go-to-line request
17912    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17913        maybe!({
17914            let breakpoint_store = self.breakpoint_store.as_ref()?;
17915
17916            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17917            else {
17918                self.clear_row_highlights::<ActiveDebugLine>();
17919                return None;
17920            };
17921
17922            let position = active_stack_frame.position;
17923            let buffer_id = position.buffer_id?;
17924            let snapshot = self
17925                .project
17926                .as_ref()?
17927                .read(cx)
17928                .buffer_for_id(buffer_id, cx)?
17929                .read(cx)
17930                .snapshot();
17931
17932            let mut handled = false;
17933            for (id, ExcerptRange { context, .. }) in
17934                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17935            {
17936                if context.start.cmp(&position, &snapshot).is_ge()
17937                    || context.end.cmp(&position, &snapshot).is_lt()
17938                {
17939                    continue;
17940                }
17941                let snapshot = self.buffer.read(cx).snapshot(cx);
17942                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17943
17944                handled = true;
17945                self.clear_row_highlights::<ActiveDebugLine>();
17946
17947                self.go_to_line::<ActiveDebugLine>(
17948                    multibuffer_anchor,
17949                    Some(cx.theme().colors().editor_debugger_active_line_background),
17950                    window,
17951                    cx,
17952                );
17953
17954                cx.notify();
17955            }
17956
17957            handled.then_some(())
17958        })
17959        .is_some()
17960    }
17961
17962    pub fn copy_file_name_without_extension(
17963        &mut self,
17964        _: &CopyFileNameWithoutExtension,
17965        _: &mut Window,
17966        cx: &mut Context<Self>,
17967    ) {
17968        if let Some(file) = self.target_file(cx) {
17969            if let Some(file_stem) = file.path().file_stem() {
17970                if let Some(name) = file_stem.to_str() {
17971                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17972                }
17973            }
17974        }
17975    }
17976
17977    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17978        if let Some(file) = self.target_file(cx) {
17979            if let Some(file_name) = file.path().file_name() {
17980                if let Some(name) = file_name.to_str() {
17981                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17982                }
17983            }
17984        }
17985    }
17986
17987    pub fn toggle_git_blame(
17988        &mut self,
17989        _: &::git::Blame,
17990        window: &mut Window,
17991        cx: &mut Context<Self>,
17992    ) {
17993        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17994
17995        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17996            self.start_git_blame(true, window, cx);
17997        }
17998
17999        cx.notify();
18000    }
18001
18002    pub fn toggle_git_blame_inline(
18003        &mut self,
18004        _: &ToggleGitBlameInline,
18005        window: &mut Window,
18006        cx: &mut Context<Self>,
18007    ) {
18008        self.toggle_git_blame_inline_internal(true, window, cx);
18009        cx.notify();
18010    }
18011
18012    pub fn open_git_blame_commit(
18013        &mut self,
18014        _: &OpenGitBlameCommit,
18015        window: &mut Window,
18016        cx: &mut Context<Self>,
18017    ) {
18018        self.open_git_blame_commit_internal(window, cx);
18019    }
18020
18021    fn open_git_blame_commit_internal(
18022        &mut self,
18023        window: &mut Window,
18024        cx: &mut Context<Self>,
18025    ) -> Option<()> {
18026        let blame = self.blame.as_ref()?;
18027        let snapshot = self.snapshot(window, cx);
18028        let cursor = self.selections.newest::<Point>(cx).head();
18029        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18030        let blame_entry = blame
18031            .update(cx, |blame, cx| {
18032                blame
18033                    .blame_for_rows(
18034                        &[RowInfo {
18035                            buffer_id: Some(buffer.remote_id()),
18036                            buffer_row: Some(point.row),
18037                            ..Default::default()
18038                        }],
18039                        cx,
18040                    )
18041                    .next()
18042            })
18043            .flatten()?;
18044        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18045        let repo = blame.read(cx).repository(cx)?;
18046        let workspace = self.workspace()?.downgrade();
18047        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18048        None
18049    }
18050
18051    pub fn git_blame_inline_enabled(&self) -> bool {
18052        self.git_blame_inline_enabled
18053    }
18054
18055    pub fn toggle_selection_menu(
18056        &mut self,
18057        _: &ToggleSelectionMenu,
18058        _: &mut Window,
18059        cx: &mut Context<Self>,
18060    ) {
18061        self.show_selection_menu = self
18062            .show_selection_menu
18063            .map(|show_selections_menu| !show_selections_menu)
18064            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18065
18066        cx.notify();
18067    }
18068
18069    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18070        self.show_selection_menu
18071            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18072    }
18073
18074    fn start_git_blame(
18075        &mut self,
18076        user_triggered: bool,
18077        window: &mut Window,
18078        cx: &mut Context<Self>,
18079    ) {
18080        if let Some(project) = self.project.as_ref() {
18081            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18082                return;
18083            };
18084
18085            if buffer.read(cx).file().is_none() {
18086                return;
18087            }
18088
18089            let focused = self.focus_handle(cx).contains_focused(window, cx);
18090
18091            let project = project.clone();
18092            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18093            self.blame_subscription =
18094                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18095            self.blame = Some(blame);
18096        }
18097    }
18098
18099    fn toggle_git_blame_inline_internal(
18100        &mut self,
18101        user_triggered: bool,
18102        window: &mut Window,
18103        cx: &mut Context<Self>,
18104    ) {
18105        if self.git_blame_inline_enabled {
18106            self.git_blame_inline_enabled = false;
18107            self.show_git_blame_inline = false;
18108            self.show_git_blame_inline_delay_task.take();
18109        } else {
18110            self.git_blame_inline_enabled = true;
18111            self.start_git_blame_inline(user_triggered, window, cx);
18112        }
18113
18114        cx.notify();
18115    }
18116
18117    fn start_git_blame_inline(
18118        &mut self,
18119        user_triggered: bool,
18120        window: &mut Window,
18121        cx: &mut Context<Self>,
18122    ) {
18123        self.start_git_blame(user_triggered, window, cx);
18124
18125        if ProjectSettings::get_global(cx)
18126            .git
18127            .inline_blame_delay()
18128            .is_some()
18129        {
18130            self.start_inline_blame_timer(window, cx);
18131        } else {
18132            self.show_git_blame_inline = true
18133        }
18134    }
18135
18136    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18137        self.blame.as_ref()
18138    }
18139
18140    pub fn show_git_blame_gutter(&self) -> bool {
18141        self.show_git_blame_gutter
18142    }
18143
18144    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18145        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18146    }
18147
18148    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18149        self.show_git_blame_inline
18150            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18151            && !self.newest_selection_head_on_empty_line(cx)
18152            && self.has_blame_entries(cx)
18153    }
18154
18155    fn has_blame_entries(&self, cx: &App) -> bool {
18156        self.blame()
18157            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18158    }
18159
18160    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18161        let cursor_anchor = self.selections.newest_anchor().head();
18162
18163        let snapshot = self.buffer.read(cx).snapshot(cx);
18164        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18165
18166        snapshot.line_len(buffer_row) == 0
18167    }
18168
18169    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18170        let buffer_and_selection = maybe!({
18171            let selection = self.selections.newest::<Point>(cx);
18172            let selection_range = selection.range();
18173
18174            let multi_buffer = self.buffer().read(cx);
18175            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18176            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18177
18178            let (buffer, range, _) = if selection.reversed {
18179                buffer_ranges.first()
18180            } else {
18181                buffer_ranges.last()
18182            }?;
18183
18184            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18185                ..text::ToPoint::to_point(&range.end, &buffer).row;
18186            Some((
18187                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18188                selection,
18189            ))
18190        });
18191
18192        let Some((buffer, selection)) = buffer_and_selection else {
18193            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18194        };
18195
18196        let Some(project) = self.project.as_ref() else {
18197            return Task::ready(Err(anyhow!("editor does not have project")));
18198        };
18199
18200        project.update(cx, |project, cx| {
18201            project.get_permalink_to_line(&buffer, selection, cx)
18202        })
18203    }
18204
18205    pub fn copy_permalink_to_line(
18206        &mut self,
18207        _: &CopyPermalinkToLine,
18208        window: &mut Window,
18209        cx: &mut Context<Self>,
18210    ) {
18211        let permalink_task = self.get_permalink_to_line(cx);
18212        let workspace = self.workspace();
18213
18214        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18215            Ok(permalink) => {
18216                cx.update(|_, cx| {
18217                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18218                })
18219                .ok();
18220            }
18221            Err(err) => {
18222                let message = format!("Failed to copy permalink: {err}");
18223
18224                anyhow::Result::<()>::Err(err).log_err();
18225
18226                if let Some(workspace) = workspace {
18227                    workspace
18228                        .update_in(cx, |workspace, _, cx| {
18229                            struct CopyPermalinkToLine;
18230
18231                            workspace.show_toast(
18232                                Toast::new(
18233                                    NotificationId::unique::<CopyPermalinkToLine>(),
18234                                    message,
18235                                ),
18236                                cx,
18237                            )
18238                        })
18239                        .ok();
18240                }
18241            }
18242        })
18243        .detach();
18244    }
18245
18246    pub fn copy_file_location(
18247        &mut self,
18248        _: &CopyFileLocation,
18249        _: &mut Window,
18250        cx: &mut Context<Self>,
18251    ) {
18252        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18253        if let Some(file) = self.target_file(cx) {
18254            if let Some(path) = file.path().to_str() {
18255                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18256            }
18257        }
18258    }
18259
18260    pub fn open_permalink_to_line(
18261        &mut self,
18262        _: &OpenPermalinkToLine,
18263        window: &mut Window,
18264        cx: &mut Context<Self>,
18265    ) {
18266        let permalink_task = self.get_permalink_to_line(cx);
18267        let workspace = self.workspace();
18268
18269        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18270            Ok(permalink) => {
18271                cx.update(|_, cx| {
18272                    cx.open_url(permalink.as_ref());
18273                })
18274                .ok();
18275            }
18276            Err(err) => {
18277                let message = format!("Failed to open permalink: {err}");
18278
18279                anyhow::Result::<()>::Err(err).log_err();
18280
18281                if let Some(workspace) = workspace {
18282                    workspace
18283                        .update(cx, |workspace, cx| {
18284                            struct OpenPermalinkToLine;
18285
18286                            workspace.show_toast(
18287                                Toast::new(
18288                                    NotificationId::unique::<OpenPermalinkToLine>(),
18289                                    message,
18290                                ),
18291                                cx,
18292                            )
18293                        })
18294                        .ok();
18295                }
18296            }
18297        })
18298        .detach();
18299    }
18300
18301    pub fn insert_uuid_v4(
18302        &mut self,
18303        _: &InsertUuidV4,
18304        window: &mut Window,
18305        cx: &mut Context<Self>,
18306    ) {
18307        self.insert_uuid(UuidVersion::V4, window, cx);
18308    }
18309
18310    pub fn insert_uuid_v7(
18311        &mut self,
18312        _: &InsertUuidV7,
18313        window: &mut Window,
18314        cx: &mut Context<Self>,
18315    ) {
18316        self.insert_uuid(UuidVersion::V7, window, cx);
18317    }
18318
18319    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18321        self.transact(window, cx, |this, window, cx| {
18322            let edits = this
18323                .selections
18324                .all::<Point>(cx)
18325                .into_iter()
18326                .map(|selection| {
18327                    let uuid = match version {
18328                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18329                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18330                    };
18331
18332                    (selection.range(), uuid.to_string())
18333                });
18334            this.edit(edits, cx);
18335            this.refresh_inline_completion(true, false, window, cx);
18336        });
18337    }
18338
18339    pub fn open_selections_in_multibuffer(
18340        &mut self,
18341        _: &OpenSelectionsInMultibuffer,
18342        window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) {
18345        let multibuffer = self.buffer.read(cx);
18346
18347        let Some(buffer) = multibuffer.as_singleton() else {
18348            return;
18349        };
18350
18351        let Some(workspace) = self.workspace() else {
18352            return;
18353        };
18354
18355        let title = multibuffer.title(cx).to_string();
18356
18357        let locations = self
18358            .selections
18359            .all_anchors(cx)
18360            .into_iter()
18361            .map(|selection| Location {
18362                buffer: buffer.clone(),
18363                range: selection.start.text_anchor..selection.end.text_anchor,
18364            })
18365            .collect::<Vec<_>>();
18366
18367        cx.spawn_in(window, async move |_, cx| {
18368            workspace.update_in(cx, |workspace, window, cx| {
18369                Self::open_locations_in_multibuffer(
18370                    workspace,
18371                    locations,
18372                    format!("Selections for '{title}'"),
18373                    false,
18374                    MultibufferSelectionMode::All,
18375                    window,
18376                    cx,
18377                );
18378            })
18379        })
18380        .detach();
18381    }
18382
18383    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18384    /// last highlight added will be used.
18385    ///
18386    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18387    pub fn highlight_rows<T: 'static>(
18388        &mut self,
18389        range: Range<Anchor>,
18390        color: Hsla,
18391        options: RowHighlightOptions,
18392        cx: &mut Context<Self>,
18393    ) {
18394        let snapshot = self.buffer().read(cx).snapshot(cx);
18395        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18396        let ix = row_highlights.binary_search_by(|highlight| {
18397            Ordering::Equal
18398                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18399                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18400        });
18401
18402        if let Err(mut ix) = ix {
18403            let index = post_inc(&mut self.highlight_order);
18404
18405            // If this range intersects with the preceding highlight, then merge it with
18406            // the preceding highlight. Otherwise insert a new highlight.
18407            let mut merged = false;
18408            if ix > 0 {
18409                let prev_highlight = &mut row_highlights[ix - 1];
18410                if prev_highlight
18411                    .range
18412                    .end
18413                    .cmp(&range.start, &snapshot)
18414                    .is_ge()
18415                {
18416                    ix -= 1;
18417                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18418                        prev_highlight.range.end = range.end;
18419                    }
18420                    merged = true;
18421                    prev_highlight.index = index;
18422                    prev_highlight.color = color;
18423                    prev_highlight.options = options;
18424                }
18425            }
18426
18427            if !merged {
18428                row_highlights.insert(
18429                    ix,
18430                    RowHighlight {
18431                        range: range.clone(),
18432                        index,
18433                        color,
18434                        options,
18435                        type_id: TypeId::of::<T>(),
18436                    },
18437                );
18438            }
18439
18440            // If any of the following highlights intersect with this one, merge them.
18441            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18442                let highlight = &row_highlights[ix];
18443                if next_highlight
18444                    .range
18445                    .start
18446                    .cmp(&highlight.range.end, &snapshot)
18447                    .is_le()
18448                {
18449                    if next_highlight
18450                        .range
18451                        .end
18452                        .cmp(&highlight.range.end, &snapshot)
18453                        .is_gt()
18454                    {
18455                        row_highlights[ix].range.end = next_highlight.range.end;
18456                    }
18457                    row_highlights.remove(ix + 1);
18458                } else {
18459                    break;
18460                }
18461            }
18462        }
18463    }
18464
18465    /// Remove any highlighted row ranges of the given type that intersect the
18466    /// given ranges.
18467    pub fn remove_highlighted_rows<T: 'static>(
18468        &mut self,
18469        ranges_to_remove: Vec<Range<Anchor>>,
18470        cx: &mut Context<Self>,
18471    ) {
18472        let snapshot = self.buffer().read(cx).snapshot(cx);
18473        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18474        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18475        row_highlights.retain(|highlight| {
18476            while let Some(range_to_remove) = ranges_to_remove.peek() {
18477                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18478                    Ordering::Less | Ordering::Equal => {
18479                        ranges_to_remove.next();
18480                    }
18481                    Ordering::Greater => {
18482                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18483                            Ordering::Less | Ordering::Equal => {
18484                                return false;
18485                            }
18486                            Ordering::Greater => break,
18487                        }
18488                    }
18489                }
18490            }
18491
18492            true
18493        })
18494    }
18495
18496    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18497    pub fn clear_row_highlights<T: 'static>(&mut self) {
18498        self.highlighted_rows.remove(&TypeId::of::<T>());
18499    }
18500
18501    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18502    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18503        self.highlighted_rows
18504            .get(&TypeId::of::<T>())
18505            .map_or(&[] as &[_], |vec| vec.as_slice())
18506            .iter()
18507            .map(|highlight| (highlight.range.clone(), highlight.color))
18508    }
18509
18510    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18511    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18512    /// Allows to ignore certain kinds of highlights.
18513    pub fn highlighted_display_rows(
18514        &self,
18515        window: &mut Window,
18516        cx: &mut App,
18517    ) -> BTreeMap<DisplayRow, LineHighlight> {
18518        let snapshot = self.snapshot(window, cx);
18519        let mut used_highlight_orders = HashMap::default();
18520        self.highlighted_rows
18521            .iter()
18522            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18523            .fold(
18524                BTreeMap::<DisplayRow, LineHighlight>::new(),
18525                |mut unique_rows, highlight| {
18526                    let start = highlight.range.start.to_display_point(&snapshot);
18527                    let end = highlight.range.end.to_display_point(&snapshot);
18528                    let start_row = start.row().0;
18529                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18530                        && end.column() == 0
18531                    {
18532                        end.row().0.saturating_sub(1)
18533                    } else {
18534                        end.row().0
18535                    };
18536                    for row in start_row..=end_row {
18537                        let used_index =
18538                            used_highlight_orders.entry(row).or_insert(highlight.index);
18539                        if highlight.index >= *used_index {
18540                            *used_index = highlight.index;
18541                            unique_rows.insert(
18542                                DisplayRow(row),
18543                                LineHighlight {
18544                                    include_gutter: highlight.options.include_gutter,
18545                                    border: None,
18546                                    background: highlight.color.into(),
18547                                    type_id: Some(highlight.type_id),
18548                                },
18549                            );
18550                        }
18551                    }
18552                    unique_rows
18553                },
18554            )
18555    }
18556
18557    pub fn highlighted_display_row_for_autoscroll(
18558        &self,
18559        snapshot: &DisplaySnapshot,
18560    ) -> Option<DisplayRow> {
18561        self.highlighted_rows
18562            .values()
18563            .flat_map(|highlighted_rows| highlighted_rows.iter())
18564            .filter_map(|highlight| {
18565                if highlight.options.autoscroll {
18566                    Some(highlight.range.start.to_display_point(snapshot).row())
18567                } else {
18568                    None
18569                }
18570            })
18571            .min()
18572    }
18573
18574    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18575        self.highlight_background::<SearchWithinRange>(
18576            ranges,
18577            |colors| colors.colors().editor_document_highlight_read_background,
18578            cx,
18579        )
18580    }
18581
18582    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18583        self.breadcrumb_header = Some(new_header);
18584    }
18585
18586    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18587        self.clear_background_highlights::<SearchWithinRange>(cx);
18588    }
18589
18590    pub fn highlight_background<T: 'static>(
18591        &mut self,
18592        ranges: &[Range<Anchor>],
18593        color_fetcher: fn(&Theme) -> Hsla,
18594        cx: &mut Context<Self>,
18595    ) {
18596        self.background_highlights.insert(
18597            HighlightKey::Type(TypeId::of::<T>()),
18598            (color_fetcher, Arc::from(ranges)),
18599        );
18600        self.scrollbar_marker_state.dirty = true;
18601        cx.notify();
18602    }
18603
18604    pub fn highlight_background_key<T: 'static>(
18605        &mut self,
18606        key: usize,
18607        ranges: &[Range<Anchor>],
18608        color_fetcher: fn(&Theme) -> Hsla,
18609        cx: &mut Context<Self>,
18610    ) {
18611        self.background_highlights.insert(
18612            HighlightKey::TypePlus(TypeId::of::<T>(), key),
18613            (color_fetcher, Arc::from(ranges)),
18614        );
18615        self.scrollbar_marker_state.dirty = true;
18616        cx.notify();
18617    }
18618
18619    pub fn clear_background_highlights<T: 'static>(
18620        &mut self,
18621        cx: &mut Context<Self>,
18622    ) -> Option<BackgroundHighlight> {
18623        let text_highlights = self
18624            .background_highlights
18625            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
18626        if !text_highlights.1.is_empty() {
18627            self.scrollbar_marker_state.dirty = true;
18628            cx.notify();
18629        }
18630        Some(text_highlights)
18631    }
18632
18633    pub fn highlight_gutter<T: 'static>(
18634        &mut self,
18635        ranges: impl Into<Vec<Range<Anchor>>>,
18636        color_fetcher: fn(&App) -> Hsla,
18637        cx: &mut Context<Self>,
18638    ) {
18639        self.gutter_highlights
18640            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18641        cx.notify();
18642    }
18643
18644    pub fn clear_gutter_highlights<T: 'static>(
18645        &mut self,
18646        cx: &mut Context<Self>,
18647    ) -> Option<GutterHighlight> {
18648        cx.notify();
18649        self.gutter_highlights.remove(&TypeId::of::<T>())
18650    }
18651
18652    pub fn insert_gutter_highlight<T: 'static>(
18653        &mut self,
18654        range: Range<Anchor>,
18655        color_fetcher: fn(&App) -> Hsla,
18656        cx: &mut Context<Self>,
18657    ) {
18658        let snapshot = self.buffer().read(cx).snapshot(cx);
18659        let mut highlights = self
18660            .gutter_highlights
18661            .remove(&TypeId::of::<T>())
18662            .map(|(_, highlights)| highlights)
18663            .unwrap_or_default();
18664        let ix = highlights.binary_search_by(|highlight| {
18665            Ordering::Equal
18666                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18667                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18668        });
18669        if let Err(ix) = ix {
18670            highlights.insert(ix, range);
18671        }
18672        self.gutter_highlights
18673            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18674    }
18675
18676    pub fn remove_gutter_highlights<T: 'static>(
18677        &mut self,
18678        ranges_to_remove: Vec<Range<Anchor>>,
18679        cx: &mut Context<Self>,
18680    ) {
18681        let snapshot = self.buffer().read(cx).snapshot(cx);
18682        let Some((color_fetcher, mut gutter_highlights)) =
18683            self.gutter_highlights.remove(&TypeId::of::<T>())
18684        else {
18685            return;
18686        };
18687        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18688        gutter_highlights.retain(|highlight| {
18689            while let Some(range_to_remove) = ranges_to_remove.peek() {
18690                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18691                    Ordering::Less | Ordering::Equal => {
18692                        ranges_to_remove.next();
18693                    }
18694                    Ordering::Greater => {
18695                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18696                            Ordering::Less | Ordering::Equal => {
18697                                return false;
18698                            }
18699                            Ordering::Greater => break,
18700                        }
18701                    }
18702                }
18703            }
18704
18705            true
18706        });
18707        self.gutter_highlights
18708            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18709    }
18710
18711    #[cfg(feature = "test-support")]
18712    pub fn all_text_highlights(
18713        &self,
18714        window: &mut Window,
18715        cx: &mut Context<Self>,
18716    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
18717        let snapshot = self.snapshot(window, cx);
18718        self.display_map.update(cx, |display_map, _| {
18719            display_map
18720                .all_text_highlights()
18721                .map(|highlight| {
18722                    let (style, ranges) = highlight.as_ref();
18723                    (
18724                        *style,
18725                        ranges
18726                            .iter()
18727                            .map(|range| range.clone().to_display_points(&snapshot))
18728                            .collect(),
18729                    )
18730                })
18731                .collect()
18732        })
18733    }
18734
18735    #[cfg(feature = "test-support")]
18736    pub fn all_text_background_highlights(
18737        &self,
18738        window: &mut Window,
18739        cx: &mut Context<Self>,
18740    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18741        let snapshot = self.snapshot(window, cx);
18742        let buffer = &snapshot.buffer_snapshot;
18743        let start = buffer.anchor_before(0);
18744        let end = buffer.anchor_after(buffer.len());
18745        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
18746    }
18747
18748    #[cfg(feature = "test-support")]
18749    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18750        let snapshot = self.buffer().read(cx).snapshot(cx);
18751
18752        let highlights = self
18753            .background_highlights
18754            .get(&HighlightKey::Type(TypeId::of::<
18755                items::BufferSearchHighlights,
18756            >()));
18757
18758        if let Some((_color, ranges)) = highlights {
18759            ranges
18760                .iter()
18761                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18762                .collect_vec()
18763        } else {
18764            vec![]
18765        }
18766    }
18767
18768    fn document_highlights_for_position<'a>(
18769        &'a self,
18770        position: Anchor,
18771        buffer: &'a MultiBufferSnapshot,
18772    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18773        let read_highlights = self
18774            .background_highlights
18775            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
18776            .map(|h| &h.1);
18777        let write_highlights = self
18778            .background_highlights
18779            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
18780            .map(|h| &h.1);
18781        let left_position = position.bias_left(buffer);
18782        let right_position = position.bias_right(buffer);
18783        read_highlights
18784            .into_iter()
18785            .chain(write_highlights)
18786            .flat_map(move |ranges| {
18787                let start_ix = match ranges.binary_search_by(|probe| {
18788                    let cmp = probe.end.cmp(&left_position, buffer);
18789                    if cmp.is_ge() {
18790                        Ordering::Greater
18791                    } else {
18792                        Ordering::Less
18793                    }
18794                }) {
18795                    Ok(i) | Err(i) => i,
18796                };
18797
18798                ranges[start_ix..]
18799                    .iter()
18800                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18801            })
18802    }
18803
18804    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18805        self.background_highlights
18806            .get(&HighlightKey::Type(TypeId::of::<T>()))
18807            .map_or(false, |(_, highlights)| !highlights.is_empty())
18808    }
18809
18810    pub fn background_highlights_in_range(
18811        &self,
18812        search_range: Range<Anchor>,
18813        display_snapshot: &DisplaySnapshot,
18814        theme: &Theme,
18815    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18816        let mut results = Vec::new();
18817        for (color_fetcher, ranges) in self.background_highlights.values() {
18818            let color = color_fetcher(theme);
18819            let start_ix = match ranges.binary_search_by(|probe| {
18820                let cmp = probe
18821                    .end
18822                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18823                if cmp.is_gt() {
18824                    Ordering::Greater
18825                } else {
18826                    Ordering::Less
18827                }
18828            }) {
18829                Ok(i) | Err(i) => i,
18830            };
18831            for range in &ranges[start_ix..] {
18832                if range
18833                    .start
18834                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18835                    .is_ge()
18836                {
18837                    break;
18838                }
18839
18840                let start = range.start.to_display_point(display_snapshot);
18841                let end = range.end.to_display_point(display_snapshot);
18842                results.push((start..end, color))
18843            }
18844        }
18845        results
18846    }
18847
18848    pub fn background_highlight_row_ranges<T: 'static>(
18849        &self,
18850        search_range: Range<Anchor>,
18851        display_snapshot: &DisplaySnapshot,
18852        count: usize,
18853    ) -> Vec<RangeInclusive<DisplayPoint>> {
18854        let mut results = Vec::new();
18855        let Some((_, ranges)) = self
18856            .background_highlights
18857            .get(&HighlightKey::Type(TypeId::of::<T>()))
18858        else {
18859            return vec![];
18860        };
18861
18862        let start_ix = match ranges.binary_search_by(|probe| {
18863            let cmp = probe
18864                .end
18865                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18866            if cmp.is_gt() {
18867                Ordering::Greater
18868            } else {
18869                Ordering::Less
18870            }
18871        }) {
18872            Ok(i) | Err(i) => i,
18873        };
18874        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18875            if let (Some(start_display), Some(end_display)) = (start, end) {
18876                results.push(
18877                    start_display.to_display_point(display_snapshot)
18878                        ..=end_display.to_display_point(display_snapshot),
18879                );
18880            }
18881        };
18882        let mut start_row: Option<Point> = None;
18883        let mut end_row: Option<Point> = None;
18884        if ranges.len() > count {
18885            return Vec::new();
18886        }
18887        for range in &ranges[start_ix..] {
18888            if range
18889                .start
18890                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18891                .is_ge()
18892            {
18893                break;
18894            }
18895            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18896            if let Some(current_row) = &end_row {
18897                if end.row == current_row.row {
18898                    continue;
18899                }
18900            }
18901            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18902            if start_row.is_none() {
18903                assert_eq!(end_row, None);
18904                start_row = Some(start);
18905                end_row = Some(end);
18906                continue;
18907            }
18908            if let Some(current_end) = end_row.as_mut() {
18909                if start.row > current_end.row + 1 {
18910                    push_region(start_row, end_row);
18911                    start_row = Some(start);
18912                    end_row = Some(end);
18913                } else {
18914                    // Merge two hunks.
18915                    *current_end = end;
18916                }
18917            } else {
18918                unreachable!();
18919            }
18920        }
18921        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18922        push_region(start_row, end_row);
18923        results
18924    }
18925
18926    pub fn gutter_highlights_in_range(
18927        &self,
18928        search_range: Range<Anchor>,
18929        display_snapshot: &DisplaySnapshot,
18930        cx: &App,
18931    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18932        let mut results = Vec::new();
18933        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18934            let color = color_fetcher(cx);
18935            let start_ix = match ranges.binary_search_by(|probe| {
18936                let cmp = probe
18937                    .end
18938                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18939                if cmp.is_gt() {
18940                    Ordering::Greater
18941                } else {
18942                    Ordering::Less
18943                }
18944            }) {
18945                Ok(i) | Err(i) => i,
18946            };
18947            for range in &ranges[start_ix..] {
18948                if range
18949                    .start
18950                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18951                    .is_ge()
18952                {
18953                    break;
18954                }
18955
18956                let start = range.start.to_display_point(display_snapshot);
18957                let end = range.end.to_display_point(display_snapshot);
18958                results.push((start..end, color))
18959            }
18960        }
18961        results
18962    }
18963
18964    /// Get the text ranges corresponding to the redaction query
18965    pub fn redacted_ranges(
18966        &self,
18967        search_range: Range<Anchor>,
18968        display_snapshot: &DisplaySnapshot,
18969        cx: &App,
18970    ) -> Vec<Range<DisplayPoint>> {
18971        display_snapshot
18972            .buffer_snapshot
18973            .redacted_ranges(search_range, |file| {
18974                if let Some(file) = file {
18975                    file.is_private()
18976                        && EditorSettings::get(
18977                            Some(SettingsLocation {
18978                                worktree_id: file.worktree_id(cx),
18979                                path: file.path().as_ref(),
18980                            }),
18981                            cx,
18982                        )
18983                        .redact_private_values
18984                } else {
18985                    false
18986                }
18987            })
18988            .map(|range| {
18989                range.start.to_display_point(display_snapshot)
18990                    ..range.end.to_display_point(display_snapshot)
18991            })
18992            .collect()
18993    }
18994
18995    pub fn highlight_text_key<T: 'static>(
18996        &mut self,
18997        key: usize,
18998        ranges: Vec<Range<Anchor>>,
18999        style: HighlightStyle,
19000        cx: &mut Context<Self>,
19001    ) {
19002        self.display_map.update(cx, |map, _| {
19003            map.highlight_text(
19004                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19005                ranges,
19006                style,
19007            );
19008        });
19009        cx.notify();
19010    }
19011
19012    pub fn highlight_text<T: 'static>(
19013        &mut self,
19014        ranges: Vec<Range<Anchor>>,
19015        style: HighlightStyle,
19016        cx: &mut Context<Self>,
19017    ) {
19018        self.display_map.update(cx, |map, _| {
19019            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19020        });
19021        cx.notify();
19022    }
19023
19024    pub(crate) fn highlight_inlays<T: 'static>(
19025        &mut self,
19026        highlights: Vec<InlayHighlight>,
19027        style: HighlightStyle,
19028        cx: &mut Context<Self>,
19029    ) {
19030        self.display_map.update(cx, |map, _| {
19031            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19032        });
19033        cx.notify();
19034    }
19035
19036    pub fn text_highlights<'a, T: 'static>(
19037        &'a self,
19038        cx: &'a App,
19039    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19040        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19041    }
19042
19043    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19044        let cleared = self
19045            .display_map
19046            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19047        if cleared {
19048            cx.notify();
19049        }
19050    }
19051
19052    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19053        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19054            && self.focus_handle.is_focused(window)
19055    }
19056
19057    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19058        self.show_cursor_when_unfocused = is_enabled;
19059        cx.notify();
19060    }
19061
19062    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19063        cx.notify();
19064    }
19065
19066    fn on_debug_session_event(
19067        &mut self,
19068        _session: Entity<Session>,
19069        event: &SessionEvent,
19070        cx: &mut Context<Self>,
19071    ) {
19072        match event {
19073            SessionEvent::InvalidateInlineValue => {
19074                self.refresh_inline_values(cx);
19075            }
19076            _ => {}
19077        }
19078    }
19079
19080    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19081        let Some(project) = self.project.clone() else {
19082            return;
19083        };
19084
19085        if !self.inline_value_cache.enabled {
19086            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19087            self.splice_inlays(&inlays, Vec::new(), cx);
19088            return;
19089        }
19090
19091        let current_execution_position = self
19092            .highlighted_rows
19093            .get(&TypeId::of::<ActiveDebugLine>())
19094            .and_then(|lines| lines.last().map(|line| line.range.start));
19095
19096        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19097            let inline_values = editor
19098                .update(cx, |editor, cx| {
19099                    let Some(current_execution_position) = current_execution_position else {
19100                        return Some(Task::ready(Ok(Vec::new())));
19101                    };
19102
19103                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19104                        let snapshot = buffer.snapshot(cx);
19105
19106                        let excerpt = snapshot.excerpt_containing(
19107                            current_execution_position..current_execution_position,
19108                        )?;
19109
19110                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19111                    })?;
19112
19113                    let range =
19114                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19115
19116                    project.inline_values(buffer, range, cx)
19117                })
19118                .ok()
19119                .flatten()?
19120                .await
19121                .context("refreshing debugger inlays")
19122                .log_err()?;
19123
19124            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19125
19126            for (buffer_id, inline_value) in inline_values
19127                .into_iter()
19128                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19129            {
19130                buffer_inline_values
19131                    .entry(buffer_id)
19132                    .or_default()
19133                    .push(inline_value);
19134            }
19135
19136            editor
19137                .update(cx, |editor, cx| {
19138                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19139                    let mut new_inlays = Vec::default();
19140
19141                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19142                        let buffer_id = buffer_snapshot.remote_id();
19143                        buffer_inline_values
19144                            .get(&buffer_id)
19145                            .into_iter()
19146                            .flatten()
19147                            .for_each(|hint| {
19148                                let inlay = Inlay::debugger(
19149                                    post_inc(&mut editor.next_inlay_id),
19150                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19151                                    hint.text(),
19152                                );
19153
19154                                new_inlays.push(inlay);
19155                            });
19156                    }
19157
19158                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19159                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19160
19161                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19162                })
19163                .ok()?;
19164            Some(())
19165        });
19166    }
19167
19168    fn on_buffer_event(
19169        &mut self,
19170        multibuffer: &Entity<MultiBuffer>,
19171        event: &multi_buffer::Event,
19172        window: &mut Window,
19173        cx: &mut Context<Self>,
19174    ) {
19175        match event {
19176            multi_buffer::Event::Edited {
19177                singleton_buffer_edited,
19178                edited_buffer,
19179            } => {
19180                self.scrollbar_marker_state.dirty = true;
19181                self.active_indent_guides_state.dirty = true;
19182                self.refresh_active_diagnostics(cx);
19183                self.refresh_code_actions(window, cx);
19184                self.refresh_selected_text_highlights(true, window, cx);
19185                refresh_matching_bracket_highlights(self, window, cx);
19186                if self.has_active_inline_completion() {
19187                    self.update_visible_inline_completion(window, cx);
19188                }
19189                if let Some(project) = self.project.as_ref() {
19190                    if let Some(edited_buffer) = edited_buffer {
19191                        project.update(cx, |project, cx| {
19192                            self.registered_buffers
19193                                .entry(edited_buffer.read(cx).remote_id())
19194                                .or_insert_with(|| {
19195                                    project
19196                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19197                                });
19198                        });
19199                    }
19200                }
19201                cx.emit(EditorEvent::BufferEdited);
19202                cx.emit(SearchEvent::MatchesInvalidated);
19203
19204                if let Some(buffer) = edited_buffer {
19205                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19206                }
19207
19208                if *singleton_buffer_edited {
19209                    if let Some(buffer) = edited_buffer {
19210                        if buffer.read(cx).file().is_none() {
19211                            cx.emit(EditorEvent::TitleChanged);
19212                        }
19213                    }
19214                    if let Some(project) = &self.project {
19215                        #[allow(clippy::mutable_key_type)]
19216                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19217                            multibuffer
19218                                .all_buffers()
19219                                .into_iter()
19220                                .filter_map(|buffer| {
19221                                    buffer.update(cx, |buffer, cx| {
19222                                        let language = buffer.language()?;
19223                                        let should_discard = project.update(cx, |project, cx| {
19224                                            project.is_local()
19225                                                && !project.has_language_servers_for(buffer, cx)
19226                                        });
19227                                        should_discard.not().then_some(language.clone())
19228                                    })
19229                                })
19230                                .collect::<HashSet<_>>()
19231                        });
19232                        if !languages_affected.is_empty() {
19233                            self.refresh_inlay_hints(
19234                                InlayHintRefreshReason::BufferEdited(languages_affected),
19235                                cx,
19236                            );
19237                        }
19238                    }
19239                }
19240
19241                let Some(project) = &self.project else { return };
19242                let (telemetry, is_via_ssh) = {
19243                    let project = project.read(cx);
19244                    let telemetry = project.client().telemetry().clone();
19245                    let is_via_ssh = project.is_via_ssh();
19246                    (telemetry, is_via_ssh)
19247                };
19248                refresh_linked_ranges(self, window, cx);
19249                telemetry.log_edit_event("editor", is_via_ssh);
19250            }
19251            multi_buffer::Event::ExcerptsAdded {
19252                buffer,
19253                predecessor,
19254                excerpts,
19255            } => {
19256                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19257                let buffer_id = buffer.read(cx).remote_id();
19258                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19259                    if let Some(project) = &self.project {
19260                        update_uncommitted_diff_for_buffer(
19261                            cx.entity(),
19262                            project,
19263                            [buffer.clone()],
19264                            self.buffer.clone(),
19265                            cx,
19266                        )
19267                        .detach();
19268                    }
19269                }
19270                self.update_lsp_data(false, Some(buffer_id), window, cx);
19271                cx.emit(EditorEvent::ExcerptsAdded {
19272                    buffer: buffer.clone(),
19273                    predecessor: *predecessor,
19274                    excerpts: excerpts.clone(),
19275                });
19276                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19277            }
19278            multi_buffer::Event::ExcerptsRemoved {
19279                ids,
19280                removed_buffer_ids,
19281            } => {
19282                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19283                let buffer = self.buffer.read(cx);
19284                self.registered_buffers
19285                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19286                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19287                cx.emit(EditorEvent::ExcerptsRemoved {
19288                    ids: ids.clone(),
19289                    removed_buffer_ids: removed_buffer_ids.clone(),
19290                });
19291            }
19292            multi_buffer::Event::ExcerptsEdited {
19293                excerpt_ids,
19294                buffer_ids,
19295            } => {
19296                self.display_map.update(cx, |map, cx| {
19297                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19298                });
19299                cx.emit(EditorEvent::ExcerptsEdited {
19300                    ids: excerpt_ids.clone(),
19301                });
19302            }
19303            multi_buffer::Event::ExcerptsExpanded { ids } => {
19304                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19305                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19306            }
19307            multi_buffer::Event::Reparsed(buffer_id) => {
19308                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19309                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19310
19311                cx.emit(EditorEvent::Reparsed(*buffer_id));
19312            }
19313            multi_buffer::Event::DiffHunksToggled => {
19314                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19315            }
19316            multi_buffer::Event::LanguageChanged(buffer_id) => {
19317                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19318                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19319                cx.emit(EditorEvent::Reparsed(*buffer_id));
19320                cx.notify();
19321            }
19322            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19323            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19324            multi_buffer::Event::FileHandleChanged
19325            | multi_buffer::Event::Reloaded
19326            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19327            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19328            multi_buffer::Event::DiagnosticsUpdated => {
19329                self.update_diagnostics_state(window, cx);
19330            }
19331            _ => {}
19332        };
19333    }
19334
19335    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19336        self.refresh_active_diagnostics(cx);
19337        self.refresh_inline_diagnostics(true, window, cx);
19338        self.scrollbar_marker_state.dirty = true;
19339        cx.notify();
19340    }
19341
19342    pub fn start_temporary_diff_override(&mut self) {
19343        self.load_diff_task.take();
19344        self.temporary_diff_override = true;
19345    }
19346
19347    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19348        self.temporary_diff_override = false;
19349        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19350        self.buffer.update(cx, |buffer, cx| {
19351            buffer.set_all_diff_hunks_collapsed(cx);
19352        });
19353
19354        if let Some(project) = self.project.clone() {
19355            self.load_diff_task = Some(
19356                update_uncommitted_diff_for_buffer(
19357                    cx.entity(),
19358                    &project,
19359                    self.buffer.read(cx).all_buffers(),
19360                    self.buffer.clone(),
19361                    cx,
19362                )
19363                .shared(),
19364            );
19365        }
19366    }
19367
19368    fn on_display_map_changed(
19369        &mut self,
19370        _: Entity<DisplayMap>,
19371        _: &mut Window,
19372        cx: &mut Context<Self>,
19373    ) {
19374        cx.notify();
19375    }
19376
19377    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19378        let new_severity = if self.diagnostics_enabled() {
19379            EditorSettings::get_global(cx)
19380                .diagnostics_max_severity
19381                .unwrap_or(DiagnosticSeverity::Hint)
19382        } else {
19383            DiagnosticSeverity::Off
19384        };
19385        self.set_max_diagnostics_severity(new_severity, cx);
19386        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19387        self.update_edit_prediction_settings(cx);
19388        self.refresh_inline_completion(true, false, window, cx);
19389        self.refresh_inlay_hints(
19390            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19391                self.selections.newest_anchor().head(),
19392                &self.buffer.read(cx).snapshot(cx),
19393                cx,
19394            )),
19395            cx,
19396        );
19397
19398        let old_cursor_shape = self.cursor_shape;
19399
19400        {
19401            let editor_settings = EditorSettings::get_global(cx);
19402            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19403            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19404            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19405            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19406            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19407        }
19408
19409        if old_cursor_shape != self.cursor_shape {
19410            cx.emit(EditorEvent::CursorShapeChanged);
19411        }
19412
19413        let project_settings = ProjectSettings::get_global(cx);
19414        self.serialize_dirty_buffers =
19415            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19416
19417        if self.mode.is_full() {
19418            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19419            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19420            if self.show_inline_diagnostics != show_inline_diagnostics {
19421                self.show_inline_diagnostics = show_inline_diagnostics;
19422                self.refresh_inline_diagnostics(false, window, cx);
19423            }
19424
19425            if self.git_blame_inline_enabled != inline_blame_enabled {
19426                self.toggle_git_blame_inline_internal(false, window, cx);
19427            }
19428
19429            let minimap_settings = EditorSettings::get_global(cx).minimap;
19430            if self.minimap_visibility != MinimapVisibility::Disabled {
19431                if self.minimap_visibility.settings_visibility()
19432                    != minimap_settings.minimap_enabled()
19433                {
19434                    self.set_minimap_visibility(
19435                        MinimapVisibility::for_mode(self.mode(), cx),
19436                        window,
19437                        cx,
19438                    );
19439                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19440                    minimap_entity.update(cx, |minimap_editor, cx| {
19441                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19442                    })
19443                }
19444            }
19445        }
19446
19447        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19448            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19449        }) {
19450            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19451                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19452            }
19453            self.refresh_colors(false, None, window, cx);
19454        }
19455
19456        cx.notify();
19457    }
19458
19459    pub fn set_searchable(&mut self, searchable: bool) {
19460        self.searchable = searchable;
19461    }
19462
19463    pub fn searchable(&self) -> bool {
19464        self.searchable
19465    }
19466
19467    fn open_proposed_changes_editor(
19468        &mut self,
19469        _: &OpenProposedChangesEditor,
19470        window: &mut Window,
19471        cx: &mut Context<Self>,
19472    ) {
19473        let Some(workspace) = self.workspace() else {
19474            cx.propagate();
19475            return;
19476        };
19477
19478        let selections = self.selections.all::<usize>(cx);
19479        let multi_buffer = self.buffer.read(cx);
19480        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19481        let mut new_selections_by_buffer = HashMap::default();
19482        for selection in selections {
19483            for (buffer, range, _) in
19484                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19485            {
19486                let mut range = range.to_point(buffer);
19487                range.start.column = 0;
19488                range.end.column = buffer.line_len(range.end.row);
19489                new_selections_by_buffer
19490                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19491                    .or_insert(Vec::new())
19492                    .push(range)
19493            }
19494        }
19495
19496        let proposed_changes_buffers = new_selections_by_buffer
19497            .into_iter()
19498            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19499            .collect::<Vec<_>>();
19500        let proposed_changes_editor = cx.new(|cx| {
19501            ProposedChangesEditor::new(
19502                "Proposed changes",
19503                proposed_changes_buffers,
19504                self.project.clone(),
19505                window,
19506                cx,
19507            )
19508        });
19509
19510        window.defer(cx, move |window, cx| {
19511            workspace.update(cx, |workspace, cx| {
19512                workspace.active_pane().update(cx, |pane, cx| {
19513                    pane.add_item(
19514                        Box::new(proposed_changes_editor),
19515                        true,
19516                        true,
19517                        None,
19518                        window,
19519                        cx,
19520                    );
19521                });
19522            });
19523        });
19524    }
19525
19526    pub fn open_excerpts_in_split(
19527        &mut self,
19528        _: &OpenExcerptsSplit,
19529        window: &mut Window,
19530        cx: &mut Context<Self>,
19531    ) {
19532        self.open_excerpts_common(None, true, window, cx)
19533    }
19534
19535    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19536        self.open_excerpts_common(None, false, window, cx)
19537    }
19538
19539    fn open_excerpts_common(
19540        &mut self,
19541        jump_data: Option<JumpData>,
19542        split: bool,
19543        window: &mut Window,
19544        cx: &mut Context<Self>,
19545    ) {
19546        let Some(workspace) = self.workspace() else {
19547            cx.propagate();
19548            return;
19549        };
19550
19551        if self.buffer.read(cx).is_singleton() {
19552            cx.propagate();
19553            return;
19554        }
19555
19556        let mut new_selections_by_buffer = HashMap::default();
19557        match &jump_data {
19558            Some(JumpData::MultiBufferPoint {
19559                excerpt_id,
19560                position,
19561                anchor,
19562                line_offset_from_top,
19563            }) => {
19564                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19565                if let Some(buffer) = multi_buffer_snapshot
19566                    .buffer_id_for_excerpt(*excerpt_id)
19567                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19568                {
19569                    let buffer_snapshot = buffer.read(cx).snapshot();
19570                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19571                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19572                    } else {
19573                        buffer_snapshot.clip_point(*position, Bias::Left)
19574                    };
19575                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19576                    new_selections_by_buffer.insert(
19577                        buffer,
19578                        (
19579                            vec![jump_to_offset..jump_to_offset],
19580                            Some(*line_offset_from_top),
19581                        ),
19582                    );
19583                }
19584            }
19585            Some(JumpData::MultiBufferRow {
19586                row,
19587                line_offset_from_top,
19588            }) => {
19589                let point = MultiBufferPoint::new(row.0, 0);
19590                if let Some((buffer, buffer_point, _)) =
19591                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19592                {
19593                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19594                    new_selections_by_buffer
19595                        .entry(buffer)
19596                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19597                        .0
19598                        .push(buffer_offset..buffer_offset)
19599                }
19600            }
19601            None => {
19602                let selections = self.selections.all::<usize>(cx);
19603                let multi_buffer = self.buffer.read(cx);
19604                for selection in selections {
19605                    for (snapshot, range, _, anchor) in multi_buffer
19606                        .snapshot(cx)
19607                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19608                    {
19609                        if let Some(anchor) = anchor {
19610                            // selection is in a deleted hunk
19611                            let Some(buffer_id) = anchor.buffer_id else {
19612                                continue;
19613                            };
19614                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19615                                continue;
19616                            };
19617                            let offset = text::ToOffset::to_offset(
19618                                &anchor.text_anchor,
19619                                &buffer_handle.read(cx).snapshot(),
19620                            );
19621                            let range = offset..offset;
19622                            new_selections_by_buffer
19623                                .entry(buffer_handle)
19624                                .or_insert((Vec::new(), None))
19625                                .0
19626                                .push(range)
19627                        } else {
19628                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19629                            else {
19630                                continue;
19631                            };
19632                            new_selections_by_buffer
19633                                .entry(buffer_handle)
19634                                .or_insert((Vec::new(), None))
19635                                .0
19636                                .push(range)
19637                        }
19638                    }
19639                }
19640            }
19641        }
19642
19643        new_selections_by_buffer
19644            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19645
19646        if new_selections_by_buffer.is_empty() {
19647            return;
19648        }
19649
19650        // We defer the pane interaction because we ourselves are a workspace item
19651        // and activating a new item causes the pane to call a method on us reentrantly,
19652        // which panics if we're on the stack.
19653        window.defer(cx, move |window, cx| {
19654            workspace.update(cx, |workspace, cx| {
19655                let pane = if split {
19656                    workspace.adjacent_pane(window, cx)
19657                } else {
19658                    workspace.active_pane().clone()
19659                };
19660
19661                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19662                    let editor = buffer
19663                        .read(cx)
19664                        .file()
19665                        .is_none()
19666                        .then(|| {
19667                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19668                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19669                            // Instead, we try to activate the existing editor in the pane first.
19670                            let (editor, pane_item_index) =
19671                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19672                                    let editor = item.downcast::<Editor>()?;
19673                                    let singleton_buffer =
19674                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19675                                    if singleton_buffer == buffer {
19676                                        Some((editor, i))
19677                                    } else {
19678                                        None
19679                                    }
19680                                })?;
19681                            pane.update(cx, |pane, cx| {
19682                                pane.activate_item(pane_item_index, true, true, window, cx)
19683                            });
19684                            Some(editor)
19685                        })
19686                        .flatten()
19687                        .unwrap_or_else(|| {
19688                            workspace.open_project_item::<Self>(
19689                                pane.clone(),
19690                                buffer,
19691                                true,
19692                                true,
19693                                window,
19694                                cx,
19695                            )
19696                        });
19697
19698                    editor.update(cx, |editor, cx| {
19699                        let autoscroll = match scroll_offset {
19700                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19701                            None => Autoscroll::newest(),
19702                        };
19703                        let nav_history = editor.nav_history.take();
19704                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19705                            s.select_ranges(ranges);
19706                        });
19707                        editor.nav_history = nav_history;
19708                    });
19709                }
19710            })
19711        });
19712    }
19713
19714    // For now, don't allow opening excerpts in buffers that aren't backed by
19715    // regular project files.
19716    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19717        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19718    }
19719
19720    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19721        let snapshot = self.buffer.read(cx).read(cx);
19722        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19723        Some(
19724            ranges
19725                .iter()
19726                .map(move |range| {
19727                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19728                })
19729                .collect(),
19730        )
19731    }
19732
19733    fn selection_replacement_ranges(
19734        &self,
19735        range: Range<OffsetUtf16>,
19736        cx: &mut App,
19737    ) -> Vec<Range<OffsetUtf16>> {
19738        let selections = self.selections.all::<OffsetUtf16>(cx);
19739        let newest_selection = selections
19740            .iter()
19741            .max_by_key(|selection| selection.id)
19742            .unwrap();
19743        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19744        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19745        let snapshot = self.buffer.read(cx).read(cx);
19746        selections
19747            .into_iter()
19748            .map(|mut selection| {
19749                selection.start.0 =
19750                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19751                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19752                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19753                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19754            })
19755            .collect()
19756    }
19757
19758    fn report_editor_event(
19759        &self,
19760        event_type: &'static str,
19761        file_extension: Option<String>,
19762        cx: &App,
19763    ) {
19764        if cfg!(any(test, feature = "test-support")) {
19765            return;
19766        }
19767
19768        let Some(project) = &self.project else { return };
19769
19770        // If None, we are in a file without an extension
19771        let file = self
19772            .buffer
19773            .read(cx)
19774            .as_singleton()
19775            .and_then(|b| b.read(cx).file());
19776        let file_extension = file_extension.or(file
19777            .as_ref()
19778            .and_then(|file| Path::new(file.file_name(cx)).extension())
19779            .and_then(|e| e.to_str())
19780            .map(|a| a.to_string()));
19781
19782        let vim_mode = vim_enabled(cx);
19783
19784        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19785        let copilot_enabled = edit_predictions_provider
19786            == language::language_settings::EditPredictionProvider::Copilot;
19787        let copilot_enabled_for_language = self
19788            .buffer
19789            .read(cx)
19790            .language_settings(cx)
19791            .show_edit_predictions;
19792
19793        let project = project.read(cx);
19794        telemetry::event!(
19795            event_type,
19796            file_extension,
19797            vim_mode,
19798            copilot_enabled,
19799            copilot_enabled_for_language,
19800            edit_predictions_provider,
19801            is_via_ssh = project.is_via_ssh(),
19802        );
19803    }
19804
19805    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19806    /// with each line being an array of {text, highlight} objects.
19807    fn copy_highlight_json(
19808        &mut self,
19809        _: &CopyHighlightJson,
19810        window: &mut Window,
19811        cx: &mut Context<Self>,
19812    ) {
19813        #[derive(Serialize)]
19814        struct Chunk<'a> {
19815            text: String,
19816            highlight: Option<&'a str>,
19817        }
19818
19819        let snapshot = self.buffer.read(cx).snapshot(cx);
19820        let range = self
19821            .selected_text_range(false, window, cx)
19822            .and_then(|selection| {
19823                if selection.range.is_empty() {
19824                    None
19825                } else {
19826                    Some(selection.range)
19827                }
19828            })
19829            .unwrap_or_else(|| 0..snapshot.len());
19830
19831        let chunks = snapshot.chunks(range, true);
19832        let mut lines = Vec::new();
19833        let mut line: VecDeque<Chunk> = VecDeque::new();
19834
19835        let Some(style) = self.style.as_ref() else {
19836            return;
19837        };
19838
19839        for chunk in chunks {
19840            let highlight = chunk
19841                .syntax_highlight_id
19842                .and_then(|id| id.name(&style.syntax));
19843            let mut chunk_lines = chunk.text.split('\n').peekable();
19844            while let Some(text) = chunk_lines.next() {
19845                let mut merged_with_last_token = false;
19846                if let Some(last_token) = line.back_mut() {
19847                    if last_token.highlight == highlight {
19848                        last_token.text.push_str(text);
19849                        merged_with_last_token = true;
19850                    }
19851                }
19852
19853                if !merged_with_last_token {
19854                    line.push_back(Chunk {
19855                        text: text.into(),
19856                        highlight,
19857                    });
19858                }
19859
19860                if chunk_lines.peek().is_some() {
19861                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19862                        line.pop_front();
19863                    }
19864                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19865                        line.pop_back();
19866                    }
19867
19868                    lines.push(mem::take(&mut line));
19869                }
19870            }
19871        }
19872
19873        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19874            return;
19875        };
19876        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19877    }
19878
19879    pub fn open_context_menu(
19880        &mut self,
19881        _: &OpenContextMenu,
19882        window: &mut Window,
19883        cx: &mut Context<Self>,
19884    ) {
19885        self.request_autoscroll(Autoscroll::newest(), cx);
19886        let position = self.selections.newest_display(cx).start;
19887        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19888    }
19889
19890    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19891        &self.inlay_hint_cache
19892    }
19893
19894    pub fn replay_insert_event(
19895        &mut self,
19896        text: &str,
19897        relative_utf16_range: Option<Range<isize>>,
19898        window: &mut Window,
19899        cx: &mut Context<Self>,
19900    ) {
19901        if !self.input_enabled {
19902            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19903            return;
19904        }
19905        if let Some(relative_utf16_range) = relative_utf16_range {
19906            let selections = self.selections.all::<OffsetUtf16>(cx);
19907            self.change_selections(None, window, cx, |s| {
19908                let new_ranges = selections.into_iter().map(|range| {
19909                    let start = OffsetUtf16(
19910                        range
19911                            .head()
19912                            .0
19913                            .saturating_add_signed(relative_utf16_range.start),
19914                    );
19915                    let end = OffsetUtf16(
19916                        range
19917                            .head()
19918                            .0
19919                            .saturating_add_signed(relative_utf16_range.end),
19920                    );
19921                    start..end
19922                });
19923                s.select_ranges(new_ranges);
19924            });
19925        }
19926
19927        self.handle_input(text, window, cx);
19928    }
19929
19930    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19931        let Some(provider) = self.semantics_provider.as_ref() else {
19932            return false;
19933        };
19934
19935        let mut supports = false;
19936        self.buffer().update(cx, |this, cx| {
19937            this.for_each_buffer(|buffer| {
19938                supports |= provider.supports_inlay_hints(buffer, cx);
19939            });
19940        });
19941
19942        supports
19943    }
19944
19945    pub fn is_focused(&self, window: &Window) -> bool {
19946        self.focus_handle.is_focused(window)
19947    }
19948
19949    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19950        cx.emit(EditorEvent::Focused);
19951
19952        if let Some(descendant) = self
19953            .last_focused_descendant
19954            .take()
19955            .and_then(|descendant| descendant.upgrade())
19956        {
19957            window.focus(&descendant);
19958        } else {
19959            if let Some(blame) = self.blame.as_ref() {
19960                blame.update(cx, GitBlame::focus)
19961            }
19962
19963            self.blink_manager.update(cx, BlinkManager::enable);
19964            self.show_cursor_names(window, cx);
19965            self.buffer.update(cx, |buffer, cx| {
19966                buffer.finalize_last_transaction(cx);
19967                if self.leader_id.is_none() {
19968                    buffer.set_active_selections(
19969                        &self.selections.disjoint_anchors(),
19970                        self.selections.line_mode,
19971                        self.cursor_shape,
19972                        cx,
19973                    );
19974                }
19975            });
19976        }
19977    }
19978
19979    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19980        cx.emit(EditorEvent::FocusedIn)
19981    }
19982
19983    fn handle_focus_out(
19984        &mut self,
19985        event: FocusOutEvent,
19986        _window: &mut Window,
19987        cx: &mut Context<Self>,
19988    ) {
19989        if event.blurred != self.focus_handle {
19990            self.last_focused_descendant = Some(event.blurred);
19991        }
19992        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19993    }
19994
19995    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19996        self.blink_manager.update(cx, BlinkManager::disable);
19997        self.buffer
19998            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19999
20000        if let Some(blame) = self.blame.as_ref() {
20001            blame.update(cx, GitBlame::blur)
20002        }
20003        if !self.hover_state.focused(window, cx) {
20004            hide_hover(self, cx);
20005        }
20006        if !self
20007            .context_menu
20008            .borrow()
20009            .as_ref()
20010            .is_some_and(|context_menu| context_menu.focused(window, cx))
20011        {
20012            self.hide_context_menu(window, cx);
20013        }
20014        self.discard_inline_completion(false, cx);
20015        cx.emit(EditorEvent::Blurred);
20016        cx.notify();
20017    }
20018
20019    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20020        let mut pending: String = window
20021            .pending_input_keystrokes()
20022            .into_iter()
20023            .flatten()
20024            .filter_map(|keystroke| {
20025                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20026                    keystroke.key_char.clone()
20027                } else {
20028                    None
20029                }
20030            })
20031            .collect();
20032
20033        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20034            pending = "".to_string();
20035        }
20036
20037        let existing_pending = self
20038            .text_highlights::<PendingInput>(cx)
20039            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20040        if existing_pending.is_none() && pending.is_empty() {
20041            return;
20042        }
20043        let transaction =
20044            self.transact(window, cx, |this, window, cx| {
20045                let selections = this.selections.all::<usize>(cx);
20046                let edits = selections
20047                    .iter()
20048                    .map(|selection| (selection.end..selection.end, pending.clone()));
20049                this.edit(edits, cx);
20050                this.change_selections(None, window, cx, |s| {
20051                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20052                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20053                    }));
20054                });
20055                if let Some(existing_ranges) = existing_pending {
20056                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20057                    this.edit(edits, cx);
20058                }
20059            });
20060
20061        let snapshot = self.snapshot(window, cx);
20062        let ranges = self
20063            .selections
20064            .all::<usize>(cx)
20065            .into_iter()
20066            .map(|selection| {
20067                snapshot.buffer_snapshot.anchor_after(selection.end)
20068                    ..snapshot
20069                        .buffer_snapshot
20070                        .anchor_before(selection.end + pending.len())
20071            })
20072            .collect();
20073
20074        if pending.is_empty() {
20075            self.clear_highlights::<PendingInput>(cx);
20076        } else {
20077            self.highlight_text::<PendingInput>(
20078                ranges,
20079                HighlightStyle {
20080                    underline: Some(UnderlineStyle {
20081                        thickness: px(1.),
20082                        color: None,
20083                        wavy: false,
20084                    }),
20085                    ..Default::default()
20086                },
20087                cx,
20088            );
20089        }
20090
20091        self.ime_transaction = self.ime_transaction.or(transaction);
20092        if let Some(transaction) = self.ime_transaction {
20093            self.buffer.update(cx, |buffer, cx| {
20094                buffer.group_until_transaction(transaction, cx);
20095            });
20096        }
20097
20098        if self.text_highlights::<PendingInput>(cx).is_none() {
20099            self.ime_transaction.take();
20100        }
20101    }
20102
20103    pub fn register_action_renderer(
20104        &mut self,
20105        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20106    ) -> Subscription {
20107        let id = self.next_editor_action_id.post_inc();
20108        self.editor_actions
20109            .borrow_mut()
20110            .insert(id, Box::new(listener));
20111
20112        let editor_actions = self.editor_actions.clone();
20113        Subscription::new(move || {
20114            editor_actions.borrow_mut().remove(&id);
20115        })
20116    }
20117
20118    pub fn register_action<A: Action>(
20119        &mut self,
20120        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20121    ) -> Subscription {
20122        let id = self.next_editor_action_id.post_inc();
20123        let listener = Arc::new(listener);
20124        self.editor_actions.borrow_mut().insert(
20125            id,
20126            Box::new(move |_, window, _| {
20127                let listener = listener.clone();
20128                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20129                    let action = action.downcast_ref().unwrap();
20130                    if phase == DispatchPhase::Bubble {
20131                        listener(action, window, cx)
20132                    }
20133                })
20134            }),
20135        );
20136
20137        let editor_actions = self.editor_actions.clone();
20138        Subscription::new(move || {
20139            editor_actions.borrow_mut().remove(&id);
20140        })
20141    }
20142
20143    pub fn file_header_size(&self) -> u32 {
20144        FILE_HEADER_HEIGHT
20145    }
20146
20147    pub fn restore(
20148        &mut self,
20149        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20150        window: &mut Window,
20151        cx: &mut Context<Self>,
20152    ) {
20153        let workspace = self.workspace();
20154        let project = self.project.as_ref();
20155        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20156            let mut tasks = Vec::new();
20157            for (buffer_id, changes) in revert_changes {
20158                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20159                    buffer.update(cx, |buffer, cx| {
20160                        buffer.edit(
20161                            changes
20162                                .into_iter()
20163                                .map(|(range, text)| (range, text.to_string())),
20164                            None,
20165                            cx,
20166                        );
20167                    });
20168
20169                    if let Some(project) =
20170                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20171                    {
20172                        project.update(cx, |project, cx| {
20173                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20174                        })
20175                    }
20176                }
20177            }
20178            tasks
20179        });
20180        cx.spawn_in(window, async move |_, cx| {
20181            for (buffer, task) in save_tasks {
20182                let result = task.await;
20183                if result.is_err() {
20184                    let Some(path) = buffer
20185                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20186                        .ok()
20187                    else {
20188                        continue;
20189                    };
20190                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20191                        let Some(task) = cx
20192                            .update_window_entity(&workspace, |workspace, window, cx| {
20193                                workspace
20194                                    .open_path_preview(path, None, false, false, false, window, cx)
20195                            })
20196                            .ok()
20197                        else {
20198                            continue;
20199                        };
20200                        task.await.log_err();
20201                    }
20202                }
20203            }
20204        })
20205        .detach();
20206        self.change_selections(None, window, cx, |selections| selections.refresh());
20207    }
20208
20209    pub fn to_pixel_point(
20210        &self,
20211        source: multi_buffer::Anchor,
20212        editor_snapshot: &EditorSnapshot,
20213        window: &mut Window,
20214    ) -> Option<gpui::Point<Pixels>> {
20215        let source_point = source.to_display_point(editor_snapshot);
20216        self.display_to_pixel_point(source_point, editor_snapshot, window)
20217    }
20218
20219    pub fn display_to_pixel_point(
20220        &self,
20221        source: DisplayPoint,
20222        editor_snapshot: &EditorSnapshot,
20223        window: &mut Window,
20224    ) -> Option<gpui::Point<Pixels>> {
20225        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20226        let text_layout_details = self.text_layout_details(window);
20227        let scroll_top = text_layout_details
20228            .scroll_anchor
20229            .scroll_position(editor_snapshot)
20230            .y;
20231
20232        if source.row().as_f32() < scroll_top.floor() {
20233            return None;
20234        }
20235        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20236        let source_y = line_height * (source.row().as_f32() - scroll_top);
20237        Some(gpui::Point::new(source_x, source_y))
20238    }
20239
20240    pub fn has_visible_completions_menu(&self) -> bool {
20241        !self.edit_prediction_preview_is_active()
20242            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20243                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20244            })
20245    }
20246
20247    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20248        if self.mode.is_minimap() {
20249            return;
20250        }
20251        self.addons
20252            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20253    }
20254
20255    pub fn unregister_addon<T: Addon>(&mut self) {
20256        self.addons.remove(&std::any::TypeId::of::<T>());
20257    }
20258
20259    pub fn addon<T: Addon>(&self) -> Option<&T> {
20260        let type_id = std::any::TypeId::of::<T>();
20261        self.addons
20262            .get(&type_id)
20263            .and_then(|item| item.to_any().downcast_ref::<T>())
20264    }
20265
20266    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20267        let type_id = std::any::TypeId::of::<T>();
20268        self.addons
20269            .get_mut(&type_id)
20270            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20271    }
20272
20273    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20274        let text_layout_details = self.text_layout_details(window);
20275        let style = &text_layout_details.editor_style;
20276        let font_id = window.text_system().resolve_font(&style.text.font());
20277        let font_size = style.text.font_size.to_pixels(window.rem_size());
20278        let line_height = style.text.line_height_in_pixels(window.rem_size());
20279        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20280
20281        gpui::Size::new(em_width, line_height)
20282    }
20283
20284    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20285        self.load_diff_task.clone()
20286    }
20287
20288    fn read_metadata_from_db(
20289        &mut self,
20290        item_id: u64,
20291        workspace_id: WorkspaceId,
20292        window: &mut Window,
20293        cx: &mut Context<Editor>,
20294    ) {
20295        if self.is_singleton(cx)
20296            && !self.mode.is_minimap()
20297            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20298        {
20299            let buffer_snapshot = OnceCell::new();
20300
20301            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20302                if !folds.is_empty() {
20303                    let snapshot =
20304                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20305                    self.fold_ranges(
20306                        folds
20307                            .into_iter()
20308                            .map(|(start, end)| {
20309                                snapshot.clip_offset(start, Bias::Left)
20310                                    ..snapshot.clip_offset(end, Bias::Right)
20311                            })
20312                            .collect(),
20313                        false,
20314                        window,
20315                        cx,
20316                    );
20317                }
20318            }
20319
20320            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20321                if !selections.is_empty() {
20322                    let snapshot =
20323                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20324                    // skip adding the initial selection to selection history
20325                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20326                    self.change_selections(None, window, cx, |s| {
20327                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20328                            snapshot.clip_offset(start, Bias::Left)
20329                                ..snapshot.clip_offset(end, Bias::Right)
20330                        }));
20331                    });
20332                    self.selection_history.mode = SelectionHistoryMode::Normal;
20333                }
20334            };
20335        }
20336
20337        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20338    }
20339
20340    fn update_lsp_data(
20341        &mut self,
20342        ignore_cache: bool,
20343        for_buffer: Option<BufferId>,
20344        window: &mut Window,
20345        cx: &mut Context<'_, Self>,
20346    ) {
20347        self.pull_diagnostics(for_buffer, window, cx);
20348        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20349    }
20350}
20351
20352fn vim_enabled(cx: &App) -> bool {
20353    cx.global::<SettingsStore>()
20354        .raw_user_settings()
20355        .get("vim_mode")
20356        == Some(&serde_json::Value::Bool(true))
20357}
20358
20359fn process_completion_for_edit(
20360    completion: &Completion,
20361    intent: CompletionIntent,
20362    buffer: &Entity<Buffer>,
20363    cursor_position: &text::Anchor,
20364    cx: &mut Context<Editor>,
20365) -> CompletionEdit {
20366    let buffer = buffer.read(cx);
20367    let buffer_snapshot = buffer.snapshot();
20368    let (snippet, new_text) = if completion.is_snippet() {
20369        // Workaround for typescript language server issues so that methods don't expand within
20370        // strings and functions with type expressions. The previous point is used because the query
20371        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20372        let mut snippet_source = completion.new_text.clone();
20373        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20374        previous_point.column = previous_point.column.saturating_sub(1);
20375        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20376            if scope.prefers_label_for_snippet_in_completion() {
20377                if let Some(label) = completion.label() {
20378                    if matches!(
20379                        completion.kind(),
20380                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20381                    ) {
20382                        snippet_source = label;
20383                    }
20384                }
20385            }
20386        }
20387        match Snippet::parse(&snippet_source).log_err() {
20388            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20389            None => (None, completion.new_text.clone()),
20390        }
20391    } else {
20392        (None, completion.new_text.clone())
20393    };
20394
20395    let mut range_to_replace = {
20396        let replace_range = &completion.replace_range;
20397        if let CompletionSource::Lsp {
20398            insert_range: Some(insert_range),
20399            ..
20400        } = &completion.source
20401        {
20402            debug_assert_eq!(
20403                insert_range.start, replace_range.start,
20404                "insert_range and replace_range should start at the same position"
20405            );
20406            debug_assert!(
20407                insert_range
20408                    .start
20409                    .cmp(&cursor_position, &buffer_snapshot)
20410                    .is_le(),
20411                "insert_range should start before or at cursor position"
20412            );
20413            debug_assert!(
20414                replace_range
20415                    .start
20416                    .cmp(&cursor_position, &buffer_snapshot)
20417                    .is_le(),
20418                "replace_range should start before or at cursor position"
20419            );
20420            debug_assert!(
20421                insert_range
20422                    .end
20423                    .cmp(&cursor_position, &buffer_snapshot)
20424                    .is_le(),
20425                "insert_range should end before or at cursor position"
20426            );
20427
20428            let should_replace = match intent {
20429                CompletionIntent::CompleteWithInsert => false,
20430                CompletionIntent::CompleteWithReplace => true,
20431                CompletionIntent::Complete | CompletionIntent::Compose => {
20432                    let insert_mode =
20433                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20434                            .completions
20435                            .lsp_insert_mode;
20436                    match insert_mode {
20437                        LspInsertMode::Insert => false,
20438                        LspInsertMode::Replace => true,
20439                        LspInsertMode::ReplaceSubsequence => {
20440                            let mut text_to_replace = buffer.chars_for_range(
20441                                buffer.anchor_before(replace_range.start)
20442                                    ..buffer.anchor_after(replace_range.end),
20443                            );
20444                            let mut current_needle = text_to_replace.next();
20445                            for haystack_ch in completion.label.text.chars() {
20446                                if let Some(needle_ch) = current_needle {
20447                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20448                                        current_needle = text_to_replace.next();
20449                                    }
20450                                }
20451                            }
20452                            current_needle.is_none()
20453                        }
20454                        LspInsertMode::ReplaceSuffix => {
20455                            if replace_range
20456                                .end
20457                                .cmp(&cursor_position, &buffer_snapshot)
20458                                .is_gt()
20459                            {
20460                                let range_after_cursor = *cursor_position..replace_range.end;
20461                                let text_after_cursor = buffer
20462                                    .text_for_range(
20463                                        buffer.anchor_before(range_after_cursor.start)
20464                                            ..buffer.anchor_after(range_after_cursor.end),
20465                                    )
20466                                    .collect::<String>()
20467                                    .to_ascii_lowercase();
20468                                completion
20469                                    .label
20470                                    .text
20471                                    .to_ascii_lowercase()
20472                                    .ends_with(&text_after_cursor)
20473                            } else {
20474                                true
20475                            }
20476                        }
20477                    }
20478                }
20479            };
20480
20481            if should_replace {
20482                replace_range.clone()
20483            } else {
20484                insert_range.clone()
20485            }
20486        } else {
20487            replace_range.clone()
20488        }
20489    };
20490
20491    if range_to_replace
20492        .end
20493        .cmp(&cursor_position, &buffer_snapshot)
20494        .is_lt()
20495    {
20496        range_to_replace.end = *cursor_position;
20497    }
20498
20499    CompletionEdit {
20500        new_text,
20501        replace_range: range_to_replace.to_offset(&buffer),
20502        snippet,
20503    }
20504}
20505
20506struct CompletionEdit {
20507    new_text: String,
20508    replace_range: Range<usize>,
20509    snippet: Option<Snippet>,
20510}
20511
20512fn insert_extra_newline_brackets(
20513    buffer: &MultiBufferSnapshot,
20514    range: Range<usize>,
20515    language: &language::LanguageScope,
20516) -> bool {
20517    let leading_whitespace_len = buffer
20518        .reversed_chars_at(range.start)
20519        .take_while(|c| c.is_whitespace() && *c != '\n')
20520        .map(|c| c.len_utf8())
20521        .sum::<usize>();
20522    let trailing_whitespace_len = buffer
20523        .chars_at(range.end)
20524        .take_while(|c| c.is_whitespace() && *c != '\n')
20525        .map(|c| c.len_utf8())
20526        .sum::<usize>();
20527    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20528
20529    language.brackets().any(|(pair, enabled)| {
20530        let pair_start = pair.start.trim_end();
20531        let pair_end = pair.end.trim_start();
20532
20533        enabled
20534            && pair.newline
20535            && buffer.contains_str_at(range.end, pair_end)
20536            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20537    })
20538}
20539
20540fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20541    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20542        [(buffer, range, _)] => (*buffer, range.clone()),
20543        _ => return false,
20544    };
20545    let pair = {
20546        let mut result: Option<BracketMatch> = None;
20547
20548        for pair in buffer
20549            .all_bracket_ranges(range.clone())
20550            .filter(move |pair| {
20551                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20552            })
20553        {
20554            let len = pair.close_range.end - pair.open_range.start;
20555
20556            if let Some(existing) = &result {
20557                let existing_len = existing.close_range.end - existing.open_range.start;
20558                if len > existing_len {
20559                    continue;
20560                }
20561            }
20562
20563            result = Some(pair);
20564        }
20565
20566        result
20567    };
20568    let Some(pair) = pair else {
20569        return false;
20570    };
20571    pair.newline_only
20572        && buffer
20573            .chars_for_range(pair.open_range.end..range.start)
20574            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20575            .all(|c| c.is_whitespace() && c != '\n')
20576}
20577
20578fn update_uncommitted_diff_for_buffer(
20579    editor: Entity<Editor>,
20580    project: &Entity<Project>,
20581    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20582    buffer: Entity<MultiBuffer>,
20583    cx: &mut App,
20584) -> Task<()> {
20585    let mut tasks = Vec::new();
20586    project.update(cx, |project, cx| {
20587        for buffer in buffers {
20588            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20589                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20590            }
20591        }
20592    });
20593    cx.spawn(async move |cx| {
20594        let diffs = future::join_all(tasks).await;
20595        if editor
20596            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20597            .unwrap_or(false)
20598        {
20599            return;
20600        }
20601
20602        buffer
20603            .update(cx, |buffer, cx| {
20604                for diff in diffs.into_iter().flatten() {
20605                    buffer.add_diff(diff, cx);
20606                }
20607            })
20608            .ok();
20609    })
20610}
20611
20612fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20613    let tab_size = tab_size.get() as usize;
20614    let mut width = offset;
20615
20616    for ch in text.chars() {
20617        width += if ch == '\t' {
20618            tab_size - (width % tab_size)
20619        } else {
20620            1
20621        };
20622    }
20623
20624    width - offset
20625}
20626
20627#[cfg(test)]
20628mod tests {
20629    use super::*;
20630
20631    #[test]
20632    fn test_string_size_with_expanded_tabs() {
20633        let nz = |val| NonZeroU32::new(val).unwrap();
20634        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20635        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20636        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20637        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20638        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20639        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20640        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20641        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20642    }
20643}
20644
20645/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20646struct WordBreakingTokenizer<'a> {
20647    input: &'a str,
20648}
20649
20650impl<'a> WordBreakingTokenizer<'a> {
20651    fn new(input: &'a str) -> Self {
20652        Self { input }
20653    }
20654}
20655
20656fn is_char_ideographic(ch: char) -> bool {
20657    use unicode_script::Script::*;
20658    use unicode_script::UnicodeScript;
20659    matches!(ch.script(), Han | Tangut | Yi)
20660}
20661
20662fn is_grapheme_ideographic(text: &str) -> bool {
20663    text.chars().any(is_char_ideographic)
20664}
20665
20666fn is_grapheme_whitespace(text: &str) -> bool {
20667    text.chars().any(|x| x.is_whitespace())
20668}
20669
20670fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20671    text.chars().next().map_or(false, |ch| {
20672        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20673    })
20674}
20675
20676#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20677enum WordBreakToken<'a> {
20678    Word { token: &'a str, grapheme_len: usize },
20679    InlineWhitespace { token: &'a str, grapheme_len: usize },
20680    Newline,
20681}
20682
20683impl<'a> Iterator for WordBreakingTokenizer<'a> {
20684    /// Yields a span, the count of graphemes in the token, and whether it was
20685    /// whitespace. Note that it also breaks at word boundaries.
20686    type Item = WordBreakToken<'a>;
20687
20688    fn next(&mut self) -> Option<Self::Item> {
20689        use unicode_segmentation::UnicodeSegmentation;
20690        if self.input.is_empty() {
20691            return None;
20692        }
20693
20694        let mut iter = self.input.graphemes(true).peekable();
20695        let mut offset = 0;
20696        let mut grapheme_len = 0;
20697        if let Some(first_grapheme) = iter.next() {
20698            let is_newline = first_grapheme == "\n";
20699            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20700            offset += first_grapheme.len();
20701            grapheme_len += 1;
20702            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20703                if let Some(grapheme) = iter.peek().copied() {
20704                    if should_stay_with_preceding_ideograph(grapheme) {
20705                        offset += grapheme.len();
20706                        grapheme_len += 1;
20707                    }
20708                }
20709            } else {
20710                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20711                let mut next_word_bound = words.peek().copied();
20712                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20713                    next_word_bound = words.next();
20714                }
20715                while let Some(grapheme) = iter.peek().copied() {
20716                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20717                        break;
20718                    };
20719                    if is_grapheme_whitespace(grapheme) != is_whitespace
20720                        || (grapheme == "\n") != is_newline
20721                    {
20722                        break;
20723                    };
20724                    offset += grapheme.len();
20725                    grapheme_len += 1;
20726                    iter.next();
20727                }
20728            }
20729            let token = &self.input[..offset];
20730            self.input = &self.input[offset..];
20731            if token == "\n" {
20732                Some(WordBreakToken::Newline)
20733            } else if is_whitespace {
20734                Some(WordBreakToken::InlineWhitespace {
20735                    token,
20736                    grapheme_len,
20737                })
20738            } else {
20739                Some(WordBreakToken::Word {
20740                    token,
20741                    grapheme_len,
20742                })
20743            }
20744        } else {
20745            None
20746        }
20747    }
20748}
20749
20750#[test]
20751fn test_word_breaking_tokenizer() {
20752    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20753        ("", &[]),
20754        ("  ", &[whitespace("  ", 2)]),
20755        ("Ʒ", &[word("Ʒ", 1)]),
20756        ("Ǽ", &[word("Ǽ", 1)]),
20757        ("", &[word("", 1)]),
20758        ("⋑⋑", &[word("⋑⋑", 2)]),
20759        (
20760            "原理,进而",
20761            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20762        ),
20763        (
20764            "hello world",
20765            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20766        ),
20767        (
20768            "hello, world",
20769            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20770        ),
20771        (
20772            "  hello world",
20773            &[
20774                whitespace("  ", 2),
20775                word("hello", 5),
20776                whitespace(" ", 1),
20777                word("world", 5),
20778            ],
20779        ),
20780        (
20781            "这是什么 \n 钢笔",
20782            &[
20783                word("", 1),
20784                word("", 1),
20785                word("", 1),
20786                word("", 1),
20787                whitespace(" ", 1),
20788                newline(),
20789                whitespace(" ", 1),
20790                word("", 1),
20791                word("", 1),
20792            ],
20793        ),
20794        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20795    ];
20796
20797    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20798        WordBreakToken::Word {
20799            token,
20800            grapheme_len,
20801        }
20802    }
20803
20804    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20805        WordBreakToken::InlineWhitespace {
20806            token,
20807            grapheme_len,
20808        }
20809    }
20810
20811    fn newline() -> WordBreakToken<'static> {
20812        WordBreakToken::Newline
20813    }
20814
20815    for (input, result) in tests {
20816        assert_eq!(
20817            WordBreakingTokenizer::new(input)
20818                .collect::<Vec<_>>()
20819                .as_slice(),
20820            *result,
20821        );
20822    }
20823}
20824
20825fn wrap_with_prefix(
20826    line_prefix: String,
20827    unwrapped_text: String,
20828    wrap_column: usize,
20829    tab_size: NonZeroU32,
20830    preserve_existing_whitespace: bool,
20831) -> String {
20832    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20833    let mut wrapped_text = String::new();
20834    let mut current_line = line_prefix.clone();
20835
20836    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20837    let mut current_line_len = line_prefix_len;
20838    let mut in_whitespace = false;
20839    for token in tokenizer {
20840        let have_preceding_whitespace = in_whitespace;
20841        match token {
20842            WordBreakToken::Word {
20843                token,
20844                grapheme_len,
20845            } => {
20846                in_whitespace = false;
20847                if current_line_len + grapheme_len > wrap_column
20848                    && current_line_len != line_prefix_len
20849                {
20850                    wrapped_text.push_str(current_line.trim_end());
20851                    wrapped_text.push('\n');
20852                    current_line.truncate(line_prefix.len());
20853                    current_line_len = line_prefix_len;
20854                }
20855                current_line.push_str(token);
20856                current_line_len += grapheme_len;
20857            }
20858            WordBreakToken::InlineWhitespace {
20859                mut token,
20860                mut grapheme_len,
20861            } => {
20862                in_whitespace = true;
20863                if have_preceding_whitespace && !preserve_existing_whitespace {
20864                    continue;
20865                }
20866                if !preserve_existing_whitespace {
20867                    token = " ";
20868                    grapheme_len = 1;
20869                }
20870                if current_line_len + grapheme_len > wrap_column {
20871                    wrapped_text.push_str(current_line.trim_end());
20872                    wrapped_text.push('\n');
20873                    current_line.truncate(line_prefix.len());
20874                    current_line_len = line_prefix_len;
20875                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20876                    current_line.push_str(token);
20877                    current_line_len += grapheme_len;
20878                }
20879            }
20880            WordBreakToken::Newline => {
20881                in_whitespace = true;
20882                if preserve_existing_whitespace {
20883                    wrapped_text.push_str(current_line.trim_end());
20884                    wrapped_text.push('\n');
20885                    current_line.truncate(line_prefix.len());
20886                    current_line_len = line_prefix_len;
20887                } else if have_preceding_whitespace {
20888                    continue;
20889                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20890                {
20891                    wrapped_text.push_str(current_line.trim_end());
20892                    wrapped_text.push('\n');
20893                    current_line.truncate(line_prefix.len());
20894                    current_line_len = line_prefix_len;
20895                } else if current_line_len != line_prefix_len {
20896                    current_line.push(' ');
20897                    current_line_len += 1;
20898                }
20899            }
20900        }
20901    }
20902
20903    if !current_line.is_empty() {
20904        wrapped_text.push_str(&current_line);
20905    }
20906    wrapped_text
20907}
20908
20909#[test]
20910fn test_wrap_with_prefix() {
20911    assert_eq!(
20912        wrap_with_prefix(
20913            "# ".to_string(),
20914            "abcdefg".to_string(),
20915            4,
20916            NonZeroU32::new(4).unwrap(),
20917            false,
20918        ),
20919        "# abcdefg"
20920    );
20921    assert_eq!(
20922        wrap_with_prefix(
20923            "".to_string(),
20924            "\thello world".to_string(),
20925            8,
20926            NonZeroU32::new(4).unwrap(),
20927            false,
20928        ),
20929        "hello\nworld"
20930    );
20931    assert_eq!(
20932        wrap_with_prefix(
20933            "// ".to_string(),
20934            "xx \nyy zz aa bb cc".to_string(),
20935            12,
20936            NonZeroU32::new(4).unwrap(),
20937            false,
20938        ),
20939        "// xx yy zz\n// aa bb cc"
20940    );
20941    assert_eq!(
20942        wrap_with_prefix(
20943            String::new(),
20944            "这是什么 \n 钢笔".to_string(),
20945            3,
20946            NonZeroU32::new(4).unwrap(),
20947            false,
20948        ),
20949        "这是什\n么 钢\n"
20950    );
20951}
20952
20953pub trait CollaborationHub {
20954    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20955    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20956    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20957}
20958
20959impl CollaborationHub for Entity<Project> {
20960    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20961        self.read(cx).collaborators()
20962    }
20963
20964    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20965        self.read(cx).user_store().read(cx).participant_indices()
20966    }
20967
20968    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20969        let this = self.read(cx);
20970        let user_ids = this.collaborators().values().map(|c| c.user_id);
20971        this.user_store().read(cx).participant_names(user_ids, cx)
20972    }
20973}
20974
20975pub trait SemanticsProvider {
20976    fn hover(
20977        &self,
20978        buffer: &Entity<Buffer>,
20979        position: text::Anchor,
20980        cx: &mut App,
20981    ) -> Option<Task<Vec<project::Hover>>>;
20982
20983    fn inline_values(
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 inlay_hints(
20991        &self,
20992        buffer_handle: Entity<Buffer>,
20993        range: Range<text::Anchor>,
20994        cx: &mut App,
20995    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20996
20997    fn resolve_inlay_hint(
20998        &self,
20999        hint: InlayHint,
21000        buffer_handle: Entity<Buffer>,
21001        server_id: LanguageServerId,
21002        cx: &mut App,
21003    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21004
21005    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21006
21007    fn document_highlights(
21008        &self,
21009        buffer: &Entity<Buffer>,
21010        position: text::Anchor,
21011        cx: &mut App,
21012    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21013
21014    fn definitions(
21015        &self,
21016        buffer: &Entity<Buffer>,
21017        position: text::Anchor,
21018        kind: GotoDefinitionKind,
21019        cx: &mut App,
21020    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21021
21022    fn range_for_rename(
21023        &self,
21024        buffer: &Entity<Buffer>,
21025        position: text::Anchor,
21026        cx: &mut App,
21027    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21028
21029    fn perform_rename(
21030        &self,
21031        buffer: &Entity<Buffer>,
21032        position: text::Anchor,
21033        new_name: String,
21034        cx: &mut App,
21035    ) -> Option<Task<Result<ProjectTransaction>>>;
21036}
21037
21038pub trait CompletionProvider {
21039    fn completions(
21040        &self,
21041        excerpt_id: ExcerptId,
21042        buffer: &Entity<Buffer>,
21043        buffer_position: text::Anchor,
21044        trigger: CompletionContext,
21045        window: &mut Window,
21046        cx: &mut Context<Editor>,
21047    ) -> Task<Result<Vec<CompletionResponse>>>;
21048
21049    fn resolve_completions(
21050        &self,
21051        _buffer: Entity<Buffer>,
21052        _completion_indices: Vec<usize>,
21053        _completions: Rc<RefCell<Box<[Completion]>>>,
21054        _cx: &mut Context<Editor>,
21055    ) -> Task<Result<bool>> {
21056        Task::ready(Ok(false))
21057    }
21058
21059    fn apply_additional_edits_for_completion(
21060        &self,
21061        _buffer: Entity<Buffer>,
21062        _completions: Rc<RefCell<Box<[Completion]>>>,
21063        _completion_index: usize,
21064        _push_to_history: bool,
21065        _cx: &mut Context<Editor>,
21066    ) -> Task<Result<Option<language::Transaction>>> {
21067        Task::ready(Ok(None))
21068    }
21069
21070    fn is_completion_trigger(
21071        &self,
21072        buffer: &Entity<Buffer>,
21073        position: language::Anchor,
21074        text: &str,
21075        trigger_in_words: bool,
21076        menu_is_open: bool,
21077        cx: &mut Context<Editor>,
21078    ) -> bool;
21079
21080    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21081
21082    fn sort_completions(&self) -> bool {
21083        true
21084    }
21085
21086    fn filter_completions(&self) -> bool {
21087        true
21088    }
21089}
21090
21091pub trait CodeActionProvider {
21092    fn id(&self) -> Arc<str>;
21093
21094    fn code_actions(
21095        &self,
21096        buffer: &Entity<Buffer>,
21097        range: Range<text::Anchor>,
21098        window: &mut Window,
21099        cx: &mut App,
21100    ) -> Task<Result<Vec<CodeAction>>>;
21101
21102    fn apply_code_action(
21103        &self,
21104        buffer_handle: Entity<Buffer>,
21105        action: CodeAction,
21106        excerpt_id: ExcerptId,
21107        push_to_history: bool,
21108        window: &mut Window,
21109        cx: &mut App,
21110    ) -> Task<Result<ProjectTransaction>>;
21111}
21112
21113impl CodeActionProvider for Entity<Project> {
21114    fn id(&self) -> Arc<str> {
21115        "project".into()
21116    }
21117
21118    fn code_actions(
21119        &self,
21120        buffer: &Entity<Buffer>,
21121        range: Range<text::Anchor>,
21122        _window: &mut Window,
21123        cx: &mut App,
21124    ) -> Task<Result<Vec<CodeAction>>> {
21125        self.update(cx, |project, cx| {
21126            let code_lens = project.code_lens(buffer, range.clone(), cx);
21127            let code_actions = project.code_actions(buffer, range, None, cx);
21128            cx.background_spawn(async move {
21129                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21130                Ok(code_lens
21131                    .context("code lens fetch")?
21132                    .into_iter()
21133                    .chain(code_actions.context("code action fetch")?)
21134                    .collect())
21135            })
21136        })
21137    }
21138
21139    fn apply_code_action(
21140        &self,
21141        buffer_handle: Entity<Buffer>,
21142        action: CodeAction,
21143        _excerpt_id: ExcerptId,
21144        push_to_history: bool,
21145        _window: &mut Window,
21146        cx: &mut App,
21147    ) -> Task<Result<ProjectTransaction>> {
21148        self.update(cx, |project, cx| {
21149            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21150        })
21151    }
21152}
21153
21154fn snippet_completions(
21155    project: &Project,
21156    buffer: &Entity<Buffer>,
21157    buffer_position: text::Anchor,
21158    cx: &mut App,
21159) -> Task<Result<CompletionResponse>> {
21160    let languages = buffer.read(cx).languages_at(buffer_position);
21161    let snippet_store = project.snippets().read(cx);
21162
21163    let scopes: Vec<_> = languages
21164        .iter()
21165        .filter_map(|language| {
21166            let language_name = language.lsp_id();
21167            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21168
21169            if snippets.is_empty() {
21170                None
21171            } else {
21172                Some((language.default_scope(), snippets))
21173            }
21174        })
21175        .collect();
21176
21177    if scopes.is_empty() {
21178        return Task::ready(Ok(CompletionResponse {
21179            completions: vec![],
21180            is_incomplete: false,
21181        }));
21182    }
21183
21184    let snapshot = buffer.read(cx).text_snapshot();
21185    let chars: String = snapshot
21186        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21187        .collect();
21188    let executor = cx.background_executor().clone();
21189
21190    cx.background_spawn(async move {
21191        let mut is_incomplete = false;
21192        let mut completions: Vec<Completion> = Vec::new();
21193        for (scope, snippets) in scopes.into_iter() {
21194            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21195            let mut last_word = chars
21196                .chars()
21197                .take_while(|c| classifier.is_word(*c))
21198                .collect::<String>();
21199            last_word = last_word.chars().rev().collect();
21200
21201            if last_word.is_empty() {
21202                return Ok(CompletionResponse {
21203                    completions: vec![],
21204                    is_incomplete: true,
21205                });
21206            }
21207
21208            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21209            let to_lsp = |point: &text::Anchor| {
21210                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21211                point_to_lsp(end)
21212            };
21213            let lsp_end = to_lsp(&buffer_position);
21214
21215            let candidates = snippets
21216                .iter()
21217                .enumerate()
21218                .flat_map(|(ix, snippet)| {
21219                    snippet
21220                        .prefix
21221                        .iter()
21222                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21223                })
21224                .collect::<Vec<StringMatchCandidate>>();
21225
21226            const MAX_RESULTS: usize = 100;
21227            let mut matches = fuzzy::match_strings(
21228                &candidates,
21229                &last_word,
21230                last_word.chars().any(|c| c.is_uppercase()),
21231                true,
21232                MAX_RESULTS,
21233                &Default::default(),
21234                executor.clone(),
21235            )
21236            .await;
21237
21238            if matches.len() >= MAX_RESULTS {
21239                is_incomplete = true;
21240            }
21241
21242            // Remove all candidates where the query's start does not match the start of any word in the candidate
21243            if let Some(query_start) = last_word.chars().next() {
21244                matches.retain(|string_match| {
21245                    split_words(&string_match.string).any(|word| {
21246                        // Check that the first codepoint of the word as lowercase matches the first
21247                        // codepoint of the query as lowercase
21248                        word.chars()
21249                            .flat_map(|codepoint| codepoint.to_lowercase())
21250                            .zip(query_start.to_lowercase())
21251                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21252                    })
21253                });
21254            }
21255
21256            let matched_strings = matches
21257                .into_iter()
21258                .map(|m| m.string)
21259                .collect::<HashSet<_>>();
21260
21261            completions.extend(snippets.iter().filter_map(|snippet| {
21262                let matching_prefix = snippet
21263                    .prefix
21264                    .iter()
21265                    .find(|prefix| matched_strings.contains(*prefix))?;
21266                let start = as_offset - last_word.len();
21267                let start = snapshot.anchor_before(start);
21268                let range = start..buffer_position;
21269                let lsp_start = to_lsp(&start);
21270                let lsp_range = lsp::Range {
21271                    start: lsp_start,
21272                    end: lsp_end,
21273                };
21274                Some(Completion {
21275                    replace_range: range,
21276                    new_text: snippet.body.clone(),
21277                    source: CompletionSource::Lsp {
21278                        insert_range: None,
21279                        server_id: LanguageServerId(usize::MAX),
21280                        resolved: true,
21281                        lsp_completion: Box::new(lsp::CompletionItem {
21282                            label: snippet.prefix.first().unwrap().clone(),
21283                            kind: Some(CompletionItemKind::SNIPPET),
21284                            label_details: snippet.description.as_ref().map(|description| {
21285                                lsp::CompletionItemLabelDetails {
21286                                    detail: Some(description.clone()),
21287                                    description: None,
21288                                }
21289                            }),
21290                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21291                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21292                                lsp::InsertReplaceEdit {
21293                                    new_text: snippet.body.clone(),
21294                                    insert: lsp_range,
21295                                    replace: lsp_range,
21296                                },
21297                            )),
21298                            filter_text: Some(snippet.body.clone()),
21299                            sort_text: Some(char::MAX.to_string()),
21300                            ..lsp::CompletionItem::default()
21301                        }),
21302                        lsp_defaults: None,
21303                    },
21304                    label: CodeLabel {
21305                        text: matching_prefix.clone(),
21306                        runs: Vec::new(),
21307                        filter_range: 0..matching_prefix.len(),
21308                    },
21309                    icon_path: None,
21310                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21311                        single_line: snippet.name.clone().into(),
21312                        plain_text: snippet
21313                            .description
21314                            .clone()
21315                            .map(|description| description.into()),
21316                    }),
21317                    insert_text_mode: None,
21318                    confirm: None,
21319                })
21320            }))
21321        }
21322
21323        Ok(CompletionResponse {
21324            completions,
21325            is_incomplete,
21326        })
21327    })
21328}
21329
21330impl CompletionProvider for Entity<Project> {
21331    fn completions(
21332        &self,
21333        _excerpt_id: ExcerptId,
21334        buffer: &Entity<Buffer>,
21335        buffer_position: text::Anchor,
21336        options: CompletionContext,
21337        _window: &mut Window,
21338        cx: &mut Context<Editor>,
21339    ) -> Task<Result<Vec<CompletionResponse>>> {
21340        self.update(cx, |project, cx| {
21341            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21342            let project_completions = project.completions(buffer, buffer_position, options, cx);
21343            cx.background_spawn(async move {
21344                let mut responses = project_completions.await?;
21345                let snippets = snippets.await?;
21346                if !snippets.completions.is_empty() {
21347                    responses.push(snippets);
21348                }
21349                Ok(responses)
21350            })
21351        })
21352    }
21353
21354    fn resolve_completions(
21355        &self,
21356        buffer: Entity<Buffer>,
21357        completion_indices: Vec<usize>,
21358        completions: Rc<RefCell<Box<[Completion]>>>,
21359        cx: &mut Context<Editor>,
21360    ) -> Task<Result<bool>> {
21361        self.update(cx, |project, cx| {
21362            project.lsp_store().update(cx, |lsp_store, cx| {
21363                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21364            })
21365        })
21366    }
21367
21368    fn apply_additional_edits_for_completion(
21369        &self,
21370        buffer: Entity<Buffer>,
21371        completions: Rc<RefCell<Box<[Completion]>>>,
21372        completion_index: usize,
21373        push_to_history: bool,
21374        cx: &mut Context<Editor>,
21375    ) -> Task<Result<Option<language::Transaction>>> {
21376        self.update(cx, |project, cx| {
21377            project.lsp_store().update(cx, |lsp_store, cx| {
21378                lsp_store.apply_additional_edits_for_completion(
21379                    buffer,
21380                    completions,
21381                    completion_index,
21382                    push_to_history,
21383                    cx,
21384                )
21385            })
21386        })
21387    }
21388
21389    fn is_completion_trigger(
21390        &self,
21391        buffer: &Entity<Buffer>,
21392        position: language::Anchor,
21393        text: &str,
21394        trigger_in_words: bool,
21395        menu_is_open: bool,
21396        cx: &mut Context<Editor>,
21397    ) -> bool {
21398        let mut chars = text.chars();
21399        let char = if let Some(char) = chars.next() {
21400            char
21401        } else {
21402            return false;
21403        };
21404        if chars.next().is_some() {
21405            return false;
21406        }
21407
21408        let buffer = buffer.read(cx);
21409        let snapshot = buffer.snapshot();
21410        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21411            return false;
21412        }
21413        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21414        if trigger_in_words && classifier.is_word(char) {
21415            return true;
21416        }
21417
21418        buffer.completion_triggers().contains(text)
21419    }
21420}
21421
21422impl SemanticsProvider for Entity<Project> {
21423    fn hover(
21424        &self,
21425        buffer: &Entity<Buffer>,
21426        position: text::Anchor,
21427        cx: &mut App,
21428    ) -> Option<Task<Vec<project::Hover>>> {
21429        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21430    }
21431
21432    fn document_highlights(
21433        &self,
21434        buffer: &Entity<Buffer>,
21435        position: text::Anchor,
21436        cx: &mut App,
21437    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21438        Some(self.update(cx, |project, cx| {
21439            project.document_highlights(buffer, position, cx)
21440        }))
21441    }
21442
21443    fn definitions(
21444        &self,
21445        buffer: &Entity<Buffer>,
21446        position: text::Anchor,
21447        kind: GotoDefinitionKind,
21448        cx: &mut App,
21449    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21450        Some(self.update(cx, |project, cx| match kind {
21451            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21452            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21453            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21454            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21455        }))
21456    }
21457
21458    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21459        // TODO: make this work for remote projects
21460        self.update(cx, |project, cx| {
21461            if project
21462                .active_debug_session(cx)
21463                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21464            {
21465                return true;
21466            }
21467
21468            buffer.update(cx, |buffer, cx| {
21469                project.any_language_server_supports_inlay_hints(buffer, cx)
21470            })
21471        })
21472    }
21473
21474    fn inline_values(
21475        &self,
21476        buffer_handle: Entity<Buffer>,
21477
21478        range: Range<text::Anchor>,
21479        cx: &mut App,
21480    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21481        self.update(cx, |project, cx| {
21482            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21483
21484            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21485        })
21486    }
21487
21488    fn inlay_hints(
21489        &self,
21490        buffer_handle: Entity<Buffer>,
21491        range: Range<text::Anchor>,
21492        cx: &mut App,
21493    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21494        Some(self.update(cx, |project, cx| {
21495            project.inlay_hints(buffer_handle, range, cx)
21496        }))
21497    }
21498
21499    fn resolve_inlay_hint(
21500        &self,
21501        hint: InlayHint,
21502        buffer_handle: Entity<Buffer>,
21503        server_id: LanguageServerId,
21504        cx: &mut App,
21505    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21506        Some(self.update(cx, |project, cx| {
21507            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21508        }))
21509    }
21510
21511    fn range_for_rename(
21512        &self,
21513        buffer: &Entity<Buffer>,
21514        position: text::Anchor,
21515        cx: &mut App,
21516    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21517        Some(self.update(cx, |project, cx| {
21518            let buffer = buffer.clone();
21519            let task = project.prepare_rename(buffer.clone(), position, cx);
21520            cx.spawn(async move |_, cx| {
21521                Ok(match task.await? {
21522                    PrepareRenameResponse::Success(range) => Some(range),
21523                    PrepareRenameResponse::InvalidPosition => None,
21524                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21525                        // Fallback on using TreeSitter info to determine identifier range
21526                        buffer.read_with(cx, |buffer, _| {
21527                            let snapshot = buffer.snapshot();
21528                            let (range, kind) = snapshot.surrounding_word(position);
21529                            if kind != Some(CharKind::Word) {
21530                                return None;
21531                            }
21532                            Some(
21533                                snapshot.anchor_before(range.start)
21534                                    ..snapshot.anchor_after(range.end),
21535                            )
21536                        })?
21537                    }
21538                })
21539            })
21540        }))
21541    }
21542
21543    fn perform_rename(
21544        &self,
21545        buffer: &Entity<Buffer>,
21546        position: text::Anchor,
21547        new_name: String,
21548        cx: &mut App,
21549    ) -> Option<Task<Result<ProjectTransaction>>> {
21550        Some(self.update(cx, |project, cx| {
21551            project.perform_rename(buffer.clone(), position, new_name, cx)
21552        }))
21553    }
21554}
21555
21556fn inlay_hint_settings(
21557    location: Anchor,
21558    snapshot: &MultiBufferSnapshot,
21559    cx: &mut Context<Editor>,
21560) -> InlayHintSettings {
21561    let file = snapshot.file_at(location);
21562    let language = snapshot.language_at(location).map(|l| l.name());
21563    language_settings(language, file, cx).inlay_hints
21564}
21565
21566fn consume_contiguous_rows(
21567    contiguous_row_selections: &mut Vec<Selection<Point>>,
21568    selection: &Selection<Point>,
21569    display_map: &DisplaySnapshot,
21570    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21571) -> (MultiBufferRow, MultiBufferRow) {
21572    contiguous_row_selections.push(selection.clone());
21573    let start_row = MultiBufferRow(selection.start.row);
21574    let mut end_row = ending_row(selection, display_map);
21575
21576    while let Some(next_selection) = selections.peek() {
21577        if next_selection.start.row <= end_row.0 {
21578            end_row = ending_row(next_selection, display_map);
21579            contiguous_row_selections.push(selections.next().unwrap().clone());
21580        } else {
21581            break;
21582        }
21583    }
21584    (start_row, end_row)
21585}
21586
21587fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21588    if next_selection.end.column > 0 || next_selection.is_empty() {
21589        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21590    } else {
21591        MultiBufferRow(next_selection.end.row)
21592    }
21593}
21594
21595impl EditorSnapshot {
21596    pub fn remote_selections_in_range<'a>(
21597        &'a self,
21598        range: &'a Range<Anchor>,
21599        collaboration_hub: &dyn CollaborationHub,
21600        cx: &'a App,
21601    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21602        let participant_names = collaboration_hub.user_names(cx);
21603        let participant_indices = collaboration_hub.user_participant_indices(cx);
21604        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21605        let collaborators_by_replica_id = collaborators_by_peer_id
21606            .values()
21607            .map(|collaborator| (collaborator.replica_id, collaborator))
21608            .collect::<HashMap<_, _>>();
21609        self.buffer_snapshot
21610            .selections_in_range(range, false)
21611            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21612                if replica_id == AGENT_REPLICA_ID {
21613                    Some(RemoteSelection {
21614                        replica_id,
21615                        selection,
21616                        cursor_shape,
21617                        line_mode,
21618                        collaborator_id: CollaboratorId::Agent,
21619                        user_name: Some("Agent".into()),
21620                        color: cx.theme().players().agent(),
21621                    })
21622                } else {
21623                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21624                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21625                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21626                    Some(RemoteSelection {
21627                        replica_id,
21628                        selection,
21629                        cursor_shape,
21630                        line_mode,
21631                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21632                        user_name,
21633                        color: if let Some(index) = participant_index {
21634                            cx.theme().players().color_for_participant(index.0)
21635                        } else {
21636                            cx.theme().players().absent()
21637                        },
21638                    })
21639                }
21640            })
21641    }
21642
21643    pub fn hunks_for_ranges(
21644        &self,
21645        ranges: impl IntoIterator<Item = Range<Point>>,
21646    ) -> Vec<MultiBufferDiffHunk> {
21647        let mut hunks = Vec::new();
21648        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21649            HashMap::default();
21650        for query_range in ranges {
21651            let query_rows =
21652                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21653            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21654                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21655            ) {
21656                // Include deleted hunks that are adjacent to the query range, because
21657                // otherwise they would be missed.
21658                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21659                if hunk.status().is_deleted() {
21660                    intersects_range |= hunk.row_range.start == query_rows.end;
21661                    intersects_range |= hunk.row_range.end == query_rows.start;
21662                }
21663                if intersects_range {
21664                    if !processed_buffer_rows
21665                        .entry(hunk.buffer_id)
21666                        .or_default()
21667                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21668                    {
21669                        continue;
21670                    }
21671                    hunks.push(hunk);
21672                }
21673            }
21674        }
21675
21676        hunks
21677    }
21678
21679    fn display_diff_hunks_for_rows<'a>(
21680        &'a self,
21681        display_rows: Range<DisplayRow>,
21682        folded_buffers: &'a HashSet<BufferId>,
21683    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21684        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21685        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21686
21687        self.buffer_snapshot
21688            .diff_hunks_in_range(buffer_start..buffer_end)
21689            .filter_map(|hunk| {
21690                if folded_buffers.contains(&hunk.buffer_id) {
21691                    return None;
21692                }
21693
21694                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21695                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21696
21697                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21698                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21699
21700                let display_hunk = if hunk_display_start.column() != 0 {
21701                    DisplayDiffHunk::Folded {
21702                        display_row: hunk_display_start.row(),
21703                    }
21704                } else {
21705                    let mut end_row = hunk_display_end.row();
21706                    if hunk_display_end.column() > 0 {
21707                        end_row.0 += 1;
21708                    }
21709                    let is_created_file = hunk.is_created_file();
21710                    DisplayDiffHunk::Unfolded {
21711                        status: hunk.status(),
21712                        diff_base_byte_range: hunk.diff_base_byte_range,
21713                        display_row_range: hunk_display_start.row()..end_row,
21714                        multi_buffer_range: Anchor::range_in_buffer(
21715                            hunk.excerpt_id,
21716                            hunk.buffer_id,
21717                            hunk.buffer_range,
21718                        ),
21719                        is_created_file,
21720                    }
21721                };
21722
21723                Some(display_hunk)
21724            })
21725    }
21726
21727    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21728        self.display_snapshot.buffer_snapshot.language_at(position)
21729    }
21730
21731    pub fn is_focused(&self) -> bool {
21732        self.is_focused
21733    }
21734
21735    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21736        self.placeholder_text.as_ref()
21737    }
21738
21739    pub fn scroll_position(&self) -> gpui::Point<f32> {
21740        self.scroll_anchor.scroll_position(&self.display_snapshot)
21741    }
21742
21743    fn gutter_dimensions(
21744        &self,
21745        font_id: FontId,
21746        font_size: Pixels,
21747        max_line_number_width: Pixels,
21748        cx: &App,
21749    ) -> Option<GutterDimensions> {
21750        if !self.show_gutter {
21751            return None;
21752        }
21753
21754        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21755        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21756
21757        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21758            matches!(
21759                ProjectSettings::get_global(cx).git.git_gutter,
21760                Some(GitGutterSetting::TrackedFiles)
21761            )
21762        });
21763        let gutter_settings = EditorSettings::get_global(cx).gutter;
21764        let show_line_numbers = self
21765            .show_line_numbers
21766            .unwrap_or(gutter_settings.line_numbers);
21767        let line_gutter_width = if show_line_numbers {
21768            // Avoid flicker-like gutter resizes when the line number gains another digit by
21769            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21770            let min_width_for_number_on_gutter =
21771                ch_advance * gutter_settings.min_line_number_digits as f32;
21772            max_line_number_width.max(min_width_for_number_on_gutter)
21773        } else {
21774            0.0.into()
21775        };
21776
21777        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21778        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21779
21780        let git_blame_entries_width =
21781            self.git_blame_gutter_max_author_length
21782                .map(|max_author_length| {
21783                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21784                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21785
21786                    /// The number of characters to dedicate to gaps and margins.
21787                    const SPACING_WIDTH: usize = 4;
21788
21789                    let max_char_count = max_author_length.min(renderer.max_author_length())
21790                        + ::git::SHORT_SHA_LENGTH
21791                        + MAX_RELATIVE_TIMESTAMP.len()
21792                        + SPACING_WIDTH;
21793
21794                    ch_advance * max_char_count
21795                });
21796
21797        let is_singleton = self.buffer_snapshot.is_singleton();
21798
21799        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21800        left_padding += if !is_singleton {
21801            ch_width * 4.0
21802        } else if show_runnables || show_breakpoints {
21803            ch_width * 3.0
21804        } else if show_git_gutter && show_line_numbers {
21805            ch_width * 2.0
21806        } else if show_git_gutter || show_line_numbers {
21807            ch_width
21808        } else {
21809            px(0.)
21810        };
21811
21812        let shows_folds = is_singleton && gutter_settings.folds;
21813
21814        let right_padding = if shows_folds && show_line_numbers {
21815            ch_width * 4.0
21816        } else if shows_folds || (!is_singleton && show_line_numbers) {
21817            ch_width * 3.0
21818        } else if show_line_numbers {
21819            ch_width
21820        } else {
21821            px(0.)
21822        };
21823
21824        Some(GutterDimensions {
21825            left_padding,
21826            right_padding,
21827            width: line_gutter_width + left_padding + right_padding,
21828            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21829            git_blame_entries_width,
21830        })
21831    }
21832
21833    pub fn render_crease_toggle(
21834        &self,
21835        buffer_row: MultiBufferRow,
21836        row_contains_cursor: bool,
21837        editor: Entity<Editor>,
21838        window: &mut Window,
21839        cx: &mut App,
21840    ) -> Option<AnyElement> {
21841        let folded = self.is_line_folded(buffer_row);
21842        let mut is_foldable = false;
21843
21844        if let Some(crease) = self
21845            .crease_snapshot
21846            .query_row(buffer_row, &self.buffer_snapshot)
21847        {
21848            is_foldable = true;
21849            match crease {
21850                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21851                    if let Some(render_toggle) = render_toggle {
21852                        let toggle_callback =
21853                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21854                                if folded {
21855                                    editor.update(cx, |editor, cx| {
21856                                        editor.fold_at(buffer_row, window, cx)
21857                                    });
21858                                } else {
21859                                    editor.update(cx, |editor, cx| {
21860                                        editor.unfold_at(buffer_row, window, cx)
21861                                    });
21862                                }
21863                            });
21864                        return Some((render_toggle)(
21865                            buffer_row,
21866                            folded,
21867                            toggle_callback,
21868                            window,
21869                            cx,
21870                        ));
21871                    }
21872                }
21873            }
21874        }
21875
21876        is_foldable |= self.starts_indent(buffer_row);
21877
21878        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21879            Some(
21880                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21881                    .toggle_state(folded)
21882                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21883                        if folded {
21884                            this.unfold_at(buffer_row, window, cx);
21885                        } else {
21886                            this.fold_at(buffer_row, window, cx);
21887                        }
21888                    }))
21889                    .into_any_element(),
21890            )
21891        } else {
21892            None
21893        }
21894    }
21895
21896    pub fn render_crease_trailer(
21897        &self,
21898        buffer_row: MultiBufferRow,
21899        window: &mut Window,
21900        cx: &mut App,
21901    ) -> Option<AnyElement> {
21902        let folded = self.is_line_folded(buffer_row);
21903        if let Crease::Inline { render_trailer, .. } = self
21904            .crease_snapshot
21905            .query_row(buffer_row, &self.buffer_snapshot)?
21906        {
21907            let render_trailer = render_trailer.as_ref()?;
21908            Some(render_trailer(buffer_row, folded, window, cx))
21909        } else {
21910            None
21911        }
21912    }
21913}
21914
21915impl Deref for EditorSnapshot {
21916    type Target = DisplaySnapshot;
21917
21918    fn deref(&self) -> &Self::Target {
21919        &self.display_snapshot
21920    }
21921}
21922
21923#[derive(Clone, Debug, PartialEq, Eq)]
21924pub enum EditorEvent {
21925    InputIgnored {
21926        text: Arc<str>,
21927    },
21928    InputHandled {
21929        utf16_range_to_replace: Option<Range<isize>>,
21930        text: Arc<str>,
21931    },
21932    ExcerptsAdded {
21933        buffer: Entity<Buffer>,
21934        predecessor: ExcerptId,
21935        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21936    },
21937    ExcerptsRemoved {
21938        ids: Vec<ExcerptId>,
21939        removed_buffer_ids: Vec<BufferId>,
21940    },
21941    BufferFoldToggled {
21942        ids: Vec<ExcerptId>,
21943        folded: bool,
21944    },
21945    ExcerptsEdited {
21946        ids: Vec<ExcerptId>,
21947    },
21948    ExcerptsExpanded {
21949        ids: Vec<ExcerptId>,
21950    },
21951    BufferEdited,
21952    Edited {
21953        transaction_id: clock::Lamport,
21954    },
21955    Reparsed(BufferId),
21956    Focused,
21957    FocusedIn,
21958    Blurred,
21959    DirtyChanged,
21960    Saved,
21961    TitleChanged,
21962    DiffBaseChanged,
21963    SelectionsChanged {
21964        local: bool,
21965    },
21966    ScrollPositionChanged {
21967        local: bool,
21968        autoscroll: bool,
21969    },
21970    Closed,
21971    TransactionUndone {
21972        transaction_id: clock::Lamport,
21973    },
21974    TransactionBegun {
21975        transaction_id: clock::Lamport,
21976    },
21977    Reloaded,
21978    CursorShapeChanged,
21979    PushedToNavHistory {
21980        anchor: Anchor,
21981        is_deactivate: bool,
21982    },
21983}
21984
21985impl EventEmitter<EditorEvent> for Editor {}
21986
21987impl Focusable for Editor {
21988    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21989        self.focus_handle.clone()
21990    }
21991}
21992
21993impl Render for Editor {
21994    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21995        let settings = ThemeSettings::get_global(cx);
21996
21997        let mut text_style = match self.mode {
21998            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21999                color: cx.theme().colors().editor_foreground,
22000                font_family: settings.ui_font.family.clone(),
22001                font_features: settings.ui_font.features.clone(),
22002                font_fallbacks: settings.ui_font.fallbacks.clone(),
22003                font_size: rems(0.875).into(),
22004                font_weight: settings.ui_font.weight,
22005                line_height: relative(settings.buffer_line_height.value()),
22006                ..Default::default()
22007            },
22008            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22009                color: cx.theme().colors().editor_foreground,
22010                font_family: settings.buffer_font.family.clone(),
22011                font_features: settings.buffer_font.features.clone(),
22012                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22013                font_size: settings.buffer_font_size(cx).into(),
22014                font_weight: settings.buffer_font.weight,
22015                line_height: relative(settings.buffer_line_height.value()),
22016                ..Default::default()
22017            },
22018        };
22019        if let Some(text_style_refinement) = &self.text_style_refinement {
22020            text_style.refine(text_style_refinement)
22021        }
22022
22023        let background = match self.mode {
22024            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22025            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22026            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22027            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22028        };
22029
22030        EditorElement::new(
22031            &cx.entity(),
22032            EditorStyle {
22033                background,
22034                local_player: cx.theme().players().local(),
22035                text: text_style,
22036                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22037                syntax: cx.theme().syntax().clone(),
22038                status: cx.theme().status().clone(),
22039                inlay_hints_style: make_inlay_hints_style(cx),
22040                inline_completion_styles: make_suggestion_styles(cx),
22041                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22042                show_underlines: !self.mode.is_minimap(),
22043            },
22044        )
22045    }
22046}
22047
22048impl EntityInputHandler for Editor {
22049    fn text_for_range(
22050        &mut self,
22051        range_utf16: Range<usize>,
22052        adjusted_range: &mut Option<Range<usize>>,
22053        _: &mut Window,
22054        cx: &mut Context<Self>,
22055    ) -> Option<String> {
22056        let snapshot = self.buffer.read(cx).read(cx);
22057        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22058        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22059        if (start.0..end.0) != range_utf16 {
22060            adjusted_range.replace(start.0..end.0);
22061        }
22062        Some(snapshot.text_for_range(start..end).collect())
22063    }
22064
22065    fn selected_text_range(
22066        &mut self,
22067        ignore_disabled_input: bool,
22068        _: &mut Window,
22069        cx: &mut Context<Self>,
22070    ) -> Option<UTF16Selection> {
22071        // Prevent the IME menu from appearing when holding down an alphabetic key
22072        // while input is disabled.
22073        if !ignore_disabled_input && !self.input_enabled {
22074            return None;
22075        }
22076
22077        let selection = self.selections.newest::<OffsetUtf16>(cx);
22078        let range = selection.range();
22079
22080        Some(UTF16Selection {
22081            range: range.start.0..range.end.0,
22082            reversed: selection.reversed,
22083        })
22084    }
22085
22086    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22087        let snapshot = self.buffer.read(cx).read(cx);
22088        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22089        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22090    }
22091
22092    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22093        self.clear_highlights::<InputComposition>(cx);
22094        self.ime_transaction.take();
22095    }
22096
22097    fn replace_text_in_range(
22098        &mut self,
22099        range_utf16: Option<Range<usize>>,
22100        text: &str,
22101        window: &mut Window,
22102        cx: &mut Context<Self>,
22103    ) {
22104        if !self.input_enabled {
22105            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22106            return;
22107        }
22108
22109        self.transact(window, cx, |this, window, cx| {
22110            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22111                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22112                Some(this.selection_replacement_ranges(range_utf16, cx))
22113            } else {
22114                this.marked_text_ranges(cx)
22115            };
22116
22117            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22118                let newest_selection_id = this.selections.newest_anchor().id;
22119                this.selections
22120                    .all::<OffsetUtf16>(cx)
22121                    .iter()
22122                    .zip(ranges_to_replace.iter())
22123                    .find_map(|(selection, range)| {
22124                        if selection.id == newest_selection_id {
22125                            Some(
22126                                (range.start.0 as isize - selection.head().0 as isize)
22127                                    ..(range.end.0 as isize - selection.head().0 as isize),
22128                            )
22129                        } else {
22130                            None
22131                        }
22132                    })
22133            });
22134
22135            cx.emit(EditorEvent::InputHandled {
22136                utf16_range_to_replace: range_to_replace,
22137                text: text.into(),
22138            });
22139
22140            if let Some(new_selected_ranges) = new_selected_ranges {
22141                this.change_selections(None, window, cx, |selections| {
22142                    selections.select_ranges(new_selected_ranges)
22143                });
22144                this.backspace(&Default::default(), window, cx);
22145            }
22146
22147            this.handle_input(text, window, cx);
22148        });
22149
22150        if let Some(transaction) = self.ime_transaction {
22151            self.buffer.update(cx, |buffer, cx| {
22152                buffer.group_until_transaction(transaction, cx);
22153            });
22154        }
22155
22156        self.unmark_text(window, cx);
22157    }
22158
22159    fn replace_and_mark_text_in_range(
22160        &mut self,
22161        range_utf16: Option<Range<usize>>,
22162        text: &str,
22163        new_selected_range_utf16: Option<Range<usize>>,
22164        window: &mut Window,
22165        cx: &mut Context<Self>,
22166    ) {
22167        if !self.input_enabled {
22168            return;
22169        }
22170
22171        let transaction = self.transact(window, cx, |this, window, cx| {
22172            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22173                let snapshot = this.buffer.read(cx).read(cx);
22174                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22175                    for marked_range in &mut marked_ranges {
22176                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22177                        marked_range.start.0 += relative_range_utf16.start;
22178                        marked_range.start =
22179                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22180                        marked_range.end =
22181                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22182                    }
22183                }
22184                Some(marked_ranges)
22185            } else if let Some(range_utf16) = range_utf16 {
22186                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22187                Some(this.selection_replacement_ranges(range_utf16, cx))
22188            } else {
22189                None
22190            };
22191
22192            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22193                let newest_selection_id = this.selections.newest_anchor().id;
22194                this.selections
22195                    .all::<OffsetUtf16>(cx)
22196                    .iter()
22197                    .zip(ranges_to_replace.iter())
22198                    .find_map(|(selection, range)| {
22199                        if selection.id == newest_selection_id {
22200                            Some(
22201                                (range.start.0 as isize - selection.head().0 as isize)
22202                                    ..(range.end.0 as isize - selection.head().0 as isize),
22203                            )
22204                        } else {
22205                            None
22206                        }
22207                    })
22208            });
22209
22210            cx.emit(EditorEvent::InputHandled {
22211                utf16_range_to_replace: range_to_replace,
22212                text: text.into(),
22213            });
22214
22215            if let Some(ranges) = ranges_to_replace {
22216                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22217            }
22218
22219            let marked_ranges = {
22220                let snapshot = this.buffer.read(cx).read(cx);
22221                this.selections
22222                    .disjoint_anchors()
22223                    .iter()
22224                    .map(|selection| {
22225                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22226                    })
22227                    .collect::<Vec<_>>()
22228            };
22229
22230            if text.is_empty() {
22231                this.unmark_text(window, cx);
22232            } else {
22233                this.highlight_text::<InputComposition>(
22234                    marked_ranges.clone(),
22235                    HighlightStyle {
22236                        underline: Some(UnderlineStyle {
22237                            thickness: px(1.),
22238                            color: None,
22239                            wavy: false,
22240                        }),
22241                        ..Default::default()
22242                    },
22243                    cx,
22244                );
22245            }
22246
22247            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22248            let use_autoclose = this.use_autoclose;
22249            let use_auto_surround = this.use_auto_surround;
22250            this.set_use_autoclose(false);
22251            this.set_use_auto_surround(false);
22252            this.handle_input(text, window, cx);
22253            this.set_use_autoclose(use_autoclose);
22254            this.set_use_auto_surround(use_auto_surround);
22255
22256            if let Some(new_selected_range) = new_selected_range_utf16 {
22257                let snapshot = this.buffer.read(cx).read(cx);
22258                let new_selected_ranges = marked_ranges
22259                    .into_iter()
22260                    .map(|marked_range| {
22261                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22262                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22263                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22264                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22265                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22266                    })
22267                    .collect::<Vec<_>>();
22268
22269                drop(snapshot);
22270                this.change_selections(None, window, cx, |selections| {
22271                    selections.select_ranges(new_selected_ranges)
22272                });
22273            }
22274        });
22275
22276        self.ime_transaction = self.ime_transaction.or(transaction);
22277        if let Some(transaction) = self.ime_transaction {
22278            self.buffer.update(cx, |buffer, cx| {
22279                buffer.group_until_transaction(transaction, cx);
22280            });
22281        }
22282
22283        if self.text_highlights::<InputComposition>(cx).is_none() {
22284            self.ime_transaction.take();
22285        }
22286    }
22287
22288    fn bounds_for_range(
22289        &mut self,
22290        range_utf16: Range<usize>,
22291        element_bounds: gpui::Bounds<Pixels>,
22292        window: &mut Window,
22293        cx: &mut Context<Self>,
22294    ) -> Option<gpui::Bounds<Pixels>> {
22295        let text_layout_details = self.text_layout_details(window);
22296        let gpui::Size {
22297            width: em_width,
22298            height: line_height,
22299        } = self.character_size(window);
22300
22301        let snapshot = self.snapshot(window, cx);
22302        let scroll_position = snapshot.scroll_position();
22303        let scroll_left = scroll_position.x * em_width;
22304
22305        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22306        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22307            + self.gutter_dimensions.width
22308            + self.gutter_dimensions.margin;
22309        let y = line_height * (start.row().as_f32() - scroll_position.y);
22310
22311        Some(Bounds {
22312            origin: element_bounds.origin + point(x, y),
22313            size: size(em_width, line_height),
22314        })
22315    }
22316
22317    fn character_index_for_point(
22318        &mut self,
22319        point: gpui::Point<Pixels>,
22320        _window: &mut Window,
22321        _cx: &mut Context<Self>,
22322    ) -> Option<usize> {
22323        let position_map = self.last_position_map.as_ref()?;
22324        if !position_map.text_hitbox.contains(&point) {
22325            return None;
22326        }
22327        let display_point = position_map.point_for_position(point).previous_valid;
22328        let anchor = position_map
22329            .snapshot
22330            .display_point_to_anchor(display_point, Bias::Left);
22331        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22332        Some(utf16_offset.0)
22333    }
22334}
22335
22336trait SelectionExt {
22337    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22338    fn spanned_rows(
22339        &self,
22340        include_end_if_at_line_start: bool,
22341        map: &DisplaySnapshot,
22342    ) -> Range<MultiBufferRow>;
22343}
22344
22345impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22346    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22347        let start = self
22348            .start
22349            .to_point(&map.buffer_snapshot)
22350            .to_display_point(map);
22351        let end = self
22352            .end
22353            .to_point(&map.buffer_snapshot)
22354            .to_display_point(map);
22355        if self.reversed {
22356            end..start
22357        } else {
22358            start..end
22359        }
22360    }
22361
22362    fn spanned_rows(
22363        &self,
22364        include_end_if_at_line_start: bool,
22365        map: &DisplaySnapshot,
22366    ) -> Range<MultiBufferRow> {
22367        let start = self.start.to_point(&map.buffer_snapshot);
22368        let mut end = self.end.to_point(&map.buffer_snapshot);
22369        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22370            end.row -= 1;
22371        }
22372
22373        let buffer_start = map.prev_line_boundary(start).0;
22374        let buffer_end = map.next_line_boundary(end).0;
22375        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22376    }
22377}
22378
22379impl<T: InvalidationRegion> InvalidationStack<T> {
22380    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22381    where
22382        S: Clone + ToOffset,
22383    {
22384        while let Some(region) = self.last() {
22385            let all_selections_inside_invalidation_ranges =
22386                if selections.len() == region.ranges().len() {
22387                    selections
22388                        .iter()
22389                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22390                        .all(|(selection, invalidation_range)| {
22391                            let head = selection.head().to_offset(buffer);
22392                            invalidation_range.start <= head && invalidation_range.end >= head
22393                        })
22394                } else {
22395                    false
22396                };
22397
22398            if all_selections_inside_invalidation_ranges {
22399                break;
22400            } else {
22401                self.pop();
22402            }
22403        }
22404    }
22405}
22406
22407impl<T> Default for InvalidationStack<T> {
22408    fn default() -> Self {
22409        Self(Default::default())
22410    }
22411}
22412
22413impl<T> Deref for InvalidationStack<T> {
22414    type Target = Vec<T>;
22415
22416    fn deref(&self) -> &Self::Target {
22417        &self.0
22418    }
22419}
22420
22421impl<T> DerefMut for InvalidationStack<T> {
22422    fn deref_mut(&mut self) -> &mut Self::Target {
22423        &mut self.0
22424    }
22425}
22426
22427impl InvalidationRegion for SnippetState {
22428    fn ranges(&self) -> &[Range<Anchor>] {
22429        &self.ranges[self.active_index]
22430    }
22431}
22432
22433fn inline_completion_edit_text(
22434    current_snapshot: &BufferSnapshot,
22435    edits: &[(Range<Anchor>, String)],
22436    edit_preview: &EditPreview,
22437    include_deletions: bool,
22438    cx: &App,
22439) -> HighlightedText {
22440    let edits = edits
22441        .iter()
22442        .map(|(anchor, text)| {
22443            (
22444                anchor.start.text_anchor..anchor.end.text_anchor,
22445                text.clone(),
22446            )
22447        })
22448        .collect::<Vec<_>>();
22449
22450    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22451}
22452
22453pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22454    match severity {
22455        lsp::DiagnosticSeverity::ERROR => colors.error,
22456        lsp::DiagnosticSeverity::WARNING => colors.warning,
22457        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22458        lsp::DiagnosticSeverity::HINT => colors.info,
22459        _ => colors.ignored,
22460    }
22461}
22462
22463pub fn styled_runs_for_code_label<'a>(
22464    label: &'a CodeLabel,
22465    syntax_theme: &'a theme::SyntaxTheme,
22466) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22467    let fade_out = HighlightStyle {
22468        fade_out: Some(0.35),
22469        ..Default::default()
22470    };
22471
22472    let mut prev_end = label.filter_range.end;
22473    label
22474        .runs
22475        .iter()
22476        .enumerate()
22477        .flat_map(move |(ix, (range, highlight_id))| {
22478            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22479                style
22480            } else {
22481                return Default::default();
22482            };
22483            let mut muted_style = style;
22484            muted_style.highlight(fade_out);
22485
22486            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22487            if range.start >= label.filter_range.end {
22488                if range.start > prev_end {
22489                    runs.push((prev_end..range.start, fade_out));
22490                }
22491                runs.push((range.clone(), muted_style));
22492            } else if range.end <= label.filter_range.end {
22493                runs.push((range.clone(), style));
22494            } else {
22495                runs.push((range.start..label.filter_range.end, style));
22496                runs.push((label.filter_range.end..range.end, muted_style));
22497            }
22498            prev_end = cmp::max(prev_end, range.end);
22499
22500            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22501                runs.push((prev_end..label.text.len(), fade_out));
22502            }
22503
22504            runs
22505        })
22506}
22507
22508pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22509    let mut prev_index = 0;
22510    let mut prev_codepoint: Option<char> = None;
22511    text.char_indices()
22512        .chain([(text.len(), '\0')])
22513        .filter_map(move |(index, codepoint)| {
22514            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22515            let is_boundary = index == text.len()
22516                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22517                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22518            if is_boundary {
22519                let chunk = &text[prev_index..index];
22520                prev_index = index;
22521                Some(chunk)
22522            } else {
22523                None
22524            }
22525        })
22526}
22527
22528pub trait RangeToAnchorExt: Sized {
22529    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22530
22531    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22532        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22533        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22534    }
22535}
22536
22537impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22538    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22539        let start_offset = self.start.to_offset(snapshot);
22540        let end_offset = self.end.to_offset(snapshot);
22541        if start_offset == end_offset {
22542            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22543        } else {
22544            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22545        }
22546    }
22547}
22548
22549pub trait RowExt {
22550    fn as_f32(&self) -> f32;
22551
22552    fn next_row(&self) -> Self;
22553
22554    fn previous_row(&self) -> Self;
22555
22556    fn minus(&self, other: Self) -> u32;
22557}
22558
22559impl RowExt for DisplayRow {
22560    fn as_f32(&self) -> f32 {
22561        self.0 as f32
22562    }
22563
22564    fn next_row(&self) -> Self {
22565        Self(self.0 + 1)
22566    }
22567
22568    fn previous_row(&self) -> Self {
22569        Self(self.0.saturating_sub(1))
22570    }
22571
22572    fn minus(&self, other: Self) -> u32 {
22573        self.0 - other.0
22574    }
22575}
22576
22577impl RowExt for MultiBufferRow {
22578    fn as_f32(&self) -> f32 {
22579        self.0 as f32
22580    }
22581
22582    fn next_row(&self) -> Self {
22583        Self(self.0 + 1)
22584    }
22585
22586    fn previous_row(&self) -> Self {
22587        Self(self.0.saturating_sub(1))
22588    }
22589
22590    fn minus(&self, other: Self) -> u32 {
22591        self.0 - other.0
22592    }
22593}
22594
22595trait RowRangeExt {
22596    type Row;
22597
22598    fn len(&self) -> usize;
22599
22600    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22601}
22602
22603impl RowRangeExt for Range<MultiBufferRow> {
22604    type Row = MultiBufferRow;
22605
22606    fn len(&self) -> usize {
22607        (self.end.0 - self.start.0) as usize
22608    }
22609
22610    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22611        (self.start.0..self.end.0).map(MultiBufferRow)
22612    }
22613}
22614
22615impl RowRangeExt for Range<DisplayRow> {
22616    type Row = DisplayRow;
22617
22618    fn len(&self) -> usize {
22619        (self.end.0 - self.start.0) as usize
22620    }
22621
22622    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22623        (self.start.0..self.end.0).map(DisplayRow)
22624    }
22625}
22626
22627/// If select range has more than one line, we
22628/// just point the cursor to range.start.
22629fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22630    if range.start.row == range.end.row {
22631        range
22632    } else {
22633        range.start..range.start
22634    }
22635}
22636pub struct KillRing(ClipboardItem);
22637impl Global for KillRing {}
22638
22639const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22640
22641enum BreakpointPromptEditAction {
22642    Log,
22643    Condition,
22644    HitCondition,
22645}
22646
22647struct BreakpointPromptEditor {
22648    pub(crate) prompt: Entity<Editor>,
22649    editor: WeakEntity<Editor>,
22650    breakpoint_anchor: Anchor,
22651    breakpoint: Breakpoint,
22652    edit_action: BreakpointPromptEditAction,
22653    block_ids: HashSet<CustomBlockId>,
22654    editor_margins: Arc<Mutex<EditorMargins>>,
22655    _subscriptions: Vec<Subscription>,
22656}
22657
22658impl BreakpointPromptEditor {
22659    const MAX_LINES: u8 = 4;
22660
22661    fn new(
22662        editor: WeakEntity<Editor>,
22663        breakpoint_anchor: Anchor,
22664        breakpoint: Breakpoint,
22665        edit_action: BreakpointPromptEditAction,
22666        window: &mut Window,
22667        cx: &mut Context<Self>,
22668    ) -> Self {
22669        let base_text = match edit_action {
22670            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22671            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22672            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22673        }
22674        .map(|msg| msg.to_string())
22675        .unwrap_or_default();
22676
22677        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22678        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22679
22680        let prompt = cx.new(|cx| {
22681            let mut prompt = Editor::new(
22682                EditorMode::AutoHeight {
22683                    min_lines: 1,
22684                    max_lines: Self::MAX_LINES as usize,
22685                },
22686                buffer,
22687                None,
22688                window,
22689                cx,
22690            );
22691            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22692            prompt.set_show_cursor_when_unfocused(false, cx);
22693            prompt.set_placeholder_text(
22694                match edit_action {
22695                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22696                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22697                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22698                },
22699                cx,
22700            );
22701
22702            prompt
22703        });
22704
22705        Self {
22706            prompt,
22707            editor,
22708            breakpoint_anchor,
22709            breakpoint,
22710            edit_action,
22711            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22712            block_ids: Default::default(),
22713            _subscriptions: vec![],
22714        }
22715    }
22716
22717    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22718        self.block_ids.extend(block_ids)
22719    }
22720
22721    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22722        if let Some(editor) = self.editor.upgrade() {
22723            let message = self
22724                .prompt
22725                .read(cx)
22726                .buffer
22727                .read(cx)
22728                .as_singleton()
22729                .expect("A multi buffer in breakpoint prompt isn't possible")
22730                .read(cx)
22731                .as_rope()
22732                .to_string();
22733
22734            editor.update(cx, |editor, cx| {
22735                editor.edit_breakpoint_at_anchor(
22736                    self.breakpoint_anchor,
22737                    self.breakpoint.clone(),
22738                    match self.edit_action {
22739                        BreakpointPromptEditAction::Log => {
22740                            BreakpointEditAction::EditLogMessage(message.into())
22741                        }
22742                        BreakpointPromptEditAction::Condition => {
22743                            BreakpointEditAction::EditCondition(message.into())
22744                        }
22745                        BreakpointPromptEditAction::HitCondition => {
22746                            BreakpointEditAction::EditHitCondition(message.into())
22747                        }
22748                    },
22749                    cx,
22750                );
22751
22752                editor.remove_blocks(self.block_ids.clone(), None, cx);
22753                cx.focus_self(window);
22754            });
22755        }
22756    }
22757
22758    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22759        self.editor
22760            .update(cx, |editor, cx| {
22761                editor.remove_blocks(self.block_ids.clone(), None, cx);
22762                window.focus(&editor.focus_handle);
22763            })
22764            .log_err();
22765    }
22766
22767    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22768        let settings = ThemeSettings::get_global(cx);
22769        let text_style = TextStyle {
22770            color: if self.prompt.read(cx).read_only(cx) {
22771                cx.theme().colors().text_disabled
22772            } else {
22773                cx.theme().colors().text
22774            },
22775            font_family: settings.buffer_font.family.clone(),
22776            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22777            font_size: settings.buffer_font_size(cx).into(),
22778            font_weight: settings.buffer_font.weight,
22779            line_height: relative(settings.buffer_line_height.value()),
22780            ..Default::default()
22781        };
22782        EditorElement::new(
22783            &self.prompt,
22784            EditorStyle {
22785                background: cx.theme().colors().editor_background,
22786                local_player: cx.theme().players().local(),
22787                text: text_style,
22788                ..Default::default()
22789            },
22790        )
22791    }
22792}
22793
22794impl Render for BreakpointPromptEditor {
22795    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22796        let editor_margins = *self.editor_margins.lock();
22797        let gutter_dimensions = editor_margins.gutter;
22798        h_flex()
22799            .key_context("Editor")
22800            .bg(cx.theme().colors().editor_background)
22801            .border_y_1()
22802            .border_color(cx.theme().status().info_border)
22803            .size_full()
22804            .py(window.line_height() / 2.5)
22805            .on_action(cx.listener(Self::confirm))
22806            .on_action(cx.listener(Self::cancel))
22807            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22808            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22809    }
22810}
22811
22812impl Focusable for BreakpointPromptEditor {
22813    fn focus_handle(&self, cx: &App) -> FocusHandle {
22814        self.prompt.focus_handle(cx)
22815    }
22816}
22817
22818fn all_edits_insertions_or_deletions(
22819    edits: &Vec<(Range<Anchor>, String)>,
22820    snapshot: &MultiBufferSnapshot,
22821) -> bool {
22822    let mut all_insertions = true;
22823    let mut all_deletions = true;
22824
22825    for (range, new_text) in edits.iter() {
22826        let range_is_empty = range.to_offset(&snapshot).is_empty();
22827        let text_is_empty = new_text.is_empty();
22828
22829        if range_is_empty != text_is_empty {
22830            if range_is_empty {
22831                all_deletions = false;
22832            } else {
22833                all_insertions = false;
22834            }
22835        } else {
22836            return false;
22837        }
22838
22839        if !all_insertions && !all_deletions {
22840            return false;
22841        }
22842    }
22843    all_insertions || all_deletions
22844}
22845
22846struct MissingEditPredictionKeybindingTooltip;
22847
22848impl Render for MissingEditPredictionKeybindingTooltip {
22849    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22850        ui::tooltip_container(window, cx, |container, _, cx| {
22851            container
22852                .flex_shrink_0()
22853                .max_w_80()
22854                .min_h(rems_from_px(124.))
22855                .justify_between()
22856                .child(
22857                    v_flex()
22858                        .flex_1()
22859                        .text_ui_sm(cx)
22860                        .child(Label::new("Conflict with Accept Keybinding"))
22861                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22862                )
22863                .child(
22864                    h_flex()
22865                        .pb_1()
22866                        .gap_1()
22867                        .items_end()
22868                        .w_full()
22869                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22870                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22871                        }))
22872                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22873                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22874                        })),
22875                )
22876        })
22877    }
22878}
22879
22880#[derive(Debug, Clone, Copy, PartialEq)]
22881pub struct LineHighlight {
22882    pub background: Background,
22883    pub border: Option<gpui::Hsla>,
22884    pub include_gutter: bool,
22885    pub type_id: Option<TypeId>,
22886}
22887
22888fn render_diff_hunk_controls(
22889    row: u32,
22890    status: &DiffHunkStatus,
22891    hunk_range: Range<Anchor>,
22892    is_created_file: bool,
22893    line_height: Pixels,
22894    editor: &Entity<Editor>,
22895    _window: &mut Window,
22896    cx: &mut App,
22897) -> AnyElement {
22898    h_flex()
22899        .h(line_height)
22900        .mr_1()
22901        .gap_1()
22902        .px_0p5()
22903        .pb_1()
22904        .border_x_1()
22905        .border_b_1()
22906        .border_color(cx.theme().colors().border_variant)
22907        .rounded_b_lg()
22908        .bg(cx.theme().colors().editor_background)
22909        .gap_1()
22910        .block_mouse_except_scroll()
22911        .shadow_md()
22912        .child(if status.has_secondary_hunk() {
22913            Button::new(("stage", row as u64), "Stage")
22914                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22915                .tooltip({
22916                    let focus_handle = editor.focus_handle(cx);
22917                    move |window, cx| {
22918                        Tooltip::for_action_in(
22919                            "Stage Hunk",
22920                            &::git::ToggleStaged,
22921                            &focus_handle,
22922                            window,
22923                            cx,
22924                        )
22925                    }
22926                })
22927                .on_click({
22928                    let editor = editor.clone();
22929                    move |_event, _window, cx| {
22930                        editor.update(cx, |editor, cx| {
22931                            editor.stage_or_unstage_diff_hunks(
22932                                true,
22933                                vec![hunk_range.start..hunk_range.start],
22934                                cx,
22935                            );
22936                        });
22937                    }
22938                })
22939        } else {
22940            Button::new(("unstage", row as u64), "Unstage")
22941                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22942                .tooltip({
22943                    let focus_handle = editor.focus_handle(cx);
22944                    move |window, cx| {
22945                        Tooltip::for_action_in(
22946                            "Unstage Hunk",
22947                            &::git::ToggleStaged,
22948                            &focus_handle,
22949                            window,
22950                            cx,
22951                        )
22952                    }
22953                })
22954                .on_click({
22955                    let editor = editor.clone();
22956                    move |_event, _window, cx| {
22957                        editor.update(cx, |editor, cx| {
22958                            editor.stage_or_unstage_diff_hunks(
22959                                false,
22960                                vec![hunk_range.start..hunk_range.start],
22961                                cx,
22962                            );
22963                        });
22964                    }
22965                })
22966        })
22967        .child(
22968            Button::new(("restore", row as u64), "Restore")
22969                .tooltip({
22970                    let focus_handle = editor.focus_handle(cx);
22971                    move |window, cx| {
22972                        Tooltip::for_action_in(
22973                            "Restore Hunk",
22974                            &::git::Restore,
22975                            &focus_handle,
22976                            window,
22977                            cx,
22978                        )
22979                    }
22980                })
22981                .on_click({
22982                    let editor = editor.clone();
22983                    move |_event, window, cx| {
22984                        editor.update(cx, |editor, cx| {
22985                            let snapshot = editor.snapshot(window, cx);
22986                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22987                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22988                        });
22989                    }
22990                })
22991                .disabled(is_created_file),
22992        )
22993        .when(
22994            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22995            |el| {
22996                el.child(
22997                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22998                        .shape(IconButtonShape::Square)
22999                        .icon_size(IconSize::Small)
23000                        // .disabled(!has_multiple_hunks)
23001                        .tooltip({
23002                            let focus_handle = editor.focus_handle(cx);
23003                            move |window, cx| {
23004                                Tooltip::for_action_in(
23005                                    "Next Hunk",
23006                                    &GoToHunk,
23007                                    &focus_handle,
23008                                    window,
23009                                    cx,
23010                                )
23011                            }
23012                        })
23013                        .on_click({
23014                            let editor = editor.clone();
23015                            move |_event, window, cx| {
23016                                editor.update(cx, |editor, cx| {
23017                                    let snapshot = editor.snapshot(window, cx);
23018                                    let position =
23019                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23020                                    editor.go_to_hunk_before_or_after_position(
23021                                        &snapshot,
23022                                        position,
23023                                        Direction::Next,
23024                                        window,
23025                                        cx,
23026                                    );
23027                                    editor.expand_selected_diff_hunks(cx);
23028                                });
23029                            }
23030                        }),
23031                )
23032                .child(
23033                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23034                        .shape(IconButtonShape::Square)
23035                        .icon_size(IconSize::Small)
23036                        // .disabled(!has_multiple_hunks)
23037                        .tooltip({
23038                            let focus_handle = editor.focus_handle(cx);
23039                            move |window, cx| {
23040                                Tooltip::for_action_in(
23041                                    "Previous Hunk",
23042                                    &GoToPreviousHunk,
23043                                    &focus_handle,
23044                                    window,
23045                                    cx,
23046                                )
23047                            }
23048                        })
23049                        .on_click({
23050                            let editor = editor.clone();
23051                            move |_event, window, cx| {
23052                                editor.update(cx, |editor, cx| {
23053                                    let snapshot = editor.snapshot(window, cx);
23054                                    let point =
23055                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23056                                    editor.go_to_hunk_before_or_after_position(
23057                                        &snapshot,
23058                                        point,
23059                                        Direction::Prev,
23060                                        window,
23061                                        cx,
23062                                    );
23063                                    editor.expand_selected_diff_hunks(cx);
23064                                });
23065                            }
23066                        }),
23067                )
23068            },
23069        )
23070        .into_any_element()
23071}