editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   55use aho_corasick::AhoCorasick;
   56use anyhow::{Context as _, Result, anyhow};
   57use blink_manager::BlinkManager;
   58use buffer_diff::DiffHunkStatus;
   59use client::{Collaborator, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82use lsp_colors::LspColorData;
   83
   84use ::git::blame::BlameEntry;
   85use ::git::{Restore, blame::ParsedCommitMessage};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use git::blame::{GitBlame, GlobalBlameRenderer};
   91use gpui::{
   92    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   93    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   94    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   95    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   96    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   97    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   98    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   99    div, point, prelude::*, pulsating_between, px, relative, size,
  100};
  101use highlight_matching_bracket::refresh_matching_bracket_highlights;
  102use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  103pub use hover_popover::hover_markdown_style;
  104use hover_popover::{HoverState, hide_hover};
  105use indent_guides::ActiveIndentGuidesState;
  106use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  107pub use inline_completion::Direction;
  108use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  109pub use items::MAX_TAB_TITLE_LEN;
  110use itertools::Itertools;
  111use language::{
  112    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  113    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  114    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  115    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, ProjectPath,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    git_store::{GitStoreEvent, RepositoryEvent},
  137    project_settings::DiagnosticSeverity,
  138};
  139
  140pub use git::blame::BlameRenderer;
  141pub use proposed_changes_editor::{
  142    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  143};
  144use std::{cell::OnceCell, iter::Peekable, ops::Not};
  145use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  146
  147pub use lsp::CompletionContext;
  148use lsp::{
  149    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  150    LanguageServerId, LanguageServerName,
  151};
  152
  153use language::BufferSnapshot;
  154pub use lsp_ext::lsp_tasks;
  155use movement::TextLayoutDetails;
  156pub use multi_buffer::{
  157    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  158    RowInfo, ToOffset, ToPoint,
  159};
  160use multi_buffer::{
  161    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  162    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  163};
  164use parking_lot::Mutex;
  165use project::{
  166    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  167    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  168    TaskSourceKind,
  169    debugger::breakpoint_store::Breakpoint,
  170    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  171    project_settings::{GitGutterSetting, ProjectSettings},
  172};
  173use rand::prelude::*;
  174use rpc::{ErrorExt, proto::*};
  175use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  176use selections_collection::{
  177    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  178};
  179use serde::{Deserialize, Serialize};
  180use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  181use smallvec::{SmallVec, smallvec};
  182use snippet::Snippet;
  183use std::sync::Arc;
  184use std::{
  185    any::TypeId,
  186    borrow::Cow,
  187    cell::RefCell,
  188    cmp::{self, Ordering, Reverse},
  189    mem,
  190    num::NonZeroU32,
  191    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  192    path::{Path, PathBuf},
  193    rc::Rc,
  194    time::{Duration, Instant},
  195};
  196pub use sum_tree::Bias;
  197use sum_tree::TreeMap;
  198use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  199use theme::{
  200    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  201    observe_buffer_font_size_adjustment,
  202};
  203use ui::{
  204    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  205    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  206};
  207use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  208use workspace::{
  209    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  210    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  211    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  212    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  213    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  214    searchable::SearchEvent,
  215};
  216
  217use crate::{
  218    code_context_menus::CompletionsMenuSource,
  219    hover_links::{find_url, find_url_from_range},
  220};
  221use crate::{
  222    editor_settings::MultiCursorModifier,
  223    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  224};
  225
  226pub const FILE_HEADER_HEIGHT: u32 = 2;
  227pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  228pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  229const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  230const MAX_LINE_LEN: usize = 1024;
  231const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  232const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  233pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  234#[doc(hidden)]
  235pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  236const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  237
  238pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  241
  242pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  243pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  244pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  245
  246pub type RenderDiffHunkControlsFn = Arc<
  247    dyn Fn(
  248        u32,
  249        &DiffHunkStatus,
  250        Range<Anchor>,
  251        bool,
  252        Pixels,
  253        &Entity<Editor>,
  254        &mut Window,
  255        &mut App,
  256    ) -> AnyElement,
  257>;
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    DebuggerValue(usize),
  279    // LSP
  280    Hint(usize),
  281    Color(usize),
  282}
  283
  284impl InlayId {
  285    fn id(&self) -> usize {
  286        match self {
  287            Self::InlineCompletion(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289            Self::Hint(id) => *id,
  290            Self::Color(id) => *id,
  291        }
  292    }
  293}
  294
  295pub enum ActiveDebugLine {}
  296pub enum DebugStackFrameLine {}
  297enum DocumentHighlightRead {}
  298enum DocumentHighlightWrite {}
  299enum InputComposition {}
  300pub enum PendingInput {}
  301enum SelectedTextHighlight {}
  302
  303pub enum ConflictsOuter {}
  304pub enum ConflictsOurs {}
  305pub enum ConflictsTheirs {}
  306pub enum ConflictsOursMarker {}
  307pub enum ConflictsTheirsMarker {}
  308
  309#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  310pub enum Navigated {
  311    Yes,
  312    No,
  313}
  314
  315impl Navigated {
  316    pub fn from_bool(yes: bool) -> Navigated {
  317        if yes { Navigated::Yes } else { Navigated::No }
  318    }
  319}
  320
  321#[derive(Debug, Clone, PartialEq, Eq)]
  322enum DisplayDiffHunk {
  323    Folded {
  324        display_row: DisplayRow,
  325    },
  326    Unfolded {
  327        is_created_file: bool,
  328        diff_base_byte_range: Range<usize>,
  329        display_row_range: Range<DisplayRow>,
  330        multi_buffer_range: Range<Anchor>,
  331        status: DiffHunkStatus,
  332    },
  333}
  334
  335pub enum HideMouseCursorOrigin {
  336    TypingAction,
  337    MovementAction,
  338}
  339
  340pub fn init_settings(cx: &mut App) {
  341    EditorSettings::register(cx);
  342}
  343
  344pub fn init(cx: &mut App) {
  345    init_settings(cx);
  346
  347    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  348
  349    workspace::register_project_item::<Editor>(cx);
  350    workspace::FollowableViewRegistry::register::<Editor>(cx);
  351    workspace::register_serializable_item::<Editor>(cx);
  352
  353    cx.observe_new(
  354        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  355            workspace.register_action(Editor::new_file);
  356            workspace.register_action(Editor::new_file_vertical);
  357            workspace.register_action(Editor::new_file_horizontal);
  358            workspace.register_action(Editor::cancel_language_server_work);
  359        },
  360    )
  361    .detach();
  362
  363    cx.on_action(move |_: &workspace::NewFile, cx| {
  364        let app_state = workspace::AppState::global(cx);
  365        if let Some(app_state) = app_state.upgrade() {
  366            workspace::open_new(
  367                Default::default(),
  368                app_state,
  369                cx,
  370                |workspace, window, cx| {
  371                    Editor::new_file(workspace, &Default::default(), window, cx)
  372                },
  373            )
  374            .detach();
  375        }
  376    });
  377    cx.on_action(move |_: &workspace::NewWindow, cx| {
  378        let app_state = workspace::AppState::global(cx);
  379        if let Some(app_state) = app_state.upgrade() {
  380            workspace::open_new(
  381                Default::default(),
  382                app_state,
  383                cx,
  384                |workspace, window, cx| {
  385                    cx.activate(true);
  386                    Editor::new_file(workspace, &Default::default(), window, cx)
  387                },
  388            )
  389            .detach();
  390        }
  391    });
  392}
  393
  394pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  395    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  396}
  397
  398pub trait DiagnosticRenderer {
  399    fn render_group(
  400        &self,
  401        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  402        buffer_id: BufferId,
  403        snapshot: EditorSnapshot,
  404        editor: WeakEntity<Editor>,
  405        cx: &mut App,
  406    ) -> Vec<BlockProperties<Anchor>>;
  407
  408    fn render_hover(
  409        &self,
  410        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  411        range: Range<Point>,
  412        buffer_id: BufferId,
  413        cx: &mut App,
  414    ) -> Option<Entity<markdown::Markdown>>;
  415
  416    fn open_link(
  417        &self,
  418        editor: &mut Editor,
  419        link: SharedString,
  420        window: &mut Window,
  421        cx: &mut Context<Editor>,
  422    );
  423}
  424
  425pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  426
  427impl GlobalDiagnosticRenderer {
  428    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  429        cx.try_global::<Self>().map(|g| g.0.clone())
  430    }
  431}
  432
  433impl gpui::Global for GlobalDiagnosticRenderer {}
  434pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  435    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  436}
  437
  438pub struct SearchWithinRange;
  439
  440trait InvalidationRegion {
  441    fn ranges(&self) -> &[Range<Anchor>];
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum SelectPhase {
  446    Begin {
  447        position: DisplayPoint,
  448        add: bool,
  449        click_count: usize,
  450    },
  451    BeginColumnar {
  452        position: DisplayPoint,
  453        reset: bool,
  454        mode: ColumnarMode,
  455        goal_column: u32,
  456    },
  457    Extend {
  458        position: DisplayPoint,
  459        click_count: usize,
  460    },
  461    Update {
  462        position: DisplayPoint,
  463        goal_column: u32,
  464        scroll_delta: gpui::Point<f32>,
  465    },
  466    End,
  467}
  468
  469#[derive(Clone, Debug, PartialEq)]
  470pub enum ColumnarMode {
  471    FromMouse,
  472    FromSelection,
  473}
  474
  475#[derive(Clone, Debug)]
  476pub enum SelectMode {
  477    Character,
  478    Word(Range<Anchor>),
  479    Line(Range<Anchor>),
  480    All,
  481}
  482
  483#[derive(Clone, PartialEq, Eq, Debug)]
  484pub enum EditorMode {
  485    SingleLine {
  486        auto_width: bool,
  487    },
  488    AutoHeight {
  489        min_lines: usize,
  490        max_lines: Option<usize>,
  491    },
  492    Full {
  493        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  494        scale_ui_elements_with_buffer_font_size: bool,
  495        /// When set to `true`, the editor will render a background for the active line.
  496        show_active_line_background: bool,
  497        /// When set to `true`, the editor's height will be determined by its content.
  498        sized_by_content: bool,
  499    },
  500    Minimap {
  501        parent: WeakEntity<Editor>,
  502    },
  503}
  504
  505impl EditorMode {
  506    pub fn full() -> Self {
  507        Self::Full {
  508            scale_ui_elements_with_buffer_font_size: true,
  509            show_active_line_background: true,
  510            sized_by_content: false,
  511        }
  512    }
  513
  514    #[inline]
  515    pub fn is_full(&self) -> bool {
  516        matches!(self, Self::Full { .. })
  517    }
  518
  519    #[inline]
  520    pub fn is_single_line(&self) -> bool {
  521        matches!(self, Self::SingleLine { .. })
  522    }
  523
  524    #[inline]
  525    fn is_minimap(&self) -> bool {
  526        matches!(self, Self::Minimap { .. })
  527    }
  528}
  529
  530#[derive(Copy, Clone, Debug)]
  531pub enum SoftWrap {
  532    /// Prefer not to wrap at all.
  533    ///
  534    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  535    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  536    GitDiff,
  537    /// Prefer a single line generally, unless an overly long line is encountered.
  538    None,
  539    /// Soft wrap lines that exceed the editor width.
  540    EditorWidth,
  541    /// Soft wrap lines at the preferred line length.
  542    Column(u32),
  543    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  544    Bounded(u32),
  545}
  546
  547#[derive(Clone)]
  548pub struct EditorStyle {
  549    pub background: Hsla,
  550    pub border: Hsla,
  551    pub local_player: PlayerColor,
  552    pub text: TextStyle,
  553    pub scrollbar_width: Pixels,
  554    pub syntax: Arc<SyntaxTheme>,
  555    pub status: StatusColors,
  556    pub inlay_hints_style: HighlightStyle,
  557    pub inline_completion_styles: InlineCompletionStyles,
  558    pub unnecessary_code_fade: f32,
  559    pub show_underlines: bool,
  560}
  561
  562impl Default for EditorStyle {
  563    fn default() -> Self {
  564        Self {
  565            background: Hsla::default(),
  566            border: Hsla::default(),
  567            local_player: PlayerColor::default(),
  568            text: TextStyle::default(),
  569            scrollbar_width: Pixels::default(),
  570            syntax: Default::default(),
  571            // HACK: Status colors don't have a real default.
  572            // We should look into removing the status colors from the editor
  573            // style and retrieve them directly from the theme.
  574            status: StatusColors::dark(),
  575            inlay_hints_style: HighlightStyle::default(),
  576            inline_completion_styles: InlineCompletionStyles {
  577                insertion: HighlightStyle::default(),
  578                whitespace: HighlightStyle::default(),
  579            },
  580            unnecessary_code_fade: Default::default(),
  581            show_underlines: true,
  582        }
  583    }
  584}
  585
  586pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  587    let show_background = language_settings::language_settings(None, None, cx)
  588        .inlay_hints
  589        .show_background;
  590
  591    HighlightStyle {
  592        color: Some(cx.theme().status().hint),
  593        background_color: show_background.then(|| cx.theme().status().hint_background),
  594        ..HighlightStyle::default()
  595    }
  596}
  597
  598pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  599    InlineCompletionStyles {
  600        insertion: HighlightStyle {
  601            color: Some(cx.theme().status().predictive),
  602            ..HighlightStyle::default()
  603        },
  604        whitespace: HighlightStyle {
  605            background_color: Some(cx.theme().status().created_background),
  606            ..HighlightStyle::default()
  607        },
  608    }
  609}
  610
  611type CompletionId = usize;
  612
  613pub(crate) enum EditDisplayMode {
  614    TabAccept,
  615    DiffPopover,
  616    Inline,
  617}
  618
  619enum InlineCompletion {
  620    Edit {
  621        edits: Vec<(Range<Anchor>, String)>,
  622        edit_preview: Option<EditPreview>,
  623        display_mode: EditDisplayMode,
  624        snapshot: BufferSnapshot,
  625    },
  626    Move {
  627        target: Anchor,
  628        snapshot: BufferSnapshot,
  629    },
  630}
  631
  632struct InlineCompletionState {
  633    inlay_ids: Vec<InlayId>,
  634    completion: InlineCompletion,
  635    completion_id: Option<SharedString>,
  636    invalidation_range: Range<Anchor>,
  637}
  638
  639enum EditPredictionSettings {
  640    Disabled,
  641    Enabled {
  642        show_in_menu: bool,
  643        preview_requires_modifier: bool,
  644    },
  645}
  646
  647enum InlineCompletionHighlight {}
  648
  649#[derive(Debug, Clone)]
  650struct InlineDiagnostic {
  651    message: SharedString,
  652    group_id: usize,
  653    is_primary: bool,
  654    start: Point,
  655    severity: lsp::DiagnosticSeverity,
  656}
  657
  658pub enum MenuInlineCompletionsPolicy {
  659    Never,
  660    ByProvider,
  661}
  662
  663pub enum EditPredictionPreview {
  664    /// Modifier is not pressed
  665    Inactive { released_too_fast: bool },
  666    /// Modifier pressed
  667    Active {
  668        since: Instant,
  669        previous_scroll_position: Option<ScrollAnchor>,
  670    },
  671}
  672
  673impl EditPredictionPreview {
  674    pub fn released_too_fast(&self) -> bool {
  675        match self {
  676            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  677            EditPredictionPreview::Active { .. } => false,
  678        }
  679    }
  680
  681    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  682        if let EditPredictionPreview::Active {
  683            previous_scroll_position,
  684            ..
  685        } = self
  686        {
  687            *previous_scroll_position = scroll_position;
  688        }
  689    }
  690}
  691
  692pub struct ContextMenuOptions {
  693    pub min_entries_visible: usize,
  694    pub max_entries_visible: usize,
  695    pub placement: Option<ContextMenuPlacement>,
  696}
  697
  698#[derive(Debug, Clone, PartialEq, Eq)]
  699pub enum ContextMenuPlacement {
  700    Above,
  701    Below,
  702}
  703
  704#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  705struct EditorActionId(usize);
  706
  707impl EditorActionId {
  708    pub fn post_inc(&mut self) -> Self {
  709        let answer = self.0;
  710
  711        *self = Self(answer + 1);
  712
  713        Self(answer)
  714    }
  715}
  716
  717// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  718// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  719
  720type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  721type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  722
  723#[derive(Default)]
  724struct ScrollbarMarkerState {
  725    scrollbar_size: Size<Pixels>,
  726    dirty: bool,
  727    markers: Arc<[PaintQuad]>,
  728    pending_refresh: Option<Task<Result<()>>>,
  729}
  730
  731impl ScrollbarMarkerState {
  732    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  733        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  734    }
  735}
  736
  737#[derive(Clone, Copy, PartialEq, Eq)]
  738pub enum MinimapVisibility {
  739    Disabled,
  740    Enabled {
  741        /// The configuration currently present in the users settings.
  742        setting_configuration: bool,
  743        /// Whether to override the currently set visibility from the users setting.
  744        toggle_override: bool,
  745    },
  746}
  747
  748impl MinimapVisibility {
  749    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  750        if mode.is_full() {
  751            Self::Enabled {
  752                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  753                toggle_override: false,
  754            }
  755        } else {
  756            Self::Disabled
  757        }
  758    }
  759
  760    fn hidden(&self) -> Self {
  761        match *self {
  762            Self::Enabled {
  763                setting_configuration,
  764                ..
  765            } => Self::Enabled {
  766                setting_configuration,
  767                toggle_override: setting_configuration,
  768            },
  769            Self::Disabled => Self::Disabled,
  770        }
  771    }
  772
  773    fn disabled(&self) -> bool {
  774        match *self {
  775            Self::Disabled => true,
  776            _ => false,
  777        }
  778    }
  779
  780    fn settings_visibility(&self) -> bool {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => setting_configuration,
  786            _ => false,
  787        }
  788    }
  789
  790    fn visible(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                toggle_override,
  795            } => setting_configuration ^ toggle_override,
  796            _ => false,
  797        }
  798    }
  799
  800    fn toggle_visibility(&self) -> Self {
  801        match *self {
  802            Self::Enabled {
  803                toggle_override,
  804                setting_configuration,
  805            } => Self::Enabled {
  806                setting_configuration,
  807                toggle_override: !toggle_override,
  808            },
  809            Self::Disabled => Self::Disabled,
  810        }
  811    }
  812}
  813
  814#[derive(Clone, Debug)]
  815struct RunnableTasks {
  816    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  817    offset: multi_buffer::Anchor,
  818    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  819    column: u32,
  820    // Values of all named captures, including those starting with '_'
  821    extra_variables: HashMap<String, String>,
  822    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  823    context_range: Range<BufferOffset>,
  824}
  825
  826impl RunnableTasks {
  827    fn resolve<'a>(
  828        &'a self,
  829        cx: &'a task::TaskContext,
  830    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  831        self.templates.iter().filter_map(|(kind, template)| {
  832            template
  833                .resolve_task(&kind.to_id_base(), cx)
  834                .map(|task| (kind.clone(), task))
  835        })
  836    }
  837}
  838
  839#[derive(Clone)]
  840pub struct ResolvedTasks {
  841    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  842    position: Anchor,
  843}
  844
  845#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  846struct BufferOffset(usize);
  847
  848// Addons allow storing per-editor state in other crates (e.g. Vim)
  849pub trait Addon: 'static {
  850    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  851
  852    fn render_buffer_header_controls(
  853        &self,
  854        _: &ExcerptInfo,
  855        _: &Window,
  856        _: &App,
  857    ) -> Option<AnyElement> {
  858        None
  859    }
  860
  861    fn to_any(&self) -> &dyn std::any::Any;
  862
  863    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  864        None
  865    }
  866}
  867
  868struct ChangeLocation {
  869    current: Option<Vec<Anchor>>,
  870    original: Vec<Anchor>,
  871}
  872impl ChangeLocation {
  873    fn locations(&self) -> &[Anchor] {
  874        self.current.as_ref().unwrap_or(&self.original)
  875    }
  876}
  877
  878/// A set of caret positions, registered when the editor was edited.
  879pub struct ChangeList {
  880    changes: Vec<ChangeLocation>,
  881    /// Currently "selected" change.
  882    position: Option<usize>,
  883}
  884
  885impl ChangeList {
  886    pub fn new() -> Self {
  887        Self {
  888            changes: Vec::new(),
  889            position: None,
  890        }
  891    }
  892
  893    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  894    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  895    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  896        if self.changes.is_empty() {
  897            return None;
  898        }
  899
  900        let prev = self.position.unwrap_or(self.changes.len());
  901        let next = if direction == Direction::Prev {
  902            prev.saturating_sub(count)
  903        } else {
  904            (prev + count).min(self.changes.len() - 1)
  905        };
  906        self.position = Some(next);
  907        self.changes.get(next).map(|change| change.locations())
  908    }
  909
  910    /// Adds a new change to the list, resetting the change list position.
  911    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  912        self.position.take();
  913        if let Some(last) = self.changes.last_mut()
  914            && group
  915        {
  916            last.current = Some(new_positions)
  917        } else {
  918            self.changes.push(ChangeLocation {
  919                original: new_positions,
  920                current: None,
  921            });
  922        }
  923    }
  924
  925    pub fn last(&self) -> Option<&[Anchor]> {
  926        self.changes.last().map(|change| change.locations())
  927    }
  928
  929    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  930        self.changes.last().map(|change| change.original.as_slice())
  931    }
  932
  933    pub fn invert_last_group(&mut self) {
  934        if let Some(last) = self.changes.last_mut() {
  935            if let Some(current) = last.current.as_mut() {
  936                mem::swap(&mut last.original, current);
  937            }
  938        }
  939    }
  940}
  941
  942#[derive(Clone)]
  943struct InlineBlamePopoverState {
  944    scroll_handle: ScrollHandle,
  945    commit_message: Option<ParsedCommitMessage>,
  946    markdown: Entity<Markdown>,
  947}
  948
  949struct InlineBlamePopover {
  950    position: gpui::Point<Pixels>,
  951    hide_task: Option<Task<()>>,
  952    popover_bounds: Option<Bounds<Pixels>>,
  953    popover_state: InlineBlamePopoverState,
  954}
  955
  956enum SelectionDragState {
  957    /// State when no drag related activity is detected.
  958    None,
  959    /// State when the mouse is down on a selection that is about to be dragged.
  960    ReadyToDrag {
  961        selection: Selection<Anchor>,
  962        click_position: gpui::Point<Pixels>,
  963        mouse_down_time: Instant,
  964    },
  965    /// State when the mouse is dragging the selection in the editor.
  966    Dragging {
  967        selection: Selection<Anchor>,
  968        drop_cursor: Selection<Anchor>,
  969        hide_drop_cursor: bool,
  970    },
  971}
  972
  973enum ColumnarSelectionState {
  974    FromMouse {
  975        selection_tail: Anchor,
  976        display_point: Option<DisplayPoint>,
  977    },
  978    FromSelection {
  979        selection_tail: Anchor,
  980    },
  981}
  982
  983/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  984/// a breakpoint on them.
  985#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  986struct PhantomBreakpointIndicator {
  987    display_row: DisplayRow,
  988    /// There's a small debounce between hovering over the line and showing the indicator.
  989    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  990    is_active: bool,
  991    collides_with_existing_breakpoint: bool,
  992}
  993
  994/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  995///
  996/// See the [module level documentation](self) for more information.
  997pub struct Editor {
  998    focus_handle: FocusHandle,
  999    last_focused_descendant: Option<WeakFocusHandle>,
 1000    /// The text buffer being edited
 1001    buffer: Entity<MultiBuffer>,
 1002    /// Map of how text in the buffer should be displayed.
 1003    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1004    pub display_map: Entity<DisplayMap>,
 1005    pub selections: SelectionsCollection,
 1006    pub scroll_manager: ScrollManager,
 1007    /// When inline assist editors are linked, they all render cursors because
 1008    /// typing enters text into each of them, even the ones that aren't focused.
 1009    pub(crate) show_cursor_when_unfocused: bool,
 1010    columnar_selection_state: Option<ColumnarSelectionState>,
 1011    add_selections_state: Option<AddSelectionsState>,
 1012    select_next_state: Option<SelectNextState>,
 1013    select_prev_state: Option<SelectNextState>,
 1014    selection_history: SelectionHistory,
 1015    defer_selection_effects: bool,
 1016    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1017    autoclose_regions: Vec<AutocloseRegion>,
 1018    snippet_stack: InvalidationStack<SnippetState>,
 1019    select_syntax_node_history: SelectSyntaxNodeHistory,
 1020    ime_transaction: Option<TransactionId>,
 1021    pub diagnostics_max_severity: DiagnosticSeverity,
 1022    active_diagnostics: ActiveDiagnostic,
 1023    show_inline_diagnostics: bool,
 1024    inline_diagnostics_update: Task<()>,
 1025    inline_diagnostics_enabled: bool,
 1026    diagnostics_enabled: bool,
 1027    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1028    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1029    hard_wrap: Option<usize>,
 1030
 1031    // TODO: make this a access method
 1032    pub project: Option<Entity<Project>>,
 1033    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1034    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1035    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1036    blink_manager: Entity<BlinkManager>,
 1037    show_cursor_names: bool,
 1038    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1039    pub show_local_selections: bool,
 1040    mode: EditorMode,
 1041    show_breadcrumbs: bool,
 1042    show_gutter: bool,
 1043    show_scrollbars: ScrollbarAxes,
 1044    minimap_visibility: MinimapVisibility,
 1045    offset_content: bool,
 1046    disable_expand_excerpt_buttons: bool,
 1047    show_line_numbers: Option<bool>,
 1048    use_relative_line_numbers: Option<bool>,
 1049    show_git_diff_gutter: Option<bool>,
 1050    show_code_actions: Option<bool>,
 1051    show_runnables: Option<bool>,
 1052    show_breakpoints: Option<bool>,
 1053    show_wrap_guides: Option<bool>,
 1054    show_indent_guides: Option<bool>,
 1055    placeholder_text: Option<Arc<str>>,
 1056    highlight_order: usize,
 1057    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1058    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1059    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1060    scrollbar_marker_state: ScrollbarMarkerState,
 1061    active_indent_guides_state: ActiveIndentGuidesState,
 1062    nav_history: Option<ItemNavHistory>,
 1063    context_menu: RefCell<Option<CodeContextMenu>>,
 1064    context_menu_options: Option<ContextMenuOptions>,
 1065    mouse_context_menu: Option<MouseContextMenu>,
 1066    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1067    inline_blame_popover: Option<InlineBlamePopover>,
 1068    inline_blame_popover_show_task: Option<Task<()>>,
 1069    signature_help_state: SignatureHelpState,
 1070    auto_signature_help: Option<bool>,
 1071    find_all_references_task_sources: Vec<Anchor>,
 1072    next_completion_id: CompletionId,
 1073    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1074    code_actions_task: Option<Task<Result<()>>>,
 1075    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1076    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    document_highlights_task: Option<Task<()>>,
 1078    linked_editing_range_task: Option<Task<Option<()>>>,
 1079    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1080    pending_rename: Option<RenameState>,
 1081    searchable: bool,
 1082    cursor_shape: CursorShape,
 1083    current_line_highlight: Option<CurrentLineHighlight>,
 1084    collapse_matches: bool,
 1085    autoindent_mode: Option<AutoindentMode>,
 1086    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1087    input_enabled: bool,
 1088    use_modal_editing: bool,
 1089    read_only: bool,
 1090    leader_id: Option<CollaboratorId>,
 1091    remote_id: Option<ViewId>,
 1092    pub hover_state: HoverState,
 1093    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1094    gutter_hovered: bool,
 1095    hovered_link_state: Option<HoveredLinkState>,
 1096    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1097    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1098    active_inline_completion: Option<InlineCompletionState>,
 1099    /// Used to prevent flickering as the user types while the menu is open
 1100    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1101    edit_prediction_settings: EditPredictionSettings,
 1102    inline_completions_hidden_for_vim_mode: bool,
 1103    show_inline_completions_override: Option<bool>,
 1104    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1105    edit_prediction_preview: EditPredictionPreview,
 1106    edit_prediction_indent_conflict: bool,
 1107    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1108    inlay_hint_cache: InlayHintCache,
 1109    next_inlay_id: usize,
 1110    _subscriptions: Vec<Subscription>,
 1111    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1112    gutter_dimensions: GutterDimensions,
 1113    style: Option<EditorStyle>,
 1114    text_style_refinement: Option<TextStyleRefinement>,
 1115    next_editor_action_id: EditorActionId,
 1116    editor_actions: Rc<
 1117        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1118    >,
 1119    use_autoclose: bool,
 1120    use_auto_surround: bool,
 1121    auto_replace_emoji_shortcode: bool,
 1122    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1123    show_git_blame_gutter: bool,
 1124    show_git_blame_inline: bool,
 1125    show_git_blame_inline_delay_task: Option<Task<()>>,
 1126    git_blame_inline_enabled: bool,
 1127    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1128    serialize_dirty_buffers: bool,
 1129    show_selection_menu: Option<bool>,
 1130    blame: Option<Entity<GitBlame>>,
 1131    blame_subscription: Option<Subscription>,
 1132    custom_context_menu: Option<
 1133        Box<
 1134            dyn 'static
 1135                + Fn(
 1136                    &mut Self,
 1137                    DisplayPoint,
 1138                    &mut Window,
 1139                    &mut Context<Self>,
 1140                ) -> Option<Entity<ui::ContextMenu>>,
 1141        >,
 1142    >,
 1143    last_bounds: Option<Bounds<Pixels>>,
 1144    last_position_map: Option<Rc<PositionMap>>,
 1145    expect_bounds_change: Option<Bounds<Pixels>>,
 1146    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1147    tasks_update_task: Option<Task<()>>,
 1148    breakpoint_store: Option<Entity<BreakpointStore>>,
 1149    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1150    hovered_diff_hunk_row: Option<DisplayRow>,
 1151    pull_diagnostics_task: Task<()>,
 1152    in_project_search: bool,
 1153    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1154    breadcrumb_header: Option<String>,
 1155    focused_block: Option<FocusedBlock>,
 1156    next_scroll_position: NextScrollCursorCenterTopBottom,
 1157    addons: HashMap<TypeId, Box<dyn Addon>>,
 1158    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1159    load_diff_task: Option<Shared<Task<()>>>,
 1160    /// Whether we are temporarily displaying a diff other than git's
 1161    temporary_diff_override: bool,
 1162    selection_mark_mode: bool,
 1163    toggle_fold_multiple_buffers: Task<()>,
 1164    _scroll_cursor_center_top_bottom_task: Task<()>,
 1165    serialize_selections: Task<()>,
 1166    serialize_folds: Task<()>,
 1167    mouse_cursor_hidden: bool,
 1168    minimap: Option<Entity<Self>>,
 1169    hide_mouse_mode: HideMouseMode,
 1170    pub change_list: ChangeList,
 1171    inline_value_cache: InlineValueCache,
 1172    selection_drag_state: SelectionDragState,
 1173    next_color_inlay_id: usize,
 1174    colors: Option<LspColorData>,
 1175    folding_newlines: Task<()>,
 1176}
 1177
 1178#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1179enum NextScrollCursorCenterTopBottom {
 1180    #[default]
 1181    Center,
 1182    Top,
 1183    Bottom,
 1184}
 1185
 1186impl NextScrollCursorCenterTopBottom {
 1187    fn next(&self) -> Self {
 1188        match self {
 1189            Self::Center => Self::Top,
 1190            Self::Top => Self::Bottom,
 1191            Self::Bottom => Self::Center,
 1192        }
 1193    }
 1194}
 1195
 1196#[derive(Clone)]
 1197pub struct EditorSnapshot {
 1198    pub mode: EditorMode,
 1199    show_gutter: bool,
 1200    show_line_numbers: Option<bool>,
 1201    show_git_diff_gutter: Option<bool>,
 1202    show_code_actions: Option<bool>,
 1203    show_runnables: Option<bool>,
 1204    show_breakpoints: Option<bool>,
 1205    git_blame_gutter_max_author_length: Option<usize>,
 1206    pub display_snapshot: DisplaySnapshot,
 1207    pub placeholder_text: Option<Arc<str>>,
 1208    is_focused: bool,
 1209    scroll_anchor: ScrollAnchor,
 1210    ongoing_scroll: OngoingScroll,
 1211    current_line_highlight: CurrentLineHighlight,
 1212    gutter_hovered: bool,
 1213}
 1214
 1215#[derive(Default, Debug, Clone, Copy)]
 1216pub struct GutterDimensions {
 1217    pub left_padding: Pixels,
 1218    pub right_padding: Pixels,
 1219    pub width: Pixels,
 1220    pub margin: Pixels,
 1221    pub git_blame_entries_width: Option<Pixels>,
 1222}
 1223
 1224impl GutterDimensions {
 1225    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1226        Self {
 1227            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1228            ..Default::default()
 1229        }
 1230    }
 1231
 1232    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1233        -cx.text_system().descent(font_id, font_size)
 1234    }
 1235    /// The full width of the space taken up by the gutter.
 1236    pub fn full_width(&self) -> Pixels {
 1237        self.margin + self.width
 1238    }
 1239
 1240    /// The width of the space reserved for the fold indicators,
 1241    /// use alongside 'justify_end' and `gutter_width` to
 1242    /// right align content with the line numbers
 1243    pub fn fold_area_width(&self) -> Pixels {
 1244        self.margin + self.right_padding
 1245    }
 1246}
 1247
 1248struct CharacterDimensions {
 1249    em_width: Pixels,
 1250    em_advance: Pixels,
 1251    line_height: Pixels,
 1252}
 1253
 1254#[derive(Debug)]
 1255pub struct RemoteSelection {
 1256    pub replica_id: ReplicaId,
 1257    pub selection: Selection<Anchor>,
 1258    pub cursor_shape: CursorShape,
 1259    pub collaborator_id: CollaboratorId,
 1260    pub line_mode: bool,
 1261    pub user_name: Option<SharedString>,
 1262    pub color: PlayerColor,
 1263}
 1264
 1265#[derive(Clone, Debug)]
 1266struct SelectionHistoryEntry {
 1267    selections: Arc<[Selection<Anchor>]>,
 1268    select_next_state: Option<SelectNextState>,
 1269    select_prev_state: Option<SelectNextState>,
 1270    add_selections_state: Option<AddSelectionsState>,
 1271}
 1272
 1273#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1274enum SelectionHistoryMode {
 1275    Normal,
 1276    Undoing,
 1277    Redoing,
 1278    Skipping,
 1279}
 1280
 1281#[derive(Clone, PartialEq, Eq, Hash)]
 1282struct HoveredCursor {
 1283    replica_id: u16,
 1284    selection_id: usize,
 1285}
 1286
 1287impl Default for SelectionHistoryMode {
 1288    fn default() -> Self {
 1289        Self::Normal
 1290    }
 1291}
 1292
 1293#[derive(Debug)]
 1294/// SelectionEffects controls the side-effects of updating the selection.
 1295///
 1296/// The default behaviour does "what you mostly want":
 1297/// - it pushes to the nav history if the cursor moved by >10 lines
 1298/// - it re-triggers completion requests
 1299/// - it scrolls to fit
 1300///
 1301/// You might want to modify these behaviours. For example when doing a "jump"
 1302/// like go to definition, we always want to add to nav history; but when scrolling
 1303/// in vim mode we never do.
 1304///
 1305/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1306/// move.
 1307pub struct SelectionEffects {
 1308    nav_history: Option<bool>,
 1309    completions: bool,
 1310    scroll: Option<Autoscroll>,
 1311}
 1312
 1313impl Default for SelectionEffects {
 1314    fn default() -> Self {
 1315        Self {
 1316            nav_history: None,
 1317            completions: true,
 1318            scroll: Some(Autoscroll::fit()),
 1319        }
 1320    }
 1321}
 1322impl SelectionEffects {
 1323    pub fn scroll(scroll: Autoscroll) -> Self {
 1324        Self {
 1325            scroll: Some(scroll),
 1326            ..Default::default()
 1327        }
 1328    }
 1329
 1330    pub fn no_scroll() -> Self {
 1331        Self {
 1332            scroll: None,
 1333            ..Default::default()
 1334        }
 1335    }
 1336
 1337    pub fn completions(self, completions: bool) -> Self {
 1338        Self {
 1339            completions,
 1340            ..self
 1341        }
 1342    }
 1343
 1344    pub fn nav_history(self, nav_history: bool) -> Self {
 1345        Self {
 1346            nav_history: Some(nav_history),
 1347            ..self
 1348        }
 1349    }
 1350}
 1351
 1352struct DeferredSelectionEffectsState {
 1353    changed: bool,
 1354    effects: SelectionEffects,
 1355    old_cursor_position: Anchor,
 1356    history_entry: SelectionHistoryEntry,
 1357}
 1358
 1359#[derive(Default)]
 1360struct SelectionHistory {
 1361    #[allow(clippy::type_complexity)]
 1362    selections_by_transaction:
 1363        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1364    mode: SelectionHistoryMode,
 1365    undo_stack: VecDeque<SelectionHistoryEntry>,
 1366    redo_stack: VecDeque<SelectionHistoryEntry>,
 1367}
 1368
 1369impl SelectionHistory {
 1370    #[track_caller]
 1371    fn insert_transaction(
 1372        &mut self,
 1373        transaction_id: TransactionId,
 1374        selections: Arc<[Selection<Anchor>]>,
 1375    ) {
 1376        if selections.is_empty() {
 1377            log::error!(
 1378                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1379                std::panic::Location::caller()
 1380            );
 1381            return;
 1382        }
 1383        self.selections_by_transaction
 1384            .insert(transaction_id, (selections, None));
 1385    }
 1386
 1387    #[allow(clippy::type_complexity)]
 1388    fn transaction(
 1389        &self,
 1390        transaction_id: TransactionId,
 1391    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1392        self.selections_by_transaction.get(&transaction_id)
 1393    }
 1394
 1395    #[allow(clippy::type_complexity)]
 1396    fn transaction_mut(
 1397        &mut self,
 1398        transaction_id: TransactionId,
 1399    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1400        self.selections_by_transaction.get_mut(&transaction_id)
 1401    }
 1402
 1403    fn push(&mut self, entry: SelectionHistoryEntry) {
 1404        if !entry.selections.is_empty() {
 1405            match self.mode {
 1406                SelectionHistoryMode::Normal => {
 1407                    self.push_undo(entry);
 1408                    self.redo_stack.clear();
 1409                }
 1410                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1411                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1412                SelectionHistoryMode::Skipping => {}
 1413            }
 1414        }
 1415    }
 1416
 1417    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1418        if self
 1419            .undo_stack
 1420            .back()
 1421            .map_or(true, |e| e.selections != entry.selections)
 1422        {
 1423            self.undo_stack.push_back(entry);
 1424            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1425                self.undo_stack.pop_front();
 1426            }
 1427        }
 1428    }
 1429
 1430    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1431        if self
 1432            .redo_stack
 1433            .back()
 1434            .map_or(true, |e| e.selections != entry.selections)
 1435        {
 1436            self.redo_stack.push_back(entry);
 1437            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1438                self.redo_stack.pop_front();
 1439            }
 1440        }
 1441    }
 1442}
 1443
 1444#[derive(Clone, Copy)]
 1445pub struct RowHighlightOptions {
 1446    pub autoscroll: bool,
 1447    pub include_gutter: bool,
 1448}
 1449
 1450impl Default for RowHighlightOptions {
 1451    fn default() -> Self {
 1452        Self {
 1453            autoscroll: Default::default(),
 1454            include_gutter: true,
 1455        }
 1456    }
 1457}
 1458
 1459struct RowHighlight {
 1460    index: usize,
 1461    range: Range<Anchor>,
 1462    color: Hsla,
 1463    options: RowHighlightOptions,
 1464    type_id: TypeId,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsState {
 1469    groups: Vec<AddSelectionsGroup>,
 1470}
 1471
 1472#[derive(Clone, Debug)]
 1473struct AddSelectionsGroup {
 1474    above: bool,
 1475    stack: Vec<usize>,
 1476}
 1477
 1478#[derive(Clone)]
 1479struct SelectNextState {
 1480    query: AhoCorasick,
 1481    wordwise: bool,
 1482    done: bool,
 1483}
 1484
 1485impl std::fmt::Debug for SelectNextState {
 1486    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1487        f.debug_struct(std::any::type_name::<Self>())
 1488            .field("wordwise", &self.wordwise)
 1489            .field("done", &self.done)
 1490            .finish()
 1491    }
 1492}
 1493
 1494#[derive(Debug)]
 1495struct AutocloseRegion {
 1496    selection_id: usize,
 1497    range: Range<Anchor>,
 1498    pair: BracketPair,
 1499}
 1500
 1501#[derive(Debug)]
 1502struct SnippetState {
 1503    ranges: Vec<Vec<Range<Anchor>>>,
 1504    active_index: usize,
 1505    choices: Vec<Option<Vec<String>>>,
 1506}
 1507
 1508#[doc(hidden)]
 1509pub struct RenameState {
 1510    pub range: Range<Anchor>,
 1511    pub old_name: Arc<str>,
 1512    pub editor: Entity<Editor>,
 1513    block_id: CustomBlockId,
 1514}
 1515
 1516struct InvalidationStack<T>(Vec<T>);
 1517
 1518struct RegisteredInlineCompletionProvider {
 1519    provider: Arc<dyn InlineCompletionProviderHandle>,
 1520    _subscription: Subscription,
 1521}
 1522
 1523#[derive(Debug, PartialEq, Eq)]
 1524pub struct ActiveDiagnosticGroup {
 1525    pub active_range: Range<Anchor>,
 1526    pub active_message: String,
 1527    pub group_id: usize,
 1528    pub blocks: HashSet<CustomBlockId>,
 1529}
 1530
 1531#[derive(Debug, PartialEq, Eq)]
 1532
 1533pub(crate) enum ActiveDiagnostic {
 1534    None,
 1535    All,
 1536    Group(ActiveDiagnosticGroup),
 1537}
 1538
 1539#[derive(Serialize, Deserialize, Clone, Debug)]
 1540pub struct ClipboardSelection {
 1541    /// The number of bytes in this selection.
 1542    pub len: usize,
 1543    /// Whether this was a full-line selection.
 1544    pub is_entire_line: bool,
 1545    /// The indentation of the first line when this content was originally copied.
 1546    pub first_line_indent: u32,
 1547}
 1548
 1549// selections, scroll behavior, was newest selection reversed
 1550type SelectSyntaxNodeHistoryState = (
 1551    Box<[Selection<usize>]>,
 1552    SelectSyntaxNodeScrollBehavior,
 1553    bool,
 1554);
 1555
 1556#[derive(Default)]
 1557struct SelectSyntaxNodeHistory {
 1558    stack: Vec<SelectSyntaxNodeHistoryState>,
 1559    // disable temporarily to allow changing selections without losing the stack
 1560    pub disable_clearing: bool,
 1561}
 1562
 1563impl SelectSyntaxNodeHistory {
 1564    pub fn try_clear(&mut self) {
 1565        if !self.disable_clearing {
 1566            self.stack.clear();
 1567        }
 1568    }
 1569
 1570    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1571        self.stack.push(selection);
 1572    }
 1573
 1574    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1575        self.stack.pop()
 1576    }
 1577}
 1578
 1579enum SelectSyntaxNodeScrollBehavior {
 1580    CursorTop,
 1581    FitSelection,
 1582    CursorBottom,
 1583}
 1584
 1585#[derive(Debug)]
 1586pub(crate) struct NavigationData {
 1587    cursor_anchor: Anchor,
 1588    cursor_position: Point,
 1589    scroll_anchor: ScrollAnchor,
 1590    scroll_top_row: u32,
 1591}
 1592
 1593#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1594pub enum GotoDefinitionKind {
 1595    Symbol,
 1596    Declaration,
 1597    Type,
 1598    Implementation,
 1599}
 1600
 1601#[derive(Debug, Clone)]
 1602enum InlayHintRefreshReason {
 1603    ModifiersChanged(bool),
 1604    Toggle(bool),
 1605    SettingsChange(InlayHintSettings),
 1606    NewLinesShown,
 1607    BufferEdited(HashSet<Arc<Language>>),
 1608    RefreshRequested,
 1609    ExcerptsRemoved(Vec<ExcerptId>),
 1610}
 1611
 1612impl InlayHintRefreshReason {
 1613    fn description(&self) -> &'static str {
 1614        match self {
 1615            Self::ModifiersChanged(_) => "modifiers changed",
 1616            Self::Toggle(_) => "toggle",
 1617            Self::SettingsChange(_) => "settings change",
 1618            Self::NewLinesShown => "new lines shown",
 1619            Self::BufferEdited(_) => "buffer edited",
 1620            Self::RefreshRequested => "refresh requested",
 1621            Self::ExcerptsRemoved(_) => "excerpts removed",
 1622        }
 1623    }
 1624}
 1625
 1626pub enum FormatTarget {
 1627    Buffers(HashSet<Entity<Buffer>>),
 1628    Ranges(Vec<Range<MultiBufferPoint>>),
 1629}
 1630
 1631pub(crate) struct FocusedBlock {
 1632    id: BlockId,
 1633    focus_handle: WeakFocusHandle,
 1634}
 1635
 1636#[derive(Clone)]
 1637enum JumpData {
 1638    MultiBufferRow {
 1639        row: MultiBufferRow,
 1640        line_offset_from_top: u32,
 1641    },
 1642    MultiBufferPoint {
 1643        excerpt_id: ExcerptId,
 1644        position: Point,
 1645        anchor: text::Anchor,
 1646        line_offset_from_top: u32,
 1647    },
 1648}
 1649
 1650pub enum MultibufferSelectionMode {
 1651    First,
 1652    All,
 1653}
 1654
 1655#[derive(Clone, Copy, Debug, Default)]
 1656pub struct RewrapOptions {
 1657    pub override_language_settings: bool,
 1658    pub preserve_existing_whitespace: bool,
 1659}
 1660
 1661impl Editor {
 1662    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1663        let buffer = cx.new(|cx| Buffer::local("", cx));
 1664        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1665        Self::new(
 1666            EditorMode::SingleLine { auto_width: false },
 1667            buffer,
 1668            None,
 1669            window,
 1670            cx,
 1671        )
 1672    }
 1673
 1674    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(EditorMode::full(), buffer, None, window, cx)
 1678    }
 1679
 1680    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1681        let buffer = cx.new(|cx| Buffer::local("", cx));
 1682        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1683        Self::new(
 1684            EditorMode::SingleLine { auto_width: true },
 1685            buffer,
 1686            None,
 1687            window,
 1688            cx,
 1689        )
 1690    }
 1691
 1692    pub fn auto_height(
 1693        min_lines: usize,
 1694        max_lines: usize,
 1695        window: &mut Window,
 1696        cx: &mut Context<Self>,
 1697    ) -> Self {
 1698        let buffer = cx.new(|cx| Buffer::local("", cx));
 1699        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1700        Self::new(
 1701            EditorMode::AutoHeight {
 1702                min_lines,
 1703                max_lines: Some(max_lines),
 1704            },
 1705            buffer,
 1706            None,
 1707            window,
 1708            cx,
 1709        )
 1710    }
 1711
 1712    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1713    /// The editor grows as tall as needed to fit its content.
 1714    pub fn auto_height_unbounded(
 1715        min_lines: usize,
 1716        window: &mut Window,
 1717        cx: &mut Context<Self>,
 1718    ) -> Self {
 1719        let buffer = cx.new(|cx| Buffer::local("", cx));
 1720        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1721        Self::new(
 1722            EditorMode::AutoHeight {
 1723                min_lines,
 1724                max_lines: None,
 1725            },
 1726            buffer,
 1727            None,
 1728            window,
 1729            cx,
 1730        )
 1731    }
 1732
 1733    pub fn for_buffer(
 1734        buffer: Entity<Buffer>,
 1735        project: Option<Entity<Project>>,
 1736        window: &mut Window,
 1737        cx: &mut Context<Self>,
 1738    ) -> Self {
 1739        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1740        Self::new(EditorMode::full(), buffer, project, window, cx)
 1741    }
 1742
 1743    pub fn for_multibuffer(
 1744        buffer: Entity<MultiBuffer>,
 1745        project: Option<Entity<Project>>,
 1746        window: &mut Window,
 1747        cx: &mut Context<Self>,
 1748    ) -> Self {
 1749        Self::new(EditorMode::full(), buffer, project, window, cx)
 1750    }
 1751
 1752    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1753        let mut clone = Self::new(
 1754            self.mode.clone(),
 1755            self.buffer.clone(),
 1756            self.project.clone(),
 1757            window,
 1758            cx,
 1759        );
 1760        self.display_map.update(cx, |display_map, cx| {
 1761            let snapshot = display_map.snapshot(cx);
 1762            clone.display_map.update(cx, |display_map, cx| {
 1763                display_map.set_state(&snapshot, cx);
 1764            });
 1765        });
 1766        clone.folds_did_change(cx);
 1767        clone.selections.clone_state(&self.selections);
 1768        clone.scroll_manager.clone_state(&self.scroll_manager);
 1769        clone.searchable = self.searchable;
 1770        clone.read_only = self.read_only;
 1771        clone
 1772    }
 1773
 1774    pub fn new(
 1775        mode: EditorMode,
 1776        buffer: Entity<MultiBuffer>,
 1777        project: Option<Entity<Project>>,
 1778        window: &mut Window,
 1779        cx: &mut Context<Self>,
 1780    ) -> Self {
 1781        Editor::new_internal(mode, buffer, project, None, window, cx)
 1782    }
 1783
 1784    fn new_internal(
 1785        mode: EditorMode,
 1786        buffer: Entity<MultiBuffer>,
 1787        project: Option<Entity<Project>>,
 1788        display_map: Option<Entity<DisplayMap>>,
 1789        window: &mut Window,
 1790        cx: &mut Context<Self>,
 1791    ) -> Self {
 1792        debug_assert!(
 1793            display_map.is_none() || mode.is_minimap(),
 1794            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1795        );
 1796
 1797        let full_mode = mode.is_full();
 1798        let diagnostics_max_severity = if full_mode {
 1799            EditorSettings::get_global(cx)
 1800                .diagnostics_max_severity
 1801                .unwrap_or(DiagnosticSeverity::Hint)
 1802        } else {
 1803            DiagnosticSeverity::Off
 1804        };
 1805        let style = window.text_style();
 1806        let font_size = style.font_size.to_pixels(window.rem_size());
 1807        let editor = cx.entity().downgrade();
 1808        let fold_placeholder = FoldPlaceholder {
 1809            constrain_width: true,
 1810            render: Arc::new(move |fold_id, fold_range, cx| {
 1811                let editor = editor.clone();
 1812                div()
 1813                    .id(fold_id)
 1814                    .bg(cx.theme().colors().ghost_element_background)
 1815                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1816                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1817                    .rounded_xs()
 1818                    .size_full()
 1819                    .cursor_pointer()
 1820                    .child("")
 1821                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1822                    .on_click(move |_, _window, cx| {
 1823                        editor
 1824                            .update(cx, |editor, cx| {
 1825                                editor.unfold_ranges(
 1826                                    &[fold_range.start..fold_range.end],
 1827                                    true,
 1828                                    false,
 1829                                    cx,
 1830                                );
 1831                                cx.stop_propagation();
 1832                            })
 1833                            .ok();
 1834                    })
 1835                    .into_any()
 1836            }),
 1837            merge_adjacent: true,
 1838            ..FoldPlaceholder::default()
 1839        };
 1840        let display_map = display_map.unwrap_or_else(|| {
 1841            cx.new(|cx| {
 1842                DisplayMap::new(
 1843                    buffer.clone(),
 1844                    style.font(),
 1845                    font_size,
 1846                    None,
 1847                    FILE_HEADER_HEIGHT,
 1848                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1849                    fold_placeholder,
 1850                    diagnostics_max_severity,
 1851                    cx,
 1852                )
 1853            })
 1854        });
 1855
 1856        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1857
 1858        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1859
 1860        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1861            .then(|| language_settings::SoftWrap::None);
 1862
 1863        let mut project_subscriptions = Vec::new();
 1864        if mode.is_full() {
 1865            if let Some(project) = project.as_ref() {
 1866                project_subscriptions.push(cx.subscribe_in(
 1867                    project,
 1868                    window,
 1869                    |editor, _, event, window, cx| match event {
 1870                        project::Event::RefreshCodeLens => {
 1871                            // we always query lens with actions, without storing them, always refreshing them
 1872                        }
 1873                        project::Event::RefreshInlayHints => {
 1874                            editor
 1875                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1876                        }
 1877                        project::Event::LanguageServerAdded(..)
 1878                        | project::Event::LanguageServerRemoved(..) => {
 1879                            if editor.tasks_update_task.is_none() {
 1880                                editor.tasks_update_task =
 1881                                    Some(editor.refresh_runnables(window, cx));
 1882                            }
 1883                            editor.update_lsp_data(true, None, window, cx);
 1884                        }
 1885                        project::Event::SnippetEdit(id, snippet_edits) => {
 1886                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1887                                let focus_handle = editor.focus_handle(cx);
 1888                                if focus_handle.is_focused(window) {
 1889                                    let snapshot = buffer.read(cx).snapshot();
 1890                                    for (range, snippet) in snippet_edits {
 1891                                        let editor_range =
 1892                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1893                                        editor
 1894                                            .insert_snippet(
 1895                                                &[editor_range],
 1896                                                snippet.clone(),
 1897                                                window,
 1898                                                cx,
 1899                                            )
 1900                                            .ok();
 1901                                    }
 1902                                }
 1903                            }
 1904                        }
 1905                        _ => {}
 1906                    },
 1907                ));
 1908                if let Some(task_inventory) = project
 1909                    .read(cx)
 1910                    .task_store()
 1911                    .read(cx)
 1912                    .task_inventory()
 1913                    .cloned()
 1914                {
 1915                    project_subscriptions.push(cx.observe_in(
 1916                        &task_inventory,
 1917                        window,
 1918                        |editor, _, window, cx| {
 1919                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1920                        },
 1921                    ));
 1922                };
 1923
 1924                project_subscriptions.push(cx.subscribe_in(
 1925                    &project.read(cx).breakpoint_store(),
 1926                    window,
 1927                    |editor, _, event, window, cx| match event {
 1928                        BreakpointStoreEvent::ClearDebugLines => {
 1929                            editor.clear_row_highlights::<ActiveDebugLine>();
 1930                            editor.refresh_inline_values(cx);
 1931                        }
 1932                        BreakpointStoreEvent::SetDebugLine => {
 1933                            if editor.go_to_active_debug_line(window, cx) {
 1934                                cx.stop_propagation();
 1935                            }
 1936
 1937                            editor.refresh_inline_values(cx);
 1938                        }
 1939                        _ => {}
 1940                    },
 1941                ));
 1942                let git_store = project.read(cx).git_store().clone();
 1943                let project = project.clone();
 1944                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1945                    match event {
 1946                        GitStoreEvent::RepositoryUpdated(
 1947                            _,
 1948                            RepositoryEvent::Updated {
 1949                                new_instance: true, ..
 1950                            },
 1951                            _,
 1952                        ) => {
 1953                            this.load_diff_task = Some(
 1954                                update_uncommitted_diff_for_buffer(
 1955                                    cx.entity(),
 1956                                    &project,
 1957                                    this.buffer.read(cx).all_buffers(),
 1958                                    this.buffer.clone(),
 1959                                    cx,
 1960                                )
 1961                                .shared(),
 1962                            );
 1963                        }
 1964                        _ => {}
 1965                    }
 1966                }));
 1967            }
 1968        }
 1969
 1970        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1971
 1972        let inlay_hint_settings =
 1973            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1974        let focus_handle = cx.focus_handle();
 1975        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1976            .detach();
 1977        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1978            .detach();
 1979        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1980            .detach();
 1981        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1982            .detach();
 1983        cx.observe_pending_input(window, Self::observe_pending_input)
 1984            .detach();
 1985
 1986        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1987            Some(false)
 1988        } else {
 1989            None
 1990        };
 1991
 1992        let breakpoint_store = match (&mode, project.as_ref()) {
 1993            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1994            _ => None,
 1995        };
 1996
 1997        let mut code_action_providers = Vec::new();
 1998        let mut load_uncommitted_diff = None;
 1999        if let Some(project) = project.clone() {
 2000            load_uncommitted_diff = Some(
 2001                update_uncommitted_diff_for_buffer(
 2002                    cx.entity(),
 2003                    &project,
 2004                    buffer.read(cx).all_buffers(),
 2005                    buffer.clone(),
 2006                    cx,
 2007                )
 2008                .shared(),
 2009            );
 2010            code_action_providers.push(Rc::new(project) as Rc<_>);
 2011        }
 2012
 2013        let mut editor = Self {
 2014            focus_handle,
 2015            show_cursor_when_unfocused: false,
 2016            last_focused_descendant: None,
 2017            buffer: buffer.clone(),
 2018            display_map: display_map.clone(),
 2019            selections,
 2020            scroll_manager: ScrollManager::new(cx),
 2021            columnar_selection_state: None,
 2022            add_selections_state: None,
 2023            select_next_state: None,
 2024            select_prev_state: None,
 2025            selection_history: SelectionHistory::default(),
 2026            defer_selection_effects: false,
 2027            deferred_selection_effects_state: None,
 2028            autoclose_regions: Vec::new(),
 2029            snippet_stack: InvalidationStack::default(),
 2030            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2031            ime_transaction: None,
 2032            active_diagnostics: ActiveDiagnostic::None,
 2033            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2034            inline_diagnostics_update: Task::ready(()),
 2035            inline_diagnostics: Vec::new(),
 2036            soft_wrap_mode_override,
 2037            diagnostics_max_severity,
 2038            hard_wrap: None,
 2039            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2040            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2041            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2042            project,
 2043            blink_manager: blink_manager.clone(),
 2044            show_local_selections: true,
 2045            show_scrollbars: ScrollbarAxes {
 2046                horizontal: full_mode,
 2047                vertical: full_mode,
 2048            },
 2049            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2050            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2051            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2052            show_gutter: mode.is_full(),
 2053            show_line_numbers: None,
 2054            use_relative_line_numbers: None,
 2055            disable_expand_excerpt_buttons: false,
 2056            show_git_diff_gutter: None,
 2057            show_code_actions: None,
 2058            show_runnables: None,
 2059            show_breakpoints: None,
 2060            show_wrap_guides: None,
 2061            show_indent_guides,
 2062            placeholder_text: None,
 2063            highlight_order: 0,
 2064            highlighted_rows: HashMap::default(),
 2065            background_highlights: TreeMap::default(),
 2066            gutter_highlights: TreeMap::default(),
 2067            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2068            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2069            nav_history: None,
 2070            context_menu: RefCell::new(None),
 2071            context_menu_options: None,
 2072            mouse_context_menu: None,
 2073            completion_tasks: Vec::new(),
 2074            inline_blame_popover: None,
 2075            inline_blame_popover_show_task: None,
 2076            signature_help_state: SignatureHelpState::default(),
 2077            auto_signature_help: None,
 2078            find_all_references_task_sources: Vec::new(),
 2079            next_completion_id: 0,
 2080            next_inlay_id: 0,
 2081            code_action_providers,
 2082            available_code_actions: None,
 2083            code_actions_task: None,
 2084            quick_selection_highlight_task: None,
 2085            debounced_selection_highlight_task: None,
 2086            document_highlights_task: None,
 2087            linked_editing_range_task: None,
 2088            pending_rename: None,
 2089            searchable: true,
 2090            cursor_shape: EditorSettings::get_global(cx)
 2091                .cursor_shape
 2092                .unwrap_or_default(),
 2093            current_line_highlight: None,
 2094            autoindent_mode: Some(AutoindentMode::EachLine),
 2095            collapse_matches: false,
 2096            workspace: None,
 2097            input_enabled: true,
 2098            use_modal_editing: mode.is_full(),
 2099            read_only: mode.is_minimap(),
 2100            use_autoclose: true,
 2101            use_auto_surround: true,
 2102            auto_replace_emoji_shortcode: false,
 2103            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2104            leader_id: None,
 2105            remote_id: None,
 2106            hover_state: HoverState::default(),
 2107            pending_mouse_down: None,
 2108            hovered_link_state: None,
 2109            edit_prediction_provider: None,
 2110            active_inline_completion: None,
 2111            stale_inline_completion_in_menu: None,
 2112            edit_prediction_preview: EditPredictionPreview::Inactive {
 2113                released_too_fast: false,
 2114            },
 2115            inline_diagnostics_enabled: mode.is_full(),
 2116            diagnostics_enabled: mode.is_full(),
 2117            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2118            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2119
 2120            gutter_hovered: false,
 2121            pixel_position_of_newest_cursor: None,
 2122            last_bounds: None,
 2123            last_position_map: None,
 2124            expect_bounds_change: None,
 2125            gutter_dimensions: GutterDimensions::default(),
 2126            style: None,
 2127            show_cursor_names: false,
 2128            hovered_cursors: HashMap::default(),
 2129            next_editor_action_id: EditorActionId::default(),
 2130            editor_actions: Rc::default(),
 2131            inline_completions_hidden_for_vim_mode: false,
 2132            show_inline_completions_override: None,
 2133            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2134            edit_prediction_settings: EditPredictionSettings::Disabled,
 2135            edit_prediction_indent_conflict: false,
 2136            edit_prediction_requires_modifier_in_indent_conflict: true,
 2137            custom_context_menu: None,
 2138            show_git_blame_gutter: false,
 2139            show_git_blame_inline: false,
 2140            show_selection_menu: None,
 2141            show_git_blame_inline_delay_task: None,
 2142            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2143            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2144            serialize_dirty_buffers: !mode.is_minimap()
 2145                && ProjectSettings::get_global(cx)
 2146                    .session
 2147                    .restore_unsaved_buffers,
 2148            blame: None,
 2149            blame_subscription: None,
 2150            tasks: BTreeMap::default(),
 2151
 2152            breakpoint_store,
 2153            gutter_breakpoint_indicator: (None, None),
 2154            hovered_diff_hunk_row: None,
 2155            _subscriptions: vec![
 2156                cx.observe(&buffer, Self::on_buffer_changed),
 2157                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2158                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2159                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2160                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2161                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2162                cx.observe_window_activation(window, |editor, window, cx| {
 2163                    let active = window.is_window_active();
 2164                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2165                        if active {
 2166                            blink_manager.enable(cx);
 2167                        } else {
 2168                            blink_manager.disable(cx);
 2169                        }
 2170                    });
 2171                    if active {
 2172                        editor.show_mouse_cursor(cx);
 2173                    }
 2174                }),
 2175            ],
 2176            tasks_update_task: None,
 2177            pull_diagnostics_task: Task::ready(()),
 2178            colors: None,
 2179            next_color_inlay_id: 0,
 2180            linked_edit_ranges: Default::default(),
 2181            in_project_search: false,
 2182            previous_search_ranges: None,
 2183            breadcrumb_header: None,
 2184            focused_block: None,
 2185            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2186            addons: HashMap::default(),
 2187            registered_buffers: HashMap::default(),
 2188            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2189            selection_mark_mode: false,
 2190            toggle_fold_multiple_buffers: Task::ready(()),
 2191            serialize_selections: Task::ready(()),
 2192            serialize_folds: Task::ready(()),
 2193            text_style_refinement: None,
 2194            load_diff_task: load_uncommitted_diff,
 2195            temporary_diff_override: false,
 2196            mouse_cursor_hidden: false,
 2197            minimap: None,
 2198            hide_mouse_mode: EditorSettings::get_global(cx)
 2199                .hide_mouse
 2200                .unwrap_or_default(),
 2201            change_list: ChangeList::new(),
 2202            mode,
 2203            selection_drag_state: SelectionDragState::None,
 2204            folding_newlines: Task::ready(()),
 2205        };
 2206        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2207            editor
 2208                ._subscriptions
 2209                .push(cx.observe(breakpoints, |_, _, cx| {
 2210                    cx.notify();
 2211                }));
 2212        }
 2213        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2214        editor._subscriptions.extend(project_subscriptions);
 2215
 2216        editor._subscriptions.push(cx.subscribe_in(
 2217            &cx.entity(),
 2218            window,
 2219            |editor, _, e: &EditorEvent, window, cx| match e {
 2220                EditorEvent::ScrollPositionChanged { local, .. } => {
 2221                    if *local {
 2222                        let new_anchor = editor.scroll_manager.anchor();
 2223                        let snapshot = editor.snapshot(window, cx);
 2224                        editor.update_restoration_data(cx, move |data| {
 2225                            data.scroll_position = (
 2226                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2227                                new_anchor.offset,
 2228                            );
 2229                        });
 2230                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2231                        editor.inline_blame_popover.take();
 2232                    }
 2233                }
 2234                EditorEvent::Edited { .. } => {
 2235                    if !vim_enabled(cx) {
 2236                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2237                        let pop_state = editor
 2238                            .change_list
 2239                            .last()
 2240                            .map(|previous| {
 2241                                previous.len() == selections.len()
 2242                                    && previous.iter().enumerate().all(|(ix, p)| {
 2243                                        p.to_display_point(&map).row()
 2244                                            == selections[ix].head().row()
 2245                                    })
 2246                            })
 2247                            .unwrap_or(false);
 2248                        let new_positions = selections
 2249                            .into_iter()
 2250                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2251                            .collect();
 2252                        editor
 2253                            .change_list
 2254                            .push_to_change_list(pop_state, new_positions);
 2255                    }
 2256                }
 2257                _ => (),
 2258            },
 2259        ));
 2260
 2261        if let Some(dap_store) = editor
 2262            .project
 2263            .as_ref()
 2264            .map(|project| project.read(cx).dap_store())
 2265        {
 2266            let weak_editor = cx.weak_entity();
 2267
 2268            editor
 2269                ._subscriptions
 2270                .push(
 2271                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2272                        let session_entity = cx.entity();
 2273                        weak_editor
 2274                            .update(cx, |editor, cx| {
 2275                                editor._subscriptions.push(
 2276                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2277                                );
 2278                            })
 2279                            .ok();
 2280                    }),
 2281                );
 2282
 2283            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2284                editor
 2285                    ._subscriptions
 2286                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2287            }
 2288        }
 2289
 2290        // skip adding the initial selection to selection history
 2291        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2292        editor.end_selection(window, cx);
 2293        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2294
 2295        editor.scroll_manager.show_scrollbars(window, cx);
 2296        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2297
 2298        if full_mode {
 2299            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2300            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2301
 2302            if editor.git_blame_inline_enabled {
 2303                editor.start_git_blame_inline(false, window, cx);
 2304            }
 2305
 2306            editor.go_to_active_debug_line(window, cx);
 2307
 2308            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2309                if let Some(project) = editor.project.as_ref() {
 2310                    let handle = project.update(cx, |project, cx| {
 2311                        project.register_buffer_with_language_servers(&buffer, cx)
 2312                    });
 2313                    editor
 2314                        .registered_buffers
 2315                        .insert(buffer.read(cx).remote_id(), handle);
 2316                }
 2317            }
 2318
 2319            editor.minimap =
 2320                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2321            editor.colors = Some(LspColorData::new(cx));
 2322            editor.update_lsp_data(false, None, window, cx);
 2323        }
 2324
 2325        editor.report_editor_event("Editor Opened", None, cx);
 2326        editor
 2327    }
 2328
 2329    pub fn deploy_mouse_context_menu(
 2330        &mut self,
 2331        position: gpui::Point<Pixels>,
 2332        context_menu: Entity<ContextMenu>,
 2333        window: &mut Window,
 2334        cx: &mut Context<Self>,
 2335    ) {
 2336        self.mouse_context_menu = Some(MouseContextMenu::new(
 2337            self,
 2338            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2339            context_menu,
 2340            window,
 2341            cx,
 2342        ));
 2343    }
 2344
 2345    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2346        self.mouse_context_menu
 2347            .as_ref()
 2348            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2349    }
 2350
 2351    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2352        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2353    }
 2354
 2355    fn key_context_internal(
 2356        &self,
 2357        has_active_edit_prediction: bool,
 2358        window: &Window,
 2359        cx: &App,
 2360    ) -> KeyContext {
 2361        let mut key_context = KeyContext::new_with_defaults();
 2362        key_context.add("Editor");
 2363        let mode = match self.mode {
 2364            EditorMode::SingleLine { .. } => "single_line",
 2365            EditorMode::AutoHeight { .. } => "auto_height",
 2366            EditorMode::Minimap { .. } => "minimap",
 2367            EditorMode::Full { .. } => "full",
 2368        };
 2369
 2370        if EditorSettings::jupyter_enabled(cx) {
 2371            key_context.add("jupyter");
 2372        }
 2373
 2374        key_context.set("mode", mode);
 2375        if self.pending_rename.is_some() {
 2376            key_context.add("renaming");
 2377        }
 2378
 2379        match self.context_menu.borrow().as_ref() {
 2380            Some(CodeContextMenu::Completions(_)) => {
 2381                key_context.add("menu");
 2382                key_context.add("showing_completions");
 2383            }
 2384            Some(CodeContextMenu::CodeActions(_)) => {
 2385                key_context.add("menu");
 2386                key_context.add("showing_code_actions")
 2387            }
 2388            None => {}
 2389        }
 2390
 2391        if self.signature_help_state.has_multiple_signatures() {
 2392            key_context.add("showing_signature_help");
 2393        }
 2394
 2395        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2396        if !self.focus_handle(cx).contains_focused(window, cx)
 2397            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2398        {
 2399            for addon in self.addons.values() {
 2400                addon.extend_key_context(&mut key_context, cx)
 2401            }
 2402        }
 2403
 2404        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2405            if let Some(extension) = singleton_buffer
 2406                .read(cx)
 2407                .file()
 2408                .and_then(|file| file.path().extension()?.to_str())
 2409            {
 2410                key_context.set("extension", extension.to_string());
 2411            }
 2412        } else {
 2413            key_context.add("multibuffer");
 2414        }
 2415
 2416        if has_active_edit_prediction {
 2417            if self.edit_prediction_in_conflict() {
 2418                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2419            } else {
 2420                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2421                key_context.add("copilot_suggestion");
 2422            }
 2423        }
 2424
 2425        if self.selection_mark_mode {
 2426            key_context.add("selection_mode");
 2427        }
 2428
 2429        key_context
 2430    }
 2431
 2432    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2433        if self.mouse_cursor_hidden {
 2434            self.mouse_cursor_hidden = false;
 2435            cx.notify();
 2436        }
 2437    }
 2438
 2439    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2440        let hide_mouse_cursor = match origin {
 2441            HideMouseCursorOrigin::TypingAction => {
 2442                matches!(
 2443                    self.hide_mouse_mode,
 2444                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2445                )
 2446            }
 2447            HideMouseCursorOrigin::MovementAction => {
 2448                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2449            }
 2450        };
 2451        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2452            self.mouse_cursor_hidden = hide_mouse_cursor;
 2453            cx.notify();
 2454        }
 2455    }
 2456
 2457    pub fn edit_prediction_in_conflict(&self) -> bool {
 2458        if !self.show_edit_predictions_in_menu() {
 2459            return false;
 2460        }
 2461
 2462        let showing_completions = self
 2463            .context_menu
 2464            .borrow()
 2465            .as_ref()
 2466            .map_or(false, |context| {
 2467                matches!(context, CodeContextMenu::Completions(_))
 2468            });
 2469
 2470        showing_completions
 2471            || self.edit_prediction_requires_modifier()
 2472            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2473            // bindings to insert tab characters.
 2474            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2475    }
 2476
 2477    pub fn accept_edit_prediction_keybind(
 2478        &self,
 2479        accept_partial: bool,
 2480        window: &Window,
 2481        cx: &App,
 2482    ) -> AcceptEditPredictionBinding {
 2483        let key_context = self.key_context_internal(true, window, cx);
 2484        let in_conflict = self.edit_prediction_in_conflict();
 2485
 2486        let bindings = if accept_partial {
 2487            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2488        } else {
 2489            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2490        };
 2491
 2492        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2493        // just the first one.
 2494        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2495            !in_conflict
 2496                || binding
 2497                    .keystrokes()
 2498                    .first()
 2499                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2500        }))
 2501    }
 2502
 2503    pub fn new_file(
 2504        workspace: &mut Workspace,
 2505        _: &workspace::NewFile,
 2506        window: &mut Window,
 2507        cx: &mut Context<Workspace>,
 2508    ) {
 2509        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2510            "Failed to create buffer",
 2511            window,
 2512            cx,
 2513            |e, _, _| match e.error_code() {
 2514                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2515                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2516                e.error_tag("required").unwrap_or("the latest version")
 2517            )),
 2518                _ => None,
 2519            },
 2520        );
 2521    }
 2522
 2523    pub fn new_in_workspace(
 2524        workspace: &mut Workspace,
 2525        window: &mut Window,
 2526        cx: &mut Context<Workspace>,
 2527    ) -> Task<Result<Entity<Editor>>> {
 2528        let project = workspace.project().clone();
 2529        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2530
 2531        cx.spawn_in(window, async move |workspace, cx| {
 2532            let buffer = create.await?;
 2533            workspace.update_in(cx, |workspace, window, cx| {
 2534                let editor =
 2535                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2536                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2537                editor
 2538            })
 2539        })
 2540    }
 2541
 2542    fn new_file_vertical(
 2543        workspace: &mut Workspace,
 2544        _: &workspace::NewFileSplitVertical,
 2545        window: &mut Window,
 2546        cx: &mut Context<Workspace>,
 2547    ) {
 2548        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2549    }
 2550
 2551    fn new_file_horizontal(
 2552        workspace: &mut Workspace,
 2553        _: &workspace::NewFileSplitHorizontal,
 2554        window: &mut Window,
 2555        cx: &mut Context<Workspace>,
 2556    ) {
 2557        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2558    }
 2559
 2560    fn new_file_in_direction(
 2561        workspace: &mut Workspace,
 2562        direction: SplitDirection,
 2563        window: &mut Window,
 2564        cx: &mut Context<Workspace>,
 2565    ) {
 2566        let project = workspace.project().clone();
 2567        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2568
 2569        cx.spawn_in(window, async move |workspace, cx| {
 2570            let buffer = create.await?;
 2571            workspace.update_in(cx, move |workspace, window, cx| {
 2572                workspace.split_item(
 2573                    direction,
 2574                    Box::new(
 2575                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2576                    ),
 2577                    window,
 2578                    cx,
 2579                )
 2580            })?;
 2581            anyhow::Ok(())
 2582        })
 2583        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2584            match e.error_code() {
 2585                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2586                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2587                e.error_tag("required").unwrap_or("the latest version")
 2588            )),
 2589                _ => None,
 2590            }
 2591        });
 2592    }
 2593
 2594    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2595        self.leader_id
 2596    }
 2597
 2598    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2599        &self.buffer
 2600    }
 2601
 2602    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2603        self.workspace.as_ref()?.0.upgrade()
 2604    }
 2605
 2606    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2607        self.buffer().read(cx).title(cx)
 2608    }
 2609
 2610    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2611        let git_blame_gutter_max_author_length = self
 2612            .render_git_blame_gutter(cx)
 2613            .then(|| {
 2614                if let Some(blame) = self.blame.as_ref() {
 2615                    let max_author_length =
 2616                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2617                    Some(max_author_length)
 2618                } else {
 2619                    None
 2620                }
 2621            })
 2622            .flatten();
 2623
 2624        EditorSnapshot {
 2625            mode: self.mode.clone(),
 2626            show_gutter: self.show_gutter,
 2627            show_line_numbers: self.show_line_numbers,
 2628            show_git_diff_gutter: self.show_git_diff_gutter,
 2629            show_code_actions: self.show_code_actions,
 2630            show_runnables: self.show_runnables,
 2631            show_breakpoints: self.show_breakpoints,
 2632            git_blame_gutter_max_author_length,
 2633            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2634            scroll_anchor: self.scroll_manager.anchor(),
 2635            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2636            placeholder_text: self.placeholder_text.clone(),
 2637            is_focused: self.focus_handle.is_focused(window),
 2638            current_line_highlight: self
 2639                .current_line_highlight
 2640                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2641            gutter_hovered: self.gutter_hovered,
 2642        }
 2643    }
 2644
 2645    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2646        self.buffer.read(cx).language_at(point, cx)
 2647    }
 2648
 2649    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2650        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2651    }
 2652
 2653    pub fn active_excerpt(
 2654        &self,
 2655        cx: &App,
 2656    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2657        self.buffer
 2658            .read(cx)
 2659            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2660    }
 2661
 2662    pub fn mode(&self) -> &EditorMode {
 2663        &self.mode
 2664    }
 2665
 2666    pub fn set_mode(&mut self, mode: EditorMode) {
 2667        self.mode = mode;
 2668    }
 2669
 2670    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2671        self.collaboration_hub.as_deref()
 2672    }
 2673
 2674    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2675        self.collaboration_hub = Some(hub);
 2676    }
 2677
 2678    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2679        self.in_project_search = in_project_search;
 2680    }
 2681
 2682    pub fn set_custom_context_menu(
 2683        &mut self,
 2684        f: impl 'static
 2685        + Fn(
 2686            &mut Self,
 2687            DisplayPoint,
 2688            &mut Window,
 2689            &mut Context<Self>,
 2690        ) -> Option<Entity<ui::ContextMenu>>,
 2691    ) {
 2692        self.custom_context_menu = Some(Box::new(f))
 2693    }
 2694
 2695    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2696        self.completion_provider = provider;
 2697    }
 2698
 2699    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2700        self.semantics_provider.clone()
 2701    }
 2702
 2703    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2704        self.semantics_provider = provider;
 2705    }
 2706
 2707    pub fn set_edit_prediction_provider<T>(
 2708        &mut self,
 2709        provider: Option<Entity<T>>,
 2710        window: &mut Window,
 2711        cx: &mut Context<Self>,
 2712    ) where
 2713        T: EditPredictionProvider,
 2714    {
 2715        self.edit_prediction_provider =
 2716            provider.map(|provider| RegisteredInlineCompletionProvider {
 2717                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2718                    if this.focus_handle.is_focused(window) {
 2719                        this.update_visible_inline_completion(window, cx);
 2720                    }
 2721                }),
 2722                provider: Arc::new(provider),
 2723            });
 2724        self.update_edit_prediction_settings(cx);
 2725        self.refresh_inline_completion(false, false, window, cx);
 2726    }
 2727
 2728    pub fn placeholder_text(&self) -> Option<&str> {
 2729        self.placeholder_text.as_deref()
 2730    }
 2731
 2732    pub fn set_placeholder_text(
 2733        &mut self,
 2734        placeholder_text: impl Into<Arc<str>>,
 2735        cx: &mut Context<Self>,
 2736    ) {
 2737        let placeholder_text = Some(placeholder_text.into());
 2738        if self.placeholder_text != placeholder_text {
 2739            self.placeholder_text = placeholder_text;
 2740            cx.notify();
 2741        }
 2742    }
 2743
 2744    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2745        self.cursor_shape = cursor_shape;
 2746
 2747        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2748        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2749
 2750        cx.notify();
 2751    }
 2752
 2753    pub fn set_current_line_highlight(
 2754        &mut self,
 2755        current_line_highlight: Option<CurrentLineHighlight>,
 2756    ) {
 2757        self.current_line_highlight = current_line_highlight;
 2758    }
 2759
 2760    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2761        self.collapse_matches = collapse_matches;
 2762    }
 2763
 2764    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2765        let buffers = self.buffer.read(cx).all_buffers();
 2766        let Some(project) = self.project.as_ref() else {
 2767            return;
 2768        };
 2769        project.update(cx, |project, cx| {
 2770            for buffer in buffers {
 2771                self.registered_buffers
 2772                    .entry(buffer.read(cx).remote_id())
 2773                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2774            }
 2775        })
 2776    }
 2777
 2778    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2779        if self.collapse_matches {
 2780            return range.start..range.start;
 2781        }
 2782        range.clone()
 2783    }
 2784
 2785    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2786        if self.display_map.read(cx).clip_at_line_ends != clip {
 2787            self.display_map
 2788                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2789        }
 2790    }
 2791
 2792    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2793        self.input_enabled = input_enabled;
 2794    }
 2795
 2796    pub fn set_inline_completions_hidden_for_vim_mode(
 2797        &mut self,
 2798        hidden: bool,
 2799        window: &mut Window,
 2800        cx: &mut Context<Self>,
 2801    ) {
 2802        if hidden != self.inline_completions_hidden_for_vim_mode {
 2803            self.inline_completions_hidden_for_vim_mode = hidden;
 2804            if hidden {
 2805                self.update_visible_inline_completion(window, cx);
 2806            } else {
 2807                self.refresh_inline_completion(true, false, window, cx);
 2808            }
 2809        }
 2810    }
 2811
 2812    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2813        self.menu_inline_completions_policy = value;
 2814    }
 2815
 2816    pub fn set_autoindent(&mut self, autoindent: bool) {
 2817        if autoindent {
 2818            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2819        } else {
 2820            self.autoindent_mode = None;
 2821        }
 2822    }
 2823
 2824    pub fn read_only(&self, cx: &App) -> bool {
 2825        self.read_only || self.buffer.read(cx).read_only()
 2826    }
 2827
 2828    pub fn set_read_only(&mut self, read_only: bool) {
 2829        self.read_only = read_only;
 2830    }
 2831
 2832    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2833        self.use_autoclose = autoclose;
 2834    }
 2835
 2836    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2837        self.use_auto_surround = auto_surround;
 2838    }
 2839
 2840    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2841        self.auto_replace_emoji_shortcode = auto_replace;
 2842    }
 2843
 2844    pub fn toggle_edit_predictions(
 2845        &mut self,
 2846        _: &ToggleEditPrediction,
 2847        window: &mut Window,
 2848        cx: &mut Context<Self>,
 2849    ) {
 2850        if self.show_inline_completions_override.is_some() {
 2851            self.set_show_edit_predictions(None, window, cx);
 2852        } else {
 2853            let show_edit_predictions = !self.edit_predictions_enabled();
 2854            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2855        }
 2856    }
 2857
 2858    pub fn set_show_edit_predictions(
 2859        &mut self,
 2860        show_edit_predictions: Option<bool>,
 2861        window: &mut Window,
 2862        cx: &mut Context<Self>,
 2863    ) {
 2864        self.show_inline_completions_override = show_edit_predictions;
 2865        self.update_edit_prediction_settings(cx);
 2866
 2867        if let Some(false) = show_edit_predictions {
 2868            self.discard_inline_completion(false, cx);
 2869        } else {
 2870            self.refresh_inline_completion(false, true, window, cx);
 2871        }
 2872    }
 2873
 2874    fn inline_completions_disabled_in_scope(
 2875        &self,
 2876        buffer: &Entity<Buffer>,
 2877        buffer_position: language::Anchor,
 2878        cx: &App,
 2879    ) -> bool {
 2880        let snapshot = buffer.read(cx).snapshot();
 2881        let settings = snapshot.settings_at(buffer_position, cx);
 2882
 2883        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2884            return false;
 2885        };
 2886
 2887        scope.override_name().map_or(false, |scope_name| {
 2888            settings
 2889                .edit_predictions_disabled_in
 2890                .iter()
 2891                .any(|s| s == scope_name)
 2892        })
 2893    }
 2894
 2895    pub fn set_use_modal_editing(&mut self, to: bool) {
 2896        self.use_modal_editing = to;
 2897    }
 2898
 2899    pub fn use_modal_editing(&self) -> bool {
 2900        self.use_modal_editing
 2901    }
 2902
 2903    fn selections_did_change(
 2904        &mut self,
 2905        local: bool,
 2906        old_cursor_position: &Anchor,
 2907        effects: SelectionEffects,
 2908        window: &mut Window,
 2909        cx: &mut Context<Self>,
 2910    ) {
 2911        window.invalidate_character_coordinates();
 2912
 2913        // Copy selections to primary selection buffer
 2914        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2915        if local {
 2916            let selections = self.selections.all::<usize>(cx);
 2917            let buffer_handle = self.buffer.read(cx).read(cx);
 2918
 2919            let mut text = String::new();
 2920            for (index, selection) in selections.iter().enumerate() {
 2921                let text_for_selection = buffer_handle
 2922                    .text_for_range(selection.start..selection.end)
 2923                    .collect::<String>();
 2924
 2925                text.push_str(&text_for_selection);
 2926                if index != selections.len() - 1 {
 2927                    text.push('\n');
 2928                }
 2929            }
 2930
 2931            if !text.is_empty() {
 2932                cx.write_to_primary(ClipboardItem::new_string(text));
 2933            }
 2934        }
 2935
 2936        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2937            self.buffer.update(cx, |buffer, cx| {
 2938                buffer.set_active_selections(
 2939                    &self.selections.disjoint_anchors(),
 2940                    self.selections.line_mode,
 2941                    self.cursor_shape,
 2942                    cx,
 2943                )
 2944            });
 2945        }
 2946        let display_map = self
 2947            .display_map
 2948            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2949        let buffer = &display_map.buffer_snapshot;
 2950        if self.selections.count() == 1 {
 2951            self.add_selections_state = None;
 2952        }
 2953        self.select_next_state = None;
 2954        self.select_prev_state = None;
 2955        self.select_syntax_node_history.try_clear();
 2956        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2957        self.snippet_stack
 2958            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2959        self.take_rename(false, window, cx);
 2960
 2961        let newest_selection = self.selections.newest_anchor();
 2962        let new_cursor_position = newest_selection.head();
 2963        let selection_start = newest_selection.start;
 2964
 2965        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2966            self.push_to_nav_history(
 2967                *old_cursor_position,
 2968                Some(new_cursor_position.to_point(buffer)),
 2969                false,
 2970                effects.nav_history == Some(true),
 2971                cx,
 2972            );
 2973        }
 2974
 2975        if local {
 2976            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2977                if !self.registered_buffers.contains_key(&buffer_id) {
 2978                    if let Some(project) = self.project.as_ref() {
 2979                        project.update(cx, |project, cx| {
 2980                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2981                                return;
 2982                            };
 2983                            self.registered_buffers.insert(
 2984                                buffer_id,
 2985                                project.register_buffer_with_language_servers(&buffer, cx),
 2986                            );
 2987                        })
 2988                    }
 2989                }
 2990            }
 2991
 2992            let mut context_menu = self.context_menu.borrow_mut();
 2993            let completion_menu = match context_menu.as_ref() {
 2994                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2995                Some(CodeContextMenu::CodeActions(_)) => {
 2996                    *context_menu = None;
 2997                    None
 2998                }
 2999                None => None,
 3000            };
 3001            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3002            drop(context_menu);
 3003
 3004            if effects.completions {
 3005                if let Some(completion_position) = completion_position {
 3006                    let start_offset = selection_start.to_offset(buffer);
 3007                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3008                    let continue_showing = if position_matches {
 3009                        if self.snippet_stack.is_empty() {
 3010                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3011                        } else {
 3012                            // Snippet choices can be shown even when the cursor is in whitespace.
 3013                            // Dismissing the menu with actions like backspace is handled by
 3014                            // invalidation regions.
 3015                            true
 3016                        }
 3017                    } else {
 3018                        false
 3019                    };
 3020
 3021                    if continue_showing {
 3022                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3023                    } else {
 3024                        self.hide_context_menu(window, cx);
 3025                    }
 3026                }
 3027            }
 3028
 3029            hide_hover(self, cx);
 3030
 3031            if old_cursor_position.to_display_point(&display_map).row()
 3032                != new_cursor_position.to_display_point(&display_map).row()
 3033            {
 3034                self.available_code_actions.take();
 3035            }
 3036            self.refresh_code_actions(window, cx);
 3037            self.refresh_document_highlights(cx);
 3038            self.refresh_selected_text_highlights(false, window, cx);
 3039            refresh_matching_bracket_highlights(self, window, cx);
 3040            self.update_visible_inline_completion(window, cx);
 3041            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3042            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3043            self.inline_blame_popover.take();
 3044            if self.git_blame_inline_enabled {
 3045                self.start_inline_blame_timer(window, cx);
 3046            }
 3047        }
 3048
 3049        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3050        cx.emit(EditorEvent::SelectionsChanged { local });
 3051
 3052        let selections = &self.selections.disjoint;
 3053        if selections.len() == 1 {
 3054            cx.emit(SearchEvent::ActiveMatchChanged)
 3055        }
 3056        if local {
 3057            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3058                let inmemory_selections = selections
 3059                    .iter()
 3060                    .map(|s| {
 3061                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3062                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3063                    })
 3064                    .collect();
 3065                self.update_restoration_data(cx, |data| {
 3066                    data.selections = inmemory_selections;
 3067                });
 3068
 3069                if WorkspaceSettings::get(None, cx).restore_on_startup
 3070                    != RestoreOnStartupBehavior::None
 3071                {
 3072                    if let Some(workspace_id) =
 3073                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3074                    {
 3075                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3076                        let selections = selections.clone();
 3077                        let background_executor = cx.background_executor().clone();
 3078                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3079                        self.serialize_selections = cx.background_spawn(async move {
 3080                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3081                            let db_selections = selections
 3082                                .iter()
 3083                                .map(|selection| {
 3084                                    (
 3085                                        selection.start.to_offset(&snapshot),
 3086                                        selection.end.to_offset(&snapshot),
 3087                                    )
 3088                                })
 3089                                .collect();
 3090
 3091                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3092                                .await
 3093                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3094                                .log_err();
 3095                        });
 3096                    }
 3097                }
 3098            }
 3099        }
 3100
 3101        cx.notify();
 3102    }
 3103
 3104    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3105        use text::ToOffset as _;
 3106        use text::ToPoint as _;
 3107
 3108        if self.mode.is_minimap()
 3109            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3110        {
 3111            return;
 3112        }
 3113
 3114        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3115            return;
 3116        };
 3117
 3118        let snapshot = singleton.read(cx).snapshot();
 3119        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3120            let display_snapshot = display_map.snapshot(cx);
 3121
 3122            display_snapshot
 3123                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3124                .map(|fold| {
 3125                    fold.range.start.text_anchor.to_point(&snapshot)
 3126                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3127                })
 3128                .collect()
 3129        });
 3130        self.update_restoration_data(cx, |data| {
 3131            data.folds = inmemory_folds;
 3132        });
 3133
 3134        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3135            return;
 3136        };
 3137        let background_executor = cx.background_executor().clone();
 3138        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3139        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3140            display_map
 3141                .snapshot(cx)
 3142                .folds_in_range(0..snapshot.len())
 3143                .map(|fold| {
 3144                    (
 3145                        fold.range.start.text_anchor.to_offset(&snapshot),
 3146                        fold.range.end.text_anchor.to_offset(&snapshot),
 3147                    )
 3148                })
 3149                .collect()
 3150        });
 3151        self.serialize_folds = cx.background_spawn(async move {
 3152            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3153            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3154                .await
 3155                .with_context(|| {
 3156                    format!(
 3157                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3158                    )
 3159                })
 3160                .log_err();
 3161        });
 3162    }
 3163
 3164    pub fn sync_selections(
 3165        &mut self,
 3166        other: Entity<Editor>,
 3167        cx: &mut Context<Self>,
 3168    ) -> gpui::Subscription {
 3169        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3170        self.selections.change_with(cx, |selections| {
 3171            selections.select_anchors(other_selections);
 3172        });
 3173
 3174        let other_subscription =
 3175            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3176                EditorEvent::SelectionsChanged { local: true } => {
 3177                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3178                    if other_selections.is_empty() {
 3179                        return;
 3180                    }
 3181                    this.selections.change_with(cx, |selections| {
 3182                        selections.select_anchors(other_selections);
 3183                    });
 3184                }
 3185                _ => {}
 3186            });
 3187
 3188        let this_subscription =
 3189            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3190                EditorEvent::SelectionsChanged { local: true } => {
 3191                    let these_selections = this.selections.disjoint.to_vec();
 3192                    if these_selections.is_empty() {
 3193                        return;
 3194                    }
 3195                    other.update(cx, |other_editor, cx| {
 3196                        other_editor.selections.change_with(cx, |selections| {
 3197                            selections.select_anchors(these_selections);
 3198                        })
 3199                    });
 3200                }
 3201                _ => {}
 3202            });
 3203
 3204        Subscription::join(other_subscription, this_subscription)
 3205    }
 3206
 3207    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3208    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3209    /// effects of selection change occur at the end of the transaction.
 3210    pub fn change_selections<R>(
 3211        &mut self,
 3212        effects: SelectionEffects,
 3213        window: &mut Window,
 3214        cx: &mut Context<Self>,
 3215        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3216    ) -> R {
 3217        if let Some(state) = &mut self.deferred_selection_effects_state {
 3218            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3219            state.effects.completions = effects.completions;
 3220            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3221            let (changed, result) = self.selections.change_with(cx, change);
 3222            state.changed |= changed;
 3223            return result;
 3224        }
 3225        let mut state = DeferredSelectionEffectsState {
 3226            changed: false,
 3227            effects,
 3228            old_cursor_position: self.selections.newest_anchor().head(),
 3229            history_entry: SelectionHistoryEntry {
 3230                selections: self.selections.disjoint_anchors(),
 3231                select_next_state: self.select_next_state.clone(),
 3232                select_prev_state: self.select_prev_state.clone(),
 3233                add_selections_state: self.add_selections_state.clone(),
 3234            },
 3235        };
 3236        let (changed, result) = self.selections.change_with(cx, change);
 3237        state.changed = state.changed || changed;
 3238        if self.defer_selection_effects {
 3239            self.deferred_selection_effects_state = Some(state);
 3240        } else {
 3241            self.apply_selection_effects(state, window, cx);
 3242        }
 3243        result
 3244    }
 3245
 3246    /// Defers the effects of selection change, so that the effects of multiple calls to
 3247    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3248    /// to selection history and the state of popovers based on selection position aren't
 3249    /// erroneously updated.
 3250    pub fn with_selection_effects_deferred<R>(
 3251        &mut self,
 3252        window: &mut Window,
 3253        cx: &mut Context<Self>,
 3254        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3255    ) -> R {
 3256        let already_deferred = self.defer_selection_effects;
 3257        self.defer_selection_effects = true;
 3258        let result = update(self, window, cx);
 3259        if !already_deferred {
 3260            self.defer_selection_effects = false;
 3261            if let Some(state) = self.deferred_selection_effects_state.take() {
 3262                self.apply_selection_effects(state, window, cx);
 3263            }
 3264        }
 3265        result
 3266    }
 3267
 3268    fn apply_selection_effects(
 3269        &mut self,
 3270        state: DeferredSelectionEffectsState,
 3271        window: &mut Window,
 3272        cx: &mut Context<Self>,
 3273    ) {
 3274        if state.changed {
 3275            self.selection_history.push(state.history_entry);
 3276
 3277            if let Some(autoscroll) = state.effects.scroll {
 3278                self.request_autoscroll(autoscroll, cx);
 3279            }
 3280
 3281            let old_cursor_position = &state.old_cursor_position;
 3282
 3283            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3284
 3285            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3286                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3287            }
 3288        }
 3289    }
 3290
 3291    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3292    where
 3293        I: IntoIterator<Item = (Range<S>, T)>,
 3294        S: ToOffset,
 3295        T: Into<Arc<str>>,
 3296    {
 3297        if self.read_only(cx) {
 3298            return;
 3299        }
 3300
 3301        self.buffer
 3302            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3303    }
 3304
 3305    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3306    where
 3307        I: IntoIterator<Item = (Range<S>, T)>,
 3308        S: ToOffset,
 3309        T: Into<Arc<str>>,
 3310    {
 3311        if self.read_only(cx) {
 3312            return;
 3313        }
 3314
 3315        self.buffer.update(cx, |buffer, cx| {
 3316            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3317        });
 3318    }
 3319
 3320    pub fn edit_with_block_indent<I, S, T>(
 3321        &mut self,
 3322        edits: I,
 3323        original_indent_columns: Vec<Option<u32>>,
 3324        cx: &mut Context<Self>,
 3325    ) where
 3326        I: IntoIterator<Item = (Range<S>, T)>,
 3327        S: ToOffset,
 3328        T: Into<Arc<str>>,
 3329    {
 3330        if self.read_only(cx) {
 3331            return;
 3332        }
 3333
 3334        self.buffer.update(cx, |buffer, cx| {
 3335            buffer.edit(
 3336                edits,
 3337                Some(AutoindentMode::Block {
 3338                    original_indent_columns,
 3339                }),
 3340                cx,
 3341            )
 3342        });
 3343    }
 3344
 3345    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3346        self.hide_context_menu(window, cx);
 3347
 3348        match phase {
 3349            SelectPhase::Begin {
 3350                position,
 3351                add,
 3352                click_count,
 3353            } => self.begin_selection(position, add, click_count, window, cx),
 3354            SelectPhase::BeginColumnar {
 3355                position,
 3356                goal_column,
 3357                reset,
 3358                mode,
 3359            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3360            SelectPhase::Extend {
 3361                position,
 3362                click_count,
 3363            } => self.extend_selection(position, click_count, window, cx),
 3364            SelectPhase::Update {
 3365                position,
 3366                goal_column,
 3367                scroll_delta,
 3368            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3369            SelectPhase::End => self.end_selection(window, cx),
 3370        }
 3371    }
 3372
 3373    fn extend_selection(
 3374        &mut self,
 3375        position: DisplayPoint,
 3376        click_count: usize,
 3377        window: &mut Window,
 3378        cx: &mut Context<Self>,
 3379    ) {
 3380        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3381        let tail = self.selections.newest::<usize>(cx).tail();
 3382        self.begin_selection(position, false, click_count, window, cx);
 3383
 3384        let position = position.to_offset(&display_map, Bias::Left);
 3385        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3386
 3387        let mut pending_selection = self
 3388            .selections
 3389            .pending_anchor()
 3390            .expect("extend_selection not called with pending selection");
 3391        if position >= tail {
 3392            pending_selection.start = tail_anchor;
 3393        } else {
 3394            pending_selection.end = tail_anchor;
 3395            pending_selection.reversed = true;
 3396        }
 3397
 3398        let mut pending_mode = self.selections.pending_mode().unwrap();
 3399        match &mut pending_mode {
 3400            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3401            _ => {}
 3402        }
 3403
 3404        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3405            SelectionEffects::scroll(Autoscroll::fit())
 3406        } else {
 3407            SelectionEffects::no_scroll()
 3408        };
 3409
 3410        self.change_selections(effects, window, cx, |s| {
 3411            s.set_pending(pending_selection, pending_mode)
 3412        });
 3413    }
 3414
 3415    fn begin_selection(
 3416        &mut self,
 3417        position: DisplayPoint,
 3418        add: bool,
 3419        click_count: usize,
 3420        window: &mut Window,
 3421        cx: &mut Context<Self>,
 3422    ) {
 3423        if !self.focus_handle.is_focused(window) {
 3424            self.last_focused_descendant = None;
 3425            window.focus(&self.focus_handle);
 3426        }
 3427
 3428        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3429        let buffer = &display_map.buffer_snapshot;
 3430        let position = display_map.clip_point(position, Bias::Left);
 3431
 3432        let start;
 3433        let end;
 3434        let mode;
 3435        let mut auto_scroll;
 3436        match click_count {
 3437            1 => {
 3438                start = buffer.anchor_before(position.to_point(&display_map));
 3439                end = start;
 3440                mode = SelectMode::Character;
 3441                auto_scroll = true;
 3442            }
 3443            2 => {
 3444                let position = display_map
 3445                    .clip_point(position, Bias::Left)
 3446                    .to_offset(&display_map, Bias::Left);
 3447                let (range, _) = buffer.surrounding_word(position, false);
 3448                start = buffer.anchor_before(range.start);
 3449                end = buffer.anchor_before(range.end);
 3450                mode = SelectMode::Word(start..end);
 3451                auto_scroll = true;
 3452            }
 3453            3 => {
 3454                let position = display_map
 3455                    .clip_point(position, Bias::Left)
 3456                    .to_point(&display_map);
 3457                let line_start = display_map.prev_line_boundary(position).0;
 3458                let next_line_start = buffer.clip_point(
 3459                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3460                    Bias::Left,
 3461                );
 3462                start = buffer.anchor_before(line_start);
 3463                end = buffer.anchor_before(next_line_start);
 3464                mode = SelectMode::Line(start..end);
 3465                auto_scroll = true;
 3466            }
 3467            _ => {
 3468                start = buffer.anchor_before(0);
 3469                end = buffer.anchor_before(buffer.len());
 3470                mode = SelectMode::All;
 3471                auto_scroll = false;
 3472            }
 3473        }
 3474        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3475
 3476        let point_to_delete: Option<usize> = {
 3477            let selected_points: Vec<Selection<Point>> =
 3478                self.selections.disjoint_in_range(start..end, cx);
 3479
 3480            if !add || click_count > 1 {
 3481                None
 3482            } else if !selected_points.is_empty() {
 3483                Some(selected_points[0].id)
 3484            } else {
 3485                let clicked_point_already_selected =
 3486                    self.selections.disjoint.iter().find(|selection| {
 3487                        selection.start.to_point(buffer) == start.to_point(buffer)
 3488                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3489                    });
 3490
 3491                clicked_point_already_selected.map(|selection| selection.id)
 3492            }
 3493        };
 3494
 3495        let selections_count = self.selections.count();
 3496        let effects = if auto_scroll {
 3497            SelectionEffects::default()
 3498        } else {
 3499            SelectionEffects::no_scroll()
 3500        };
 3501
 3502        self.change_selections(effects, window, cx, |s| {
 3503            if let Some(point_to_delete) = point_to_delete {
 3504                s.delete(point_to_delete);
 3505
 3506                if selections_count == 1 {
 3507                    s.set_pending_anchor_range(start..end, mode);
 3508                }
 3509            } else {
 3510                if !add {
 3511                    s.clear_disjoint();
 3512                }
 3513
 3514                s.set_pending_anchor_range(start..end, mode);
 3515            }
 3516        });
 3517    }
 3518
 3519    fn begin_columnar_selection(
 3520        &mut self,
 3521        position: DisplayPoint,
 3522        goal_column: u32,
 3523        reset: bool,
 3524        mode: ColumnarMode,
 3525        window: &mut Window,
 3526        cx: &mut Context<Self>,
 3527    ) {
 3528        if !self.focus_handle.is_focused(window) {
 3529            self.last_focused_descendant = None;
 3530            window.focus(&self.focus_handle);
 3531        }
 3532
 3533        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3534
 3535        if reset {
 3536            let pointer_position = display_map
 3537                .buffer_snapshot
 3538                .anchor_before(position.to_point(&display_map));
 3539
 3540            self.change_selections(
 3541                SelectionEffects::scroll(Autoscroll::newest()),
 3542                window,
 3543                cx,
 3544                |s| {
 3545                    s.clear_disjoint();
 3546                    s.set_pending_anchor_range(
 3547                        pointer_position..pointer_position,
 3548                        SelectMode::Character,
 3549                    );
 3550                },
 3551            );
 3552        };
 3553
 3554        let tail = self.selections.newest::<Point>(cx).tail();
 3555        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3556        self.columnar_selection_state = match mode {
 3557            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3558                selection_tail: selection_anchor,
 3559                display_point: if reset {
 3560                    if position.column() != goal_column {
 3561                        Some(DisplayPoint::new(position.row(), goal_column))
 3562                    } else {
 3563                        None
 3564                    }
 3565                } else {
 3566                    None
 3567                },
 3568            }),
 3569            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3570                selection_tail: selection_anchor,
 3571            }),
 3572        };
 3573
 3574        if !reset {
 3575            self.select_columns(position, goal_column, &display_map, window, cx);
 3576        }
 3577    }
 3578
 3579    fn update_selection(
 3580        &mut self,
 3581        position: DisplayPoint,
 3582        goal_column: u32,
 3583        scroll_delta: gpui::Point<f32>,
 3584        window: &mut Window,
 3585        cx: &mut Context<Self>,
 3586    ) {
 3587        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3588
 3589        if self.columnar_selection_state.is_some() {
 3590            self.select_columns(position, goal_column, &display_map, window, cx);
 3591        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3592            let buffer = &display_map.buffer_snapshot;
 3593            let head;
 3594            let tail;
 3595            let mode = self.selections.pending_mode().unwrap();
 3596            match &mode {
 3597                SelectMode::Character => {
 3598                    head = position.to_point(&display_map);
 3599                    tail = pending.tail().to_point(buffer);
 3600                }
 3601                SelectMode::Word(original_range) => {
 3602                    let offset = display_map
 3603                        .clip_point(position, Bias::Left)
 3604                        .to_offset(&display_map, Bias::Left);
 3605                    let original_range = original_range.to_offset(buffer);
 3606
 3607                    let head_offset = if buffer.is_inside_word(offset, false)
 3608                        || original_range.contains(&offset)
 3609                    {
 3610                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3611                        if word_range.start < original_range.start {
 3612                            word_range.start
 3613                        } else {
 3614                            word_range.end
 3615                        }
 3616                    } else {
 3617                        offset
 3618                    };
 3619
 3620                    head = head_offset.to_point(buffer);
 3621                    if head_offset <= original_range.start {
 3622                        tail = original_range.end.to_point(buffer);
 3623                    } else {
 3624                        tail = original_range.start.to_point(buffer);
 3625                    }
 3626                }
 3627                SelectMode::Line(original_range) => {
 3628                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3629
 3630                    let position = display_map
 3631                        .clip_point(position, Bias::Left)
 3632                        .to_point(&display_map);
 3633                    let line_start = display_map.prev_line_boundary(position).0;
 3634                    let next_line_start = buffer.clip_point(
 3635                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3636                        Bias::Left,
 3637                    );
 3638
 3639                    if line_start < original_range.start {
 3640                        head = line_start
 3641                    } else {
 3642                        head = next_line_start
 3643                    }
 3644
 3645                    if head <= original_range.start {
 3646                        tail = original_range.end;
 3647                    } else {
 3648                        tail = original_range.start;
 3649                    }
 3650                }
 3651                SelectMode::All => {
 3652                    return;
 3653                }
 3654            };
 3655
 3656            if head < tail {
 3657                pending.start = buffer.anchor_before(head);
 3658                pending.end = buffer.anchor_before(tail);
 3659                pending.reversed = true;
 3660            } else {
 3661                pending.start = buffer.anchor_before(tail);
 3662                pending.end = buffer.anchor_before(head);
 3663                pending.reversed = false;
 3664            }
 3665
 3666            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3667                s.set_pending(pending, mode);
 3668            });
 3669        } else {
 3670            log::error!("update_selection dispatched with no pending selection");
 3671            return;
 3672        }
 3673
 3674        self.apply_scroll_delta(scroll_delta, window, cx);
 3675        cx.notify();
 3676    }
 3677
 3678    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3679        self.columnar_selection_state.take();
 3680        if self.selections.pending_anchor().is_some() {
 3681            let selections = self.selections.all::<usize>(cx);
 3682            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3683                s.select(selections);
 3684                s.clear_pending();
 3685            });
 3686        }
 3687    }
 3688
 3689    fn select_columns(
 3690        &mut self,
 3691        head: DisplayPoint,
 3692        goal_column: u32,
 3693        display_map: &DisplaySnapshot,
 3694        window: &mut Window,
 3695        cx: &mut Context<Self>,
 3696    ) {
 3697        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3698            return;
 3699        };
 3700
 3701        let tail = match columnar_state {
 3702            ColumnarSelectionState::FromMouse {
 3703                selection_tail,
 3704                display_point,
 3705            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3706            ColumnarSelectionState::FromSelection { selection_tail } => {
 3707                selection_tail.to_display_point(&display_map)
 3708            }
 3709        };
 3710
 3711        let start_row = cmp::min(tail.row(), head.row());
 3712        let end_row = cmp::max(tail.row(), head.row());
 3713        let start_column = cmp::min(tail.column(), goal_column);
 3714        let end_column = cmp::max(tail.column(), goal_column);
 3715        let reversed = start_column < tail.column();
 3716
 3717        let selection_ranges = (start_row.0..=end_row.0)
 3718            .map(DisplayRow)
 3719            .filter_map(|row| {
 3720                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3721                    || start_column <= display_map.line_len(row))
 3722                    && !display_map.is_block_line(row)
 3723                {
 3724                    let start = display_map
 3725                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3726                        .to_point(display_map);
 3727                    let end = display_map
 3728                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3729                        .to_point(display_map);
 3730                    if reversed {
 3731                        Some(end..start)
 3732                    } else {
 3733                        Some(start..end)
 3734                    }
 3735                } else {
 3736                    None
 3737                }
 3738            })
 3739            .collect::<Vec<_>>();
 3740
 3741        let ranges = match columnar_state {
 3742            ColumnarSelectionState::FromMouse { .. } => {
 3743                let mut non_empty_ranges = selection_ranges
 3744                    .iter()
 3745                    .filter(|selection_range| selection_range.start != selection_range.end)
 3746                    .peekable();
 3747                if non_empty_ranges.peek().is_some() {
 3748                    non_empty_ranges.cloned().collect()
 3749                } else {
 3750                    selection_ranges
 3751                }
 3752            }
 3753            _ => selection_ranges,
 3754        };
 3755
 3756        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3757            s.select_ranges(ranges);
 3758        });
 3759        cx.notify();
 3760    }
 3761
 3762    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3763        self.selections
 3764            .all_adjusted(cx)
 3765            .iter()
 3766            .any(|selection| !selection.is_empty())
 3767    }
 3768
 3769    pub fn has_pending_nonempty_selection(&self) -> bool {
 3770        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3771            Some(Selection { start, end, .. }) => start != end,
 3772            None => false,
 3773        };
 3774
 3775        pending_nonempty_selection
 3776            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3777    }
 3778
 3779    pub fn has_pending_selection(&self) -> bool {
 3780        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3781    }
 3782
 3783    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3784        self.selection_mark_mode = false;
 3785        self.selection_drag_state = SelectionDragState::None;
 3786
 3787        if self.clear_expanded_diff_hunks(cx) {
 3788            cx.notify();
 3789            return;
 3790        }
 3791        if self.dismiss_menus_and_popups(true, window, cx) {
 3792            return;
 3793        }
 3794
 3795        if self.mode.is_full()
 3796            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3797        {
 3798            return;
 3799        }
 3800
 3801        cx.propagate();
 3802    }
 3803
 3804    pub fn dismiss_menus_and_popups(
 3805        &mut self,
 3806        is_user_requested: bool,
 3807        window: &mut Window,
 3808        cx: &mut Context<Self>,
 3809    ) -> bool {
 3810        if self.take_rename(false, window, cx).is_some() {
 3811            return true;
 3812        }
 3813
 3814        if hide_hover(self, cx) {
 3815            return true;
 3816        }
 3817
 3818        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3819            return true;
 3820        }
 3821
 3822        if self.hide_context_menu(window, cx).is_some() {
 3823            return true;
 3824        }
 3825
 3826        if self.mouse_context_menu.take().is_some() {
 3827            return true;
 3828        }
 3829
 3830        if is_user_requested && self.discard_inline_completion(true, cx) {
 3831            return true;
 3832        }
 3833
 3834        if self.snippet_stack.pop().is_some() {
 3835            return true;
 3836        }
 3837
 3838        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3839            self.dismiss_diagnostics(cx);
 3840            return true;
 3841        }
 3842
 3843        false
 3844    }
 3845
 3846    fn linked_editing_ranges_for(
 3847        &self,
 3848        selection: Range<text::Anchor>,
 3849        cx: &App,
 3850    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3851        if self.linked_edit_ranges.is_empty() {
 3852            return None;
 3853        }
 3854        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3855            selection.end.buffer_id.and_then(|end_buffer_id| {
 3856                if selection.start.buffer_id != Some(end_buffer_id) {
 3857                    return None;
 3858                }
 3859                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3860                let snapshot = buffer.read(cx).snapshot();
 3861                self.linked_edit_ranges
 3862                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3863                    .map(|ranges| (ranges, snapshot, buffer))
 3864            })?;
 3865        use text::ToOffset as TO;
 3866        // find offset from the start of current range to current cursor position
 3867        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3868
 3869        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3870        let start_difference = start_offset - start_byte_offset;
 3871        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3872        let end_difference = end_offset - start_byte_offset;
 3873        // Current range has associated linked ranges.
 3874        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3875        for range in linked_ranges.iter() {
 3876            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3877            let end_offset = start_offset + end_difference;
 3878            let start_offset = start_offset + start_difference;
 3879            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3880                continue;
 3881            }
 3882            if self.selections.disjoint_anchor_ranges().any(|s| {
 3883                if s.start.buffer_id != selection.start.buffer_id
 3884                    || s.end.buffer_id != selection.end.buffer_id
 3885                {
 3886                    return false;
 3887                }
 3888                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3889                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3890            }) {
 3891                continue;
 3892            }
 3893            let start = buffer_snapshot.anchor_after(start_offset);
 3894            let end = buffer_snapshot.anchor_after(end_offset);
 3895            linked_edits
 3896                .entry(buffer.clone())
 3897                .or_default()
 3898                .push(start..end);
 3899        }
 3900        Some(linked_edits)
 3901    }
 3902
 3903    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3904        let text: Arc<str> = text.into();
 3905
 3906        if self.read_only(cx) {
 3907            return;
 3908        }
 3909
 3910        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3911
 3912        let selections = self.selections.all_adjusted(cx);
 3913        let mut bracket_inserted = false;
 3914        let mut edits = Vec::new();
 3915        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3916        let mut new_selections = Vec::with_capacity(selections.len());
 3917        let mut new_autoclose_regions = Vec::new();
 3918        let snapshot = self.buffer.read(cx).read(cx);
 3919        let mut clear_linked_edit_ranges = false;
 3920
 3921        for (selection, autoclose_region) in
 3922            self.selections_with_autoclose_regions(selections, &snapshot)
 3923        {
 3924            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3925                // Determine if the inserted text matches the opening or closing
 3926                // bracket of any of this language's bracket pairs.
 3927                let mut bracket_pair = None;
 3928                let mut is_bracket_pair_start = false;
 3929                let mut is_bracket_pair_end = false;
 3930                if !text.is_empty() {
 3931                    let mut bracket_pair_matching_end = None;
 3932                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3933                    //  and they are removing the character that triggered IME popup.
 3934                    for (pair, enabled) in scope.brackets() {
 3935                        if !pair.close && !pair.surround {
 3936                            continue;
 3937                        }
 3938
 3939                        if enabled && pair.start.ends_with(text.as_ref()) {
 3940                            let prefix_len = pair.start.len() - text.len();
 3941                            let preceding_text_matches_prefix = prefix_len == 0
 3942                                || (selection.start.column >= (prefix_len as u32)
 3943                                    && snapshot.contains_str_at(
 3944                                        Point::new(
 3945                                            selection.start.row,
 3946                                            selection.start.column - (prefix_len as u32),
 3947                                        ),
 3948                                        &pair.start[..prefix_len],
 3949                                    ));
 3950                            if preceding_text_matches_prefix {
 3951                                bracket_pair = Some(pair.clone());
 3952                                is_bracket_pair_start = true;
 3953                                break;
 3954                            }
 3955                        }
 3956                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3957                        {
 3958                            // take first bracket pair matching end, but don't break in case a later bracket
 3959                            // pair matches start
 3960                            bracket_pair_matching_end = Some(pair.clone());
 3961                        }
 3962                    }
 3963                    if let Some(end) = bracket_pair_matching_end
 3964                        && bracket_pair.is_none()
 3965                    {
 3966                        bracket_pair = Some(end);
 3967                        is_bracket_pair_end = true;
 3968                    }
 3969                }
 3970
 3971                if let Some(bracket_pair) = bracket_pair {
 3972                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3973                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3974                    let auto_surround =
 3975                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3976                    if selection.is_empty() {
 3977                        if is_bracket_pair_start {
 3978                            // If the inserted text is a suffix of an opening bracket and the
 3979                            // selection is preceded by the rest of the opening bracket, then
 3980                            // insert the closing bracket.
 3981                            let following_text_allows_autoclose = snapshot
 3982                                .chars_at(selection.start)
 3983                                .next()
 3984                                .map_or(true, |c| scope.should_autoclose_before(c));
 3985
 3986                            let preceding_text_allows_autoclose = selection.start.column == 0
 3987                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3988                                    true,
 3989                                    |c| {
 3990                                        bracket_pair.start != bracket_pair.end
 3991                                            || !snapshot
 3992                                                .char_classifier_at(selection.start)
 3993                                                .is_word(c)
 3994                                    },
 3995                                );
 3996
 3997                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3998                                && bracket_pair.start.len() == 1
 3999                            {
 4000                                let target = bracket_pair.start.chars().next().unwrap();
 4001                                let current_line_count = snapshot
 4002                                    .reversed_chars_at(selection.start)
 4003                                    .take_while(|&c| c != '\n')
 4004                                    .filter(|&c| c == target)
 4005                                    .count();
 4006                                current_line_count % 2 == 1
 4007                            } else {
 4008                                false
 4009                            };
 4010
 4011                            if autoclose
 4012                                && bracket_pair.close
 4013                                && following_text_allows_autoclose
 4014                                && preceding_text_allows_autoclose
 4015                                && !is_closing_quote
 4016                            {
 4017                                let anchor = snapshot.anchor_before(selection.end);
 4018                                new_selections.push((selection.map(|_| anchor), text.len()));
 4019                                new_autoclose_regions.push((
 4020                                    anchor,
 4021                                    text.len(),
 4022                                    selection.id,
 4023                                    bracket_pair.clone(),
 4024                                ));
 4025                                edits.push((
 4026                                    selection.range(),
 4027                                    format!("{}{}", text, bracket_pair.end).into(),
 4028                                ));
 4029                                bracket_inserted = true;
 4030                                continue;
 4031                            }
 4032                        }
 4033
 4034                        if let Some(region) = autoclose_region {
 4035                            // If the selection is followed by an auto-inserted closing bracket,
 4036                            // then don't insert that closing bracket again; just move the selection
 4037                            // past the closing bracket.
 4038                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4039                                && text.as_ref() == region.pair.end.as_str();
 4040                            if should_skip {
 4041                                let anchor = snapshot.anchor_after(selection.end);
 4042                                new_selections
 4043                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4044                                continue;
 4045                            }
 4046                        }
 4047
 4048                        let always_treat_brackets_as_autoclosed = snapshot
 4049                            .language_settings_at(selection.start, cx)
 4050                            .always_treat_brackets_as_autoclosed;
 4051                        if always_treat_brackets_as_autoclosed
 4052                            && is_bracket_pair_end
 4053                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4054                        {
 4055                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4056                            // and the inserted text is a closing bracket and the selection is followed
 4057                            // by the closing bracket then move the selection past the closing bracket.
 4058                            let anchor = snapshot.anchor_after(selection.end);
 4059                            new_selections.push((selection.map(|_| anchor), text.len()));
 4060                            continue;
 4061                        }
 4062                    }
 4063                    // If an opening bracket is 1 character long and is typed while
 4064                    // text is selected, then surround that text with the bracket pair.
 4065                    else if auto_surround
 4066                        && bracket_pair.surround
 4067                        && is_bracket_pair_start
 4068                        && bracket_pair.start.chars().count() == 1
 4069                    {
 4070                        edits.push((selection.start..selection.start, text.clone()));
 4071                        edits.push((
 4072                            selection.end..selection.end,
 4073                            bracket_pair.end.as_str().into(),
 4074                        ));
 4075                        bracket_inserted = true;
 4076                        new_selections.push((
 4077                            Selection {
 4078                                id: selection.id,
 4079                                start: snapshot.anchor_after(selection.start),
 4080                                end: snapshot.anchor_before(selection.end),
 4081                                reversed: selection.reversed,
 4082                                goal: selection.goal,
 4083                            },
 4084                            0,
 4085                        ));
 4086                        continue;
 4087                    }
 4088                }
 4089            }
 4090
 4091            if self.auto_replace_emoji_shortcode
 4092                && selection.is_empty()
 4093                && text.as_ref().ends_with(':')
 4094            {
 4095                if let Some(possible_emoji_short_code) =
 4096                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4097                {
 4098                    if !possible_emoji_short_code.is_empty() {
 4099                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4100                            let emoji_shortcode_start = Point::new(
 4101                                selection.start.row,
 4102                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4103                            );
 4104
 4105                            // Remove shortcode from buffer
 4106                            edits.push((
 4107                                emoji_shortcode_start..selection.start,
 4108                                "".to_string().into(),
 4109                            ));
 4110                            new_selections.push((
 4111                                Selection {
 4112                                    id: selection.id,
 4113                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4114                                    end: snapshot.anchor_before(selection.start),
 4115                                    reversed: selection.reversed,
 4116                                    goal: selection.goal,
 4117                                },
 4118                                0,
 4119                            ));
 4120
 4121                            // Insert emoji
 4122                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4123                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4124                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4125
 4126                            continue;
 4127                        }
 4128                    }
 4129                }
 4130            }
 4131
 4132            // If not handling any auto-close operation, then just replace the selected
 4133            // text with the given input and move the selection to the end of the
 4134            // newly inserted text.
 4135            let anchor = snapshot.anchor_after(selection.end);
 4136            if !self.linked_edit_ranges.is_empty() {
 4137                let start_anchor = snapshot.anchor_before(selection.start);
 4138
 4139                let is_word_char = text.chars().next().map_or(true, |char| {
 4140                    let classifier = snapshot
 4141                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4142                        .ignore_punctuation(true);
 4143                    classifier.is_word(char)
 4144                });
 4145
 4146                if is_word_char {
 4147                    if let Some(ranges) = self
 4148                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4149                    {
 4150                        for (buffer, edits) in ranges {
 4151                            linked_edits
 4152                                .entry(buffer.clone())
 4153                                .or_default()
 4154                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4155                        }
 4156                    }
 4157                } else {
 4158                    clear_linked_edit_ranges = true;
 4159                }
 4160            }
 4161
 4162            new_selections.push((selection.map(|_| anchor), 0));
 4163            edits.push((selection.start..selection.end, text.clone()));
 4164        }
 4165
 4166        drop(snapshot);
 4167
 4168        self.transact(window, cx, |this, window, cx| {
 4169            if clear_linked_edit_ranges {
 4170                this.linked_edit_ranges.clear();
 4171            }
 4172            let initial_buffer_versions =
 4173                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4174
 4175            this.buffer.update(cx, |buffer, cx| {
 4176                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4177            });
 4178            for (buffer, edits) in linked_edits {
 4179                buffer.update(cx, |buffer, cx| {
 4180                    let snapshot = buffer.snapshot();
 4181                    let edits = edits
 4182                        .into_iter()
 4183                        .map(|(range, text)| {
 4184                            use text::ToPoint as TP;
 4185                            let end_point = TP::to_point(&range.end, &snapshot);
 4186                            let start_point = TP::to_point(&range.start, &snapshot);
 4187                            (start_point..end_point, text)
 4188                        })
 4189                        .sorted_by_key(|(range, _)| range.start);
 4190                    buffer.edit(edits, None, cx);
 4191                })
 4192            }
 4193            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4194            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4195            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4196            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4197                .zip(new_selection_deltas)
 4198                .map(|(selection, delta)| Selection {
 4199                    id: selection.id,
 4200                    start: selection.start + delta,
 4201                    end: selection.end + delta,
 4202                    reversed: selection.reversed,
 4203                    goal: SelectionGoal::None,
 4204                })
 4205                .collect::<Vec<_>>();
 4206
 4207            let mut i = 0;
 4208            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4209                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4210                let start = map.buffer_snapshot.anchor_before(position);
 4211                let end = map.buffer_snapshot.anchor_after(position);
 4212                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4213                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4214                        Ordering::Less => i += 1,
 4215                        Ordering::Greater => break,
 4216                        Ordering::Equal => {
 4217                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4218                                Ordering::Less => i += 1,
 4219                                Ordering::Equal => break,
 4220                                Ordering::Greater => break,
 4221                            }
 4222                        }
 4223                    }
 4224                }
 4225                this.autoclose_regions.insert(
 4226                    i,
 4227                    AutocloseRegion {
 4228                        selection_id,
 4229                        range: start..end,
 4230                        pair,
 4231                    },
 4232                );
 4233            }
 4234
 4235            let had_active_inline_completion = this.has_active_inline_completion();
 4236            this.change_selections(
 4237                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4238                window,
 4239                cx,
 4240                |s| s.select(new_selections),
 4241            );
 4242
 4243            if !bracket_inserted {
 4244                if let Some(on_type_format_task) =
 4245                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4246                {
 4247                    on_type_format_task.detach_and_log_err(cx);
 4248                }
 4249            }
 4250
 4251            let editor_settings = EditorSettings::get_global(cx);
 4252            if bracket_inserted
 4253                && (editor_settings.auto_signature_help
 4254                    || editor_settings.show_signature_help_after_edits)
 4255            {
 4256                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4257            }
 4258
 4259            let trigger_in_words =
 4260                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4261            if this.hard_wrap.is_some() {
 4262                let latest: Range<Point> = this.selections.newest(cx).range();
 4263                if latest.is_empty()
 4264                    && this
 4265                        .buffer()
 4266                        .read(cx)
 4267                        .snapshot(cx)
 4268                        .line_len(MultiBufferRow(latest.start.row))
 4269                        == latest.start.column
 4270                {
 4271                    this.rewrap_impl(
 4272                        RewrapOptions {
 4273                            override_language_settings: true,
 4274                            preserve_existing_whitespace: true,
 4275                        },
 4276                        cx,
 4277                    )
 4278                }
 4279            }
 4280            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4281            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4282            this.refresh_inline_completion(true, false, window, cx);
 4283            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4284        });
 4285    }
 4286
 4287    fn find_possible_emoji_shortcode_at_position(
 4288        snapshot: &MultiBufferSnapshot,
 4289        position: Point,
 4290    ) -> Option<String> {
 4291        let mut chars = Vec::new();
 4292        let mut found_colon = false;
 4293        for char in snapshot.reversed_chars_at(position).take(100) {
 4294            // Found a possible emoji shortcode in the middle of the buffer
 4295            if found_colon {
 4296                if char.is_whitespace() {
 4297                    chars.reverse();
 4298                    return Some(chars.iter().collect());
 4299                }
 4300                // If the previous character is not a whitespace, we are in the middle of a word
 4301                // and we only want to complete the shortcode if the word is made up of other emojis
 4302                let mut containing_word = String::new();
 4303                for ch in snapshot
 4304                    .reversed_chars_at(position)
 4305                    .skip(chars.len() + 1)
 4306                    .take(100)
 4307                {
 4308                    if ch.is_whitespace() {
 4309                        break;
 4310                    }
 4311                    containing_word.push(ch);
 4312                }
 4313                let containing_word = containing_word.chars().rev().collect::<String>();
 4314                if util::word_consists_of_emojis(containing_word.as_str()) {
 4315                    chars.reverse();
 4316                    return Some(chars.iter().collect());
 4317                }
 4318            }
 4319
 4320            if char.is_whitespace() || !char.is_ascii() {
 4321                return None;
 4322            }
 4323            if char == ':' {
 4324                found_colon = true;
 4325            } else {
 4326                chars.push(char);
 4327            }
 4328        }
 4329        // Found a possible emoji shortcode at the beginning of the buffer
 4330        chars.reverse();
 4331        Some(chars.iter().collect())
 4332    }
 4333
 4334    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4335        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4336        self.transact(window, cx, |this, window, cx| {
 4337            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4338                let selections = this.selections.all::<usize>(cx);
 4339                let multi_buffer = this.buffer.read(cx);
 4340                let buffer = multi_buffer.snapshot(cx);
 4341                selections
 4342                    .iter()
 4343                    .map(|selection| {
 4344                        let start_point = selection.start.to_point(&buffer);
 4345                        let mut existing_indent =
 4346                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4347                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4348                        let start = selection.start;
 4349                        let end = selection.end;
 4350                        let selection_is_empty = start == end;
 4351                        let language_scope = buffer.language_scope_at(start);
 4352                        let (
 4353                            comment_delimiter,
 4354                            doc_delimiter,
 4355                            insert_extra_newline,
 4356                            indent_on_newline,
 4357                            indent_on_extra_newline,
 4358                        ) = if let Some(language) = &language_scope {
 4359                            let mut insert_extra_newline =
 4360                                insert_extra_newline_brackets(&buffer, start..end, language)
 4361                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4362
 4363                            // Comment extension on newline is allowed only for cursor selections
 4364                            let comment_delimiter = maybe!({
 4365                                if !selection_is_empty {
 4366                                    return None;
 4367                                }
 4368
 4369                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4370                                    return None;
 4371                                }
 4372
 4373                                let delimiters = language.line_comment_prefixes();
 4374                                let max_len_of_delimiter =
 4375                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4376                                let (snapshot, range) =
 4377                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4378
 4379                                let num_of_whitespaces = snapshot
 4380                                    .chars_for_range(range.clone())
 4381                                    .take_while(|c| c.is_whitespace())
 4382                                    .count();
 4383                                let comment_candidate = snapshot
 4384                                    .chars_for_range(range.clone())
 4385                                    .skip(num_of_whitespaces)
 4386                                    .take(max_len_of_delimiter)
 4387                                    .collect::<String>();
 4388                                let (delimiter, trimmed_len) = delimiters
 4389                                    .iter()
 4390                                    .filter_map(|delimiter| {
 4391                                        let prefix = delimiter.trim_end();
 4392                                        if comment_candidate.starts_with(prefix) {
 4393                                            Some((delimiter, prefix.len()))
 4394                                        } else {
 4395                                            None
 4396                                        }
 4397                                    })
 4398                                    .max_by_key(|(_, len)| *len)?;
 4399
 4400                                if let Some((block_start, _)) = language.block_comment_delimiters()
 4401                                {
 4402                                    let block_start_trimmed = block_start.trim_end();
 4403                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4404                                        let line_content = snapshot
 4405                                            .chars_for_range(range)
 4406                                            .skip(num_of_whitespaces)
 4407                                            .take(block_start_trimmed.len())
 4408                                            .collect::<String>();
 4409
 4410                                        if line_content.starts_with(block_start_trimmed) {
 4411                                            return None;
 4412                                        }
 4413                                    }
 4414                                }
 4415
 4416                                let cursor_is_placed_after_comment_marker =
 4417                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4418                                if cursor_is_placed_after_comment_marker {
 4419                                    Some(delimiter.clone())
 4420                                } else {
 4421                                    None
 4422                                }
 4423                            });
 4424
 4425                            let mut indent_on_newline = IndentSize::spaces(0);
 4426                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4427
 4428                            let doc_delimiter = maybe!({
 4429                                if !selection_is_empty {
 4430                                    return None;
 4431                                }
 4432
 4433                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4434                                    return None;
 4435                                }
 4436
 4437                                let DocumentationConfig {
 4438                                    start: start_tag,
 4439                                    end: end_tag,
 4440                                    prefix: delimiter,
 4441                                    tab_size: len,
 4442                                } = language.documentation()?;
 4443
 4444                                let is_within_block_comment = buffer
 4445                                    .language_scope_at(start_point)
 4446                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4447                                if !is_within_block_comment {
 4448                                    return None;
 4449                                }
 4450
 4451                                let (snapshot, range) =
 4452                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4453
 4454                                let num_of_whitespaces = snapshot
 4455                                    .chars_for_range(range.clone())
 4456                                    .take_while(|c| c.is_whitespace())
 4457                                    .count();
 4458
 4459                                // 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.
 4460                                let column = start_point.column;
 4461                                let cursor_is_after_start_tag = {
 4462                                    let start_tag_len = start_tag.len();
 4463                                    let start_tag_line = snapshot
 4464                                        .chars_for_range(range.clone())
 4465                                        .skip(num_of_whitespaces)
 4466                                        .take(start_tag_len)
 4467                                        .collect::<String>();
 4468                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4469                                        num_of_whitespaces + start_tag_len <= column as usize
 4470                                    } else {
 4471                                        false
 4472                                    }
 4473                                };
 4474
 4475                                let cursor_is_after_delimiter = {
 4476                                    let delimiter_trim = delimiter.trim_end();
 4477                                    let delimiter_line = snapshot
 4478                                        .chars_for_range(range.clone())
 4479                                        .skip(num_of_whitespaces)
 4480                                        .take(delimiter_trim.len())
 4481                                        .collect::<String>();
 4482                                    if delimiter_line.starts_with(delimiter_trim) {
 4483                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4484                                    } else {
 4485                                        false
 4486                                    }
 4487                                };
 4488
 4489                                let cursor_is_before_end_tag_if_exists = {
 4490                                    let mut char_position = 0u32;
 4491                                    let mut end_tag_offset = None;
 4492
 4493                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4494                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4495                                            let chars_before_match =
 4496                                                chunk[..byte_pos].chars().count() as u32;
 4497                                            end_tag_offset =
 4498                                                Some(char_position + chars_before_match);
 4499                                            break 'outer;
 4500                                        }
 4501                                        char_position += chunk.chars().count() as u32;
 4502                                    }
 4503
 4504                                    if let Some(end_tag_offset) = end_tag_offset {
 4505                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4506                                        if cursor_is_after_start_tag {
 4507                                            if cursor_is_before_end_tag {
 4508                                                insert_extra_newline = true;
 4509                                            }
 4510                                            let cursor_is_at_start_of_end_tag =
 4511                                                column == end_tag_offset;
 4512                                            if cursor_is_at_start_of_end_tag {
 4513                                                indent_on_extra_newline.len = (*len).into();
 4514                                            }
 4515                                        }
 4516                                        cursor_is_before_end_tag
 4517                                    } else {
 4518                                        true
 4519                                    }
 4520                                };
 4521
 4522                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4523                                    && cursor_is_before_end_tag_if_exists
 4524                                {
 4525                                    if cursor_is_after_start_tag {
 4526                                        indent_on_newline.len = (*len).into();
 4527                                    }
 4528                                    Some(delimiter.clone())
 4529                                } else {
 4530                                    None
 4531                                }
 4532                            });
 4533
 4534                            (
 4535                                comment_delimiter,
 4536                                doc_delimiter,
 4537                                insert_extra_newline,
 4538                                indent_on_newline,
 4539                                indent_on_extra_newline,
 4540                            )
 4541                        } else {
 4542                            (
 4543                                None,
 4544                                None,
 4545                                false,
 4546                                IndentSize::default(),
 4547                                IndentSize::default(),
 4548                            )
 4549                        };
 4550
 4551                        let prevent_auto_indent = doc_delimiter.is_some();
 4552                        let delimiter = comment_delimiter.or(doc_delimiter);
 4553
 4554                        let capacity_for_delimiter =
 4555                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4556                        let mut new_text = String::with_capacity(
 4557                            1 + capacity_for_delimiter
 4558                                + existing_indent.len as usize
 4559                                + indent_on_newline.len as usize
 4560                                + indent_on_extra_newline.len as usize,
 4561                        );
 4562                        new_text.push('\n');
 4563                        new_text.extend(existing_indent.chars());
 4564                        new_text.extend(indent_on_newline.chars());
 4565
 4566                        if let Some(delimiter) = &delimiter {
 4567                            new_text.push_str(delimiter);
 4568                        }
 4569
 4570                        if insert_extra_newline {
 4571                            new_text.push('\n');
 4572                            new_text.extend(existing_indent.chars());
 4573                            new_text.extend(indent_on_extra_newline.chars());
 4574                        }
 4575
 4576                        let anchor = buffer.anchor_after(end);
 4577                        let new_selection = selection.map(|_| anchor);
 4578                        (
 4579                            ((start..end, new_text), prevent_auto_indent),
 4580                            (insert_extra_newline, new_selection),
 4581                        )
 4582                    })
 4583                    .unzip()
 4584            };
 4585
 4586            let mut auto_indent_edits = Vec::new();
 4587            let mut edits = Vec::new();
 4588            for (edit, prevent_auto_indent) in edits_with_flags {
 4589                if prevent_auto_indent {
 4590                    edits.push(edit);
 4591                } else {
 4592                    auto_indent_edits.push(edit);
 4593                }
 4594            }
 4595            if !edits.is_empty() {
 4596                this.edit(edits, cx);
 4597            }
 4598            if !auto_indent_edits.is_empty() {
 4599                this.edit_with_autoindent(auto_indent_edits, cx);
 4600            }
 4601
 4602            let buffer = this.buffer.read(cx).snapshot(cx);
 4603            let new_selections = selection_info
 4604                .into_iter()
 4605                .map(|(extra_newline_inserted, new_selection)| {
 4606                    let mut cursor = new_selection.end.to_point(&buffer);
 4607                    if extra_newline_inserted {
 4608                        cursor.row -= 1;
 4609                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4610                    }
 4611                    new_selection.map(|_| cursor)
 4612                })
 4613                .collect();
 4614
 4615            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4616            this.refresh_inline_completion(true, false, window, cx);
 4617        });
 4618    }
 4619
 4620    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4621        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4622
 4623        let buffer = self.buffer.read(cx);
 4624        let snapshot = buffer.snapshot(cx);
 4625
 4626        let mut edits = Vec::new();
 4627        let mut rows = Vec::new();
 4628
 4629        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4630            let cursor = selection.head();
 4631            let row = cursor.row;
 4632
 4633            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4634
 4635            let newline = "\n".to_string();
 4636            edits.push((start_of_line..start_of_line, newline));
 4637
 4638            rows.push(row + rows_inserted as u32);
 4639        }
 4640
 4641        self.transact(window, cx, |editor, window, cx| {
 4642            editor.edit(edits, cx);
 4643
 4644            editor.change_selections(Default::default(), window, cx, |s| {
 4645                let mut index = 0;
 4646                s.move_cursors_with(|map, _, _| {
 4647                    let row = rows[index];
 4648                    index += 1;
 4649
 4650                    let point = Point::new(row, 0);
 4651                    let boundary = map.next_line_boundary(point).1;
 4652                    let clipped = map.clip_point(boundary, Bias::Left);
 4653
 4654                    (clipped, SelectionGoal::None)
 4655                });
 4656            });
 4657
 4658            let mut indent_edits = Vec::new();
 4659            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4660            for row in rows {
 4661                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4662                for (row, indent) in indents {
 4663                    if indent.len == 0 {
 4664                        continue;
 4665                    }
 4666
 4667                    let text = match indent.kind {
 4668                        IndentKind::Space => " ".repeat(indent.len as usize),
 4669                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4670                    };
 4671                    let point = Point::new(row.0, 0);
 4672                    indent_edits.push((point..point, text));
 4673                }
 4674            }
 4675            editor.edit(indent_edits, cx);
 4676        });
 4677    }
 4678
 4679    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4680        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4681
 4682        let buffer = self.buffer.read(cx);
 4683        let snapshot = buffer.snapshot(cx);
 4684
 4685        let mut edits = Vec::new();
 4686        let mut rows = Vec::new();
 4687        let mut rows_inserted = 0;
 4688
 4689        for selection in self.selections.all_adjusted(cx) {
 4690            let cursor = selection.head();
 4691            let row = cursor.row;
 4692
 4693            let point = Point::new(row + 1, 0);
 4694            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4695
 4696            let newline = "\n".to_string();
 4697            edits.push((start_of_line..start_of_line, newline));
 4698
 4699            rows_inserted += 1;
 4700            rows.push(row + rows_inserted);
 4701        }
 4702
 4703        self.transact(window, cx, |editor, window, cx| {
 4704            editor.edit(edits, cx);
 4705
 4706            editor.change_selections(Default::default(), window, cx, |s| {
 4707                let mut index = 0;
 4708                s.move_cursors_with(|map, _, _| {
 4709                    let row = rows[index];
 4710                    index += 1;
 4711
 4712                    let point = Point::new(row, 0);
 4713                    let boundary = map.next_line_boundary(point).1;
 4714                    let clipped = map.clip_point(boundary, Bias::Left);
 4715
 4716                    (clipped, SelectionGoal::None)
 4717                });
 4718            });
 4719
 4720            let mut indent_edits = Vec::new();
 4721            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4722            for row in rows {
 4723                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4724                for (row, indent) in indents {
 4725                    if indent.len == 0 {
 4726                        continue;
 4727                    }
 4728
 4729                    let text = match indent.kind {
 4730                        IndentKind::Space => " ".repeat(indent.len as usize),
 4731                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4732                    };
 4733                    let point = Point::new(row.0, 0);
 4734                    indent_edits.push((point..point, text));
 4735                }
 4736            }
 4737            editor.edit(indent_edits, cx);
 4738        });
 4739    }
 4740
 4741    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4742        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4743            original_indent_columns: Vec::new(),
 4744        });
 4745        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4746    }
 4747
 4748    fn insert_with_autoindent_mode(
 4749        &mut self,
 4750        text: &str,
 4751        autoindent_mode: Option<AutoindentMode>,
 4752        window: &mut Window,
 4753        cx: &mut Context<Self>,
 4754    ) {
 4755        if self.read_only(cx) {
 4756            return;
 4757        }
 4758
 4759        let text: Arc<str> = text.into();
 4760        self.transact(window, cx, |this, window, cx| {
 4761            let old_selections = this.selections.all_adjusted(cx);
 4762            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4763                let anchors = {
 4764                    let snapshot = buffer.read(cx);
 4765                    old_selections
 4766                        .iter()
 4767                        .map(|s| {
 4768                            let anchor = snapshot.anchor_after(s.head());
 4769                            s.map(|_| anchor)
 4770                        })
 4771                        .collect::<Vec<_>>()
 4772                };
 4773                buffer.edit(
 4774                    old_selections
 4775                        .iter()
 4776                        .map(|s| (s.start..s.end, text.clone())),
 4777                    autoindent_mode,
 4778                    cx,
 4779                );
 4780                anchors
 4781            });
 4782
 4783            this.change_selections(Default::default(), window, cx, |s| {
 4784                s.select_anchors(selection_anchors);
 4785            });
 4786
 4787            cx.notify();
 4788        });
 4789    }
 4790
 4791    fn trigger_completion_on_input(
 4792        &mut self,
 4793        text: &str,
 4794        trigger_in_words: bool,
 4795        window: &mut Window,
 4796        cx: &mut Context<Self>,
 4797    ) {
 4798        let completions_source = self
 4799            .context_menu
 4800            .borrow()
 4801            .as_ref()
 4802            .and_then(|menu| match menu {
 4803                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4804                CodeContextMenu::CodeActions(_) => None,
 4805            });
 4806
 4807        match completions_source {
 4808            Some(CompletionsMenuSource::Words) => {
 4809                self.show_word_completions(&ShowWordCompletions, window, cx)
 4810            }
 4811            Some(CompletionsMenuSource::Normal)
 4812            | Some(CompletionsMenuSource::SnippetChoices)
 4813            | None
 4814                if self.is_completion_trigger(
 4815                    text,
 4816                    trigger_in_words,
 4817                    completions_source.is_some(),
 4818                    cx,
 4819                ) =>
 4820            {
 4821                self.show_completions(
 4822                    &ShowCompletions {
 4823                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4824                    },
 4825                    window,
 4826                    cx,
 4827                )
 4828            }
 4829            _ => {
 4830                self.hide_context_menu(window, cx);
 4831            }
 4832        }
 4833    }
 4834
 4835    fn is_completion_trigger(
 4836        &self,
 4837        text: &str,
 4838        trigger_in_words: bool,
 4839        menu_is_open: bool,
 4840        cx: &mut Context<Self>,
 4841    ) -> bool {
 4842        let position = self.selections.newest_anchor().head();
 4843        let multibuffer = self.buffer.read(cx);
 4844        let Some(buffer) = position
 4845            .buffer_id
 4846            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4847        else {
 4848            return false;
 4849        };
 4850
 4851        if let Some(completion_provider) = &self.completion_provider {
 4852            completion_provider.is_completion_trigger(
 4853                &buffer,
 4854                position.text_anchor,
 4855                text,
 4856                trigger_in_words,
 4857                menu_is_open,
 4858                cx,
 4859            )
 4860        } else {
 4861            false
 4862        }
 4863    }
 4864
 4865    /// If any empty selections is touching the start of its innermost containing autoclose
 4866    /// region, expand it to select the brackets.
 4867    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4868        let selections = self.selections.all::<usize>(cx);
 4869        let buffer = self.buffer.read(cx).read(cx);
 4870        let new_selections = self
 4871            .selections_with_autoclose_regions(selections, &buffer)
 4872            .map(|(mut selection, region)| {
 4873                if !selection.is_empty() {
 4874                    return selection;
 4875                }
 4876
 4877                if let Some(region) = region {
 4878                    let mut range = region.range.to_offset(&buffer);
 4879                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4880                        range.start -= region.pair.start.len();
 4881                        if buffer.contains_str_at(range.start, &region.pair.start)
 4882                            && buffer.contains_str_at(range.end, &region.pair.end)
 4883                        {
 4884                            range.end += region.pair.end.len();
 4885                            selection.start = range.start;
 4886                            selection.end = range.end;
 4887
 4888                            return selection;
 4889                        }
 4890                    }
 4891                }
 4892
 4893                let always_treat_brackets_as_autoclosed = buffer
 4894                    .language_settings_at(selection.start, cx)
 4895                    .always_treat_brackets_as_autoclosed;
 4896
 4897                if !always_treat_brackets_as_autoclosed {
 4898                    return selection;
 4899                }
 4900
 4901                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4902                    for (pair, enabled) in scope.brackets() {
 4903                        if !enabled || !pair.close {
 4904                            continue;
 4905                        }
 4906
 4907                        if buffer.contains_str_at(selection.start, &pair.end) {
 4908                            let pair_start_len = pair.start.len();
 4909                            if buffer.contains_str_at(
 4910                                selection.start.saturating_sub(pair_start_len),
 4911                                &pair.start,
 4912                            ) {
 4913                                selection.start -= pair_start_len;
 4914                                selection.end += pair.end.len();
 4915
 4916                                return selection;
 4917                            }
 4918                        }
 4919                    }
 4920                }
 4921
 4922                selection
 4923            })
 4924            .collect();
 4925
 4926        drop(buffer);
 4927        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4928            selections.select(new_selections)
 4929        });
 4930    }
 4931
 4932    /// Iterate the given selections, and for each one, find the smallest surrounding
 4933    /// autoclose region. This uses the ordering of the selections and the autoclose
 4934    /// regions to avoid repeated comparisons.
 4935    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4936        &'a self,
 4937        selections: impl IntoIterator<Item = Selection<D>>,
 4938        buffer: &'a MultiBufferSnapshot,
 4939    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4940        let mut i = 0;
 4941        let mut regions = self.autoclose_regions.as_slice();
 4942        selections.into_iter().map(move |selection| {
 4943            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4944
 4945            let mut enclosing = None;
 4946            while let Some(pair_state) = regions.get(i) {
 4947                if pair_state.range.end.to_offset(buffer) < range.start {
 4948                    regions = &regions[i + 1..];
 4949                    i = 0;
 4950                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4951                    break;
 4952                } else {
 4953                    if pair_state.selection_id == selection.id {
 4954                        enclosing = Some(pair_state);
 4955                    }
 4956                    i += 1;
 4957                }
 4958            }
 4959
 4960            (selection, enclosing)
 4961        })
 4962    }
 4963
 4964    /// Remove any autoclose regions that no longer contain their selection.
 4965    fn invalidate_autoclose_regions(
 4966        &mut self,
 4967        mut selections: &[Selection<Anchor>],
 4968        buffer: &MultiBufferSnapshot,
 4969    ) {
 4970        self.autoclose_regions.retain(|state| {
 4971            let mut i = 0;
 4972            while let Some(selection) = selections.get(i) {
 4973                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4974                    selections = &selections[1..];
 4975                    continue;
 4976                }
 4977                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4978                    break;
 4979                }
 4980                if selection.id == state.selection_id {
 4981                    return true;
 4982                } else {
 4983                    i += 1;
 4984                }
 4985            }
 4986            false
 4987        });
 4988    }
 4989
 4990    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4991        let offset = position.to_offset(buffer);
 4992        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4993        if offset > word_range.start && kind == Some(CharKind::Word) {
 4994            Some(
 4995                buffer
 4996                    .text_for_range(word_range.start..offset)
 4997                    .collect::<String>(),
 4998            )
 4999        } else {
 5000            None
 5001        }
 5002    }
 5003
 5004    pub fn toggle_inline_values(
 5005        &mut self,
 5006        _: &ToggleInlineValues,
 5007        _: &mut Window,
 5008        cx: &mut Context<Self>,
 5009    ) {
 5010        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5011
 5012        self.refresh_inline_values(cx);
 5013    }
 5014
 5015    pub fn toggle_inlay_hints(
 5016        &mut self,
 5017        _: &ToggleInlayHints,
 5018        _: &mut Window,
 5019        cx: &mut Context<Self>,
 5020    ) {
 5021        self.refresh_inlay_hints(
 5022            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5023            cx,
 5024        );
 5025    }
 5026
 5027    pub fn inlay_hints_enabled(&self) -> bool {
 5028        self.inlay_hint_cache.enabled
 5029    }
 5030
 5031    pub fn inline_values_enabled(&self) -> bool {
 5032        self.inline_value_cache.enabled
 5033    }
 5034
 5035    #[cfg(any(test, feature = "test-support"))]
 5036    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5037        self.display_map
 5038            .read(cx)
 5039            .current_inlays()
 5040            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5041            .cloned()
 5042            .collect()
 5043    }
 5044
 5045    #[cfg(any(test, feature = "test-support"))]
 5046    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5047        self.display_map
 5048            .read(cx)
 5049            .current_inlays()
 5050            .cloned()
 5051            .collect()
 5052    }
 5053
 5054    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5055        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5056            return;
 5057        }
 5058
 5059        let reason_description = reason.description();
 5060        let ignore_debounce = matches!(
 5061            reason,
 5062            InlayHintRefreshReason::SettingsChange(_)
 5063                | InlayHintRefreshReason::Toggle(_)
 5064                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5065                | InlayHintRefreshReason::ModifiersChanged(_)
 5066        );
 5067        let (invalidate_cache, required_languages) = match reason {
 5068            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5069                match self.inlay_hint_cache.modifiers_override(enabled) {
 5070                    Some(enabled) => {
 5071                        if enabled {
 5072                            (InvalidationStrategy::RefreshRequested, None)
 5073                        } else {
 5074                            self.splice_inlays(
 5075                                &self
 5076                                    .visible_inlay_hints(cx)
 5077                                    .iter()
 5078                                    .map(|inlay| inlay.id)
 5079                                    .collect::<Vec<InlayId>>(),
 5080                                Vec::new(),
 5081                                cx,
 5082                            );
 5083                            return;
 5084                        }
 5085                    }
 5086                    None => return,
 5087                }
 5088            }
 5089            InlayHintRefreshReason::Toggle(enabled) => {
 5090                if self.inlay_hint_cache.toggle(enabled) {
 5091                    if enabled {
 5092                        (InvalidationStrategy::RefreshRequested, None)
 5093                    } else {
 5094                        self.splice_inlays(
 5095                            &self
 5096                                .visible_inlay_hints(cx)
 5097                                .iter()
 5098                                .map(|inlay| inlay.id)
 5099                                .collect::<Vec<InlayId>>(),
 5100                            Vec::new(),
 5101                            cx,
 5102                        );
 5103                        return;
 5104                    }
 5105                } else {
 5106                    return;
 5107                }
 5108            }
 5109            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5110                match self.inlay_hint_cache.update_settings(
 5111                    &self.buffer,
 5112                    new_settings,
 5113                    self.visible_inlay_hints(cx),
 5114                    cx,
 5115                ) {
 5116                    ControlFlow::Break(Some(InlaySplice {
 5117                        to_remove,
 5118                        to_insert,
 5119                    })) => {
 5120                        self.splice_inlays(&to_remove, to_insert, cx);
 5121                        return;
 5122                    }
 5123                    ControlFlow::Break(None) => return,
 5124                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5125                }
 5126            }
 5127            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5128                if let Some(InlaySplice {
 5129                    to_remove,
 5130                    to_insert,
 5131                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5132                {
 5133                    self.splice_inlays(&to_remove, to_insert, cx);
 5134                }
 5135                self.display_map.update(cx, |display_map, _| {
 5136                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5137                });
 5138                return;
 5139            }
 5140            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5141            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5142                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5143            }
 5144            InlayHintRefreshReason::RefreshRequested => {
 5145                (InvalidationStrategy::RefreshRequested, None)
 5146            }
 5147        };
 5148
 5149        if let Some(InlaySplice {
 5150            to_remove,
 5151            to_insert,
 5152        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5153            reason_description,
 5154            self.visible_excerpts(required_languages.as_ref(), cx),
 5155            invalidate_cache,
 5156            ignore_debounce,
 5157            cx,
 5158        ) {
 5159            self.splice_inlays(&to_remove, to_insert, cx);
 5160        }
 5161    }
 5162
 5163    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5164        self.display_map
 5165            .read(cx)
 5166            .current_inlays()
 5167            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5168            .cloned()
 5169            .collect()
 5170    }
 5171
 5172    pub fn visible_excerpts(
 5173        &self,
 5174        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5175        cx: &mut Context<Editor>,
 5176    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5177        let Some(project) = self.project.as_ref() else {
 5178            return HashMap::default();
 5179        };
 5180        let project = project.read(cx);
 5181        let multi_buffer = self.buffer().read(cx);
 5182        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5183        let multi_buffer_visible_start = self
 5184            .scroll_manager
 5185            .anchor()
 5186            .anchor
 5187            .to_point(&multi_buffer_snapshot);
 5188        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5189            multi_buffer_visible_start
 5190                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5191            Bias::Left,
 5192        );
 5193        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5194        multi_buffer_snapshot
 5195            .range_to_buffer_ranges(multi_buffer_visible_range)
 5196            .into_iter()
 5197            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5198            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5199                let buffer_file = project::File::from_dyn(buffer.file())?;
 5200                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5201                let worktree_entry = buffer_worktree
 5202                    .read(cx)
 5203                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5204                if worktree_entry.is_ignored {
 5205                    return None;
 5206                }
 5207
 5208                let language = buffer.language()?;
 5209                if let Some(restrict_to_languages) = restrict_to_languages {
 5210                    if !restrict_to_languages.contains(language) {
 5211                        return None;
 5212                    }
 5213                }
 5214                Some((
 5215                    excerpt_id,
 5216                    (
 5217                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5218                        buffer.version().clone(),
 5219                        excerpt_visible_range,
 5220                    ),
 5221                ))
 5222            })
 5223            .collect()
 5224    }
 5225
 5226    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5227        TextLayoutDetails {
 5228            text_system: window.text_system().clone(),
 5229            editor_style: self.style.clone().unwrap(),
 5230            rem_size: window.rem_size(),
 5231            scroll_anchor: self.scroll_manager.anchor(),
 5232            visible_rows: self.visible_line_count(),
 5233            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5234        }
 5235    }
 5236
 5237    pub fn splice_inlays(
 5238        &self,
 5239        to_remove: &[InlayId],
 5240        to_insert: Vec<Inlay>,
 5241        cx: &mut Context<Self>,
 5242    ) {
 5243        self.display_map.update(cx, |display_map, cx| {
 5244            display_map.splice_inlays(to_remove, to_insert, cx)
 5245        });
 5246        cx.notify();
 5247    }
 5248
 5249    fn trigger_on_type_formatting(
 5250        &self,
 5251        input: String,
 5252        window: &mut Window,
 5253        cx: &mut Context<Self>,
 5254    ) -> Option<Task<Result<()>>> {
 5255        if input.len() != 1 {
 5256            return None;
 5257        }
 5258
 5259        let project = self.project.as_ref()?;
 5260        let position = self.selections.newest_anchor().head();
 5261        let (buffer, buffer_position) = self
 5262            .buffer
 5263            .read(cx)
 5264            .text_anchor_for_position(position, cx)?;
 5265
 5266        let settings = language_settings::language_settings(
 5267            buffer
 5268                .read(cx)
 5269                .language_at(buffer_position)
 5270                .map(|l| l.name()),
 5271            buffer.read(cx).file(),
 5272            cx,
 5273        );
 5274        if !settings.use_on_type_format {
 5275            return None;
 5276        }
 5277
 5278        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5279        // hence we do LSP request & edit on host side only — add formats to host's history.
 5280        let push_to_lsp_host_history = true;
 5281        // If this is not the host, append its history with new edits.
 5282        let push_to_client_history = project.read(cx).is_via_collab();
 5283
 5284        let on_type_formatting = project.update(cx, |project, cx| {
 5285            project.on_type_format(
 5286                buffer.clone(),
 5287                buffer_position,
 5288                input,
 5289                push_to_lsp_host_history,
 5290                cx,
 5291            )
 5292        });
 5293        Some(cx.spawn_in(window, async move |editor, cx| {
 5294            if let Some(transaction) = on_type_formatting.await? {
 5295                if push_to_client_history {
 5296                    buffer
 5297                        .update(cx, |buffer, _| {
 5298                            buffer.push_transaction(transaction, Instant::now());
 5299                            buffer.finalize_last_transaction();
 5300                        })
 5301                        .ok();
 5302                }
 5303                editor.update(cx, |editor, cx| {
 5304                    editor.refresh_document_highlights(cx);
 5305                })?;
 5306            }
 5307            Ok(())
 5308        }))
 5309    }
 5310
 5311    pub fn show_word_completions(
 5312        &mut self,
 5313        _: &ShowWordCompletions,
 5314        window: &mut Window,
 5315        cx: &mut Context<Self>,
 5316    ) {
 5317        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5318    }
 5319
 5320    pub fn show_completions(
 5321        &mut self,
 5322        options: &ShowCompletions,
 5323        window: &mut Window,
 5324        cx: &mut Context<Self>,
 5325    ) {
 5326        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5327    }
 5328
 5329    fn open_or_update_completions_menu(
 5330        &mut self,
 5331        requested_source: Option<CompletionsMenuSource>,
 5332        trigger: Option<&str>,
 5333        window: &mut Window,
 5334        cx: &mut Context<Self>,
 5335    ) {
 5336        if self.pending_rename.is_some() {
 5337            return;
 5338        }
 5339
 5340        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5341
 5342        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5343        // inserted and selected. To handle that case, the start of the selection is used so that
 5344        // the menu starts with all choices.
 5345        let position = self
 5346            .selections
 5347            .newest_anchor()
 5348            .start
 5349            .bias_right(&multibuffer_snapshot);
 5350        if position.diff_base_anchor.is_some() {
 5351            return;
 5352        }
 5353        let (buffer, buffer_position) =
 5354            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5355                output
 5356            } else {
 5357                return;
 5358            };
 5359        let buffer_snapshot = buffer.read(cx).snapshot();
 5360
 5361        let query: Option<Arc<String>> =
 5362            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5363
 5364        drop(multibuffer_snapshot);
 5365
 5366        let provider = match requested_source {
 5367            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5368            Some(CompletionsMenuSource::Words) => None,
 5369            Some(CompletionsMenuSource::SnippetChoices) => {
 5370                log::error!("bug: SnippetChoices requested_source is not handled");
 5371                None
 5372            }
 5373        };
 5374
 5375        let sort_completions = provider
 5376            .as_ref()
 5377            .map_or(false, |provider| provider.sort_completions());
 5378
 5379        let filter_completions = provider
 5380            .as_ref()
 5381            .map_or(true, |provider| provider.filter_completions());
 5382
 5383        let trigger_kind = match trigger {
 5384            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5385                CompletionTriggerKind::TRIGGER_CHARACTER
 5386            }
 5387            _ => CompletionTriggerKind::INVOKED,
 5388        };
 5389        let completion_context = CompletionContext {
 5390            trigger_character: trigger.and_then(|trigger| {
 5391                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5392                    Some(String::from(trigger))
 5393                } else {
 5394                    None
 5395                }
 5396            }),
 5397            trigger_kind,
 5398        };
 5399
 5400        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5401        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5402        // involve trigger chars, so this is skipped in that case.
 5403        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5404        {
 5405            let menu_is_open = matches!(
 5406                self.context_menu.borrow().as_ref(),
 5407                Some(CodeContextMenu::Completions(_))
 5408            );
 5409            if menu_is_open {
 5410                self.hide_context_menu(window, cx);
 5411            }
 5412        }
 5413
 5414        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5415            if filter_completions {
 5416                menu.filter(query.clone(), provider.clone(), window, cx);
 5417            }
 5418            // When `is_incomplete` is false, no need to re-query completions when the current query
 5419            // is a suffix of the initial query.
 5420            if !menu.is_incomplete {
 5421                // If the new query is a suffix of the old query (typing more characters) and
 5422                // the previous result was complete, the existing completions can be filtered.
 5423                //
 5424                // Note that this is always true for snippet completions.
 5425                let query_matches = match (&menu.initial_query, &query) {
 5426                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5427                    (None, _) => true,
 5428                    _ => false,
 5429                };
 5430                if query_matches {
 5431                    let position_matches = if menu.initial_position == position {
 5432                        true
 5433                    } else {
 5434                        let snapshot = self.buffer.read(cx).read(cx);
 5435                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5436                    };
 5437                    if position_matches {
 5438                        return;
 5439                    }
 5440                }
 5441            }
 5442        };
 5443
 5444        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5445            buffer_snapshot.surrounding_word(buffer_position)
 5446        {
 5447            let word_to_exclude = buffer_snapshot
 5448                .text_for_range(word_range.clone())
 5449                .collect::<String>();
 5450            (
 5451                buffer_snapshot.anchor_before(word_range.start)
 5452                    ..buffer_snapshot.anchor_after(buffer_position),
 5453                Some(word_to_exclude),
 5454            )
 5455        } else {
 5456            (buffer_position..buffer_position, None)
 5457        };
 5458
 5459        let language = buffer_snapshot
 5460            .language_at(buffer_position)
 5461            .map(|language| language.name());
 5462
 5463        let completion_settings =
 5464            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5465
 5466        let show_completion_documentation = buffer_snapshot
 5467            .settings_at(buffer_position, cx)
 5468            .show_completion_documentation;
 5469
 5470        // The document can be large, so stay in reasonable bounds when searching for words,
 5471        // otherwise completion pop-up might be slow to appear.
 5472        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5473        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5474        let min_word_search = buffer_snapshot.clip_point(
 5475            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5476            Bias::Left,
 5477        );
 5478        let max_word_search = buffer_snapshot.clip_point(
 5479            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5480            Bias::Right,
 5481        );
 5482        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5483            ..buffer_snapshot.point_to_offset(max_word_search);
 5484
 5485        let skip_digits = query
 5486            .as_ref()
 5487            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5488
 5489        let (mut words, provider_responses) = match &provider {
 5490            Some(provider) => {
 5491                let provider_responses = provider.completions(
 5492                    position.excerpt_id,
 5493                    &buffer,
 5494                    buffer_position,
 5495                    completion_context,
 5496                    window,
 5497                    cx,
 5498                );
 5499
 5500                let words = match completion_settings.words {
 5501                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5502                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5503                        .background_spawn(async move {
 5504                            buffer_snapshot.words_in_range(WordsQuery {
 5505                                fuzzy_contents: None,
 5506                                range: word_search_range,
 5507                                skip_digits,
 5508                            })
 5509                        }),
 5510                };
 5511
 5512                (words, provider_responses)
 5513            }
 5514            None => (
 5515                cx.background_spawn(async move {
 5516                    buffer_snapshot.words_in_range(WordsQuery {
 5517                        fuzzy_contents: None,
 5518                        range: word_search_range,
 5519                        skip_digits,
 5520                    })
 5521                }),
 5522                Task::ready(Ok(Vec::new())),
 5523            ),
 5524        };
 5525
 5526        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5527
 5528        let id = post_inc(&mut self.next_completion_id);
 5529        let task = cx.spawn_in(window, async move |editor, cx| {
 5530            let Ok(()) = editor.update(cx, |this, _| {
 5531                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5532            }) else {
 5533                return;
 5534            };
 5535
 5536            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5537            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5538            let mut completions = Vec::new();
 5539            let mut is_incomplete = false;
 5540            if let Some(provider_responses) = provider_responses.await.log_err() {
 5541                if !provider_responses.is_empty() {
 5542                    for response in provider_responses {
 5543                        completions.extend(response.completions);
 5544                        is_incomplete = is_incomplete || response.is_incomplete;
 5545                    }
 5546                    if completion_settings.words == WordsCompletionMode::Fallback {
 5547                        words = Task::ready(BTreeMap::default());
 5548                    }
 5549                }
 5550            }
 5551
 5552            let mut words = words.await;
 5553            if let Some(word_to_exclude) = &word_to_exclude {
 5554                words.remove(word_to_exclude);
 5555            }
 5556            for lsp_completion in &completions {
 5557                words.remove(&lsp_completion.new_text);
 5558            }
 5559            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5560                replace_range: word_replace_range.clone(),
 5561                new_text: word.clone(),
 5562                label: CodeLabel::plain(word, None),
 5563                icon_path: None,
 5564                documentation: None,
 5565                source: CompletionSource::BufferWord {
 5566                    word_range,
 5567                    resolved: false,
 5568                },
 5569                insert_text_mode: Some(InsertTextMode::AS_IS),
 5570                confirm: None,
 5571            }));
 5572
 5573            let menu = if completions.is_empty() {
 5574                None
 5575            } else {
 5576                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5577                    let languages = editor
 5578                        .workspace
 5579                        .as_ref()
 5580                        .and_then(|(workspace, _)| workspace.upgrade())
 5581                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5582                    let menu = CompletionsMenu::new(
 5583                        id,
 5584                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5585                        sort_completions,
 5586                        show_completion_documentation,
 5587                        position,
 5588                        query.clone(),
 5589                        is_incomplete,
 5590                        buffer.clone(),
 5591                        completions.into(),
 5592                        snippet_sort_order,
 5593                        languages,
 5594                        language,
 5595                        cx,
 5596                    );
 5597
 5598                    let query = if filter_completions { query } else { None };
 5599                    let matches_task = if let Some(query) = query {
 5600                        menu.do_async_filtering(query, cx)
 5601                    } else {
 5602                        Task::ready(menu.unfiltered_matches())
 5603                    };
 5604                    (menu, matches_task)
 5605                }) else {
 5606                    return;
 5607                };
 5608
 5609                let matches = matches_task.await;
 5610
 5611                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5612                    // Newer menu already set, so exit.
 5613                    match editor.context_menu.borrow().as_ref() {
 5614                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5615                            if prev_menu.id > id {
 5616                                return;
 5617                            }
 5618                        }
 5619                        _ => {}
 5620                    };
 5621
 5622                    // Only valid to take prev_menu because it the new menu is immediately set
 5623                    // below, or the menu is hidden.
 5624                    match editor.context_menu.borrow_mut().take() {
 5625                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5626                            let position_matches =
 5627                                if prev_menu.initial_position == menu.initial_position {
 5628                                    true
 5629                                } else {
 5630                                    let snapshot = editor.buffer.read(cx).read(cx);
 5631                                    prev_menu.initial_position.to_offset(&snapshot)
 5632                                        == menu.initial_position.to_offset(&snapshot)
 5633                                };
 5634                            if position_matches {
 5635                                // Preserve markdown cache before `set_filter_results` because it will
 5636                                // try to populate the documentation cache.
 5637                                menu.preserve_markdown_cache(prev_menu);
 5638                            }
 5639                        }
 5640                        _ => {}
 5641                    };
 5642
 5643                    menu.set_filter_results(matches, provider, window, cx);
 5644                }) else {
 5645                    return;
 5646                };
 5647
 5648                menu.visible().then_some(menu)
 5649            };
 5650
 5651            editor
 5652                .update_in(cx, |editor, window, cx| {
 5653                    if editor.focus_handle.is_focused(window) {
 5654                        if let Some(menu) = menu {
 5655                            *editor.context_menu.borrow_mut() =
 5656                                Some(CodeContextMenu::Completions(menu));
 5657
 5658                            crate::hover_popover::hide_hover(editor, cx);
 5659                            if editor.show_edit_predictions_in_menu() {
 5660                                editor.update_visible_inline_completion(window, cx);
 5661                            } else {
 5662                                editor.discard_inline_completion(false, cx);
 5663                            }
 5664
 5665                            cx.notify();
 5666                            return;
 5667                        }
 5668                    }
 5669
 5670                    if editor.completion_tasks.len() <= 1 {
 5671                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5672                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5673                        // If it was already hidden and we don't show inline completions in the menu, we should
 5674                        // also show the inline-completion when available.
 5675                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5676                            editor.update_visible_inline_completion(window, cx);
 5677                        }
 5678                    }
 5679                })
 5680                .ok();
 5681        });
 5682
 5683        self.completion_tasks.push((id, task));
 5684    }
 5685
 5686    #[cfg(feature = "test-support")]
 5687    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5688        let menu = self.context_menu.borrow();
 5689        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5690            let completions = menu.completions.borrow();
 5691            Some(completions.to_vec())
 5692        } else {
 5693            None
 5694        }
 5695    }
 5696
 5697    pub fn with_completions_menu_matching_id<R>(
 5698        &self,
 5699        id: CompletionId,
 5700        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5701    ) -> R {
 5702        let mut context_menu = self.context_menu.borrow_mut();
 5703        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5704            return f(None);
 5705        };
 5706        if completions_menu.id != id {
 5707            return f(None);
 5708        }
 5709        f(Some(completions_menu))
 5710    }
 5711
 5712    pub fn confirm_completion(
 5713        &mut self,
 5714        action: &ConfirmCompletion,
 5715        window: &mut Window,
 5716        cx: &mut Context<Self>,
 5717    ) -> Option<Task<Result<()>>> {
 5718        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5719        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5720    }
 5721
 5722    pub fn confirm_completion_insert(
 5723        &mut self,
 5724        _: &ConfirmCompletionInsert,
 5725        window: &mut Window,
 5726        cx: &mut Context<Self>,
 5727    ) -> Option<Task<Result<()>>> {
 5728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5729        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5730    }
 5731
 5732    pub fn confirm_completion_replace(
 5733        &mut self,
 5734        _: &ConfirmCompletionReplace,
 5735        window: &mut Window,
 5736        cx: &mut Context<Self>,
 5737    ) -> Option<Task<Result<()>>> {
 5738        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5739        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5740    }
 5741
 5742    pub fn compose_completion(
 5743        &mut self,
 5744        action: &ComposeCompletion,
 5745        window: &mut Window,
 5746        cx: &mut Context<Self>,
 5747    ) -> Option<Task<Result<()>>> {
 5748        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5749        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5750    }
 5751
 5752    fn do_completion(
 5753        &mut self,
 5754        item_ix: Option<usize>,
 5755        intent: CompletionIntent,
 5756        window: &mut Window,
 5757        cx: &mut Context<Editor>,
 5758    ) -> Option<Task<Result<()>>> {
 5759        use language::ToOffset as _;
 5760
 5761        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5762        else {
 5763            return None;
 5764        };
 5765
 5766        let candidate_id = {
 5767            let entries = completions_menu.entries.borrow();
 5768            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5769            if self.show_edit_predictions_in_menu() {
 5770                self.discard_inline_completion(true, cx);
 5771            }
 5772            mat.candidate_id
 5773        };
 5774
 5775        let completion = completions_menu
 5776            .completions
 5777            .borrow()
 5778            .get(candidate_id)?
 5779            .clone();
 5780        cx.stop_propagation();
 5781
 5782        let buffer_handle = completions_menu.buffer.clone();
 5783
 5784        let CompletionEdit {
 5785            new_text,
 5786            snippet,
 5787            replace_range,
 5788        } = process_completion_for_edit(
 5789            &completion,
 5790            intent,
 5791            &buffer_handle,
 5792            &completions_menu.initial_position.text_anchor,
 5793            cx,
 5794        );
 5795
 5796        let buffer = buffer_handle.read(cx);
 5797        let snapshot = self.buffer.read(cx).snapshot(cx);
 5798        let newest_anchor = self.selections.newest_anchor();
 5799        let replace_range_multibuffer = {
 5800            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5801            let multibuffer_anchor = snapshot
 5802                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5803                .unwrap()
 5804                ..snapshot
 5805                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5806                    .unwrap();
 5807            multibuffer_anchor.start.to_offset(&snapshot)
 5808                ..multibuffer_anchor.end.to_offset(&snapshot)
 5809        };
 5810        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5811            return None;
 5812        }
 5813
 5814        let old_text = buffer
 5815            .text_for_range(replace_range.clone())
 5816            .collect::<String>();
 5817        let lookbehind = newest_anchor
 5818            .start
 5819            .text_anchor
 5820            .to_offset(buffer)
 5821            .saturating_sub(replace_range.start);
 5822        let lookahead = replace_range
 5823            .end
 5824            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5825        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5826        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5827
 5828        let selections = self.selections.all::<usize>(cx);
 5829        let mut ranges = Vec::new();
 5830        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5831
 5832        for selection in &selections {
 5833            let range = if selection.id == newest_anchor.id {
 5834                replace_range_multibuffer.clone()
 5835            } else {
 5836                let mut range = selection.range();
 5837
 5838                // if prefix is present, don't duplicate it
 5839                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5840                    range.start = range.start.saturating_sub(lookbehind);
 5841
 5842                    // if suffix is also present, mimic the newest cursor and replace it
 5843                    if selection.id != newest_anchor.id
 5844                        && snapshot.contains_str_at(range.end, suffix)
 5845                    {
 5846                        range.end += lookahead;
 5847                    }
 5848                }
 5849                range
 5850            };
 5851
 5852            ranges.push(range.clone());
 5853
 5854            if !self.linked_edit_ranges.is_empty() {
 5855                let start_anchor = snapshot.anchor_before(range.start);
 5856                let end_anchor = snapshot.anchor_after(range.end);
 5857                if let Some(ranges) = self
 5858                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5859                {
 5860                    for (buffer, edits) in ranges {
 5861                        linked_edits
 5862                            .entry(buffer.clone())
 5863                            .or_default()
 5864                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5865                    }
 5866                }
 5867            }
 5868        }
 5869
 5870        let common_prefix_len = old_text
 5871            .chars()
 5872            .zip(new_text.chars())
 5873            .take_while(|(a, b)| a == b)
 5874            .map(|(a, _)| a.len_utf8())
 5875            .sum::<usize>();
 5876
 5877        cx.emit(EditorEvent::InputHandled {
 5878            utf16_range_to_replace: None,
 5879            text: new_text[common_prefix_len..].into(),
 5880        });
 5881
 5882        self.transact(window, cx, |this, window, cx| {
 5883            if let Some(mut snippet) = snippet {
 5884                snippet.text = new_text.to_string();
 5885                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5886            } else {
 5887                this.buffer.update(cx, |buffer, cx| {
 5888                    let auto_indent = match completion.insert_text_mode {
 5889                        Some(InsertTextMode::AS_IS) => None,
 5890                        _ => this.autoindent_mode.clone(),
 5891                    };
 5892                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5893                    buffer.edit(edits, auto_indent, cx);
 5894                });
 5895            }
 5896            for (buffer, edits) in linked_edits {
 5897                buffer.update(cx, |buffer, cx| {
 5898                    let snapshot = buffer.snapshot();
 5899                    let edits = edits
 5900                        .into_iter()
 5901                        .map(|(range, text)| {
 5902                            use text::ToPoint as TP;
 5903                            let end_point = TP::to_point(&range.end, &snapshot);
 5904                            let start_point = TP::to_point(&range.start, &snapshot);
 5905                            (start_point..end_point, text)
 5906                        })
 5907                        .sorted_by_key(|(range, _)| range.start);
 5908                    buffer.edit(edits, None, cx);
 5909                })
 5910            }
 5911
 5912            this.refresh_inline_completion(true, false, window, cx);
 5913        });
 5914
 5915        let show_new_completions_on_confirm = completion
 5916            .confirm
 5917            .as_ref()
 5918            .map_or(false, |confirm| confirm(intent, window, cx));
 5919        if show_new_completions_on_confirm {
 5920            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5921        }
 5922
 5923        let provider = self.completion_provider.as_ref()?;
 5924        drop(completion);
 5925        let apply_edits = provider.apply_additional_edits_for_completion(
 5926            buffer_handle,
 5927            completions_menu.completions.clone(),
 5928            candidate_id,
 5929            true,
 5930            cx,
 5931        );
 5932
 5933        let editor_settings = EditorSettings::get_global(cx);
 5934        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5935            // After the code completion is finished, users often want to know what signatures are needed.
 5936            // so we should automatically call signature_help
 5937            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5938        }
 5939
 5940        Some(cx.foreground_executor().spawn(async move {
 5941            apply_edits.await?;
 5942            Ok(())
 5943        }))
 5944    }
 5945
 5946    pub fn toggle_code_actions(
 5947        &mut self,
 5948        action: &ToggleCodeActions,
 5949        window: &mut Window,
 5950        cx: &mut Context<Self>,
 5951    ) {
 5952        let quick_launch = action.quick_launch;
 5953        let mut context_menu = self.context_menu.borrow_mut();
 5954        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5955            if code_actions.deployed_from == action.deployed_from {
 5956                // Toggle if we're selecting the same one
 5957                *context_menu = None;
 5958                cx.notify();
 5959                return;
 5960            } else {
 5961                // Otherwise, clear it and start a new one
 5962                *context_menu = None;
 5963                cx.notify();
 5964            }
 5965        }
 5966        drop(context_menu);
 5967        let snapshot = self.snapshot(window, cx);
 5968        let deployed_from = action.deployed_from.clone();
 5969        let action = action.clone();
 5970        self.completion_tasks.clear();
 5971        self.discard_inline_completion(false, cx);
 5972
 5973        let multibuffer_point = match &action.deployed_from {
 5974            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5975                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5976            }
 5977            _ => self.selections.newest::<Point>(cx).head(),
 5978        };
 5979        let Some((buffer, buffer_row)) = snapshot
 5980            .buffer_snapshot
 5981            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5982            .and_then(|(buffer_snapshot, range)| {
 5983                self.buffer()
 5984                    .read(cx)
 5985                    .buffer(buffer_snapshot.remote_id())
 5986                    .map(|buffer| (buffer, range.start.row))
 5987            })
 5988        else {
 5989            return;
 5990        };
 5991        let buffer_id = buffer.read(cx).remote_id();
 5992        let tasks = self
 5993            .tasks
 5994            .get(&(buffer_id, buffer_row))
 5995            .map(|t| Arc::new(t.to_owned()));
 5996
 5997        if !self.focus_handle.is_focused(window) {
 5998            return;
 5999        }
 6000        let project = self.project.clone();
 6001
 6002        let code_actions_task = match deployed_from {
 6003            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6004            _ => self.code_actions(buffer_row, window, cx),
 6005        };
 6006
 6007        let runnable_task = match deployed_from {
 6008            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6009            _ => {
 6010                let mut task_context_task = Task::ready(None);
 6011                if let Some(tasks) = &tasks {
 6012                    if let Some(project) = project {
 6013                        task_context_task =
 6014                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6015                    }
 6016                }
 6017
 6018                cx.spawn_in(window, {
 6019                    let buffer = buffer.clone();
 6020                    async move |editor, cx| {
 6021                        let task_context = task_context_task.await;
 6022
 6023                        let resolved_tasks =
 6024                            tasks
 6025                                .zip(task_context.clone())
 6026                                .map(|(tasks, task_context)| ResolvedTasks {
 6027                                    templates: tasks.resolve(&task_context).collect(),
 6028                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6029                                        multibuffer_point.row,
 6030                                        tasks.column,
 6031                                    )),
 6032                                });
 6033                        let debug_scenarios = editor
 6034                            .update(cx, |editor, cx| {
 6035                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6036                            })?
 6037                            .await;
 6038                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6039                    }
 6040                })
 6041            }
 6042        };
 6043
 6044        cx.spawn_in(window, async move |editor, cx| {
 6045            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6046            let code_actions = code_actions_task.await;
 6047            let spawn_straight_away = quick_launch
 6048                && resolved_tasks
 6049                    .as_ref()
 6050                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6051                && code_actions
 6052                    .as_ref()
 6053                    .map_or(true, |actions| actions.is_empty())
 6054                && debug_scenarios.is_empty();
 6055
 6056            editor.update_in(cx, |editor, window, cx| {
 6057                crate::hover_popover::hide_hover(editor, cx);
 6058                let actions = CodeActionContents::new(
 6059                    resolved_tasks,
 6060                    code_actions,
 6061                    debug_scenarios,
 6062                    task_context.unwrap_or_default(),
 6063                );
 6064
 6065                // Don't show the menu if there are no actions available
 6066                if actions.is_empty() {
 6067                    cx.notify();
 6068                    return Task::ready(Ok(()));
 6069                }
 6070
 6071                *editor.context_menu.borrow_mut() =
 6072                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6073                        buffer,
 6074                        actions,
 6075                        selected_item: Default::default(),
 6076                        scroll_handle: UniformListScrollHandle::default(),
 6077                        deployed_from,
 6078                    }));
 6079                cx.notify();
 6080                if spawn_straight_away {
 6081                    if let Some(task) = editor.confirm_code_action(
 6082                        &ConfirmCodeAction { item_ix: Some(0) },
 6083                        window,
 6084                        cx,
 6085                    ) {
 6086                        return task;
 6087                    }
 6088                }
 6089
 6090                Task::ready(Ok(()))
 6091            })
 6092        })
 6093        .detach_and_log_err(cx);
 6094    }
 6095
 6096    fn debug_scenarios(
 6097        &mut self,
 6098        resolved_tasks: &Option<ResolvedTasks>,
 6099        buffer: &Entity<Buffer>,
 6100        cx: &mut App,
 6101    ) -> Task<Vec<task::DebugScenario>> {
 6102        maybe!({
 6103            let project = self.project.as_ref()?;
 6104            let dap_store = project.read(cx).dap_store();
 6105            let mut scenarios = vec![];
 6106            let resolved_tasks = resolved_tasks.as_ref()?;
 6107            let buffer = buffer.read(cx);
 6108            let language = buffer.language()?;
 6109            let file = buffer.file();
 6110            let debug_adapter = language_settings(language.name().into(), file, cx)
 6111                .debuggers
 6112                .first()
 6113                .map(SharedString::from)
 6114                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6115
 6116            dap_store.update(cx, |dap_store, cx| {
 6117                for (_, task) in &resolved_tasks.templates {
 6118                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6119                        task.original_task().clone(),
 6120                        debug_adapter.clone().into(),
 6121                        task.display_label().to_owned().into(),
 6122                        cx,
 6123                    );
 6124                    scenarios.push(maybe_scenario);
 6125                }
 6126            });
 6127            Some(cx.background_spawn(async move {
 6128                let scenarios = futures::future::join_all(scenarios)
 6129                    .await
 6130                    .into_iter()
 6131                    .flatten()
 6132                    .collect::<Vec<_>>();
 6133                scenarios
 6134            }))
 6135        })
 6136        .unwrap_or_else(|| Task::ready(vec![]))
 6137    }
 6138
 6139    fn code_actions(
 6140        &mut self,
 6141        buffer_row: u32,
 6142        window: &mut Window,
 6143        cx: &mut Context<Self>,
 6144    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6145        let mut task = self.code_actions_task.take();
 6146        cx.spawn_in(window, async move |editor, cx| {
 6147            while let Some(prev_task) = task {
 6148                prev_task.await.log_err();
 6149                task = editor
 6150                    .update(cx, |this, _| this.code_actions_task.take())
 6151                    .ok()?;
 6152            }
 6153
 6154            editor
 6155                .update(cx, |editor, cx| {
 6156                    editor
 6157                        .available_code_actions
 6158                        .clone()
 6159                        .and_then(|(location, code_actions)| {
 6160                            let snapshot = location.buffer.read(cx).snapshot();
 6161                            let point_range = location.range.to_point(&snapshot);
 6162                            let point_range = point_range.start.row..=point_range.end.row;
 6163                            if point_range.contains(&buffer_row) {
 6164                                Some(code_actions)
 6165                            } else {
 6166                                None
 6167                            }
 6168                        })
 6169                })
 6170                .ok()
 6171                .flatten()
 6172        })
 6173    }
 6174
 6175    pub fn confirm_code_action(
 6176        &mut self,
 6177        action: &ConfirmCodeAction,
 6178        window: &mut Window,
 6179        cx: &mut Context<Self>,
 6180    ) -> Option<Task<Result<()>>> {
 6181        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6182
 6183        let actions_menu =
 6184            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6185                menu
 6186            } else {
 6187                return None;
 6188            };
 6189
 6190        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6191        let action = actions_menu.actions.get(action_ix)?;
 6192        let title = action.label();
 6193        let buffer = actions_menu.buffer;
 6194        let workspace = self.workspace()?;
 6195
 6196        match action {
 6197            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6198                workspace.update(cx, |workspace, cx| {
 6199                    workspace.schedule_resolved_task(
 6200                        task_source_kind,
 6201                        resolved_task,
 6202                        false,
 6203                        window,
 6204                        cx,
 6205                    );
 6206
 6207                    Some(Task::ready(Ok(())))
 6208                })
 6209            }
 6210            CodeActionsItem::CodeAction {
 6211                excerpt_id,
 6212                action,
 6213                provider,
 6214            } => {
 6215                let apply_code_action =
 6216                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6217                let workspace = workspace.downgrade();
 6218                Some(cx.spawn_in(window, async move |editor, cx| {
 6219                    let project_transaction = apply_code_action.await?;
 6220                    Self::open_project_transaction(
 6221                        &editor,
 6222                        workspace,
 6223                        project_transaction,
 6224                        title,
 6225                        cx,
 6226                    )
 6227                    .await
 6228                }))
 6229            }
 6230            CodeActionsItem::DebugScenario(scenario) => {
 6231                let context = actions_menu.actions.context.clone();
 6232
 6233                workspace.update(cx, |workspace, cx| {
 6234                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6235                    workspace.start_debug_session(
 6236                        scenario,
 6237                        context,
 6238                        Some(buffer),
 6239                        None,
 6240                        window,
 6241                        cx,
 6242                    );
 6243                });
 6244                Some(Task::ready(Ok(())))
 6245            }
 6246        }
 6247    }
 6248
 6249    pub async fn open_project_transaction(
 6250        this: &WeakEntity<Editor>,
 6251        workspace: WeakEntity<Workspace>,
 6252        transaction: ProjectTransaction,
 6253        title: String,
 6254        cx: &mut AsyncWindowContext,
 6255    ) -> Result<()> {
 6256        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6257        cx.update(|_, cx| {
 6258            entries.sort_unstable_by_key(|(buffer, _)| {
 6259                buffer.read(cx).file().map(|f| f.path().clone())
 6260            });
 6261        })?;
 6262
 6263        // If the project transaction's edits are all contained within this editor, then
 6264        // avoid opening a new editor to display them.
 6265
 6266        if let Some((buffer, transaction)) = entries.first() {
 6267            if entries.len() == 1 {
 6268                let excerpt = this.update(cx, |editor, cx| {
 6269                    editor
 6270                        .buffer()
 6271                        .read(cx)
 6272                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6273                })?;
 6274                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6275                    if excerpted_buffer == *buffer {
 6276                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6277                            let excerpt_range = excerpt_range.to_offset(buffer);
 6278                            buffer
 6279                                .edited_ranges_for_transaction::<usize>(transaction)
 6280                                .all(|range| {
 6281                                    excerpt_range.start <= range.start
 6282                                        && excerpt_range.end >= range.end
 6283                                })
 6284                        })?;
 6285
 6286                        if all_edits_within_excerpt {
 6287                            return Ok(());
 6288                        }
 6289                    }
 6290                }
 6291            }
 6292        } else {
 6293            return Ok(());
 6294        }
 6295
 6296        let mut ranges_to_highlight = Vec::new();
 6297        let excerpt_buffer = cx.new(|cx| {
 6298            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6299            for (buffer_handle, transaction) in &entries {
 6300                let edited_ranges = buffer_handle
 6301                    .read(cx)
 6302                    .edited_ranges_for_transaction::<Point>(transaction)
 6303                    .collect::<Vec<_>>();
 6304                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6305                    PathKey::for_buffer(buffer_handle, cx),
 6306                    buffer_handle.clone(),
 6307                    edited_ranges,
 6308                    DEFAULT_MULTIBUFFER_CONTEXT,
 6309                    cx,
 6310                );
 6311
 6312                ranges_to_highlight.extend(ranges);
 6313            }
 6314            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6315            multibuffer
 6316        })?;
 6317
 6318        workspace.update_in(cx, |workspace, window, cx| {
 6319            let project = workspace.project().clone();
 6320            let editor =
 6321                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6322            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6323            editor.update(cx, |editor, cx| {
 6324                editor.highlight_background::<Self>(
 6325                    &ranges_to_highlight,
 6326                    |theme| theme.colors().editor_highlighted_line_background,
 6327                    cx,
 6328                );
 6329            });
 6330        })?;
 6331
 6332        Ok(())
 6333    }
 6334
 6335    pub fn clear_code_action_providers(&mut self) {
 6336        self.code_action_providers.clear();
 6337        self.available_code_actions.take();
 6338    }
 6339
 6340    pub fn add_code_action_provider(
 6341        &mut self,
 6342        provider: Rc<dyn CodeActionProvider>,
 6343        window: &mut Window,
 6344        cx: &mut Context<Self>,
 6345    ) {
 6346        if self
 6347            .code_action_providers
 6348            .iter()
 6349            .any(|existing_provider| existing_provider.id() == provider.id())
 6350        {
 6351            return;
 6352        }
 6353
 6354        self.code_action_providers.push(provider);
 6355        self.refresh_code_actions(window, cx);
 6356    }
 6357
 6358    pub fn remove_code_action_provider(
 6359        &mut self,
 6360        id: Arc<str>,
 6361        window: &mut Window,
 6362        cx: &mut Context<Self>,
 6363    ) {
 6364        self.code_action_providers
 6365            .retain(|provider| provider.id() != id);
 6366        self.refresh_code_actions(window, cx);
 6367    }
 6368
 6369    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6370        !self.code_action_providers.is_empty()
 6371            && EditorSettings::get_global(cx).toolbar.code_actions
 6372    }
 6373
 6374    pub fn has_available_code_actions(&self) -> bool {
 6375        self.available_code_actions
 6376            .as_ref()
 6377            .is_some_and(|(_, actions)| !actions.is_empty())
 6378    }
 6379
 6380    fn render_inline_code_actions(
 6381        &self,
 6382        icon_size: ui::IconSize,
 6383        display_row: DisplayRow,
 6384        is_active: bool,
 6385        cx: &mut Context<Self>,
 6386    ) -> AnyElement {
 6387        let show_tooltip = !self.context_menu_visible();
 6388        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6389            .icon_size(icon_size)
 6390            .shape(ui::IconButtonShape::Square)
 6391            .style(ButtonStyle::Transparent)
 6392            .icon_color(ui::Color::Hidden)
 6393            .toggle_state(is_active)
 6394            .when(show_tooltip, |this| {
 6395                this.tooltip({
 6396                    let focus_handle = self.focus_handle.clone();
 6397                    move |window, cx| {
 6398                        Tooltip::for_action_in(
 6399                            "Toggle Code Actions",
 6400                            &ToggleCodeActions {
 6401                                deployed_from: None,
 6402                                quick_launch: false,
 6403                            },
 6404                            &focus_handle,
 6405                            window,
 6406                            cx,
 6407                        )
 6408                    }
 6409                })
 6410            })
 6411            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6412                window.focus(&editor.focus_handle(cx));
 6413                editor.toggle_code_actions(
 6414                    &crate::actions::ToggleCodeActions {
 6415                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6416                            display_row,
 6417                        )),
 6418                        quick_launch: false,
 6419                    },
 6420                    window,
 6421                    cx,
 6422                );
 6423            }))
 6424            .into_any_element()
 6425    }
 6426
 6427    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6428        &self.context_menu
 6429    }
 6430
 6431    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6432        let newest_selection = self.selections.newest_anchor().clone();
 6433        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6434        let buffer = self.buffer.read(cx);
 6435        if newest_selection.head().diff_base_anchor.is_some() {
 6436            return None;
 6437        }
 6438        let (start_buffer, start) =
 6439            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6440        let (end_buffer, end) =
 6441            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6442        if start_buffer != end_buffer {
 6443            return None;
 6444        }
 6445
 6446        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6447            cx.background_executor()
 6448                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6449                .await;
 6450
 6451            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6452                let providers = this.code_action_providers.clone();
 6453                let tasks = this
 6454                    .code_action_providers
 6455                    .iter()
 6456                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6457                    .collect::<Vec<_>>();
 6458                (providers, tasks)
 6459            })?;
 6460
 6461            let mut actions = Vec::new();
 6462            for (provider, provider_actions) in
 6463                providers.into_iter().zip(future::join_all(tasks).await)
 6464            {
 6465                if let Some(provider_actions) = provider_actions.log_err() {
 6466                    actions.extend(provider_actions.into_iter().map(|action| {
 6467                        AvailableCodeAction {
 6468                            excerpt_id: newest_selection.start.excerpt_id,
 6469                            action,
 6470                            provider: provider.clone(),
 6471                        }
 6472                    }));
 6473                }
 6474            }
 6475
 6476            this.update(cx, |this, cx| {
 6477                this.available_code_actions = if actions.is_empty() {
 6478                    None
 6479                } else {
 6480                    Some((
 6481                        Location {
 6482                            buffer: start_buffer,
 6483                            range: start..end,
 6484                        },
 6485                        actions.into(),
 6486                    ))
 6487                };
 6488                cx.notify();
 6489            })
 6490        }));
 6491        None
 6492    }
 6493
 6494    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6495        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6496            self.show_git_blame_inline = false;
 6497
 6498            self.show_git_blame_inline_delay_task =
 6499                Some(cx.spawn_in(window, async move |this, cx| {
 6500                    cx.background_executor().timer(delay).await;
 6501
 6502                    this.update(cx, |this, cx| {
 6503                        this.show_git_blame_inline = true;
 6504                        cx.notify();
 6505                    })
 6506                    .log_err();
 6507                }));
 6508        }
 6509    }
 6510
 6511    fn show_blame_popover(
 6512        &mut self,
 6513        blame_entry: &BlameEntry,
 6514        position: gpui::Point<Pixels>,
 6515        cx: &mut Context<Self>,
 6516    ) {
 6517        if let Some(state) = &mut self.inline_blame_popover {
 6518            state.hide_task.take();
 6519        } else {
 6520            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6521            let blame_entry = blame_entry.clone();
 6522            let show_task = cx.spawn(async move |editor, cx| {
 6523                cx.background_executor()
 6524                    .timer(std::time::Duration::from_millis(delay))
 6525                    .await;
 6526                editor
 6527                    .update(cx, |editor, cx| {
 6528                        editor.inline_blame_popover_show_task.take();
 6529                        let Some(blame) = editor.blame.as_ref() else {
 6530                            return;
 6531                        };
 6532                        let blame = blame.read(cx);
 6533                        let details = blame.details_for_entry(&blame_entry);
 6534                        let markdown = cx.new(|cx| {
 6535                            Markdown::new(
 6536                                details
 6537                                    .as_ref()
 6538                                    .map(|message| message.message.clone())
 6539                                    .unwrap_or_default(),
 6540                                None,
 6541                                None,
 6542                                cx,
 6543                            )
 6544                        });
 6545                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6546                            position,
 6547                            hide_task: None,
 6548                            popover_bounds: None,
 6549                            popover_state: InlineBlamePopoverState {
 6550                                scroll_handle: ScrollHandle::new(),
 6551                                commit_message: details,
 6552                                markdown,
 6553                            },
 6554                        });
 6555                        cx.notify();
 6556                    })
 6557                    .ok();
 6558            });
 6559            self.inline_blame_popover_show_task = Some(show_task);
 6560        }
 6561    }
 6562
 6563    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6564        self.inline_blame_popover_show_task.take();
 6565        if let Some(state) = &mut self.inline_blame_popover {
 6566            let hide_task = cx.spawn(async move |editor, cx| {
 6567                cx.background_executor()
 6568                    .timer(std::time::Duration::from_millis(100))
 6569                    .await;
 6570                editor
 6571                    .update(cx, |editor, cx| {
 6572                        editor.inline_blame_popover.take();
 6573                        cx.notify();
 6574                    })
 6575                    .ok();
 6576            });
 6577            state.hide_task = Some(hide_task);
 6578        }
 6579    }
 6580
 6581    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6582        if self.pending_rename.is_some() {
 6583            return None;
 6584        }
 6585
 6586        let provider = self.semantics_provider.clone()?;
 6587        let buffer = self.buffer.read(cx);
 6588        let newest_selection = self.selections.newest_anchor().clone();
 6589        let cursor_position = newest_selection.head();
 6590        let (cursor_buffer, cursor_buffer_position) =
 6591            buffer.text_anchor_for_position(cursor_position, cx)?;
 6592        let (tail_buffer, tail_buffer_position) =
 6593            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6594        if cursor_buffer != tail_buffer {
 6595            return None;
 6596        }
 6597
 6598        let snapshot = cursor_buffer.read(cx).snapshot();
 6599        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6600        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6601        if start_word_range != end_word_range {
 6602            self.document_highlights_task.take();
 6603            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6604            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6605            return None;
 6606        }
 6607
 6608        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6609        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6610            cx.background_executor()
 6611                .timer(Duration::from_millis(debounce))
 6612                .await;
 6613
 6614            let highlights = if let Some(highlights) = cx
 6615                .update(|cx| {
 6616                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6617                })
 6618                .ok()
 6619                .flatten()
 6620            {
 6621                highlights.await.log_err()
 6622            } else {
 6623                None
 6624            };
 6625
 6626            if let Some(highlights) = highlights {
 6627                this.update(cx, |this, cx| {
 6628                    if this.pending_rename.is_some() {
 6629                        return;
 6630                    }
 6631
 6632                    let buffer_id = cursor_position.buffer_id;
 6633                    let buffer = this.buffer.read(cx);
 6634                    if !buffer
 6635                        .text_anchor_for_position(cursor_position, cx)
 6636                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6637                    {
 6638                        return;
 6639                    }
 6640
 6641                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6642                    let mut write_ranges = Vec::new();
 6643                    let mut read_ranges = Vec::new();
 6644                    for highlight in highlights {
 6645                        for (excerpt_id, excerpt_range) in
 6646                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6647                        {
 6648                            let start = highlight
 6649                                .range
 6650                                .start
 6651                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6652                            let end = highlight
 6653                                .range
 6654                                .end
 6655                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6656                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6657                                continue;
 6658                            }
 6659
 6660                            let range = Anchor {
 6661                                buffer_id,
 6662                                excerpt_id,
 6663                                text_anchor: start,
 6664                                diff_base_anchor: None,
 6665                            }..Anchor {
 6666                                buffer_id,
 6667                                excerpt_id,
 6668                                text_anchor: end,
 6669                                diff_base_anchor: None,
 6670                            };
 6671                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6672                                write_ranges.push(range);
 6673                            } else {
 6674                                read_ranges.push(range);
 6675                            }
 6676                        }
 6677                    }
 6678
 6679                    this.highlight_background::<DocumentHighlightRead>(
 6680                        &read_ranges,
 6681                        |theme| theme.colors().editor_document_highlight_read_background,
 6682                        cx,
 6683                    );
 6684                    this.highlight_background::<DocumentHighlightWrite>(
 6685                        &write_ranges,
 6686                        |theme| theme.colors().editor_document_highlight_write_background,
 6687                        cx,
 6688                    );
 6689                    cx.notify();
 6690                })
 6691                .log_err();
 6692            }
 6693        }));
 6694        None
 6695    }
 6696
 6697    fn prepare_highlight_query_from_selection(
 6698        &mut self,
 6699        cx: &mut Context<Editor>,
 6700    ) -> Option<(String, Range<Anchor>)> {
 6701        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6702            return None;
 6703        }
 6704        if !EditorSettings::get_global(cx).selection_highlight {
 6705            return None;
 6706        }
 6707        if self.selections.count() != 1 || self.selections.line_mode {
 6708            return None;
 6709        }
 6710        let selection = self.selections.newest::<Point>(cx);
 6711        if selection.is_empty() || selection.start.row != selection.end.row {
 6712            return None;
 6713        }
 6714        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6715        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6716        let query = multi_buffer_snapshot
 6717            .text_for_range(selection_anchor_range.clone())
 6718            .collect::<String>();
 6719        if query.trim().is_empty() {
 6720            return None;
 6721        }
 6722        Some((query, selection_anchor_range))
 6723    }
 6724
 6725    fn update_selection_occurrence_highlights(
 6726        &mut self,
 6727        query_text: String,
 6728        query_range: Range<Anchor>,
 6729        multi_buffer_range_to_query: Range<Point>,
 6730        use_debounce: bool,
 6731        window: &mut Window,
 6732        cx: &mut Context<Editor>,
 6733    ) -> Task<()> {
 6734        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6735        cx.spawn_in(window, async move |editor, cx| {
 6736            if use_debounce {
 6737                cx.background_executor()
 6738                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6739                    .await;
 6740            }
 6741            let match_task = cx.background_spawn(async move {
 6742                let buffer_ranges = multi_buffer_snapshot
 6743                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6744                    .into_iter()
 6745                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6746                let mut match_ranges = Vec::new();
 6747                let Ok(regex) = project::search::SearchQuery::text(
 6748                    query_text.clone(),
 6749                    false,
 6750                    false,
 6751                    false,
 6752                    Default::default(),
 6753                    Default::default(),
 6754                    false,
 6755                    None,
 6756                ) else {
 6757                    return Vec::default();
 6758                };
 6759                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6760                    match_ranges.extend(
 6761                        regex
 6762                            .search(&buffer_snapshot, Some(search_range.clone()))
 6763                            .await
 6764                            .into_iter()
 6765                            .filter_map(|match_range| {
 6766                                let match_start = buffer_snapshot
 6767                                    .anchor_after(search_range.start + match_range.start);
 6768                                let match_end = buffer_snapshot
 6769                                    .anchor_before(search_range.start + match_range.end);
 6770                                let match_anchor_range = Anchor::range_in_buffer(
 6771                                    excerpt_id,
 6772                                    buffer_snapshot.remote_id(),
 6773                                    match_start..match_end,
 6774                                );
 6775                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6776                            }),
 6777                    );
 6778                }
 6779                match_ranges
 6780            });
 6781            let match_ranges = match_task.await;
 6782            editor
 6783                .update_in(cx, |editor, _, cx| {
 6784                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6785                    if !match_ranges.is_empty() {
 6786                        editor.highlight_background::<SelectedTextHighlight>(
 6787                            &match_ranges,
 6788                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6789                            cx,
 6790                        )
 6791                    }
 6792                })
 6793                .log_err();
 6794        })
 6795    }
 6796
 6797    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6798        struct NewlineFold;
 6799        let type_id = std::any::TypeId::of::<NewlineFold>();
 6800        if !self.mode.is_single_line() {
 6801            return;
 6802        }
 6803        let snapshot = self.snapshot(window, cx);
 6804        if snapshot.buffer_snapshot.max_point().row == 0 {
 6805            return;
 6806        }
 6807        let task = cx.background_spawn(async move {
 6808            let new_newlines = snapshot
 6809                .buffer_chars_at(0)
 6810                .filter_map(|(c, i)| {
 6811                    if c == '\n' {
 6812                        Some(
 6813                            snapshot.buffer_snapshot.anchor_after(i)
 6814                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6815                        )
 6816                    } else {
 6817                        None
 6818                    }
 6819                })
 6820                .collect::<Vec<_>>();
 6821            let existing_newlines = snapshot
 6822                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6823                .filter_map(|fold| {
 6824                    if fold.placeholder.type_tag == Some(type_id) {
 6825                        Some(fold.range.start..fold.range.end)
 6826                    } else {
 6827                        None
 6828                    }
 6829                })
 6830                .collect::<Vec<_>>();
 6831
 6832            (new_newlines, existing_newlines)
 6833        });
 6834        self.folding_newlines = cx.spawn(async move |this, cx| {
 6835            let (new_newlines, existing_newlines) = task.await;
 6836            if new_newlines == existing_newlines {
 6837                return;
 6838            }
 6839            let placeholder = FoldPlaceholder {
 6840                render: Arc::new(move |_, _, cx| {
 6841                    div()
 6842                        .bg(cx.theme().status().hint_background)
 6843                        .border_b_1()
 6844                        .size_full()
 6845                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6846                        .border_color(cx.theme().status().hint)
 6847                        .child("\\n")
 6848                        .into_any()
 6849                }),
 6850                constrain_width: false,
 6851                merge_adjacent: false,
 6852                type_tag: Some(type_id),
 6853            };
 6854            let creases = new_newlines
 6855                .into_iter()
 6856                .map(|range| Crease::simple(range, placeholder.clone()))
 6857                .collect();
 6858            this.update(cx, |this, cx| {
 6859                this.display_map.update(cx, |display_map, cx| {
 6860                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6861                    display_map.fold(creases, cx);
 6862                });
 6863            })
 6864            .ok();
 6865        });
 6866    }
 6867
 6868    fn refresh_selected_text_highlights(
 6869        &mut self,
 6870        on_buffer_edit: bool,
 6871        window: &mut Window,
 6872        cx: &mut Context<Editor>,
 6873    ) {
 6874        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6875        else {
 6876            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6877            self.quick_selection_highlight_task.take();
 6878            self.debounced_selection_highlight_task.take();
 6879            return;
 6880        };
 6881        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6882        if on_buffer_edit
 6883            || self
 6884                .quick_selection_highlight_task
 6885                .as_ref()
 6886                .map_or(true, |(prev_anchor_range, _)| {
 6887                    prev_anchor_range != &query_range
 6888                })
 6889        {
 6890            let multi_buffer_visible_start = self
 6891                .scroll_manager
 6892                .anchor()
 6893                .anchor
 6894                .to_point(&multi_buffer_snapshot);
 6895            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6896                multi_buffer_visible_start
 6897                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6898                Bias::Left,
 6899            );
 6900            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6901            self.quick_selection_highlight_task = Some((
 6902                query_range.clone(),
 6903                self.update_selection_occurrence_highlights(
 6904                    query_text.clone(),
 6905                    query_range.clone(),
 6906                    multi_buffer_visible_range,
 6907                    false,
 6908                    window,
 6909                    cx,
 6910                ),
 6911            ));
 6912        }
 6913        if on_buffer_edit
 6914            || self
 6915                .debounced_selection_highlight_task
 6916                .as_ref()
 6917                .map_or(true, |(prev_anchor_range, _)| {
 6918                    prev_anchor_range != &query_range
 6919                })
 6920        {
 6921            let multi_buffer_start = multi_buffer_snapshot
 6922                .anchor_before(0)
 6923                .to_point(&multi_buffer_snapshot);
 6924            let multi_buffer_end = multi_buffer_snapshot
 6925                .anchor_after(multi_buffer_snapshot.len())
 6926                .to_point(&multi_buffer_snapshot);
 6927            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6928            self.debounced_selection_highlight_task = Some((
 6929                query_range.clone(),
 6930                self.update_selection_occurrence_highlights(
 6931                    query_text,
 6932                    query_range,
 6933                    multi_buffer_full_range,
 6934                    true,
 6935                    window,
 6936                    cx,
 6937                ),
 6938            ));
 6939        }
 6940    }
 6941
 6942    pub fn refresh_inline_completion(
 6943        &mut self,
 6944        debounce: bool,
 6945        user_requested: bool,
 6946        window: &mut Window,
 6947        cx: &mut Context<Self>,
 6948    ) -> Option<()> {
 6949        let provider = self.edit_prediction_provider()?;
 6950        let cursor = self.selections.newest_anchor().head();
 6951        let (buffer, cursor_buffer_position) =
 6952            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6953
 6954        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6955            self.discard_inline_completion(false, cx);
 6956            return None;
 6957        }
 6958
 6959        if !user_requested
 6960            && (!self.should_show_edit_predictions()
 6961                || !self.is_focused(window)
 6962                || buffer.read(cx).is_empty())
 6963        {
 6964            self.discard_inline_completion(false, cx);
 6965            return None;
 6966        }
 6967
 6968        self.update_visible_inline_completion(window, cx);
 6969        provider.refresh(
 6970            self.project.clone(),
 6971            buffer,
 6972            cursor_buffer_position,
 6973            debounce,
 6974            cx,
 6975        );
 6976        Some(())
 6977    }
 6978
 6979    fn show_edit_predictions_in_menu(&self) -> bool {
 6980        match self.edit_prediction_settings {
 6981            EditPredictionSettings::Disabled => false,
 6982            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6983        }
 6984    }
 6985
 6986    pub fn edit_predictions_enabled(&self) -> bool {
 6987        match self.edit_prediction_settings {
 6988            EditPredictionSettings::Disabled => false,
 6989            EditPredictionSettings::Enabled { .. } => true,
 6990        }
 6991    }
 6992
 6993    fn edit_prediction_requires_modifier(&self) -> bool {
 6994        match self.edit_prediction_settings {
 6995            EditPredictionSettings::Disabled => false,
 6996            EditPredictionSettings::Enabled {
 6997                preview_requires_modifier,
 6998                ..
 6999            } => preview_requires_modifier,
 7000        }
 7001    }
 7002
 7003    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7004        if self.edit_prediction_provider.is_none() {
 7005            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7006        } else {
 7007            let selection = self.selections.newest_anchor();
 7008            let cursor = selection.head();
 7009
 7010            if let Some((buffer, cursor_buffer_position)) =
 7011                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7012            {
 7013                self.edit_prediction_settings =
 7014                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7015            }
 7016        }
 7017    }
 7018
 7019    fn edit_prediction_settings_at_position(
 7020        &self,
 7021        buffer: &Entity<Buffer>,
 7022        buffer_position: language::Anchor,
 7023        cx: &App,
 7024    ) -> EditPredictionSettings {
 7025        if !self.mode.is_full()
 7026            || !self.show_inline_completions_override.unwrap_or(true)
 7027            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7028        {
 7029            return EditPredictionSettings::Disabled;
 7030        }
 7031
 7032        let buffer = buffer.read(cx);
 7033
 7034        let file = buffer.file();
 7035
 7036        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7037            return EditPredictionSettings::Disabled;
 7038        };
 7039
 7040        let by_provider = matches!(
 7041            self.menu_inline_completions_policy,
 7042            MenuInlineCompletionsPolicy::ByProvider
 7043        );
 7044
 7045        let show_in_menu = by_provider
 7046            && self
 7047                .edit_prediction_provider
 7048                .as_ref()
 7049                .map_or(false, |provider| {
 7050                    provider.provider.show_completions_in_menu()
 7051                });
 7052
 7053        let preview_requires_modifier =
 7054            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7055
 7056        EditPredictionSettings::Enabled {
 7057            show_in_menu,
 7058            preview_requires_modifier,
 7059        }
 7060    }
 7061
 7062    fn should_show_edit_predictions(&self) -> bool {
 7063        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7064    }
 7065
 7066    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7067        matches!(
 7068            self.edit_prediction_preview,
 7069            EditPredictionPreview::Active { .. }
 7070        )
 7071    }
 7072
 7073    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7074        let cursor = self.selections.newest_anchor().head();
 7075        if let Some((buffer, cursor_position)) =
 7076            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7077        {
 7078            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7079        } else {
 7080            false
 7081        }
 7082    }
 7083
 7084    pub fn supports_minimap(&self, cx: &App) -> bool {
 7085        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7086    }
 7087
 7088    fn edit_predictions_enabled_in_buffer(
 7089        &self,
 7090        buffer: &Entity<Buffer>,
 7091        buffer_position: language::Anchor,
 7092        cx: &App,
 7093    ) -> bool {
 7094        maybe!({
 7095            if self.read_only(cx) {
 7096                return Some(false);
 7097            }
 7098            let provider = self.edit_prediction_provider()?;
 7099            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7100                return Some(false);
 7101            }
 7102            let buffer = buffer.read(cx);
 7103            let Some(file) = buffer.file() else {
 7104                return Some(true);
 7105            };
 7106            let settings = all_language_settings(Some(file), cx);
 7107            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7108        })
 7109        .unwrap_or(false)
 7110    }
 7111
 7112    fn cycle_inline_completion(
 7113        &mut self,
 7114        direction: Direction,
 7115        window: &mut Window,
 7116        cx: &mut Context<Self>,
 7117    ) -> Option<()> {
 7118        let provider = self.edit_prediction_provider()?;
 7119        let cursor = self.selections.newest_anchor().head();
 7120        let (buffer, cursor_buffer_position) =
 7121            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7122        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7123            return None;
 7124        }
 7125
 7126        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7127        self.update_visible_inline_completion(window, cx);
 7128
 7129        Some(())
 7130    }
 7131
 7132    pub fn show_inline_completion(
 7133        &mut self,
 7134        _: &ShowEditPrediction,
 7135        window: &mut Window,
 7136        cx: &mut Context<Self>,
 7137    ) {
 7138        if !self.has_active_inline_completion() {
 7139            self.refresh_inline_completion(false, true, window, cx);
 7140            return;
 7141        }
 7142
 7143        self.update_visible_inline_completion(window, cx);
 7144    }
 7145
 7146    pub fn display_cursor_names(
 7147        &mut self,
 7148        _: &DisplayCursorNames,
 7149        window: &mut Window,
 7150        cx: &mut Context<Self>,
 7151    ) {
 7152        self.show_cursor_names(window, cx);
 7153    }
 7154
 7155    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7156        self.show_cursor_names = true;
 7157        cx.notify();
 7158        cx.spawn_in(window, async move |this, cx| {
 7159            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7160            this.update(cx, |this, cx| {
 7161                this.show_cursor_names = false;
 7162                cx.notify()
 7163            })
 7164            .ok()
 7165        })
 7166        .detach();
 7167    }
 7168
 7169    pub fn next_edit_prediction(
 7170        &mut self,
 7171        _: &NextEditPrediction,
 7172        window: &mut Window,
 7173        cx: &mut Context<Self>,
 7174    ) {
 7175        if self.has_active_inline_completion() {
 7176            self.cycle_inline_completion(Direction::Next, window, cx);
 7177        } else {
 7178            let is_copilot_disabled = self
 7179                .refresh_inline_completion(false, true, window, cx)
 7180                .is_none();
 7181            if is_copilot_disabled {
 7182                cx.propagate();
 7183            }
 7184        }
 7185    }
 7186
 7187    pub fn previous_edit_prediction(
 7188        &mut self,
 7189        _: &PreviousEditPrediction,
 7190        window: &mut Window,
 7191        cx: &mut Context<Self>,
 7192    ) {
 7193        if self.has_active_inline_completion() {
 7194            self.cycle_inline_completion(Direction::Prev, window, cx);
 7195        } else {
 7196            let is_copilot_disabled = self
 7197                .refresh_inline_completion(false, true, window, cx)
 7198                .is_none();
 7199            if is_copilot_disabled {
 7200                cx.propagate();
 7201            }
 7202        }
 7203    }
 7204
 7205    pub fn accept_edit_prediction(
 7206        &mut self,
 7207        _: &AcceptEditPrediction,
 7208        window: &mut Window,
 7209        cx: &mut Context<Self>,
 7210    ) {
 7211        if self.show_edit_predictions_in_menu() {
 7212            self.hide_context_menu(window, cx);
 7213        }
 7214
 7215        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7216            return;
 7217        };
 7218
 7219        self.report_inline_completion_event(
 7220            active_inline_completion.completion_id.clone(),
 7221            true,
 7222            cx,
 7223        );
 7224
 7225        match &active_inline_completion.completion {
 7226            InlineCompletion::Move { target, .. } => {
 7227                let target = *target;
 7228
 7229                if let Some(position_map) = &self.last_position_map {
 7230                    if position_map
 7231                        .visible_row_range
 7232                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7233                        || !self.edit_prediction_requires_modifier()
 7234                    {
 7235                        self.unfold_ranges(&[target..target], true, false, cx);
 7236                        // Note that this is also done in vim's handler of the Tab action.
 7237                        self.change_selections(
 7238                            SelectionEffects::scroll(Autoscroll::newest()),
 7239                            window,
 7240                            cx,
 7241                            |selections| {
 7242                                selections.select_anchor_ranges([target..target]);
 7243                            },
 7244                        );
 7245                        self.clear_row_highlights::<EditPredictionPreview>();
 7246
 7247                        self.edit_prediction_preview
 7248                            .set_previous_scroll_position(None);
 7249                    } else {
 7250                        self.edit_prediction_preview
 7251                            .set_previous_scroll_position(Some(
 7252                                position_map.snapshot.scroll_anchor,
 7253                            ));
 7254
 7255                        self.highlight_rows::<EditPredictionPreview>(
 7256                            target..target,
 7257                            cx.theme().colors().editor_highlighted_line_background,
 7258                            RowHighlightOptions {
 7259                                autoscroll: true,
 7260                                ..Default::default()
 7261                            },
 7262                            cx,
 7263                        );
 7264                        self.request_autoscroll(Autoscroll::fit(), cx);
 7265                    }
 7266                }
 7267            }
 7268            InlineCompletion::Edit { edits, .. } => {
 7269                if let Some(provider) = self.edit_prediction_provider() {
 7270                    provider.accept(cx);
 7271                }
 7272
 7273                // Store the transaction ID and selections before applying the edit
 7274                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7275
 7276                let snapshot = self.buffer.read(cx).snapshot(cx);
 7277                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7278
 7279                self.buffer.update(cx, |buffer, cx| {
 7280                    buffer.edit(edits.iter().cloned(), None, cx)
 7281                });
 7282
 7283                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7284                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7285                });
 7286
 7287                let selections = self.selections.disjoint_anchors();
 7288                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7289                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7290                    if has_new_transaction {
 7291                        self.selection_history
 7292                            .insert_transaction(transaction_id_now, selections);
 7293                    }
 7294                }
 7295
 7296                self.update_visible_inline_completion(window, cx);
 7297                if self.active_inline_completion.is_none() {
 7298                    self.refresh_inline_completion(true, true, window, cx);
 7299                }
 7300
 7301                cx.notify();
 7302            }
 7303        }
 7304
 7305        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7306    }
 7307
 7308    pub fn accept_partial_inline_completion(
 7309        &mut self,
 7310        _: &AcceptPartialEditPrediction,
 7311        window: &mut Window,
 7312        cx: &mut Context<Self>,
 7313    ) {
 7314        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7315            return;
 7316        };
 7317        if self.selections.count() != 1 {
 7318            return;
 7319        }
 7320
 7321        self.report_inline_completion_event(
 7322            active_inline_completion.completion_id.clone(),
 7323            true,
 7324            cx,
 7325        );
 7326
 7327        match &active_inline_completion.completion {
 7328            InlineCompletion::Move { target, .. } => {
 7329                let target = *target;
 7330                self.change_selections(
 7331                    SelectionEffects::scroll(Autoscroll::newest()),
 7332                    window,
 7333                    cx,
 7334                    |selections| {
 7335                        selections.select_anchor_ranges([target..target]);
 7336                    },
 7337                );
 7338            }
 7339            InlineCompletion::Edit { edits, .. } => {
 7340                // Find an insertion that starts at the cursor position.
 7341                let snapshot = self.buffer.read(cx).snapshot(cx);
 7342                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7343                let insertion = edits.iter().find_map(|(range, text)| {
 7344                    let range = range.to_offset(&snapshot);
 7345                    if range.is_empty() && range.start == cursor_offset {
 7346                        Some(text)
 7347                    } else {
 7348                        None
 7349                    }
 7350                });
 7351
 7352                if let Some(text) = insertion {
 7353                    let mut partial_completion = text
 7354                        .chars()
 7355                        .by_ref()
 7356                        .take_while(|c| c.is_alphabetic())
 7357                        .collect::<String>();
 7358                    if partial_completion.is_empty() {
 7359                        partial_completion = text
 7360                            .chars()
 7361                            .by_ref()
 7362                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7363                            .collect::<String>();
 7364                    }
 7365
 7366                    cx.emit(EditorEvent::InputHandled {
 7367                        utf16_range_to_replace: None,
 7368                        text: partial_completion.clone().into(),
 7369                    });
 7370
 7371                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7372
 7373                    self.refresh_inline_completion(true, true, window, cx);
 7374                    cx.notify();
 7375                } else {
 7376                    self.accept_edit_prediction(&Default::default(), window, cx);
 7377                }
 7378            }
 7379        }
 7380    }
 7381
 7382    fn discard_inline_completion(
 7383        &mut self,
 7384        should_report_inline_completion_event: bool,
 7385        cx: &mut Context<Self>,
 7386    ) -> bool {
 7387        if should_report_inline_completion_event {
 7388            let completion_id = self
 7389                .active_inline_completion
 7390                .as_ref()
 7391                .and_then(|active_completion| active_completion.completion_id.clone());
 7392
 7393            self.report_inline_completion_event(completion_id, false, cx);
 7394        }
 7395
 7396        if let Some(provider) = self.edit_prediction_provider() {
 7397            provider.discard(cx);
 7398        }
 7399
 7400        self.take_active_inline_completion(cx)
 7401    }
 7402
 7403    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7404        let Some(provider) = self.edit_prediction_provider() else {
 7405            return;
 7406        };
 7407
 7408        let Some((_, buffer, _)) = self
 7409            .buffer
 7410            .read(cx)
 7411            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7412        else {
 7413            return;
 7414        };
 7415
 7416        let extension = buffer
 7417            .read(cx)
 7418            .file()
 7419            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7420
 7421        let event_type = match accepted {
 7422            true => "Edit Prediction Accepted",
 7423            false => "Edit Prediction Discarded",
 7424        };
 7425        telemetry::event!(
 7426            event_type,
 7427            provider = provider.name(),
 7428            prediction_id = id,
 7429            suggestion_accepted = accepted,
 7430            file_extension = extension,
 7431        );
 7432    }
 7433
 7434    pub fn has_active_inline_completion(&self) -> bool {
 7435        self.active_inline_completion.is_some()
 7436    }
 7437
 7438    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7439        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7440            return false;
 7441        };
 7442
 7443        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7444        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7445        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7446        true
 7447    }
 7448
 7449    /// Returns true when we're displaying the edit prediction popover below the cursor
 7450    /// like we are not previewing and the LSP autocomplete menu is visible
 7451    /// or we are in `when_holding_modifier` mode.
 7452    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7453        if self.edit_prediction_preview_is_active()
 7454            || !self.show_edit_predictions_in_menu()
 7455            || !self.edit_predictions_enabled()
 7456        {
 7457            return false;
 7458        }
 7459
 7460        if self.has_visible_completions_menu() {
 7461            return true;
 7462        }
 7463
 7464        has_completion && self.edit_prediction_requires_modifier()
 7465    }
 7466
 7467    fn handle_modifiers_changed(
 7468        &mut self,
 7469        modifiers: Modifiers,
 7470        position_map: &PositionMap,
 7471        window: &mut Window,
 7472        cx: &mut Context<Self>,
 7473    ) {
 7474        if self.show_edit_predictions_in_menu() {
 7475            self.update_edit_prediction_preview(&modifiers, window, cx);
 7476        }
 7477
 7478        self.update_selection_mode(&modifiers, position_map, window, cx);
 7479
 7480        let mouse_position = window.mouse_position();
 7481        if !position_map.text_hitbox.is_hovered(window) {
 7482            return;
 7483        }
 7484
 7485        self.update_hovered_link(
 7486            position_map.point_for_position(mouse_position),
 7487            &position_map.snapshot,
 7488            modifiers,
 7489            window,
 7490            cx,
 7491        )
 7492    }
 7493
 7494    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7495        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7496        if invert {
 7497            match multi_cursor_setting {
 7498                MultiCursorModifier::Alt => modifiers.alt,
 7499                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7500            }
 7501        } else {
 7502            match multi_cursor_setting {
 7503                MultiCursorModifier::Alt => modifiers.secondary(),
 7504                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7505            }
 7506        }
 7507    }
 7508
 7509    fn columnar_selection_mode(
 7510        modifiers: &Modifiers,
 7511        cx: &mut Context<Self>,
 7512    ) -> Option<ColumnarMode> {
 7513        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7514            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7515                Some(ColumnarMode::FromMouse)
 7516            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7517                Some(ColumnarMode::FromSelection)
 7518            } else {
 7519                None
 7520            }
 7521        } else {
 7522            None
 7523        }
 7524    }
 7525
 7526    fn update_selection_mode(
 7527        &mut self,
 7528        modifiers: &Modifiers,
 7529        position_map: &PositionMap,
 7530        window: &mut Window,
 7531        cx: &mut Context<Self>,
 7532    ) {
 7533        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7534            return;
 7535        };
 7536        if self.selections.pending.is_none() {
 7537            return;
 7538        }
 7539
 7540        let mouse_position = window.mouse_position();
 7541        let point_for_position = position_map.point_for_position(mouse_position);
 7542        let position = point_for_position.previous_valid;
 7543
 7544        self.select(
 7545            SelectPhase::BeginColumnar {
 7546                position,
 7547                reset: false,
 7548                mode,
 7549                goal_column: point_for_position.exact_unclipped.column(),
 7550            },
 7551            window,
 7552            cx,
 7553        );
 7554    }
 7555
 7556    fn update_edit_prediction_preview(
 7557        &mut self,
 7558        modifiers: &Modifiers,
 7559        window: &mut Window,
 7560        cx: &mut Context<Self>,
 7561    ) {
 7562        let mut modifiers_held = false;
 7563        if let Some(accept_keystroke) = self
 7564            .accept_edit_prediction_keybind(false, window, cx)
 7565            .keystroke()
 7566        {
 7567            modifiers_held = modifiers_held
 7568                || (&accept_keystroke.modifiers == modifiers
 7569                    && accept_keystroke.modifiers.modified());
 7570        };
 7571        if let Some(accept_partial_keystroke) = self
 7572            .accept_edit_prediction_keybind(true, window, cx)
 7573            .keystroke()
 7574        {
 7575            modifiers_held = modifiers_held
 7576                || (&accept_partial_keystroke.modifiers == modifiers
 7577                    && accept_partial_keystroke.modifiers.modified());
 7578        }
 7579
 7580        if modifiers_held {
 7581            if matches!(
 7582                self.edit_prediction_preview,
 7583                EditPredictionPreview::Inactive { .. }
 7584            ) {
 7585                self.edit_prediction_preview = EditPredictionPreview::Active {
 7586                    previous_scroll_position: None,
 7587                    since: Instant::now(),
 7588                };
 7589
 7590                self.update_visible_inline_completion(window, cx);
 7591                cx.notify();
 7592            }
 7593        } else if let EditPredictionPreview::Active {
 7594            previous_scroll_position,
 7595            since,
 7596        } = self.edit_prediction_preview
 7597        {
 7598            if let (Some(previous_scroll_position), Some(position_map)) =
 7599                (previous_scroll_position, self.last_position_map.as_ref())
 7600            {
 7601                self.set_scroll_position(
 7602                    previous_scroll_position
 7603                        .scroll_position(&position_map.snapshot.display_snapshot),
 7604                    window,
 7605                    cx,
 7606                );
 7607            }
 7608
 7609            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7610                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7611            };
 7612            self.clear_row_highlights::<EditPredictionPreview>();
 7613            self.update_visible_inline_completion(window, cx);
 7614            cx.notify();
 7615        }
 7616    }
 7617
 7618    fn update_visible_inline_completion(
 7619        &mut self,
 7620        _window: &mut Window,
 7621        cx: &mut Context<Self>,
 7622    ) -> Option<()> {
 7623        let selection = self.selections.newest_anchor();
 7624        let cursor = selection.head();
 7625        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7626        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7627        let excerpt_id = cursor.excerpt_id;
 7628
 7629        let show_in_menu = self.show_edit_predictions_in_menu();
 7630        let completions_menu_has_precedence = !show_in_menu
 7631            && (self.context_menu.borrow().is_some()
 7632                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7633
 7634        if completions_menu_has_precedence
 7635            || !offset_selection.is_empty()
 7636            || self
 7637                .active_inline_completion
 7638                .as_ref()
 7639                .map_or(false, |completion| {
 7640                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7641                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7642                    !invalidation_range.contains(&offset_selection.head())
 7643                })
 7644        {
 7645            self.discard_inline_completion(false, cx);
 7646            return None;
 7647        }
 7648
 7649        self.take_active_inline_completion(cx);
 7650        let Some(provider) = self.edit_prediction_provider() else {
 7651            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7652            return None;
 7653        };
 7654
 7655        let (buffer, cursor_buffer_position) =
 7656            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7657
 7658        self.edit_prediction_settings =
 7659            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7660
 7661        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7662
 7663        if self.edit_prediction_indent_conflict {
 7664            let cursor_point = cursor.to_point(&multibuffer);
 7665
 7666            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7667
 7668            if let Some((_, indent)) = indents.iter().next() {
 7669                if indent.len == cursor_point.column {
 7670                    self.edit_prediction_indent_conflict = false;
 7671                }
 7672            }
 7673        }
 7674
 7675        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7676        let edits = inline_completion
 7677            .edits
 7678            .into_iter()
 7679            .flat_map(|(range, new_text)| {
 7680                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7681                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7682                Some((start..end, new_text))
 7683            })
 7684            .collect::<Vec<_>>();
 7685        if edits.is_empty() {
 7686            return None;
 7687        }
 7688
 7689        let first_edit_start = edits.first().unwrap().0.start;
 7690        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7691        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7692
 7693        let last_edit_end = edits.last().unwrap().0.end;
 7694        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7695        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7696
 7697        let cursor_row = cursor.to_point(&multibuffer).row;
 7698
 7699        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7700
 7701        let mut inlay_ids = Vec::new();
 7702        let invalidation_row_range;
 7703        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7704            Some(cursor_row..edit_end_row)
 7705        } else if cursor_row > edit_end_row {
 7706            Some(edit_start_row..cursor_row)
 7707        } else {
 7708            None
 7709        };
 7710        let is_move =
 7711            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7712        let completion = if is_move {
 7713            invalidation_row_range =
 7714                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7715            let target = first_edit_start;
 7716            InlineCompletion::Move { target, snapshot }
 7717        } else {
 7718            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7719                && !self.inline_completions_hidden_for_vim_mode;
 7720
 7721            if show_completions_in_buffer {
 7722                if edits
 7723                    .iter()
 7724                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7725                {
 7726                    let mut inlays = Vec::new();
 7727                    for (range, new_text) in &edits {
 7728                        let inlay = Inlay::inline_completion(
 7729                            post_inc(&mut self.next_inlay_id),
 7730                            range.start,
 7731                            new_text.as_str(),
 7732                        );
 7733                        inlay_ids.push(inlay.id);
 7734                        inlays.push(inlay);
 7735                    }
 7736
 7737                    self.splice_inlays(&[], inlays, cx);
 7738                } else {
 7739                    let background_color = cx.theme().status().deleted_background;
 7740                    self.highlight_text::<InlineCompletionHighlight>(
 7741                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7742                        HighlightStyle {
 7743                            background_color: Some(background_color),
 7744                            ..Default::default()
 7745                        },
 7746                        cx,
 7747                    );
 7748                }
 7749            }
 7750
 7751            invalidation_row_range = edit_start_row..edit_end_row;
 7752
 7753            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7754                if provider.show_tab_accept_marker() {
 7755                    EditDisplayMode::TabAccept
 7756                } else {
 7757                    EditDisplayMode::Inline
 7758                }
 7759            } else {
 7760                EditDisplayMode::DiffPopover
 7761            };
 7762
 7763            InlineCompletion::Edit {
 7764                edits,
 7765                edit_preview: inline_completion.edit_preview,
 7766                display_mode,
 7767                snapshot,
 7768            }
 7769        };
 7770
 7771        let invalidation_range = multibuffer
 7772            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7773            ..multibuffer.anchor_after(Point::new(
 7774                invalidation_row_range.end,
 7775                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7776            ));
 7777
 7778        self.stale_inline_completion_in_menu = None;
 7779        self.active_inline_completion = Some(InlineCompletionState {
 7780            inlay_ids,
 7781            completion,
 7782            completion_id: inline_completion.id,
 7783            invalidation_range,
 7784        });
 7785
 7786        cx.notify();
 7787
 7788        Some(())
 7789    }
 7790
 7791    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7792        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7793    }
 7794
 7795    fn clear_tasks(&mut self) {
 7796        self.tasks.clear()
 7797    }
 7798
 7799    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7800        if self.tasks.insert(key, value).is_some() {
 7801            // This case should hopefully be rare, but just in case...
 7802            log::error!(
 7803                "multiple different run targets found on a single line, only the last target will be rendered"
 7804            )
 7805        }
 7806    }
 7807
 7808    /// Get all display points of breakpoints that will be rendered within editor
 7809    ///
 7810    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7811    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7812    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7813    fn active_breakpoints(
 7814        &self,
 7815        range: Range<DisplayRow>,
 7816        window: &mut Window,
 7817        cx: &mut Context<Self>,
 7818    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7819        let mut breakpoint_display_points = HashMap::default();
 7820
 7821        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7822            return breakpoint_display_points;
 7823        };
 7824
 7825        let snapshot = self.snapshot(window, cx);
 7826
 7827        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7828        let Some(project) = self.project.as_ref() else {
 7829            return breakpoint_display_points;
 7830        };
 7831
 7832        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7833            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7834
 7835        for (buffer_snapshot, range, excerpt_id) in
 7836            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7837        {
 7838            let Some(buffer) = project
 7839                .read(cx)
 7840                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7841            else {
 7842                continue;
 7843            };
 7844            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7845                &buffer,
 7846                Some(
 7847                    buffer_snapshot.anchor_before(range.start)
 7848                        ..buffer_snapshot.anchor_after(range.end),
 7849                ),
 7850                buffer_snapshot,
 7851                cx,
 7852            );
 7853            for (breakpoint, state) in breakpoints {
 7854                let multi_buffer_anchor =
 7855                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7856                let position = multi_buffer_anchor
 7857                    .to_point(&multi_buffer_snapshot)
 7858                    .to_display_point(&snapshot);
 7859
 7860                breakpoint_display_points.insert(
 7861                    position.row(),
 7862                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7863                );
 7864            }
 7865        }
 7866
 7867        breakpoint_display_points
 7868    }
 7869
 7870    fn breakpoint_context_menu(
 7871        &self,
 7872        anchor: Anchor,
 7873        window: &mut Window,
 7874        cx: &mut Context<Self>,
 7875    ) -> Entity<ui::ContextMenu> {
 7876        let weak_editor = cx.weak_entity();
 7877        let focus_handle = self.focus_handle(cx);
 7878
 7879        let row = self
 7880            .buffer
 7881            .read(cx)
 7882            .snapshot(cx)
 7883            .summary_for_anchor::<Point>(&anchor)
 7884            .row;
 7885
 7886        let breakpoint = self
 7887            .breakpoint_at_row(row, window, cx)
 7888            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7889
 7890        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7891            "Edit Log Breakpoint"
 7892        } else {
 7893            "Set Log Breakpoint"
 7894        };
 7895
 7896        let condition_breakpoint_msg = if breakpoint
 7897            .as_ref()
 7898            .is_some_and(|bp| bp.1.condition.is_some())
 7899        {
 7900            "Edit Condition Breakpoint"
 7901        } else {
 7902            "Set Condition Breakpoint"
 7903        };
 7904
 7905        let hit_condition_breakpoint_msg = if breakpoint
 7906            .as_ref()
 7907            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7908        {
 7909            "Edit Hit Condition Breakpoint"
 7910        } else {
 7911            "Set Hit Condition Breakpoint"
 7912        };
 7913
 7914        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7915            "Unset Breakpoint"
 7916        } else {
 7917            "Set Breakpoint"
 7918        };
 7919
 7920        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7921
 7922        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7923            BreakpointState::Enabled => Some("Disable"),
 7924            BreakpointState::Disabled => Some("Enable"),
 7925        });
 7926
 7927        let (anchor, breakpoint) =
 7928            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7929
 7930        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7931            menu.on_blur_subscription(Subscription::new(|| {}))
 7932                .context(focus_handle)
 7933                .when(run_to_cursor, |this| {
 7934                    let weak_editor = weak_editor.clone();
 7935                    this.entry("Run to cursor", None, move |window, cx| {
 7936                        weak_editor
 7937                            .update(cx, |editor, cx| {
 7938                                editor.change_selections(
 7939                                    SelectionEffects::no_scroll(),
 7940                                    window,
 7941                                    cx,
 7942                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7943                                );
 7944                            })
 7945                            .ok();
 7946
 7947                        window.dispatch_action(Box::new(RunToCursor), cx);
 7948                    })
 7949                    .separator()
 7950                })
 7951                .when_some(toggle_state_msg, |this, msg| {
 7952                    this.entry(msg, None, {
 7953                        let weak_editor = weak_editor.clone();
 7954                        let breakpoint = breakpoint.clone();
 7955                        move |_window, cx| {
 7956                            weak_editor
 7957                                .update(cx, |this, cx| {
 7958                                    this.edit_breakpoint_at_anchor(
 7959                                        anchor,
 7960                                        breakpoint.as_ref().clone(),
 7961                                        BreakpointEditAction::InvertState,
 7962                                        cx,
 7963                                    );
 7964                                })
 7965                                .log_err();
 7966                        }
 7967                    })
 7968                })
 7969                .entry(set_breakpoint_msg, None, {
 7970                    let weak_editor = weak_editor.clone();
 7971                    let breakpoint = breakpoint.clone();
 7972                    move |_window, cx| {
 7973                        weak_editor
 7974                            .update(cx, |this, cx| {
 7975                                this.edit_breakpoint_at_anchor(
 7976                                    anchor,
 7977                                    breakpoint.as_ref().clone(),
 7978                                    BreakpointEditAction::Toggle,
 7979                                    cx,
 7980                                );
 7981                            })
 7982                            .log_err();
 7983                    }
 7984                })
 7985                .entry(log_breakpoint_msg, None, {
 7986                    let breakpoint = breakpoint.clone();
 7987                    let weak_editor = weak_editor.clone();
 7988                    move |window, cx| {
 7989                        weak_editor
 7990                            .update(cx, |this, cx| {
 7991                                this.add_edit_breakpoint_block(
 7992                                    anchor,
 7993                                    breakpoint.as_ref(),
 7994                                    BreakpointPromptEditAction::Log,
 7995                                    window,
 7996                                    cx,
 7997                                );
 7998                            })
 7999                            .log_err();
 8000                    }
 8001                })
 8002                .entry(condition_breakpoint_msg, None, {
 8003                    let breakpoint = breakpoint.clone();
 8004                    let weak_editor = weak_editor.clone();
 8005                    move |window, cx| {
 8006                        weak_editor
 8007                            .update(cx, |this, cx| {
 8008                                this.add_edit_breakpoint_block(
 8009                                    anchor,
 8010                                    breakpoint.as_ref(),
 8011                                    BreakpointPromptEditAction::Condition,
 8012                                    window,
 8013                                    cx,
 8014                                );
 8015                            })
 8016                            .log_err();
 8017                    }
 8018                })
 8019                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8020                    weak_editor
 8021                        .update(cx, |this, cx| {
 8022                            this.add_edit_breakpoint_block(
 8023                                anchor,
 8024                                breakpoint.as_ref(),
 8025                                BreakpointPromptEditAction::HitCondition,
 8026                                window,
 8027                                cx,
 8028                            );
 8029                        })
 8030                        .log_err();
 8031                })
 8032        })
 8033    }
 8034
 8035    fn render_breakpoint(
 8036        &self,
 8037        position: Anchor,
 8038        row: DisplayRow,
 8039        breakpoint: &Breakpoint,
 8040        state: Option<BreakpointSessionState>,
 8041        cx: &mut Context<Self>,
 8042    ) -> IconButton {
 8043        let is_rejected = state.is_some_and(|s| !s.verified);
 8044        // Is it a breakpoint that shows up when hovering over gutter?
 8045        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8046            (false, false),
 8047            |PhantomBreakpointIndicator {
 8048                 is_active,
 8049                 display_row,
 8050                 collides_with_existing_breakpoint,
 8051             }| {
 8052                (
 8053                    is_active && display_row == row,
 8054                    collides_with_existing_breakpoint,
 8055                )
 8056            },
 8057        );
 8058
 8059        let (color, icon) = {
 8060            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8061                (false, false) => ui::IconName::DebugBreakpoint,
 8062                (true, false) => ui::IconName::DebugLogBreakpoint,
 8063                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8064                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8065            };
 8066
 8067            let color = if is_phantom {
 8068                Color::Hint
 8069            } else if is_rejected {
 8070                Color::Disabled
 8071            } else {
 8072                Color::Debugger
 8073            };
 8074
 8075            (color, icon)
 8076        };
 8077
 8078        let breakpoint = Arc::from(breakpoint.clone());
 8079
 8080        let alt_as_text = gpui::Keystroke {
 8081            modifiers: Modifiers::secondary_key(),
 8082            ..Default::default()
 8083        };
 8084        let primary_action_text = if breakpoint.is_disabled() {
 8085            "Enable breakpoint"
 8086        } else if is_phantom && !collides_with_existing {
 8087            "Set breakpoint"
 8088        } else {
 8089            "Unset breakpoint"
 8090        };
 8091        let focus_handle = self.focus_handle.clone();
 8092
 8093        let meta = if is_rejected {
 8094            SharedString::from("No executable code is associated with this line.")
 8095        } else if collides_with_existing && !breakpoint.is_disabled() {
 8096            SharedString::from(format!(
 8097                "{alt_as_text}-click to disable,\nright-click for more options."
 8098            ))
 8099        } else {
 8100            SharedString::from("Right-click for more options.")
 8101        };
 8102        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8103            .icon_size(IconSize::XSmall)
 8104            .size(ui::ButtonSize::None)
 8105            .when(is_rejected, |this| {
 8106                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8107            })
 8108            .icon_color(color)
 8109            .style(ButtonStyle::Transparent)
 8110            .on_click(cx.listener({
 8111                let breakpoint = breakpoint.clone();
 8112
 8113                move |editor, event: &ClickEvent, window, cx| {
 8114                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8115                        BreakpointEditAction::InvertState
 8116                    } else {
 8117                        BreakpointEditAction::Toggle
 8118                    };
 8119
 8120                    window.focus(&editor.focus_handle(cx));
 8121                    editor.edit_breakpoint_at_anchor(
 8122                        position,
 8123                        breakpoint.as_ref().clone(),
 8124                        edit_action,
 8125                        cx,
 8126                    );
 8127                }
 8128            }))
 8129            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8130                editor.set_breakpoint_context_menu(
 8131                    row,
 8132                    Some(position),
 8133                    event.down.position,
 8134                    window,
 8135                    cx,
 8136                );
 8137            }))
 8138            .tooltip(move |window, cx| {
 8139                Tooltip::with_meta_in(
 8140                    primary_action_text,
 8141                    Some(&ToggleBreakpoint),
 8142                    meta.clone(),
 8143                    &focus_handle,
 8144                    window,
 8145                    cx,
 8146                )
 8147            })
 8148    }
 8149
 8150    fn build_tasks_context(
 8151        project: &Entity<Project>,
 8152        buffer: &Entity<Buffer>,
 8153        buffer_row: u32,
 8154        tasks: &Arc<RunnableTasks>,
 8155        cx: &mut Context<Self>,
 8156    ) -> Task<Option<task::TaskContext>> {
 8157        let position = Point::new(buffer_row, tasks.column);
 8158        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8159        let location = Location {
 8160            buffer: buffer.clone(),
 8161            range: range_start..range_start,
 8162        };
 8163        // Fill in the environmental variables from the tree-sitter captures
 8164        let mut captured_task_variables = TaskVariables::default();
 8165        for (capture_name, value) in tasks.extra_variables.clone() {
 8166            captured_task_variables.insert(
 8167                task::VariableName::Custom(capture_name.into()),
 8168                value.clone(),
 8169            );
 8170        }
 8171        project.update(cx, |project, cx| {
 8172            project.task_store().update(cx, |task_store, cx| {
 8173                task_store.task_context_for_location(captured_task_variables, location, cx)
 8174            })
 8175        })
 8176    }
 8177
 8178    pub fn spawn_nearest_task(
 8179        &mut self,
 8180        action: &SpawnNearestTask,
 8181        window: &mut Window,
 8182        cx: &mut Context<Self>,
 8183    ) {
 8184        let Some((workspace, _)) = self.workspace.clone() else {
 8185            return;
 8186        };
 8187        let Some(project) = self.project.clone() else {
 8188            return;
 8189        };
 8190
 8191        // Try to find a closest, enclosing node using tree-sitter that has a
 8192        // task
 8193        let Some((buffer, buffer_row, tasks)) = self
 8194            .find_enclosing_node_task(cx)
 8195            // Or find the task that's closest in row-distance.
 8196            .or_else(|| self.find_closest_task(cx))
 8197        else {
 8198            return;
 8199        };
 8200
 8201        let reveal_strategy = action.reveal;
 8202        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8203        cx.spawn_in(window, async move |_, cx| {
 8204            let context = task_context.await?;
 8205            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8206
 8207            let resolved = &mut resolved_task.resolved;
 8208            resolved.reveal = reveal_strategy;
 8209
 8210            workspace
 8211                .update_in(cx, |workspace, window, cx| {
 8212                    workspace.schedule_resolved_task(
 8213                        task_source_kind,
 8214                        resolved_task,
 8215                        false,
 8216                        window,
 8217                        cx,
 8218                    );
 8219                })
 8220                .ok()
 8221        })
 8222        .detach();
 8223    }
 8224
 8225    fn find_closest_task(
 8226        &mut self,
 8227        cx: &mut Context<Self>,
 8228    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8229        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8230
 8231        let ((buffer_id, row), tasks) = self
 8232            .tasks
 8233            .iter()
 8234            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8235
 8236        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8237        let tasks = Arc::new(tasks.to_owned());
 8238        Some((buffer, *row, tasks))
 8239    }
 8240
 8241    fn find_enclosing_node_task(
 8242        &mut self,
 8243        cx: &mut Context<Self>,
 8244    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8245        let snapshot = self.buffer.read(cx).snapshot(cx);
 8246        let offset = self.selections.newest::<usize>(cx).head();
 8247        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8248        let buffer_id = excerpt.buffer().remote_id();
 8249
 8250        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8251        let mut cursor = layer.node().walk();
 8252
 8253        while cursor.goto_first_child_for_byte(offset).is_some() {
 8254            if cursor.node().end_byte() == offset {
 8255                cursor.goto_next_sibling();
 8256            }
 8257        }
 8258
 8259        // Ascend to the smallest ancestor that contains the range and has a task.
 8260        loop {
 8261            let node = cursor.node();
 8262            let node_range = node.byte_range();
 8263            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8264
 8265            // Check if this node contains our offset
 8266            if node_range.start <= offset && node_range.end >= offset {
 8267                // If it contains offset, check for task
 8268                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8269                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8270                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8271                }
 8272            }
 8273
 8274            if !cursor.goto_parent() {
 8275                break;
 8276            }
 8277        }
 8278        None
 8279    }
 8280
 8281    fn render_run_indicator(
 8282        &self,
 8283        _style: &EditorStyle,
 8284        is_active: bool,
 8285        row: DisplayRow,
 8286        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8287        cx: &mut Context<Self>,
 8288    ) -> IconButton {
 8289        let color = Color::Muted;
 8290        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8291
 8292        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8293            .shape(ui::IconButtonShape::Square)
 8294            .icon_size(IconSize::XSmall)
 8295            .icon_color(color)
 8296            .toggle_state(is_active)
 8297            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8298                let quick_launch = e.down.button == MouseButton::Left;
 8299                window.focus(&editor.focus_handle(cx));
 8300                editor.toggle_code_actions(
 8301                    &ToggleCodeActions {
 8302                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8303                        quick_launch,
 8304                    },
 8305                    window,
 8306                    cx,
 8307                );
 8308            }))
 8309            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8310                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8311            }))
 8312    }
 8313
 8314    pub fn context_menu_visible(&self) -> bool {
 8315        !self.edit_prediction_preview_is_active()
 8316            && self
 8317                .context_menu
 8318                .borrow()
 8319                .as_ref()
 8320                .map_or(false, |menu| menu.visible())
 8321    }
 8322
 8323    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8324        self.context_menu
 8325            .borrow()
 8326            .as_ref()
 8327            .map(|menu| menu.origin())
 8328    }
 8329
 8330    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8331        self.context_menu_options = Some(options);
 8332    }
 8333
 8334    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8335    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8336
 8337    fn render_edit_prediction_popover(
 8338        &mut self,
 8339        text_bounds: &Bounds<Pixels>,
 8340        content_origin: gpui::Point<Pixels>,
 8341        right_margin: Pixels,
 8342        editor_snapshot: &EditorSnapshot,
 8343        visible_row_range: Range<DisplayRow>,
 8344        scroll_top: f32,
 8345        scroll_bottom: f32,
 8346        line_layouts: &[LineWithInvisibles],
 8347        line_height: Pixels,
 8348        scroll_pixel_position: gpui::Point<Pixels>,
 8349        newest_selection_head: Option<DisplayPoint>,
 8350        editor_width: Pixels,
 8351        style: &EditorStyle,
 8352        window: &mut Window,
 8353        cx: &mut App,
 8354    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8355        if self.mode().is_minimap() {
 8356            return None;
 8357        }
 8358        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8359
 8360        if self.edit_prediction_visible_in_cursor_popover(true) {
 8361            return None;
 8362        }
 8363
 8364        match &active_inline_completion.completion {
 8365            InlineCompletion::Move { target, .. } => {
 8366                let target_display_point = target.to_display_point(editor_snapshot);
 8367
 8368                if self.edit_prediction_requires_modifier() {
 8369                    if !self.edit_prediction_preview_is_active() {
 8370                        return None;
 8371                    }
 8372
 8373                    self.render_edit_prediction_modifier_jump_popover(
 8374                        text_bounds,
 8375                        content_origin,
 8376                        visible_row_range,
 8377                        line_layouts,
 8378                        line_height,
 8379                        scroll_pixel_position,
 8380                        newest_selection_head,
 8381                        target_display_point,
 8382                        window,
 8383                        cx,
 8384                    )
 8385                } else {
 8386                    self.render_edit_prediction_eager_jump_popover(
 8387                        text_bounds,
 8388                        content_origin,
 8389                        editor_snapshot,
 8390                        visible_row_range,
 8391                        scroll_top,
 8392                        scroll_bottom,
 8393                        line_height,
 8394                        scroll_pixel_position,
 8395                        target_display_point,
 8396                        editor_width,
 8397                        window,
 8398                        cx,
 8399                    )
 8400                }
 8401            }
 8402            InlineCompletion::Edit {
 8403                display_mode: EditDisplayMode::Inline,
 8404                ..
 8405            } => None,
 8406            InlineCompletion::Edit {
 8407                display_mode: EditDisplayMode::TabAccept,
 8408                edits,
 8409                ..
 8410            } => {
 8411                let range = &edits.first()?.0;
 8412                let target_display_point = range.end.to_display_point(editor_snapshot);
 8413
 8414                self.render_edit_prediction_end_of_line_popover(
 8415                    "Accept",
 8416                    editor_snapshot,
 8417                    visible_row_range,
 8418                    target_display_point,
 8419                    line_height,
 8420                    scroll_pixel_position,
 8421                    content_origin,
 8422                    editor_width,
 8423                    window,
 8424                    cx,
 8425                )
 8426            }
 8427            InlineCompletion::Edit {
 8428                edits,
 8429                edit_preview,
 8430                display_mode: EditDisplayMode::DiffPopover,
 8431                snapshot,
 8432            } => self.render_edit_prediction_diff_popover(
 8433                text_bounds,
 8434                content_origin,
 8435                right_margin,
 8436                editor_snapshot,
 8437                visible_row_range,
 8438                line_layouts,
 8439                line_height,
 8440                scroll_pixel_position,
 8441                newest_selection_head,
 8442                editor_width,
 8443                style,
 8444                edits,
 8445                edit_preview,
 8446                snapshot,
 8447                window,
 8448                cx,
 8449            ),
 8450        }
 8451    }
 8452
 8453    fn render_edit_prediction_modifier_jump_popover(
 8454        &mut self,
 8455        text_bounds: &Bounds<Pixels>,
 8456        content_origin: gpui::Point<Pixels>,
 8457        visible_row_range: Range<DisplayRow>,
 8458        line_layouts: &[LineWithInvisibles],
 8459        line_height: Pixels,
 8460        scroll_pixel_position: gpui::Point<Pixels>,
 8461        newest_selection_head: Option<DisplayPoint>,
 8462        target_display_point: DisplayPoint,
 8463        window: &mut Window,
 8464        cx: &mut App,
 8465    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8466        let scrolled_content_origin =
 8467            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8468
 8469        const SCROLL_PADDING_Y: Pixels = px(12.);
 8470
 8471        if target_display_point.row() < visible_row_range.start {
 8472            return self.render_edit_prediction_scroll_popover(
 8473                |_| SCROLL_PADDING_Y,
 8474                IconName::ArrowUp,
 8475                visible_row_range,
 8476                line_layouts,
 8477                newest_selection_head,
 8478                scrolled_content_origin,
 8479                window,
 8480                cx,
 8481            );
 8482        } else if target_display_point.row() >= visible_row_range.end {
 8483            return self.render_edit_prediction_scroll_popover(
 8484                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8485                IconName::ArrowDown,
 8486                visible_row_range,
 8487                line_layouts,
 8488                newest_selection_head,
 8489                scrolled_content_origin,
 8490                window,
 8491                cx,
 8492            );
 8493        }
 8494
 8495        const POLE_WIDTH: Pixels = px(2.);
 8496
 8497        let line_layout =
 8498            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8499        let target_column = target_display_point.column() as usize;
 8500
 8501        let target_x = line_layout.x_for_index(target_column);
 8502        let target_y =
 8503            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8504
 8505        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8506
 8507        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8508        border_color.l += 0.001;
 8509
 8510        let mut element = v_flex()
 8511            .items_end()
 8512            .when(flag_on_right, |el| el.items_start())
 8513            .child(if flag_on_right {
 8514                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8515                    .rounded_bl(px(0.))
 8516                    .rounded_tl(px(0.))
 8517                    .border_l_2()
 8518                    .border_color(border_color)
 8519            } else {
 8520                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8521                    .rounded_br(px(0.))
 8522                    .rounded_tr(px(0.))
 8523                    .border_r_2()
 8524                    .border_color(border_color)
 8525            })
 8526            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8527            .into_any();
 8528
 8529        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8530
 8531        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8532            - point(
 8533                if flag_on_right {
 8534                    POLE_WIDTH
 8535                } else {
 8536                    size.width - POLE_WIDTH
 8537                },
 8538                size.height - line_height,
 8539            );
 8540
 8541        origin.x = origin.x.max(content_origin.x);
 8542
 8543        element.prepaint_at(origin, window, cx);
 8544
 8545        Some((element, origin))
 8546    }
 8547
 8548    fn render_edit_prediction_scroll_popover(
 8549        &mut self,
 8550        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8551        scroll_icon: IconName,
 8552        visible_row_range: Range<DisplayRow>,
 8553        line_layouts: &[LineWithInvisibles],
 8554        newest_selection_head: Option<DisplayPoint>,
 8555        scrolled_content_origin: gpui::Point<Pixels>,
 8556        window: &mut Window,
 8557        cx: &mut App,
 8558    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8559        let mut element = self
 8560            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8561            .into_any();
 8562
 8563        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8564
 8565        let cursor = newest_selection_head?;
 8566        let cursor_row_layout =
 8567            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8568        let cursor_column = cursor.column() as usize;
 8569
 8570        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8571
 8572        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8573
 8574        element.prepaint_at(origin, window, cx);
 8575        Some((element, origin))
 8576    }
 8577
 8578    fn render_edit_prediction_eager_jump_popover(
 8579        &mut self,
 8580        text_bounds: &Bounds<Pixels>,
 8581        content_origin: gpui::Point<Pixels>,
 8582        editor_snapshot: &EditorSnapshot,
 8583        visible_row_range: Range<DisplayRow>,
 8584        scroll_top: f32,
 8585        scroll_bottom: f32,
 8586        line_height: Pixels,
 8587        scroll_pixel_position: gpui::Point<Pixels>,
 8588        target_display_point: DisplayPoint,
 8589        editor_width: Pixels,
 8590        window: &mut Window,
 8591        cx: &mut App,
 8592    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8593        if target_display_point.row().as_f32() < scroll_top {
 8594            let mut element = self
 8595                .render_edit_prediction_line_popover(
 8596                    "Jump to Edit",
 8597                    Some(IconName::ArrowUp),
 8598                    window,
 8599                    cx,
 8600                )?
 8601                .into_any();
 8602
 8603            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8604            let offset = point(
 8605                (text_bounds.size.width - size.width) / 2.,
 8606                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8607            );
 8608
 8609            let origin = text_bounds.origin + offset;
 8610            element.prepaint_at(origin, window, cx);
 8611            Some((element, origin))
 8612        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8613            let mut element = self
 8614                .render_edit_prediction_line_popover(
 8615                    "Jump to Edit",
 8616                    Some(IconName::ArrowDown),
 8617                    window,
 8618                    cx,
 8619                )?
 8620                .into_any();
 8621
 8622            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8623            let offset = point(
 8624                (text_bounds.size.width - size.width) / 2.,
 8625                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8626            );
 8627
 8628            let origin = text_bounds.origin + offset;
 8629            element.prepaint_at(origin, window, cx);
 8630            Some((element, origin))
 8631        } else {
 8632            self.render_edit_prediction_end_of_line_popover(
 8633                "Jump to Edit",
 8634                editor_snapshot,
 8635                visible_row_range,
 8636                target_display_point,
 8637                line_height,
 8638                scroll_pixel_position,
 8639                content_origin,
 8640                editor_width,
 8641                window,
 8642                cx,
 8643            )
 8644        }
 8645    }
 8646
 8647    fn render_edit_prediction_end_of_line_popover(
 8648        self: &mut Editor,
 8649        label: &'static str,
 8650        editor_snapshot: &EditorSnapshot,
 8651        visible_row_range: Range<DisplayRow>,
 8652        target_display_point: DisplayPoint,
 8653        line_height: Pixels,
 8654        scroll_pixel_position: gpui::Point<Pixels>,
 8655        content_origin: gpui::Point<Pixels>,
 8656        editor_width: Pixels,
 8657        window: &mut Window,
 8658        cx: &mut App,
 8659    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8660        let target_line_end = DisplayPoint::new(
 8661            target_display_point.row(),
 8662            editor_snapshot.line_len(target_display_point.row()),
 8663        );
 8664
 8665        let mut element = self
 8666            .render_edit_prediction_line_popover(label, None, window, cx)?
 8667            .into_any();
 8668
 8669        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8670
 8671        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8672
 8673        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8674        let mut origin = start_point
 8675            + line_origin
 8676            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8677        origin.x = origin.x.max(content_origin.x);
 8678
 8679        let max_x = content_origin.x + editor_width - size.width;
 8680
 8681        if origin.x > max_x {
 8682            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8683
 8684            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8685                origin.y += offset;
 8686                IconName::ArrowUp
 8687            } else {
 8688                origin.y -= offset;
 8689                IconName::ArrowDown
 8690            };
 8691
 8692            element = self
 8693                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8694                .into_any();
 8695
 8696            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8697
 8698            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8699        }
 8700
 8701        element.prepaint_at(origin, window, cx);
 8702        Some((element, origin))
 8703    }
 8704
 8705    fn render_edit_prediction_diff_popover(
 8706        self: &Editor,
 8707        text_bounds: &Bounds<Pixels>,
 8708        content_origin: gpui::Point<Pixels>,
 8709        right_margin: Pixels,
 8710        editor_snapshot: &EditorSnapshot,
 8711        visible_row_range: Range<DisplayRow>,
 8712        line_layouts: &[LineWithInvisibles],
 8713        line_height: Pixels,
 8714        scroll_pixel_position: gpui::Point<Pixels>,
 8715        newest_selection_head: Option<DisplayPoint>,
 8716        editor_width: Pixels,
 8717        style: &EditorStyle,
 8718        edits: &Vec<(Range<Anchor>, String)>,
 8719        edit_preview: &Option<language::EditPreview>,
 8720        snapshot: &language::BufferSnapshot,
 8721        window: &mut Window,
 8722        cx: &mut App,
 8723    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8724        let edit_start = edits
 8725            .first()
 8726            .unwrap()
 8727            .0
 8728            .start
 8729            .to_display_point(editor_snapshot);
 8730        let edit_end = edits
 8731            .last()
 8732            .unwrap()
 8733            .0
 8734            .end
 8735            .to_display_point(editor_snapshot);
 8736
 8737        let is_visible = visible_row_range.contains(&edit_start.row())
 8738            || visible_row_range.contains(&edit_end.row());
 8739        if !is_visible {
 8740            return None;
 8741        }
 8742
 8743        let highlighted_edits =
 8744            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8745
 8746        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8747        let line_count = highlighted_edits.text.lines().count();
 8748
 8749        const BORDER_WIDTH: Pixels = px(1.);
 8750
 8751        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8752        let has_keybind = keybind.is_some();
 8753
 8754        let mut element = h_flex()
 8755            .items_start()
 8756            .child(
 8757                h_flex()
 8758                    .bg(cx.theme().colors().editor_background)
 8759                    .border(BORDER_WIDTH)
 8760                    .shadow_xs()
 8761                    .border_color(cx.theme().colors().border)
 8762                    .rounded_l_lg()
 8763                    .when(line_count > 1, |el| el.rounded_br_lg())
 8764                    .pr_1()
 8765                    .child(styled_text),
 8766            )
 8767            .child(
 8768                h_flex()
 8769                    .h(line_height + BORDER_WIDTH * 2.)
 8770                    .px_1p5()
 8771                    .gap_1()
 8772                    // Workaround: For some reason, there's a gap if we don't do this
 8773                    .ml(-BORDER_WIDTH)
 8774                    .shadow(vec![gpui::BoxShadow {
 8775                        color: gpui::black().opacity(0.05),
 8776                        offset: point(px(1.), px(1.)),
 8777                        blur_radius: px(2.),
 8778                        spread_radius: px(0.),
 8779                    }])
 8780                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8781                    .border(BORDER_WIDTH)
 8782                    .border_color(cx.theme().colors().border)
 8783                    .rounded_r_lg()
 8784                    .id("edit_prediction_diff_popover_keybind")
 8785                    .when(!has_keybind, |el| {
 8786                        let status_colors = cx.theme().status();
 8787
 8788                        el.bg(status_colors.error_background)
 8789                            .border_color(status_colors.error.opacity(0.6))
 8790                            .child(Icon::new(IconName::Info).color(Color::Error))
 8791                            .cursor_default()
 8792                            .hoverable_tooltip(move |_window, cx| {
 8793                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8794                            })
 8795                    })
 8796                    .children(keybind),
 8797            )
 8798            .into_any();
 8799
 8800        let longest_row =
 8801            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8802        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8803            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8804        } else {
 8805            layout_line(
 8806                longest_row,
 8807                editor_snapshot,
 8808                style,
 8809                editor_width,
 8810                |_| false,
 8811                window,
 8812                cx,
 8813            )
 8814            .width
 8815        };
 8816
 8817        let viewport_bounds =
 8818            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8819                right: -right_margin,
 8820                ..Default::default()
 8821            });
 8822
 8823        let x_after_longest =
 8824            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8825                - scroll_pixel_position.x;
 8826
 8827        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8828
 8829        // Fully visible if it can be displayed within the window (allow overlapping other
 8830        // panes). However, this is only allowed if the popover starts within text_bounds.
 8831        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8832            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8833
 8834        let mut origin = if can_position_to_the_right {
 8835            point(
 8836                x_after_longest,
 8837                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8838                    - scroll_pixel_position.y,
 8839            )
 8840        } else {
 8841            let cursor_row = newest_selection_head.map(|head| head.row());
 8842            let above_edit = edit_start
 8843                .row()
 8844                .0
 8845                .checked_sub(line_count as u32)
 8846                .map(DisplayRow);
 8847            let below_edit = Some(edit_end.row() + 1);
 8848            let above_cursor =
 8849                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8850            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8851
 8852            // Place the edit popover adjacent to the edit if there is a location
 8853            // available that is onscreen and does not obscure the cursor. Otherwise,
 8854            // place it adjacent to the cursor.
 8855            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8856                .into_iter()
 8857                .flatten()
 8858                .find(|&start_row| {
 8859                    let end_row = start_row + line_count as u32;
 8860                    visible_row_range.contains(&start_row)
 8861                        && visible_row_range.contains(&end_row)
 8862                        && cursor_row.map_or(true, |cursor_row| {
 8863                            !((start_row..end_row).contains(&cursor_row))
 8864                        })
 8865                })?;
 8866
 8867            content_origin
 8868                + point(
 8869                    -scroll_pixel_position.x,
 8870                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8871                )
 8872        };
 8873
 8874        origin.x -= BORDER_WIDTH;
 8875
 8876        window.defer_draw(element, origin, 1);
 8877
 8878        // Do not return an element, since it will already be drawn due to defer_draw.
 8879        None
 8880    }
 8881
 8882    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8883        px(30.)
 8884    }
 8885
 8886    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8887        if self.read_only(cx) {
 8888            cx.theme().players().read_only()
 8889        } else {
 8890            self.style.as_ref().unwrap().local_player
 8891        }
 8892    }
 8893
 8894    fn render_edit_prediction_accept_keybind(
 8895        &self,
 8896        window: &mut Window,
 8897        cx: &App,
 8898    ) -> Option<AnyElement> {
 8899        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8900        let accept_keystroke = accept_binding.keystroke()?;
 8901
 8902        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8903
 8904        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8905            Color::Accent
 8906        } else {
 8907            Color::Muted
 8908        };
 8909
 8910        h_flex()
 8911            .px_0p5()
 8912            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8913            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8914            .text_size(TextSize::XSmall.rems(cx))
 8915            .child(h_flex().children(ui::render_modifiers(
 8916                &accept_keystroke.modifiers,
 8917                PlatformStyle::platform(),
 8918                Some(modifiers_color),
 8919                Some(IconSize::XSmall.rems().into()),
 8920                true,
 8921            )))
 8922            .when(is_platform_style_mac, |parent| {
 8923                parent.child(accept_keystroke.key.clone())
 8924            })
 8925            .when(!is_platform_style_mac, |parent| {
 8926                parent.child(
 8927                    Key::new(
 8928                        util::capitalize(&accept_keystroke.key),
 8929                        Some(Color::Default),
 8930                    )
 8931                    .size(Some(IconSize::XSmall.rems().into())),
 8932                )
 8933            })
 8934            .into_any()
 8935            .into()
 8936    }
 8937
 8938    fn render_edit_prediction_line_popover(
 8939        &self,
 8940        label: impl Into<SharedString>,
 8941        icon: Option<IconName>,
 8942        window: &mut Window,
 8943        cx: &App,
 8944    ) -> Option<Stateful<Div>> {
 8945        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8946
 8947        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8948        let has_keybind = keybind.is_some();
 8949
 8950        let result = h_flex()
 8951            .id("ep-line-popover")
 8952            .py_0p5()
 8953            .pl_1()
 8954            .pr(padding_right)
 8955            .gap_1()
 8956            .rounded_md()
 8957            .border_1()
 8958            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8959            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8960            .shadow_xs()
 8961            .when(!has_keybind, |el| {
 8962                let status_colors = cx.theme().status();
 8963
 8964                el.bg(status_colors.error_background)
 8965                    .border_color(status_colors.error.opacity(0.6))
 8966                    .pl_2()
 8967                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8968                    .cursor_default()
 8969                    .hoverable_tooltip(move |_window, cx| {
 8970                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8971                    })
 8972            })
 8973            .children(keybind)
 8974            .child(
 8975                Label::new(label)
 8976                    .size(LabelSize::Small)
 8977                    .when(!has_keybind, |el| {
 8978                        el.color(cx.theme().status().error.into()).strikethrough()
 8979                    }),
 8980            )
 8981            .when(!has_keybind, |el| {
 8982                el.child(
 8983                    h_flex().ml_1().child(
 8984                        Icon::new(IconName::Info)
 8985                            .size(IconSize::Small)
 8986                            .color(cx.theme().status().error.into()),
 8987                    ),
 8988                )
 8989            })
 8990            .when_some(icon, |element, icon| {
 8991                element.child(
 8992                    div()
 8993                        .mt(px(1.5))
 8994                        .child(Icon::new(icon).size(IconSize::Small)),
 8995                )
 8996            });
 8997
 8998        Some(result)
 8999    }
 9000
 9001    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9002        let accent_color = cx.theme().colors().text_accent;
 9003        let editor_bg_color = cx.theme().colors().editor_background;
 9004        editor_bg_color.blend(accent_color.opacity(0.1))
 9005    }
 9006
 9007    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9008        let accent_color = cx.theme().colors().text_accent;
 9009        let editor_bg_color = cx.theme().colors().editor_background;
 9010        editor_bg_color.blend(accent_color.opacity(0.6))
 9011    }
 9012
 9013    fn render_edit_prediction_cursor_popover(
 9014        &self,
 9015        min_width: Pixels,
 9016        max_width: Pixels,
 9017        cursor_point: Point,
 9018        style: &EditorStyle,
 9019        accept_keystroke: Option<&gpui::Keystroke>,
 9020        _window: &Window,
 9021        cx: &mut Context<Editor>,
 9022    ) -> Option<AnyElement> {
 9023        let provider = self.edit_prediction_provider.as_ref()?;
 9024
 9025        if provider.provider.needs_terms_acceptance(cx) {
 9026            return Some(
 9027                h_flex()
 9028                    .min_w(min_width)
 9029                    .flex_1()
 9030                    .px_2()
 9031                    .py_1()
 9032                    .gap_3()
 9033                    .elevation_2(cx)
 9034                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9035                    .id("accept-terms")
 9036                    .cursor_pointer()
 9037                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9038                    .on_click(cx.listener(|this, _event, window, cx| {
 9039                        cx.stop_propagation();
 9040                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9041                        window.dispatch_action(
 9042                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9043                            cx,
 9044                        );
 9045                    }))
 9046                    .child(
 9047                        h_flex()
 9048                            .flex_1()
 9049                            .gap_2()
 9050                            .child(Icon::new(IconName::ZedPredict))
 9051                            .child(Label::new("Accept Terms of Service"))
 9052                            .child(div().w_full())
 9053                            .child(
 9054                                Icon::new(IconName::ArrowUpRight)
 9055                                    .color(Color::Muted)
 9056                                    .size(IconSize::Small),
 9057                            )
 9058                            .into_any_element(),
 9059                    )
 9060                    .into_any(),
 9061            );
 9062        }
 9063
 9064        let is_refreshing = provider.provider.is_refreshing(cx);
 9065
 9066        fn pending_completion_container() -> Div {
 9067            h_flex()
 9068                .h_full()
 9069                .flex_1()
 9070                .gap_2()
 9071                .child(Icon::new(IconName::ZedPredict))
 9072        }
 9073
 9074        let completion = match &self.active_inline_completion {
 9075            Some(prediction) => {
 9076                if !self.has_visible_completions_menu() {
 9077                    const RADIUS: Pixels = px(6.);
 9078                    const BORDER_WIDTH: Pixels = px(1.);
 9079
 9080                    return Some(
 9081                        h_flex()
 9082                            .elevation_2(cx)
 9083                            .border(BORDER_WIDTH)
 9084                            .border_color(cx.theme().colors().border)
 9085                            .when(accept_keystroke.is_none(), |el| {
 9086                                el.border_color(cx.theme().status().error)
 9087                            })
 9088                            .rounded(RADIUS)
 9089                            .rounded_tl(px(0.))
 9090                            .overflow_hidden()
 9091                            .child(div().px_1p5().child(match &prediction.completion {
 9092                                InlineCompletion::Move { target, snapshot } => {
 9093                                    use text::ToPoint as _;
 9094                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9095                                    {
 9096                                        Icon::new(IconName::ZedPredictDown)
 9097                                    } else {
 9098                                        Icon::new(IconName::ZedPredictUp)
 9099                                    }
 9100                                }
 9101                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9102                            }))
 9103                            .child(
 9104                                h_flex()
 9105                                    .gap_1()
 9106                                    .py_1()
 9107                                    .px_2()
 9108                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9109                                    .border_l_1()
 9110                                    .border_color(cx.theme().colors().border)
 9111                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9112                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9113                                        el.child(
 9114                                            Label::new("Hold")
 9115                                                .size(LabelSize::Small)
 9116                                                .when(accept_keystroke.is_none(), |el| {
 9117                                                    el.strikethrough()
 9118                                                })
 9119                                                .line_height_style(LineHeightStyle::UiLabel),
 9120                                        )
 9121                                    })
 9122                                    .id("edit_prediction_cursor_popover_keybind")
 9123                                    .when(accept_keystroke.is_none(), |el| {
 9124                                        let status_colors = cx.theme().status();
 9125
 9126                                        el.bg(status_colors.error_background)
 9127                                            .border_color(status_colors.error.opacity(0.6))
 9128                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9129                                            .cursor_default()
 9130                                            .hoverable_tooltip(move |_window, cx| {
 9131                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9132                                                    .into()
 9133                                            })
 9134                                    })
 9135                                    .when_some(
 9136                                        accept_keystroke.as_ref(),
 9137                                        |el, accept_keystroke| {
 9138                                            el.child(h_flex().children(ui::render_modifiers(
 9139                                                &accept_keystroke.modifiers,
 9140                                                PlatformStyle::platform(),
 9141                                                Some(Color::Default),
 9142                                                Some(IconSize::XSmall.rems().into()),
 9143                                                false,
 9144                                            )))
 9145                                        },
 9146                                    ),
 9147                            )
 9148                            .into_any(),
 9149                    );
 9150                }
 9151
 9152                self.render_edit_prediction_cursor_popover_preview(
 9153                    prediction,
 9154                    cursor_point,
 9155                    style,
 9156                    cx,
 9157                )?
 9158            }
 9159
 9160            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9161                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9162                    stale_completion,
 9163                    cursor_point,
 9164                    style,
 9165                    cx,
 9166                )?,
 9167
 9168                None => {
 9169                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9170                }
 9171            },
 9172
 9173            None => pending_completion_container().child(Label::new("No Prediction")),
 9174        };
 9175
 9176        let completion = if is_refreshing {
 9177            completion
 9178                .with_animation(
 9179                    "loading-completion",
 9180                    Animation::new(Duration::from_secs(2))
 9181                        .repeat()
 9182                        .with_easing(pulsating_between(0.4, 0.8)),
 9183                    |label, delta| label.opacity(delta),
 9184                )
 9185                .into_any_element()
 9186        } else {
 9187            completion.into_any_element()
 9188        };
 9189
 9190        let has_completion = self.active_inline_completion.is_some();
 9191
 9192        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9193        Some(
 9194            h_flex()
 9195                .min_w(min_width)
 9196                .max_w(max_width)
 9197                .flex_1()
 9198                .elevation_2(cx)
 9199                .border_color(cx.theme().colors().border)
 9200                .child(
 9201                    div()
 9202                        .flex_1()
 9203                        .py_1()
 9204                        .px_2()
 9205                        .overflow_hidden()
 9206                        .child(completion),
 9207                )
 9208                .when_some(accept_keystroke, |el, accept_keystroke| {
 9209                    if !accept_keystroke.modifiers.modified() {
 9210                        return el;
 9211                    }
 9212
 9213                    el.child(
 9214                        h_flex()
 9215                            .h_full()
 9216                            .border_l_1()
 9217                            .rounded_r_lg()
 9218                            .border_color(cx.theme().colors().border)
 9219                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9220                            .gap_1()
 9221                            .py_1()
 9222                            .px_2()
 9223                            .child(
 9224                                h_flex()
 9225                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9226                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9227                                    .child(h_flex().children(ui::render_modifiers(
 9228                                        &accept_keystroke.modifiers,
 9229                                        PlatformStyle::platform(),
 9230                                        Some(if !has_completion {
 9231                                            Color::Muted
 9232                                        } else {
 9233                                            Color::Default
 9234                                        }),
 9235                                        None,
 9236                                        false,
 9237                                    ))),
 9238                            )
 9239                            .child(Label::new("Preview").into_any_element())
 9240                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9241                    )
 9242                })
 9243                .into_any(),
 9244        )
 9245    }
 9246
 9247    fn render_edit_prediction_cursor_popover_preview(
 9248        &self,
 9249        completion: &InlineCompletionState,
 9250        cursor_point: Point,
 9251        style: &EditorStyle,
 9252        cx: &mut Context<Editor>,
 9253    ) -> Option<Div> {
 9254        use text::ToPoint as _;
 9255
 9256        fn render_relative_row_jump(
 9257            prefix: impl Into<String>,
 9258            current_row: u32,
 9259            target_row: u32,
 9260        ) -> Div {
 9261            let (row_diff, arrow) = if target_row < current_row {
 9262                (current_row - target_row, IconName::ArrowUp)
 9263            } else {
 9264                (target_row - current_row, IconName::ArrowDown)
 9265            };
 9266
 9267            h_flex()
 9268                .child(
 9269                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9270                        .color(Color::Muted)
 9271                        .size(LabelSize::Small),
 9272                )
 9273                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9274        }
 9275
 9276        match &completion.completion {
 9277            InlineCompletion::Move {
 9278                target, snapshot, ..
 9279            } => Some(
 9280                h_flex()
 9281                    .px_2()
 9282                    .gap_2()
 9283                    .flex_1()
 9284                    .child(
 9285                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9286                            Icon::new(IconName::ZedPredictDown)
 9287                        } else {
 9288                            Icon::new(IconName::ZedPredictUp)
 9289                        },
 9290                    )
 9291                    .child(Label::new("Jump to Edit")),
 9292            ),
 9293
 9294            InlineCompletion::Edit {
 9295                edits,
 9296                edit_preview,
 9297                snapshot,
 9298                display_mode: _,
 9299            } => {
 9300                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9301
 9302                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9303                    &snapshot,
 9304                    &edits,
 9305                    edit_preview.as_ref()?,
 9306                    true,
 9307                    cx,
 9308                )
 9309                .first_line_preview();
 9310
 9311                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9312                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9313
 9314                let preview = h_flex()
 9315                    .gap_1()
 9316                    .min_w_16()
 9317                    .child(styled_text)
 9318                    .when(has_more_lines, |parent| parent.child(""));
 9319
 9320                let left = if first_edit_row != cursor_point.row {
 9321                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9322                        .into_any_element()
 9323                } else {
 9324                    Icon::new(IconName::ZedPredict).into_any_element()
 9325                };
 9326
 9327                Some(
 9328                    h_flex()
 9329                        .h_full()
 9330                        .flex_1()
 9331                        .gap_2()
 9332                        .pr_1()
 9333                        .overflow_x_hidden()
 9334                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9335                        .child(left)
 9336                        .child(preview),
 9337                )
 9338            }
 9339        }
 9340    }
 9341
 9342    pub fn render_context_menu(
 9343        &self,
 9344        style: &EditorStyle,
 9345        max_height_in_lines: u32,
 9346        window: &mut Window,
 9347        cx: &mut Context<Editor>,
 9348    ) -> Option<AnyElement> {
 9349        let menu = self.context_menu.borrow();
 9350        let menu = menu.as_ref()?;
 9351        if !menu.visible() {
 9352            return None;
 9353        };
 9354        Some(menu.render(style, max_height_in_lines, window, cx))
 9355    }
 9356
 9357    fn render_context_menu_aside(
 9358        &mut self,
 9359        max_size: Size<Pixels>,
 9360        window: &mut Window,
 9361        cx: &mut Context<Editor>,
 9362    ) -> Option<AnyElement> {
 9363        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9364            if menu.visible() {
 9365                menu.render_aside(max_size, window, cx)
 9366            } else {
 9367                None
 9368            }
 9369        })
 9370    }
 9371
 9372    fn hide_context_menu(
 9373        &mut self,
 9374        window: &mut Window,
 9375        cx: &mut Context<Self>,
 9376    ) -> Option<CodeContextMenu> {
 9377        cx.notify();
 9378        self.completion_tasks.clear();
 9379        let context_menu = self.context_menu.borrow_mut().take();
 9380        self.stale_inline_completion_in_menu.take();
 9381        self.update_visible_inline_completion(window, cx);
 9382        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9383            if let Some(completion_provider) = &self.completion_provider {
 9384                completion_provider.selection_changed(None, window, cx);
 9385            }
 9386        }
 9387        context_menu
 9388    }
 9389
 9390    fn show_snippet_choices(
 9391        &mut self,
 9392        choices: &Vec<String>,
 9393        selection: Range<Anchor>,
 9394        cx: &mut Context<Self>,
 9395    ) {
 9396        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9397            (Some(a), Some(b)) if a == b => a,
 9398            _ => {
 9399                log::error!("expected anchor range to have matching buffer IDs");
 9400                return;
 9401            }
 9402        };
 9403        let multi_buffer = self.buffer().read(cx);
 9404        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9405            return;
 9406        };
 9407
 9408        let id = post_inc(&mut self.next_completion_id);
 9409        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9410        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9411            CompletionsMenu::new_snippet_choices(
 9412                id,
 9413                true,
 9414                choices,
 9415                selection,
 9416                buffer,
 9417                snippet_sort_order,
 9418            ),
 9419        ));
 9420    }
 9421
 9422    pub fn insert_snippet(
 9423        &mut self,
 9424        insertion_ranges: &[Range<usize>],
 9425        snippet: Snippet,
 9426        window: &mut Window,
 9427        cx: &mut Context<Self>,
 9428    ) -> Result<()> {
 9429        struct Tabstop<T> {
 9430            is_end_tabstop: bool,
 9431            ranges: Vec<Range<T>>,
 9432            choices: Option<Vec<String>>,
 9433        }
 9434
 9435        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9436            let snippet_text: Arc<str> = snippet.text.clone().into();
 9437            let edits = insertion_ranges
 9438                .iter()
 9439                .cloned()
 9440                .map(|range| (range, snippet_text.clone()));
 9441            let autoindent_mode = AutoindentMode::Block {
 9442                original_indent_columns: Vec::new(),
 9443            };
 9444            buffer.edit(edits, Some(autoindent_mode), cx);
 9445
 9446            let snapshot = &*buffer.read(cx);
 9447            let snippet = &snippet;
 9448            snippet
 9449                .tabstops
 9450                .iter()
 9451                .map(|tabstop| {
 9452                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9453                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9454                    });
 9455                    let mut tabstop_ranges = tabstop
 9456                        .ranges
 9457                        .iter()
 9458                        .flat_map(|tabstop_range| {
 9459                            let mut delta = 0_isize;
 9460                            insertion_ranges.iter().map(move |insertion_range| {
 9461                                let insertion_start = insertion_range.start as isize + delta;
 9462                                delta +=
 9463                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9464
 9465                                let start = ((insertion_start + tabstop_range.start) as usize)
 9466                                    .min(snapshot.len());
 9467                                let end = ((insertion_start + tabstop_range.end) as usize)
 9468                                    .min(snapshot.len());
 9469                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9470                            })
 9471                        })
 9472                        .collect::<Vec<_>>();
 9473                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9474
 9475                    Tabstop {
 9476                        is_end_tabstop,
 9477                        ranges: tabstop_ranges,
 9478                        choices: tabstop.choices.clone(),
 9479                    }
 9480                })
 9481                .collect::<Vec<_>>()
 9482        });
 9483        if let Some(tabstop) = tabstops.first() {
 9484            self.change_selections(Default::default(), window, cx, |s| {
 9485                // Reverse order so that the first range is the newest created selection.
 9486                // Completions will use it and autoscroll will prioritize it.
 9487                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9488            });
 9489
 9490            if let Some(choices) = &tabstop.choices {
 9491                if let Some(selection) = tabstop.ranges.first() {
 9492                    self.show_snippet_choices(choices, selection.clone(), cx)
 9493                }
 9494            }
 9495
 9496            // If we're already at the last tabstop and it's at the end of the snippet,
 9497            // we're done, we don't need to keep the state around.
 9498            if !tabstop.is_end_tabstop {
 9499                let choices = tabstops
 9500                    .iter()
 9501                    .map(|tabstop| tabstop.choices.clone())
 9502                    .collect();
 9503
 9504                let ranges = tabstops
 9505                    .into_iter()
 9506                    .map(|tabstop| tabstop.ranges)
 9507                    .collect::<Vec<_>>();
 9508
 9509                self.snippet_stack.push(SnippetState {
 9510                    active_index: 0,
 9511                    ranges,
 9512                    choices,
 9513                });
 9514            }
 9515
 9516            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9517            if self.autoclose_regions.is_empty() {
 9518                let snapshot = self.buffer.read(cx).snapshot(cx);
 9519                for selection in &mut self.selections.all::<Point>(cx) {
 9520                    let selection_head = selection.head();
 9521                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9522                        continue;
 9523                    };
 9524
 9525                    let mut bracket_pair = None;
 9526                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9527                    let prev_chars = snapshot
 9528                        .reversed_chars_at(selection_head)
 9529                        .collect::<String>();
 9530                    for (pair, enabled) in scope.brackets() {
 9531                        if enabled
 9532                            && pair.close
 9533                            && prev_chars.starts_with(pair.start.as_str())
 9534                            && next_chars.starts_with(pair.end.as_str())
 9535                        {
 9536                            bracket_pair = Some(pair.clone());
 9537                            break;
 9538                        }
 9539                    }
 9540                    if let Some(pair) = bracket_pair {
 9541                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9542                        let autoclose_enabled =
 9543                            self.use_autoclose && snapshot_settings.use_autoclose;
 9544                        if autoclose_enabled {
 9545                            let start = snapshot.anchor_after(selection_head);
 9546                            let end = snapshot.anchor_after(selection_head);
 9547                            self.autoclose_regions.push(AutocloseRegion {
 9548                                selection_id: selection.id,
 9549                                range: start..end,
 9550                                pair,
 9551                            });
 9552                        }
 9553                    }
 9554                }
 9555            }
 9556        }
 9557        Ok(())
 9558    }
 9559
 9560    pub fn move_to_next_snippet_tabstop(
 9561        &mut self,
 9562        window: &mut Window,
 9563        cx: &mut Context<Self>,
 9564    ) -> bool {
 9565        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9566    }
 9567
 9568    pub fn move_to_prev_snippet_tabstop(
 9569        &mut self,
 9570        window: &mut Window,
 9571        cx: &mut Context<Self>,
 9572    ) -> bool {
 9573        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9574    }
 9575
 9576    pub fn move_to_snippet_tabstop(
 9577        &mut self,
 9578        bias: Bias,
 9579        window: &mut Window,
 9580        cx: &mut Context<Self>,
 9581    ) -> bool {
 9582        if let Some(mut snippet) = self.snippet_stack.pop() {
 9583            match bias {
 9584                Bias::Left => {
 9585                    if snippet.active_index > 0 {
 9586                        snippet.active_index -= 1;
 9587                    } else {
 9588                        self.snippet_stack.push(snippet);
 9589                        return false;
 9590                    }
 9591                }
 9592                Bias::Right => {
 9593                    if snippet.active_index + 1 < snippet.ranges.len() {
 9594                        snippet.active_index += 1;
 9595                    } else {
 9596                        self.snippet_stack.push(snippet);
 9597                        return false;
 9598                    }
 9599                }
 9600            }
 9601            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9602                self.change_selections(Default::default(), window, cx, |s| {
 9603                    // Reverse order so that the first range is the newest created selection.
 9604                    // Completions will use it and autoscroll will prioritize it.
 9605                    s.select_ranges(current_ranges.iter().rev().cloned())
 9606                });
 9607
 9608                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9609                    if let Some(selection) = current_ranges.first() {
 9610                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9611                    }
 9612                }
 9613
 9614                // If snippet state is not at the last tabstop, push it back on the stack
 9615                if snippet.active_index + 1 < snippet.ranges.len() {
 9616                    self.snippet_stack.push(snippet);
 9617                }
 9618                return true;
 9619            }
 9620        }
 9621
 9622        false
 9623    }
 9624
 9625    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9626        self.transact(window, cx, |this, window, cx| {
 9627            this.select_all(&SelectAll, window, cx);
 9628            this.insert("", window, cx);
 9629        });
 9630    }
 9631
 9632    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9633        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9634        self.transact(window, cx, |this, window, cx| {
 9635            this.select_autoclose_pair(window, cx);
 9636            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9637            if !this.linked_edit_ranges.is_empty() {
 9638                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9639                let snapshot = this.buffer.read(cx).snapshot(cx);
 9640
 9641                for selection in selections.iter() {
 9642                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9643                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9644                    if selection_start.buffer_id != selection_end.buffer_id {
 9645                        continue;
 9646                    }
 9647                    if let Some(ranges) =
 9648                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9649                    {
 9650                        for (buffer, entries) in ranges {
 9651                            linked_ranges.entry(buffer).or_default().extend(entries);
 9652                        }
 9653                    }
 9654                }
 9655            }
 9656
 9657            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9658            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9659            for selection in &mut selections {
 9660                if selection.is_empty() {
 9661                    let old_head = selection.head();
 9662                    let mut new_head =
 9663                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9664                            .to_point(&display_map);
 9665                    if let Some((buffer, line_buffer_range)) = display_map
 9666                        .buffer_snapshot
 9667                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9668                    {
 9669                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9670                        let indent_len = match indent_size.kind {
 9671                            IndentKind::Space => {
 9672                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9673                            }
 9674                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9675                        };
 9676                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9677                            let indent_len = indent_len.get();
 9678                            new_head = cmp::min(
 9679                                new_head,
 9680                                MultiBufferPoint::new(
 9681                                    old_head.row,
 9682                                    ((old_head.column - 1) / indent_len) * indent_len,
 9683                                ),
 9684                            );
 9685                        }
 9686                    }
 9687
 9688                    selection.set_head(new_head, SelectionGoal::None);
 9689                }
 9690            }
 9691
 9692            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9693            this.insert("", window, cx);
 9694            let empty_str: Arc<str> = Arc::from("");
 9695            for (buffer, edits) in linked_ranges {
 9696                let snapshot = buffer.read(cx).snapshot();
 9697                use text::ToPoint as TP;
 9698
 9699                let edits = edits
 9700                    .into_iter()
 9701                    .map(|range| {
 9702                        let end_point = TP::to_point(&range.end, &snapshot);
 9703                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9704
 9705                        if end_point == start_point {
 9706                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9707                                .saturating_sub(1);
 9708                            start_point =
 9709                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9710                        };
 9711
 9712                        (start_point..end_point, empty_str.clone())
 9713                    })
 9714                    .sorted_by_key(|(range, _)| range.start)
 9715                    .collect::<Vec<_>>();
 9716                buffer.update(cx, |this, cx| {
 9717                    this.edit(edits, None, cx);
 9718                })
 9719            }
 9720            this.refresh_inline_completion(true, false, window, cx);
 9721            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9722        });
 9723    }
 9724
 9725    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9726        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9727        self.transact(window, cx, |this, window, cx| {
 9728            this.change_selections(Default::default(), window, cx, |s| {
 9729                s.move_with(|map, selection| {
 9730                    if selection.is_empty() {
 9731                        let cursor = movement::right(map, selection.head());
 9732                        selection.end = cursor;
 9733                        selection.reversed = true;
 9734                        selection.goal = SelectionGoal::None;
 9735                    }
 9736                })
 9737            });
 9738            this.insert("", window, cx);
 9739            this.refresh_inline_completion(true, false, window, cx);
 9740        });
 9741    }
 9742
 9743    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9744        if self.mode.is_single_line() {
 9745            cx.propagate();
 9746            return;
 9747        }
 9748
 9749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9750        if self.move_to_prev_snippet_tabstop(window, cx) {
 9751            return;
 9752        }
 9753        self.outdent(&Outdent, window, cx);
 9754    }
 9755
 9756    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9757        if self.mode.is_single_line() {
 9758            cx.propagate();
 9759            return;
 9760        }
 9761
 9762        if self.move_to_next_snippet_tabstop(window, cx) {
 9763            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9764            return;
 9765        }
 9766        if self.read_only(cx) {
 9767            return;
 9768        }
 9769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9770        let mut selections = self.selections.all_adjusted(cx);
 9771        let buffer = self.buffer.read(cx);
 9772        let snapshot = buffer.snapshot(cx);
 9773        let rows_iter = selections.iter().map(|s| s.head().row);
 9774        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9775
 9776        let has_some_cursor_in_whitespace = selections
 9777            .iter()
 9778            .filter(|selection| selection.is_empty())
 9779            .any(|selection| {
 9780                let cursor = selection.head();
 9781                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9782                cursor.column < current_indent.len
 9783            });
 9784
 9785        let mut edits = Vec::new();
 9786        let mut prev_edited_row = 0;
 9787        let mut row_delta = 0;
 9788        for selection in &mut selections {
 9789            if selection.start.row != prev_edited_row {
 9790                row_delta = 0;
 9791            }
 9792            prev_edited_row = selection.end.row;
 9793
 9794            // If the selection is non-empty, then increase the indentation of the selected lines.
 9795            if !selection.is_empty() {
 9796                row_delta =
 9797                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9798                continue;
 9799            }
 9800
 9801            let cursor = selection.head();
 9802            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9803            if let Some(suggested_indent) =
 9804                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9805            {
 9806                // Don't do anything if already at suggested indent
 9807                // and there is any other cursor which is not
 9808                if has_some_cursor_in_whitespace
 9809                    && cursor.column == current_indent.len
 9810                    && current_indent.len == suggested_indent.len
 9811                {
 9812                    continue;
 9813                }
 9814
 9815                // Adjust line and move cursor to suggested indent
 9816                // if cursor is not at suggested indent
 9817                if cursor.column < suggested_indent.len
 9818                    && cursor.column <= current_indent.len
 9819                    && current_indent.len <= suggested_indent.len
 9820                {
 9821                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9822                    selection.end = selection.start;
 9823                    if row_delta == 0 {
 9824                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9825                            cursor.row,
 9826                            current_indent,
 9827                            suggested_indent,
 9828                        ));
 9829                        row_delta = suggested_indent.len - current_indent.len;
 9830                    }
 9831                    continue;
 9832                }
 9833
 9834                // If current indent is more than suggested indent
 9835                // only move cursor to current indent and skip indent
 9836                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9837                    selection.start = Point::new(cursor.row, current_indent.len);
 9838                    selection.end = selection.start;
 9839                    continue;
 9840                }
 9841            }
 9842
 9843            // Otherwise, insert a hard or soft tab.
 9844            let settings = buffer.language_settings_at(cursor, cx);
 9845            let tab_size = if settings.hard_tabs {
 9846                IndentSize::tab()
 9847            } else {
 9848                let tab_size = settings.tab_size.get();
 9849                let indent_remainder = snapshot
 9850                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9851                    .flat_map(str::chars)
 9852                    .fold(row_delta % tab_size, |counter: u32, c| {
 9853                        if c == '\t' {
 9854                            0
 9855                        } else {
 9856                            (counter + 1) % tab_size
 9857                        }
 9858                    });
 9859
 9860                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9861                IndentSize::spaces(chars_to_next_tab_stop)
 9862            };
 9863            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9864            selection.end = selection.start;
 9865            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9866            row_delta += tab_size.len;
 9867        }
 9868
 9869        self.transact(window, cx, |this, window, cx| {
 9870            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9871            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9872            this.refresh_inline_completion(true, false, window, cx);
 9873        });
 9874    }
 9875
 9876    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9877        if self.read_only(cx) {
 9878            return;
 9879        }
 9880        if self.mode.is_single_line() {
 9881            cx.propagate();
 9882            return;
 9883        }
 9884
 9885        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9886        let mut selections = self.selections.all::<Point>(cx);
 9887        let mut prev_edited_row = 0;
 9888        let mut row_delta = 0;
 9889        let mut edits = Vec::new();
 9890        let buffer = self.buffer.read(cx);
 9891        let snapshot = buffer.snapshot(cx);
 9892        for selection in &mut selections {
 9893            if selection.start.row != prev_edited_row {
 9894                row_delta = 0;
 9895            }
 9896            prev_edited_row = selection.end.row;
 9897
 9898            row_delta =
 9899                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9900        }
 9901
 9902        self.transact(window, cx, |this, window, cx| {
 9903            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9904            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9905        });
 9906    }
 9907
 9908    fn indent_selection(
 9909        buffer: &MultiBuffer,
 9910        snapshot: &MultiBufferSnapshot,
 9911        selection: &mut Selection<Point>,
 9912        edits: &mut Vec<(Range<Point>, String)>,
 9913        delta_for_start_row: u32,
 9914        cx: &App,
 9915    ) -> u32 {
 9916        let settings = buffer.language_settings_at(selection.start, cx);
 9917        let tab_size = settings.tab_size.get();
 9918        let indent_kind = if settings.hard_tabs {
 9919            IndentKind::Tab
 9920        } else {
 9921            IndentKind::Space
 9922        };
 9923        let mut start_row = selection.start.row;
 9924        let mut end_row = selection.end.row + 1;
 9925
 9926        // If a selection ends at the beginning of a line, don't indent
 9927        // that last line.
 9928        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9929            end_row -= 1;
 9930        }
 9931
 9932        // Avoid re-indenting a row that has already been indented by a
 9933        // previous selection, but still update this selection's column
 9934        // to reflect that indentation.
 9935        if delta_for_start_row > 0 {
 9936            start_row += 1;
 9937            selection.start.column += delta_for_start_row;
 9938            if selection.end.row == selection.start.row {
 9939                selection.end.column += delta_for_start_row;
 9940            }
 9941        }
 9942
 9943        let mut delta_for_end_row = 0;
 9944        let has_multiple_rows = start_row + 1 != end_row;
 9945        for row in start_row..end_row {
 9946            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9947            let indent_delta = match (current_indent.kind, indent_kind) {
 9948                (IndentKind::Space, IndentKind::Space) => {
 9949                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9950                    IndentSize::spaces(columns_to_next_tab_stop)
 9951                }
 9952                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9953                (_, IndentKind::Tab) => IndentSize::tab(),
 9954            };
 9955
 9956            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9957                0
 9958            } else {
 9959                selection.start.column
 9960            };
 9961            let row_start = Point::new(row, start);
 9962            edits.push((
 9963                row_start..row_start,
 9964                indent_delta.chars().collect::<String>(),
 9965            ));
 9966
 9967            // Update this selection's endpoints to reflect the indentation.
 9968            if row == selection.start.row {
 9969                selection.start.column += indent_delta.len;
 9970            }
 9971            if row == selection.end.row {
 9972                selection.end.column += indent_delta.len;
 9973                delta_for_end_row = indent_delta.len;
 9974            }
 9975        }
 9976
 9977        if selection.start.row == selection.end.row {
 9978            delta_for_start_row + delta_for_end_row
 9979        } else {
 9980            delta_for_end_row
 9981        }
 9982    }
 9983
 9984    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9985        if self.read_only(cx) {
 9986            return;
 9987        }
 9988        if self.mode.is_single_line() {
 9989            cx.propagate();
 9990            return;
 9991        }
 9992
 9993        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9994        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9995        let selections = self.selections.all::<Point>(cx);
 9996        let mut deletion_ranges = Vec::new();
 9997        let mut last_outdent = None;
 9998        {
 9999            let buffer = self.buffer.read(cx);
10000            let snapshot = buffer.snapshot(cx);
10001            for selection in &selections {
10002                let settings = buffer.language_settings_at(selection.start, cx);
10003                let tab_size = settings.tab_size.get();
10004                let mut rows = selection.spanned_rows(false, &display_map);
10005
10006                // Avoid re-outdenting a row that has already been outdented by a
10007                // previous selection.
10008                if let Some(last_row) = last_outdent {
10009                    if last_row == rows.start {
10010                        rows.start = rows.start.next_row();
10011                    }
10012                }
10013                let has_multiple_rows = rows.len() > 1;
10014                for row in rows.iter_rows() {
10015                    let indent_size = snapshot.indent_size_for_line(row);
10016                    if indent_size.len > 0 {
10017                        let deletion_len = match indent_size.kind {
10018                            IndentKind::Space => {
10019                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10020                                if columns_to_prev_tab_stop == 0 {
10021                                    tab_size
10022                                } else {
10023                                    columns_to_prev_tab_stop
10024                                }
10025                            }
10026                            IndentKind::Tab => 1,
10027                        };
10028                        let start = if has_multiple_rows
10029                            || deletion_len > selection.start.column
10030                            || indent_size.len < selection.start.column
10031                        {
10032                            0
10033                        } else {
10034                            selection.start.column - deletion_len
10035                        };
10036                        deletion_ranges.push(
10037                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10038                        );
10039                        last_outdent = Some(row);
10040                    }
10041                }
10042            }
10043        }
10044
10045        self.transact(window, cx, |this, window, cx| {
10046            this.buffer.update(cx, |buffer, cx| {
10047                let empty_str: Arc<str> = Arc::default();
10048                buffer.edit(
10049                    deletion_ranges
10050                        .into_iter()
10051                        .map(|range| (range, empty_str.clone())),
10052                    None,
10053                    cx,
10054                );
10055            });
10056            let selections = this.selections.all::<usize>(cx);
10057            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10058        });
10059    }
10060
10061    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10062        if self.read_only(cx) {
10063            return;
10064        }
10065        if self.mode.is_single_line() {
10066            cx.propagate();
10067            return;
10068        }
10069
10070        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10071        let selections = self
10072            .selections
10073            .all::<usize>(cx)
10074            .into_iter()
10075            .map(|s| s.range());
10076
10077        self.transact(window, cx, |this, window, cx| {
10078            this.buffer.update(cx, |buffer, cx| {
10079                buffer.autoindent_ranges(selections, cx);
10080            });
10081            let selections = this.selections.all::<usize>(cx);
10082            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10083        });
10084    }
10085
10086    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10087        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10088        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10089        let selections = self.selections.all::<Point>(cx);
10090
10091        let mut new_cursors = Vec::new();
10092        let mut edit_ranges = Vec::new();
10093        let mut selections = selections.iter().peekable();
10094        while let Some(selection) = selections.next() {
10095            let mut rows = selection.spanned_rows(false, &display_map);
10096            let goal_display_column = selection.head().to_display_point(&display_map).column();
10097
10098            // Accumulate contiguous regions of rows that we want to delete.
10099            while let Some(next_selection) = selections.peek() {
10100                let next_rows = next_selection.spanned_rows(false, &display_map);
10101                if next_rows.start <= rows.end {
10102                    rows.end = next_rows.end;
10103                    selections.next().unwrap();
10104                } else {
10105                    break;
10106                }
10107            }
10108
10109            let buffer = &display_map.buffer_snapshot;
10110            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10111            let edit_end;
10112            let cursor_buffer_row;
10113            if buffer.max_point().row >= rows.end.0 {
10114                // If there's a line after the range, delete the \n from the end of the row range
10115                // and position the cursor on the next line.
10116                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10117                cursor_buffer_row = rows.end;
10118            } else {
10119                // If there isn't a line after the range, delete the \n from the line before the
10120                // start of the row range and position the cursor there.
10121                edit_start = edit_start.saturating_sub(1);
10122                edit_end = buffer.len();
10123                cursor_buffer_row = rows.start.previous_row();
10124            }
10125
10126            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10127            *cursor.column_mut() =
10128                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10129
10130            new_cursors.push((
10131                selection.id,
10132                buffer.anchor_after(cursor.to_point(&display_map)),
10133            ));
10134            edit_ranges.push(edit_start..edit_end);
10135        }
10136
10137        self.transact(window, cx, |this, window, cx| {
10138            let buffer = this.buffer.update(cx, |buffer, cx| {
10139                let empty_str: Arc<str> = Arc::default();
10140                buffer.edit(
10141                    edit_ranges
10142                        .into_iter()
10143                        .map(|range| (range, empty_str.clone())),
10144                    None,
10145                    cx,
10146                );
10147                buffer.snapshot(cx)
10148            });
10149            let new_selections = new_cursors
10150                .into_iter()
10151                .map(|(id, cursor)| {
10152                    let cursor = cursor.to_point(&buffer);
10153                    Selection {
10154                        id,
10155                        start: cursor,
10156                        end: cursor,
10157                        reversed: false,
10158                        goal: SelectionGoal::None,
10159                    }
10160                })
10161                .collect();
10162
10163            this.change_selections(Default::default(), window, cx, |s| {
10164                s.select(new_selections);
10165            });
10166        });
10167    }
10168
10169    pub fn join_lines_impl(
10170        &mut self,
10171        insert_whitespace: bool,
10172        window: &mut Window,
10173        cx: &mut Context<Self>,
10174    ) {
10175        if self.read_only(cx) {
10176            return;
10177        }
10178        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10179        for selection in self.selections.all::<Point>(cx) {
10180            let start = MultiBufferRow(selection.start.row);
10181            // Treat single line selections as if they include the next line. Otherwise this action
10182            // would do nothing for single line selections individual cursors.
10183            let end = if selection.start.row == selection.end.row {
10184                MultiBufferRow(selection.start.row + 1)
10185            } else {
10186                MultiBufferRow(selection.end.row)
10187            };
10188
10189            if let Some(last_row_range) = row_ranges.last_mut() {
10190                if start <= last_row_range.end {
10191                    last_row_range.end = end;
10192                    continue;
10193                }
10194            }
10195            row_ranges.push(start..end);
10196        }
10197
10198        let snapshot = self.buffer.read(cx).snapshot(cx);
10199        let mut cursor_positions = Vec::new();
10200        for row_range in &row_ranges {
10201            let anchor = snapshot.anchor_before(Point::new(
10202                row_range.end.previous_row().0,
10203                snapshot.line_len(row_range.end.previous_row()),
10204            ));
10205            cursor_positions.push(anchor..anchor);
10206        }
10207
10208        self.transact(window, cx, |this, window, cx| {
10209            for row_range in row_ranges.into_iter().rev() {
10210                for row in row_range.iter_rows().rev() {
10211                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10212                    let next_line_row = row.next_row();
10213                    let indent = snapshot.indent_size_for_line(next_line_row);
10214                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10215
10216                    let replace =
10217                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10218                            " "
10219                        } else {
10220                            ""
10221                        };
10222
10223                    this.buffer.update(cx, |buffer, cx| {
10224                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10225                    });
10226                }
10227            }
10228
10229            this.change_selections(Default::default(), window, cx, |s| {
10230                s.select_anchor_ranges(cursor_positions)
10231            });
10232        });
10233    }
10234
10235    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10236        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10237        self.join_lines_impl(true, window, cx);
10238    }
10239
10240    pub fn sort_lines_case_sensitive(
10241        &mut self,
10242        _: &SortLinesCaseSensitive,
10243        window: &mut Window,
10244        cx: &mut Context<Self>,
10245    ) {
10246        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10247    }
10248
10249    pub fn sort_lines_by_length(
10250        &mut self,
10251        _: &SortLinesByLength,
10252        window: &mut Window,
10253        cx: &mut Context<Self>,
10254    ) {
10255        self.manipulate_immutable_lines(window, cx, |lines| {
10256            lines.sort_by_key(|&line| line.chars().count())
10257        })
10258    }
10259
10260    pub fn sort_lines_case_insensitive(
10261        &mut self,
10262        _: &SortLinesCaseInsensitive,
10263        window: &mut Window,
10264        cx: &mut Context<Self>,
10265    ) {
10266        self.manipulate_immutable_lines(window, cx, |lines| {
10267            lines.sort_by_key(|line| line.to_lowercase())
10268        })
10269    }
10270
10271    pub fn unique_lines_case_insensitive(
10272        &mut self,
10273        _: &UniqueLinesCaseInsensitive,
10274        window: &mut Window,
10275        cx: &mut Context<Self>,
10276    ) {
10277        self.manipulate_immutable_lines(window, cx, |lines| {
10278            let mut seen = HashSet::default();
10279            lines.retain(|line| seen.insert(line.to_lowercase()));
10280        })
10281    }
10282
10283    pub fn unique_lines_case_sensitive(
10284        &mut self,
10285        _: &UniqueLinesCaseSensitive,
10286        window: &mut Window,
10287        cx: &mut Context<Self>,
10288    ) {
10289        self.manipulate_immutable_lines(window, cx, |lines| {
10290            let mut seen = HashSet::default();
10291            lines.retain(|line| seen.insert(*line));
10292        })
10293    }
10294
10295    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10296        let Some(project) = self.project.clone() else {
10297            return;
10298        };
10299        self.reload(project, window, cx)
10300            .detach_and_notify_err(window, cx);
10301    }
10302
10303    pub fn restore_file(
10304        &mut self,
10305        _: &::git::RestoreFile,
10306        window: &mut Window,
10307        cx: &mut Context<Self>,
10308    ) {
10309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10310        let mut buffer_ids = HashSet::default();
10311        let snapshot = self.buffer().read(cx).snapshot(cx);
10312        for selection in self.selections.all::<usize>(cx) {
10313            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10314        }
10315
10316        let buffer = self.buffer().read(cx);
10317        let ranges = buffer_ids
10318            .into_iter()
10319            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10320            .collect::<Vec<_>>();
10321
10322        self.restore_hunks_in_ranges(ranges, window, cx);
10323    }
10324
10325    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10326        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10327        let selections = self
10328            .selections
10329            .all(cx)
10330            .into_iter()
10331            .map(|s| s.range())
10332            .collect();
10333        self.restore_hunks_in_ranges(selections, window, cx);
10334    }
10335
10336    pub fn restore_hunks_in_ranges(
10337        &mut self,
10338        ranges: Vec<Range<Point>>,
10339        window: &mut Window,
10340        cx: &mut Context<Editor>,
10341    ) {
10342        let mut revert_changes = HashMap::default();
10343        let chunk_by = self
10344            .snapshot(window, cx)
10345            .hunks_for_ranges(ranges)
10346            .into_iter()
10347            .chunk_by(|hunk| hunk.buffer_id);
10348        for (buffer_id, hunks) in &chunk_by {
10349            let hunks = hunks.collect::<Vec<_>>();
10350            for hunk in &hunks {
10351                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10352            }
10353            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10354        }
10355        drop(chunk_by);
10356        if !revert_changes.is_empty() {
10357            self.transact(window, cx, |editor, window, cx| {
10358                editor.restore(revert_changes, window, cx);
10359            });
10360        }
10361    }
10362
10363    pub fn open_active_item_in_terminal(
10364        &mut self,
10365        _: &OpenInTerminal,
10366        window: &mut Window,
10367        cx: &mut Context<Self>,
10368    ) {
10369        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10370            let project_path = buffer.read(cx).project_path(cx)?;
10371            let project = self.project.as_ref()?.read(cx);
10372            let entry = project.entry_for_path(&project_path, cx)?;
10373            let parent = match &entry.canonical_path {
10374                Some(canonical_path) => canonical_path.to_path_buf(),
10375                None => project.absolute_path(&project_path, cx)?,
10376            }
10377            .parent()?
10378            .to_path_buf();
10379            Some(parent)
10380        }) {
10381            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10382        }
10383    }
10384
10385    fn set_breakpoint_context_menu(
10386        &mut self,
10387        display_row: DisplayRow,
10388        position: Option<Anchor>,
10389        clicked_point: gpui::Point<Pixels>,
10390        window: &mut Window,
10391        cx: &mut Context<Self>,
10392    ) {
10393        let source = self
10394            .buffer
10395            .read(cx)
10396            .snapshot(cx)
10397            .anchor_before(Point::new(display_row.0, 0u32));
10398
10399        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10400
10401        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10402            self,
10403            source,
10404            clicked_point,
10405            context_menu,
10406            window,
10407            cx,
10408        );
10409    }
10410
10411    fn add_edit_breakpoint_block(
10412        &mut self,
10413        anchor: Anchor,
10414        breakpoint: &Breakpoint,
10415        edit_action: BreakpointPromptEditAction,
10416        window: &mut Window,
10417        cx: &mut Context<Self>,
10418    ) {
10419        let weak_editor = cx.weak_entity();
10420        let bp_prompt = cx.new(|cx| {
10421            BreakpointPromptEditor::new(
10422                weak_editor,
10423                anchor,
10424                breakpoint.clone(),
10425                edit_action,
10426                window,
10427                cx,
10428            )
10429        });
10430
10431        let height = bp_prompt.update(cx, |this, cx| {
10432            this.prompt
10433                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10434        });
10435        let cloned_prompt = bp_prompt.clone();
10436        let blocks = vec![BlockProperties {
10437            style: BlockStyle::Sticky,
10438            placement: BlockPlacement::Above(anchor),
10439            height: Some(height),
10440            render: Arc::new(move |cx| {
10441                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10442                cloned_prompt.clone().into_any_element()
10443            }),
10444            priority: 0,
10445            render_in_minimap: true,
10446        }];
10447
10448        let focus_handle = bp_prompt.focus_handle(cx);
10449        window.focus(&focus_handle);
10450
10451        let block_ids = self.insert_blocks(blocks, None, cx);
10452        bp_prompt.update(cx, |prompt, _| {
10453            prompt.add_block_ids(block_ids);
10454        });
10455    }
10456
10457    pub(crate) fn breakpoint_at_row(
10458        &self,
10459        row: u32,
10460        window: &mut Window,
10461        cx: &mut Context<Self>,
10462    ) -> Option<(Anchor, Breakpoint)> {
10463        let snapshot = self.snapshot(window, cx);
10464        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10465
10466        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10467    }
10468
10469    pub(crate) fn breakpoint_at_anchor(
10470        &self,
10471        breakpoint_position: Anchor,
10472        snapshot: &EditorSnapshot,
10473        cx: &mut Context<Self>,
10474    ) -> Option<(Anchor, Breakpoint)> {
10475        let project = self.project.clone()?;
10476
10477        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10478            snapshot
10479                .buffer_snapshot
10480                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10481        })?;
10482
10483        let enclosing_excerpt = breakpoint_position.excerpt_id;
10484        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10485        let buffer_snapshot = buffer.read(cx).snapshot();
10486
10487        let row = buffer_snapshot
10488            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10489            .row;
10490
10491        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10492        let anchor_end = snapshot
10493            .buffer_snapshot
10494            .anchor_after(Point::new(row, line_len));
10495
10496        let bp = self
10497            .breakpoint_store
10498            .as_ref()?
10499            .read_with(cx, |breakpoint_store, cx| {
10500                breakpoint_store
10501                    .breakpoints(
10502                        &buffer,
10503                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10504                        &buffer_snapshot,
10505                        cx,
10506                    )
10507                    .next()
10508                    .and_then(|(bp, _)| {
10509                        let breakpoint_row = buffer_snapshot
10510                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10511                            .row;
10512
10513                        if breakpoint_row == row {
10514                            snapshot
10515                                .buffer_snapshot
10516                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10517                                .map(|position| (position, bp.bp.clone()))
10518                        } else {
10519                            None
10520                        }
10521                    })
10522            });
10523        bp
10524    }
10525
10526    pub fn edit_log_breakpoint(
10527        &mut self,
10528        _: &EditLogBreakpoint,
10529        window: &mut Window,
10530        cx: &mut Context<Self>,
10531    ) {
10532        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10533            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10534                message: None,
10535                state: BreakpointState::Enabled,
10536                condition: None,
10537                hit_condition: None,
10538            });
10539
10540            self.add_edit_breakpoint_block(
10541                anchor,
10542                &breakpoint,
10543                BreakpointPromptEditAction::Log,
10544                window,
10545                cx,
10546            );
10547        }
10548    }
10549
10550    fn breakpoints_at_cursors(
10551        &self,
10552        window: &mut Window,
10553        cx: &mut Context<Self>,
10554    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10555        let snapshot = self.snapshot(window, cx);
10556        let cursors = self
10557            .selections
10558            .disjoint_anchors()
10559            .into_iter()
10560            .map(|selection| {
10561                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10562
10563                let breakpoint_position = self
10564                    .breakpoint_at_row(cursor_position.row, window, cx)
10565                    .map(|bp| bp.0)
10566                    .unwrap_or_else(|| {
10567                        snapshot
10568                            .display_snapshot
10569                            .buffer_snapshot
10570                            .anchor_after(Point::new(cursor_position.row, 0))
10571                    });
10572
10573                let breakpoint = self
10574                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10575                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10576
10577                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10578            })
10579            // 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.
10580            .collect::<HashMap<Anchor, _>>();
10581
10582        cursors.into_iter().collect()
10583    }
10584
10585    pub fn enable_breakpoint(
10586        &mut self,
10587        _: &crate::actions::EnableBreakpoint,
10588        window: &mut Window,
10589        cx: &mut Context<Self>,
10590    ) {
10591        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10592            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10593                continue;
10594            };
10595            self.edit_breakpoint_at_anchor(
10596                anchor,
10597                breakpoint,
10598                BreakpointEditAction::InvertState,
10599                cx,
10600            );
10601        }
10602    }
10603
10604    pub fn disable_breakpoint(
10605        &mut self,
10606        _: &crate::actions::DisableBreakpoint,
10607        window: &mut Window,
10608        cx: &mut Context<Self>,
10609    ) {
10610        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10611            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10612                continue;
10613            };
10614            self.edit_breakpoint_at_anchor(
10615                anchor,
10616                breakpoint,
10617                BreakpointEditAction::InvertState,
10618                cx,
10619            );
10620        }
10621    }
10622
10623    pub fn toggle_breakpoint(
10624        &mut self,
10625        _: &crate::actions::ToggleBreakpoint,
10626        window: &mut Window,
10627        cx: &mut Context<Self>,
10628    ) {
10629        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10630            if let Some(breakpoint) = breakpoint {
10631                self.edit_breakpoint_at_anchor(
10632                    anchor,
10633                    breakpoint,
10634                    BreakpointEditAction::Toggle,
10635                    cx,
10636                );
10637            } else {
10638                self.edit_breakpoint_at_anchor(
10639                    anchor,
10640                    Breakpoint::new_standard(),
10641                    BreakpointEditAction::Toggle,
10642                    cx,
10643                );
10644            }
10645        }
10646    }
10647
10648    pub fn edit_breakpoint_at_anchor(
10649        &mut self,
10650        breakpoint_position: Anchor,
10651        breakpoint: Breakpoint,
10652        edit_action: BreakpointEditAction,
10653        cx: &mut Context<Self>,
10654    ) {
10655        let Some(breakpoint_store) = &self.breakpoint_store else {
10656            return;
10657        };
10658
10659        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10660            if breakpoint_position == Anchor::min() {
10661                self.buffer()
10662                    .read(cx)
10663                    .excerpt_buffer_ids()
10664                    .into_iter()
10665                    .next()
10666            } else {
10667                None
10668            }
10669        }) else {
10670            return;
10671        };
10672
10673        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10674            return;
10675        };
10676
10677        breakpoint_store.update(cx, |breakpoint_store, cx| {
10678            breakpoint_store.toggle_breakpoint(
10679                buffer,
10680                BreakpointWithPosition {
10681                    position: breakpoint_position.text_anchor,
10682                    bp: breakpoint,
10683                },
10684                edit_action,
10685                cx,
10686            );
10687        });
10688
10689        cx.notify();
10690    }
10691
10692    #[cfg(any(test, feature = "test-support"))]
10693    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10694        self.breakpoint_store.clone()
10695    }
10696
10697    pub fn prepare_restore_change(
10698        &self,
10699        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10700        hunk: &MultiBufferDiffHunk,
10701        cx: &mut App,
10702    ) -> Option<()> {
10703        if hunk.is_created_file() {
10704            return None;
10705        }
10706        let buffer = self.buffer.read(cx);
10707        let diff = buffer.diff_for(hunk.buffer_id)?;
10708        let buffer = buffer.buffer(hunk.buffer_id)?;
10709        let buffer = buffer.read(cx);
10710        let original_text = diff
10711            .read(cx)
10712            .base_text()
10713            .as_rope()
10714            .slice(hunk.diff_base_byte_range.clone());
10715        let buffer_snapshot = buffer.snapshot();
10716        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10717        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10718            probe
10719                .0
10720                .start
10721                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10722                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10723        }) {
10724            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10725            Some(())
10726        } else {
10727            None
10728        }
10729    }
10730
10731    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10732        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10733    }
10734
10735    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10736        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10737    }
10738
10739    fn manipulate_lines<M>(
10740        &mut self,
10741        window: &mut Window,
10742        cx: &mut Context<Self>,
10743        mut manipulate: M,
10744    ) where
10745        M: FnMut(&str) -> LineManipulationResult,
10746    {
10747        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10748
10749        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10750        let buffer = self.buffer.read(cx).snapshot(cx);
10751
10752        let mut edits = Vec::new();
10753
10754        let selections = self.selections.all::<Point>(cx);
10755        let mut selections = selections.iter().peekable();
10756        let mut contiguous_row_selections = Vec::new();
10757        let mut new_selections = Vec::new();
10758        let mut added_lines = 0;
10759        let mut removed_lines = 0;
10760
10761        while let Some(selection) = selections.next() {
10762            let (start_row, end_row) = consume_contiguous_rows(
10763                &mut contiguous_row_selections,
10764                selection,
10765                &display_map,
10766                &mut selections,
10767            );
10768
10769            let start_point = Point::new(start_row.0, 0);
10770            let end_point = Point::new(
10771                end_row.previous_row().0,
10772                buffer.line_len(end_row.previous_row()),
10773            );
10774            let text = buffer
10775                .text_for_range(start_point..end_point)
10776                .collect::<String>();
10777
10778            let LineManipulationResult {
10779                new_text,
10780                line_count_before,
10781                line_count_after,
10782            } = manipulate(&text);
10783
10784            edits.push((start_point..end_point, new_text));
10785
10786            // Selections must change based on added and removed line count
10787            let start_row =
10788                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10789            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10790            new_selections.push(Selection {
10791                id: selection.id,
10792                start: start_row,
10793                end: end_row,
10794                goal: SelectionGoal::None,
10795                reversed: selection.reversed,
10796            });
10797
10798            if line_count_after > line_count_before {
10799                added_lines += line_count_after - line_count_before;
10800            } else if line_count_before > line_count_after {
10801                removed_lines += line_count_before - line_count_after;
10802            }
10803        }
10804
10805        self.transact(window, cx, |this, window, cx| {
10806            let buffer = this.buffer.update(cx, |buffer, cx| {
10807                buffer.edit(edits, None, cx);
10808                buffer.snapshot(cx)
10809            });
10810
10811            // Recalculate offsets on newly edited buffer
10812            let new_selections = new_selections
10813                .iter()
10814                .map(|s| {
10815                    let start_point = Point::new(s.start.0, 0);
10816                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10817                    Selection {
10818                        id: s.id,
10819                        start: buffer.point_to_offset(start_point),
10820                        end: buffer.point_to_offset(end_point),
10821                        goal: s.goal,
10822                        reversed: s.reversed,
10823                    }
10824                })
10825                .collect();
10826
10827            this.change_selections(Default::default(), window, cx, |s| {
10828                s.select(new_selections);
10829            });
10830
10831            this.request_autoscroll(Autoscroll::fit(), cx);
10832        });
10833    }
10834
10835    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10836        self.manipulate_text(window, cx, |text| {
10837            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10838            if has_upper_case_characters {
10839                text.to_lowercase()
10840            } else {
10841                text.to_uppercase()
10842            }
10843        })
10844    }
10845
10846    fn manipulate_immutable_lines<Fn>(
10847        &mut self,
10848        window: &mut Window,
10849        cx: &mut Context<Self>,
10850        mut callback: Fn,
10851    ) where
10852        Fn: FnMut(&mut Vec<&str>),
10853    {
10854        self.manipulate_lines(window, cx, |text| {
10855            let mut lines: Vec<&str> = text.split('\n').collect();
10856            let line_count_before = lines.len();
10857
10858            callback(&mut lines);
10859
10860            LineManipulationResult {
10861                new_text: lines.join("\n"),
10862                line_count_before,
10863                line_count_after: lines.len(),
10864            }
10865        });
10866    }
10867
10868    fn manipulate_mutable_lines<Fn>(
10869        &mut self,
10870        window: &mut Window,
10871        cx: &mut Context<Self>,
10872        mut callback: Fn,
10873    ) where
10874        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10875    {
10876        self.manipulate_lines(window, cx, |text| {
10877            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10878            let line_count_before = lines.len();
10879
10880            callback(&mut lines);
10881
10882            LineManipulationResult {
10883                new_text: lines.join("\n"),
10884                line_count_before,
10885                line_count_after: lines.len(),
10886            }
10887        });
10888    }
10889
10890    pub fn convert_indentation_to_spaces(
10891        &mut self,
10892        _: &ConvertIndentationToSpaces,
10893        window: &mut Window,
10894        cx: &mut Context<Self>,
10895    ) {
10896        let settings = self.buffer.read(cx).language_settings(cx);
10897        let tab_size = settings.tab_size.get() as usize;
10898
10899        self.manipulate_mutable_lines(window, cx, |lines| {
10900            // Allocates a reasonably sized scratch buffer once for the whole loop
10901            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10902            // Avoids recomputing spaces that could be inserted many times
10903            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10904                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10905                .collect();
10906
10907            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10908                let mut chars = line.as_ref().chars();
10909                let mut col = 0;
10910                let mut changed = false;
10911
10912                while let Some(ch) = chars.next() {
10913                    match ch {
10914                        ' ' => {
10915                            reindented_line.push(' ');
10916                            col += 1;
10917                        }
10918                        '\t' => {
10919                            // \t are converted to spaces depending on the current column
10920                            let spaces_len = tab_size - (col % tab_size);
10921                            reindented_line.extend(&space_cache[spaces_len - 1]);
10922                            col += spaces_len;
10923                            changed = true;
10924                        }
10925                        _ => {
10926                            // If we dont append before break, the character is consumed
10927                            reindented_line.push(ch);
10928                            break;
10929                        }
10930                    }
10931                }
10932
10933                if !changed {
10934                    reindented_line.clear();
10935                    continue;
10936                }
10937                // Append the rest of the line and replace old reference with new one
10938                reindented_line.extend(chars);
10939                *line = Cow::Owned(reindented_line.clone());
10940                reindented_line.clear();
10941            }
10942        });
10943    }
10944
10945    pub fn convert_indentation_to_tabs(
10946        &mut self,
10947        _: &ConvertIndentationToTabs,
10948        window: &mut Window,
10949        cx: &mut Context<Self>,
10950    ) {
10951        let settings = self.buffer.read(cx).language_settings(cx);
10952        let tab_size = settings.tab_size.get() as usize;
10953
10954        self.manipulate_mutable_lines(window, cx, |lines| {
10955            // Allocates a reasonably sized buffer once for the whole loop
10956            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10957            // Avoids recomputing spaces that could be inserted many times
10958            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10959                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10960                .collect();
10961
10962            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10963                let mut chars = line.chars();
10964                let mut spaces_count = 0;
10965                let mut first_non_indent_char = None;
10966                let mut changed = false;
10967
10968                while let Some(ch) = chars.next() {
10969                    match ch {
10970                        ' ' => {
10971                            // Keep track of spaces. Append \t when we reach tab_size
10972                            spaces_count += 1;
10973                            changed = true;
10974                            if spaces_count == tab_size {
10975                                reindented_line.push('\t');
10976                                spaces_count = 0;
10977                            }
10978                        }
10979                        '\t' => {
10980                            reindented_line.push('\t');
10981                            spaces_count = 0;
10982                        }
10983                        _ => {
10984                            // Dont append it yet, we might have remaining spaces
10985                            first_non_indent_char = Some(ch);
10986                            break;
10987                        }
10988                    }
10989                }
10990
10991                if !changed {
10992                    reindented_line.clear();
10993                    continue;
10994                }
10995                // Remaining spaces that didn't make a full tab stop
10996                if spaces_count > 0 {
10997                    reindented_line.extend(&space_cache[spaces_count - 1]);
10998                }
10999                // If we consume an extra character that was not indentation, add it back
11000                if let Some(extra_char) = first_non_indent_char {
11001                    reindented_line.push(extra_char);
11002                }
11003                // Append the rest of the line and replace old reference with new one
11004                reindented_line.extend(chars);
11005                *line = Cow::Owned(reindented_line.clone());
11006                reindented_line.clear();
11007            }
11008        });
11009    }
11010
11011    pub fn convert_to_upper_case(
11012        &mut self,
11013        _: &ConvertToUpperCase,
11014        window: &mut Window,
11015        cx: &mut Context<Self>,
11016    ) {
11017        self.manipulate_text(window, cx, |text| text.to_uppercase())
11018    }
11019
11020    pub fn convert_to_lower_case(
11021        &mut self,
11022        _: &ConvertToLowerCase,
11023        window: &mut Window,
11024        cx: &mut Context<Self>,
11025    ) {
11026        self.manipulate_text(window, cx, |text| text.to_lowercase())
11027    }
11028
11029    pub fn convert_to_title_case(
11030        &mut self,
11031        _: &ConvertToTitleCase,
11032        window: &mut Window,
11033        cx: &mut Context<Self>,
11034    ) {
11035        self.manipulate_text(window, cx, |text| {
11036            text.split('\n')
11037                .map(|line| line.to_case(Case::Title))
11038                .join("\n")
11039        })
11040    }
11041
11042    pub fn convert_to_snake_case(
11043        &mut self,
11044        _: &ConvertToSnakeCase,
11045        window: &mut Window,
11046        cx: &mut Context<Self>,
11047    ) {
11048        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11049    }
11050
11051    pub fn convert_to_kebab_case(
11052        &mut self,
11053        _: &ConvertToKebabCase,
11054        window: &mut Window,
11055        cx: &mut Context<Self>,
11056    ) {
11057        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11058    }
11059
11060    pub fn convert_to_upper_camel_case(
11061        &mut self,
11062        _: &ConvertToUpperCamelCase,
11063        window: &mut Window,
11064        cx: &mut Context<Self>,
11065    ) {
11066        self.manipulate_text(window, cx, |text| {
11067            text.split('\n')
11068                .map(|line| line.to_case(Case::UpperCamel))
11069                .join("\n")
11070        })
11071    }
11072
11073    pub fn convert_to_lower_camel_case(
11074        &mut self,
11075        _: &ConvertToLowerCamelCase,
11076        window: &mut Window,
11077        cx: &mut Context<Self>,
11078    ) {
11079        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11080    }
11081
11082    pub fn convert_to_opposite_case(
11083        &mut self,
11084        _: &ConvertToOppositeCase,
11085        window: &mut Window,
11086        cx: &mut Context<Self>,
11087    ) {
11088        self.manipulate_text(window, cx, |text| {
11089            text.chars()
11090                .fold(String::with_capacity(text.len()), |mut t, c| {
11091                    if c.is_uppercase() {
11092                        t.extend(c.to_lowercase());
11093                    } else {
11094                        t.extend(c.to_uppercase());
11095                    }
11096                    t
11097                })
11098        })
11099    }
11100
11101    pub fn convert_to_rot13(
11102        &mut self,
11103        _: &ConvertToRot13,
11104        window: &mut Window,
11105        cx: &mut Context<Self>,
11106    ) {
11107        self.manipulate_text(window, cx, |text| {
11108            text.chars()
11109                .map(|c| match c {
11110                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11111                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11112                    _ => c,
11113                })
11114                .collect()
11115        })
11116    }
11117
11118    pub fn convert_to_rot47(
11119        &mut self,
11120        _: &ConvertToRot47,
11121        window: &mut Window,
11122        cx: &mut Context<Self>,
11123    ) {
11124        self.manipulate_text(window, cx, |text| {
11125            text.chars()
11126                .map(|c| {
11127                    let code_point = c as u32;
11128                    if code_point >= 33 && code_point <= 126 {
11129                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11130                    }
11131                    c
11132                })
11133                .collect()
11134        })
11135    }
11136
11137    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11138    where
11139        Fn: FnMut(&str) -> String,
11140    {
11141        let buffer = self.buffer.read(cx).snapshot(cx);
11142
11143        let mut new_selections = Vec::new();
11144        let mut edits = Vec::new();
11145        let mut selection_adjustment = 0i32;
11146
11147        for selection in self.selections.all::<usize>(cx) {
11148            let selection_is_empty = selection.is_empty();
11149
11150            let (start, end) = if selection_is_empty {
11151                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11152                (word_range.start, word_range.end)
11153            } else {
11154                (selection.start, selection.end)
11155            };
11156
11157            let text = buffer.text_for_range(start..end).collect::<String>();
11158            let old_length = text.len() as i32;
11159            let text = callback(&text);
11160
11161            new_selections.push(Selection {
11162                start: (start as i32 - selection_adjustment) as usize,
11163                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11164                goal: SelectionGoal::None,
11165                ..selection
11166            });
11167
11168            selection_adjustment += old_length - text.len() as i32;
11169
11170            edits.push((start..end, text));
11171        }
11172
11173        self.transact(window, cx, |this, window, cx| {
11174            this.buffer.update(cx, |buffer, cx| {
11175                buffer.edit(edits, None, cx);
11176            });
11177
11178            this.change_selections(Default::default(), window, cx, |s| {
11179                s.select(new_selections);
11180            });
11181
11182            this.request_autoscroll(Autoscroll::fit(), cx);
11183        });
11184    }
11185
11186    pub fn move_selection_on_drop(
11187        &mut self,
11188        selection: &Selection<Anchor>,
11189        target: DisplayPoint,
11190        is_cut: bool,
11191        window: &mut Window,
11192        cx: &mut Context<Self>,
11193    ) {
11194        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11195        let buffer = &display_map.buffer_snapshot;
11196        let mut edits = Vec::new();
11197        let insert_point = display_map
11198            .clip_point(target, Bias::Left)
11199            .to_point(&display_map);
11200        let text = buffer
11201            .text_for_range(selection.start..selection.end)
11202            .collect::<String>();
11203        if is_cut {
11204            edits.push(((selection.start..selection.end), String::new()));
11205        }
11206        let insert_anchor = buffer.anchor_before(insert_point);
11207        edits.push(((insert_anchor..insert_anchor), text));
11208        let last_edit_start = insert_anchor.bias_left(buffer);
11209        let last_edit_end = insert_anchor.bias_right(buffer);
11210        self.transact(window, cx, |this, window, cx| {
11211            this.buffer.update(cx, |buffer, cx| {
11212                buffer.edit(edits, None, cx);
11213            });
11214            this.change_selections(Default::default(), window, cx, |s| {
11215                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11216            });
11217        });
11218    }
11219
11220    pub fn clear_selection_drag_state(&mut self) {
11221        self.selection_drag_state = SelectionDragState::None;
11222    }
11223
11224    pub fn duplicate(
11225        &mut self,
11226        upwards: bool,
11227        whole_lines: bool,
11228        window: &mut Window,
11229        cx: &mut Context<Self>,
11230    ) {
11231        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11232
11233        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11234        let buffer = &display_map.buffer_snapshot;
11235        let selections = self.selections.all::<Point>(cx);
11236
11237        let mut edits = Vec::new();
11238        let mut selections_iter = selections.iter().peekable();
11239        while let Some(selection) = selections_iter.next() {
11240            let mut rows = selection.spanned_rows(false, &display_map);
11241            // duplicate line-wise
11242            if whole_lines || selection.start == selection.end {
11243                // Avoid duplicating the same lines twice.
11244                while let Some(next_selection) = selections_iter.peek() {
11245                    let next_rows = next_selection.spanned_rows(false, &display_map);
11246                    if next_rows.start < rows.end {
11247                        rows.end = next_rows.end;
11248                        selections_iter.next().unwrap();
11249                    } else {
11250                        break;
11251                    }
11252                }
11253
11254                // Copy the text from the selected row region and splice it either at the start
11255                // or end of the region.
11256                let start = Point::new(rows.start.0, 0);
11257                let end = Point::new(
11258                    rows.end.previous_row().0,
11259                    buffer.line_len(rows.end.previous_row()),
11260                );
11261                let text = buffer
11262                    .text_for_range(start..end)
11263                    .chain(Some("\n"))
11264                    .collect::<String>();
11265                let insert_location = if upwards {
11266                    Point::new(rows.end.0, 0)
11267                } else {
11268                    start
11269                };
11270                edits.push((insert_location..insert_location, text));
11271            } else {
11272                // duplicate character-wise
11273                let start = selection.start;
11274                let end = selection.end;
11275                let text = buffer.text_for_range(start..end).collect::<String>();
11276                edits.push((selection.end..selection.end, text));
11277            }
11278        }
11279
11280        self.transact(window, cx, |this, _, cx| {
11281            this.buffer.update(cx, |buffer, cx| {
11282                buffer.edit(edits, None, cx);
11283            });
11284
11285            this.request_autoscroll(Autoscroll::fit(), cx);
11286        });
11287    }
11288
11289    pub fn duplicate_line_up(
11290        &mut self,
11291        _: &DuplicateLineUp,
11292        window: &mut Window,
11293        cx: &mut Context<Self>,
11294    ) {
11295        self.duplicate(true, true, window, cx);
11296    }
11297
11298    pub fn duplicate_line_down(
11299        &mut self,
11300        _: &DuplicateLineDown,
11301        window: &mut Window,
11302        cx: &mut Context<Self>,
11303    ) {
11304        self.duplicate(false, true, window, cx);
11305    }
11306
11307    pub fn duplicate_selection(
11308        &mut self,
11309        _: &DuplicateSelection,
11310        window: &mut Window,
11311        cx: &mut Context<Self>,
11312    ) {
11313        self.duplicate(false, false, window, cx);
11314    }
11315
11316    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11318        if self.mode.is_single_line() {
11319            cx.propagate();
11320            return;
11321        }
11322
11323        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11324        let buffer = self.buffer.read(cx).snapshot(cx);
11325
11326        let mut edits = Vec::new();
11327        let mut unfold_ranges = Vec::new();
11328        let mut refold_creases = Vec::new();
11329
11330        let selections = self.selections.all::<Point>(cx);
11331        let mut selections = selections.iter().peekable();
11332        let mut contiguous_row_selections = Vec::new();
11333        let mut new_selections = Vec::new();
11334
11335        while let Some(selection) = selections.next() {
11336            // Find all the selections that span a contiguous row range
11337            let (start_row, end_row) = consume_contiguous_rows(
11338                &mut contiguous_row_selections,
11339                selection,
11340                &display_map,
11341                &mut selections,
11342            );
11343
11344            // Move the text spanned by the row range to be before the line preceding the row range
11345            if start_row.0 > 0 {
11346                let range_to_move = Point::new(
11347                    start_row.previous_row().0,
11348                    buffer.line_len(start_row.previous_row()),
11349                )
11350                    ..Point::new(
11351                        end_row.previous_row().0,
11352                        buffer.line_len(end_row.previous_row()),
11353                    );
11354                let insertion_point = display_map
11355                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11356                    .0;
11357
11358                // Don't move lines across excerpts
11359                if buffer
11360                    .excerpt_containing(insertion_point..range_to_move.end)
11361                    .is_some()
11362                {
11363                    let text = buffer
11364                        .text_for_range(range_to_move.clone())
11365                        .flat_map(|s| s.chars())
11366                        .skip(1)
11367                        .chain(['\n'])
11368                        .collect::<String>();
11369
11370                    edits.push((
11371                        buffer.anchor_after(range_to_move.start)
11372                            ..buffer.anchor_before(range_to_move.end),
11373                        String::new(),
11374                    ));
11375                    let insertion_anchor = buffer.anchor_after(insertion_point);
11376                    edits.push((insertion_anchor..insertion_anchor, text));
11377
11378                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11379
11380                    // Move selections up
11381                    new_selections.extend(contiguous_row_selections.drain(..).map(
11382                        |mut selection| {
11383                            selection.start.row -= row_delta;
11384                            selection.end.row -= row_delta;
11385                            selection
11386                        },
11387                    ));
11388
11389                    // Move folds up
11390                    unfold_ranges.push(range_to_move.clone());
11391                    for fold in display_map.folds_in_range(
11392                        buffer.anchor_before(range_to_move.start)
11393                            ..buffer.anchor_after(range_to_move.end),
11394                    ) {
11395                        let mut start = fold.range.start.to_point(&buffer);
11396                        let mut end = fold.range.end.to_point(&buffer);
11397                        start.row -= row_delta;
11398                        end.row -= row_delta;
11399                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11400                    }
11401                }
11402            }
11403
11404            // If we didn't move line(s), preserve the existing selections
11405            new_selections.append(&mut contiguous_row_selections);
11406        }
11407
11408        self.transact(window, cx, |this, window, cx| {
11409            this.unfold_ranges(&unfold_ranges, true, true, cx);
11410            this.buffer.update(cx, |buffer, cx| {
11411                for (range, text) in edits {
11412                    buffer.edit([(range, text)], None, cx);
11413                }
11414            });
11415            this.fold_creases(refold_creases, true, window, cx);
11416            this.change_selections(Default::default(), window, cx, |s| {
11417                s.select(new_selections);
11418            })
11419        });
11420    }
11421
11422    pub fn move_line_down(
11423        &mut self,
11424        _: &MoveLineDown,
11425        window: &mut Window,
11426        cx: &mut Context<Self>,
11427    ) {
11428        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11429        if self.mode.is_single_line() {
11430            cx.propagate();
11431            return;
11432        }
11433
11434        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11435        let buffer = self.buffer.read(cx).snapshot(cx);
11436
11437        let mut edits = Vec::new();
11438        let mut unfold_ranges = Vec::new();
11439        let mut refold_creases = Vec::new();
11440
11441        let selections = self.selections.all::<Point>(cx);
11442        let mut selections = selections.iter().peekable();
11443        let mut contiguous_row_selections = Vec::new();
11444        let mut new_selections = Vec::new();
11445
11446        while let Some(selection) = selections.next() {
11447            // Find all the selections that span a contiguous row range
11448            let (start_row, end_row) = consume_contiguous_rows(
11449                &mut contiguous_row_selections,
11450                selection,
11451                &display_map,
11452                &mut selections,
11453            );
11454
11455            // Move the text spanned by the row range to be after the last line of the row range
11456            if end_row.0 <= buffer.max_point().row {
11457                let range_to_move =
11458                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11459                let insertion_point = display_map
11460                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11461                    .0;
11462
11463                // Don't move lines across excerpt boundaries
11464                if buffer
11465                    .excerpt_containing(range_to_move.start..insertion_point)
11466                    .is_some()
11467                {
11468                    let mut text = String::from("\n");
11469                    text.extend(buffer.text_for_range(range_to_move.clone()));
11470                    text.pop(); // Drop trailing newline
11471                    edits.push((
11472                        buffer.anchor_after(range_to_move.start)
11473                            ..buffer.anchor_before(range_to_move.end),
11474                        String::new(),
11475                    ));
11476                    let insertion_anchor = buffer.anchor_after(insertion_point);
11477                    edits.push((insertion_anchor..insertion_anchor, text));
11478
11479                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11480
11481                    // Move selections down
11482                    new_selections.extend(contiguous_row_selections.drain(..).map(
11483                        |mut selection| {
11484                            selection.start.row += row_delta;
11485                            selection.end.row += row_delta;
11486                            selection
11487                        },
11488                    ));
11489
11490                    // Move folds down
11491                    unfold_ranges.push(range_to_move.clone());
11492                    for fold in display_map.folds_in_range(
11493                        buffer.anchor_before(range_to_move.start)
11494                            ..buffer.anchor_after(range_to_move.end),
11495                    ) {
11496                        let mut start = fold.range.start.to_point(&buffer);
11497                        let mut end = fold.range.end.to_point(&buffer);
11498                        start.row += row_delta;
11499                        end.row += row_delta;
11500                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11501                    }
11502                }
11503            }
11504
11505            // If we didn't move line(s), preserve the existing selections
11506            new_selections.append(&mut contiguous_row_selections);
11507        }
11508
11509        self.transact(window, cx, |this, window, cx| {
11510            this.unfold_ranges(&unfold_ranges, true, true, cx);
11511            this.buffer.update(cx, |buffer, cx| {
11512                for (range, text) in edits {
11513                    buffer.edit([(range, text)], None, cx);
11514                }
11515            });
11516            this.fold_creases(refold_creases, true, window, cx);
11517            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11518        });
11519    }
11520
11521    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11522        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11523        let text_layout_details = &self.text_layout_details(window);
11524        self.transact(window, cx, |this, window, cx| {
11525            let edits = this.change_selections(Default::default(), window, cx, |s| {
11526                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11527                s.move_with(|display_map, selection| {
11528                    if !selection.is_empty() {
11529                        return;
11530                    }
11531
11532                    let mut head = selection.head();
11533                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11534                    if head.column() == display_map.line_len(head.row()) {
11535                        transpose_offset = display_map
11536                            .buffer_snapshot
11537                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11538                    }
11539
11540                    if transpose_offset == 0 {
11541                        return;
11542                    }
11543
11544                    *head.column_mut() += 1;
11545                    head = display_map.clip_point(head, Bias::Right);
11546                    let goal = SelectionGoal::HorizontalPosition(
11547                        display_map
11548                            .x_for_display_point(head, text_layout_details)
11549                            .into(),
11550                    );
11551                    selection.collapse_to(head, goal);
11552
11553                    let transpose_start = display_map
11554                        .buffer_snapshot
11555                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11556                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11557                        let transpose_end = display_map
11558                            .buffer_snapshot
11559                            .clip_offset(transpose_offset + 1, Bias::Right);
11560                        if let Some(ch) =
11561                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11562                        {
11563                            edits.push((transpose_start..transpose_offset, String::new()));
11564                            edits.push((transpose_end..transpose_end, ch.to_string()));
11565                        }
11566                    }
11567                });
11568                edits
11569            });
11570            this.buffer
11571                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11572            let selections = this.selections.all::<usize>(cx);
11573            this.change_selections(Default::default(), window, cx, |s| {
11574                s.select(selections);
11575            });
11576        });
11577    }
11578
11579    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11580        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11581        if self.mode.is_single_line() {
11582            cx.propagate();
11583            return;
11584        }
11585
11586        self.rewrap_impl(RewrapOptions::default(), cx)
11587    }
11588
11589    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11590        let buffer = self.buffer.read(cx).snapshot(cx);
11591        let selections = self.selections.all::<Point>(cx);
11592
11593        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11594        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11595            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11596                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11597                .peekable();
11598
11599            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11600                row
11601            } else {
11602                return Vec::new();
11603            };
11604
11605            let language_settings = buffer.language_settings_at(selection.head(), cx);
11606            let language_scope = buffer.language_scope_at(selection.head());
11607
11608            let indent_and_prefix_for_row =
11609                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11610                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11611                    let (comment_prefix, rewrap_prefix) =
11612                        if let Some(language_scope) = &language_scope {
11613                            let indent_end = Point::new(row, indent.len);
11614                            let comment_prefix = language_scope
11615                                .line_comment_prefixes()
11616                                .iter()
11617                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11618                                .map(|prefix| prefix.to_string());
11619                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11620                            let line_text_after_indent = buffer
11621                                .text_for_range(indent_end..line_end)
11622                                .collect::<String>();
11623                            let rewrap_prefix = language_scope
11624                                .rewrap_prefixes()
11625                                .iter()
11626                                .find_map(|prefix_regex| {
11627                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11628                                        if mat.start() == 0 {
11629                                            Some(mat.as_str().to_string())
11630                                        } else {
11631                                            None
11632                                        }
11633                                    })
11634                                })
11635                                .flatten();
11636                            (comment_prefix, rewrap_prefix)
11637                        } else {
11638                            (None, None)
11639                        };
11640                    (indent, comment_prefix, rewrap_prefix)
11641                };
11642
11643            let mut ranges = Vec::new();
11644            let from_empty_selection = selection.is_empty();
11645
11646            let mut current_range_start = first_row;
11647            let mut prev_row = first_row;
11648            let (
11649                mut current_range_indent,
11650                mut current_range_comment_prefix,
11651                mut current_range_rewrap_prefix,
11652            ) = indent_and_prefix_for_row(first_row);
11653
11654            for row in non_blank_rows_iter.skip(1) {
11655                let has_paragraph_break = row > prev_row + 1;
11656
11657                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11658                    indent_and_prefix_for_row(row);
11659
11660                let has_indent_change = row_indent != current_range_indent;
11661                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11662
11663                let has_boundary_change = has_comment_change
11664                    || row_rewrap_prefix.is_some()
11665                    || (has_indent_change && current_range_comment_prefix.is_some());
11666
11667                if has_paragraph_break || has_boundary_change {
11668                    ranges.push((
11669                        language_settings.clone(),
11670                        Point::new(current_range_start, 0)
11671                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11672                        current_range_indent,
11673                        current_range_comment_prefix.clone(),
11674                        current_range_rewrap_prefix.clone(),
11675                        from_empty_selection,
11676                    ));
11677                    current_range_start = row;
11678                    current_range_indent = row_indent;
11679                    current_range_comment_prefix = row_comment_prefix;
11680                    current_range_rewrap_prefix = row_rewrap_prefix;
11681                }
11682                prev_row = row;
11683            }
11684
11685            ranges.push((
11686                language_settings.clone(),
11687                Point::new(current_range_start, 0)
11688                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11689                current_range_indent,
11690                current_range_comment_prefix,
11691                current_range_rewrap_prefix,
11692                from_empty_selection,
11693            ));
11694
11695            ranges
11696        });
11697
11698        let mut edits = Vec::new();
11699        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11700
11701        for (
11702            language_settings,
11703            wrap_range,
11704            indent_size,
11705            comment_prefix,
11706            rewrap_prefix,
11707            from_empty_selection,
11708        ) in wrap_ranges
11709        {
11710            let mut start_row = wrap_range.start.row;
11711            let mut end_row = wrap_range.end.row;
11712
11713            // Skip selections that overlap with a range that has already been rewrapped.
11714            let selection_range = start_row..end_row;
11715            if rewrapped_row_ranges
11716                .iter()
11717                .any(|range| range.overlaps(&selection_range))
11718            {
11719                continue;
11720            }
11721
11722            let tab_size = language_settings.tab_size;
11723
11724            let indent_prefix = indent_size.chars().collect::<String>();
11725            let mut line_prefix = indent_prefix.clone();
11726            let mut inside_comment = false;
11727            if let Some(prefix) = &comment_prefix {
11728                line_prefix.push_str(prefix);
11729                inside_comment = true;
11730            }
11731            if let Some(prefix) = &rewrap_prefix {
11732                line_prefix.push_str(prefix);
11733            }
11734
11735            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11736                RewrapBehavior::InComments => inside_comment,
11737                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11738                RewrapBehavior::Anywhere => true,
11739            };
11740
11741            let should_rewrap = options.override_language_settings
11742                || allow_rewrap_based_on_language
11743                || self.hard_wrap.is_some();
11744            if !should_rewrap {
11745                continue;
11746            }
11747
11748            if from_empty_selection {
11749                'expand_upwards: while start_row > 0 {
11750                    let prev_row = start_row - 1;
11751                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11752                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11753                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11754                    {
11755                        start_row = prev_row;
11756                    } else {
11757                        break 'expand_upwards;
11758                    }
11759                }
11760
11761                'expand_downwards: while end_row < buffer.max_point().row {
11762                    let next_row = end_row + 1;
11763                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11764                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11765                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11766                    {
11767                        end_row = next_row;
11768                    } else {
11769                        break 'expand_downwards;
11770                    }
11771                }
11772            }
11773
11774            let start = Point::new(start_row, 0);
11775            let start_offset = start.to_offset(&buffer);
11776            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11777            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11778            let Some(lines_without_prefixes) = selection_text
11779                .lines()
11780                .enumerate()
11781                .map(|(ix, line)| {
11782                    let line_trimmed = line.trim_start();
11783                    if rewrap_prefix.is_some() && ix > 0 {
11784                        Ok(line_trimmed)
11785                    } else {
11786                        line_trimmed
11787                            .strip_prefix(&line_prefix.trim_start())
11788                            .with_context(|| {
11789                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11790                            })
11791                    }
11792                })
11793                .collect::<Result<Vec<_>, _>>()
11794                .log_err()
11795            else {
11796                continue;
11797            };
11798
11799            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11800                buffer
11801                    .language_settings_at(Point::new(start_row, 0), cx)
11802                    .preferred_line_length as usize
11803            });
11804
11805            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11806                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11807            } else {
11808                line_prefix.clone()
11809            };
11810
11811            let wrapped_text = wrap_with_prefix(
11812                line_prefix,
11813                subsequent_lines_prefix,
11814                lines_without_prefixes.join("\n"),
11815                wrap_column,
11816                tab_size,
11817                options.preserve_existing_whitespace,
11818            );
11819
11820            // TODO: should always use char-based diff while still supporting cursor behavior that
11821            // matches vim.
11822            let mut diff_options = DiffOptions::default();
11823            if options.override_language_settings {
11824                diff_options.max_word_diff_len = 0;
11825                diff_options.max_word_diff_line_count = 0;
11826            } else {
11827                diff_options.max_word_diff_len = usize::MAX;
11828                diff_options.max_word_diff_line_count = usize::MAX;
11829            }
11830
11831            for (old_range, new_text) in
11832                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11833            {
11834                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11835                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11836                edits.push((edit_start..edit_end, new_text));
11837            }
11838
11839            rewrapped_row_ranges.push(start_row..=end_row);
11840        }
11841
11842        self.buffer
11843            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11844    }
11845
11846    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11847        let mut text = String::new();
11848        let buffer = self.buffer.read(cx).snapshot(cx);
11849        let mut selections = self.selections.all::<Point>(cx);
11850        let mut clipboard_selections = Vec::with_capacity(selections.len());
11851        {
11852            let max_point = buffer.max_point();
11853            let mut is_first = true;
11854            for selection in &mut selections {
11855                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11856                if is_entire_line {
11857                    selection.start = Point::new(selection.start.row, 0);
11858                    if !selection.is_empty() && selection.end.column == 0 {
11859                        selection.end = cmp::min(max_point, selection.end);
11860                    } else {
11861                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11862                    }
11863                    selection.goal = SelectionGoal::None;
11864                }
11865                if is_first {
11866                    is_first = false;
11867                } else {
11868                    text += "\n";
11869                }
11870                let mut len = 0;
11871                for chunk in buffer.text_for_range(selection.start..selection.end) {
11872                    text.push_str(chunk);
11873                    len += chunk.len();
11874                }
11875                clipboard_selections.push(ClipboardSelection {
11876                    len,
11877                    is_entire_line,
11878                    first_line_indent: buffer
11879                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11880                        .len,
11881                });
11882            }
11883        }
11884
11885        self.transact(window, cx, |this, window, cx| {
11886            this.change_selections(Default::default(), window, cx, |s| {
11887                s.select(selections);
11888            });
11889            this.insert("", window, cx);
11890        });
11891        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11892    }
11893
11894    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11895        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11896        let item = self.cut_common(window, cx);
11897        cx.write_to_clipboard(item);
11898    }
11899
11900    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11901        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11902        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11903            s.move_with(|snapshot, sel| {
11904                if sel.is_empty() {
11905                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11906                }
11907            });
11908        });
11909        let item = self.cut_common(window, cx);
11910        cx.set_global(KillRing(item))
11911    }
11912
11913    pub fn kill_ring_yank(
11914        &mut self,
11915        _: &KillRingYank,
11916        window: &mut Window,
11917        cx: &mut Context<Self>,
11918    ) {
11919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11920        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11921            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11922                (kill_ring.text().to_string(), kill_ring.metadata_json())
11923            } else {
11924                return;
11925            }
11926        } else {
11927            return;
11928        };
11929        self.do_paste(&text, metadata, false, window, cx);
11930    }
11931
11932    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11933        self.do_copy(true, cx);
11934    }
11935
11936    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11937        self.do_copy(false, cx);
11938    }
11939
11940    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11941        let selections = self.selections.all::<Point>(cx);
11942        let buffer = self.buffer.read(cx).read(cx);
11943        let mut text = String::new();
11944
11945        let mut clipboard_selections = Vec::with_capacity(selections.len());
11946        {
11947            let max_point = buffer.max_point();
11948            let mut is_first = true;
11949            for selection in &selections {
11950                let mut start = selection.start;
11951                let mut end = selection.end;
11952                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11953                if is_entire_line {
11954                    start = Point::new(start.row, 0);
11955                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11956                }
11957
11958                let mut trimmed_selections = Vec::new();
11959                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11960                    let row = MultiBufferRow(start.row);
11961                    let first_indent = buffer.indent_size_for_line(row);
11962                    if first_indent.len == 0 || start.column > first_indent.len {
11963                        trimmed_selections.push(start..end);
11964                    } else {
11965                        trimmed_selections.push(
11966                            Point::new(row.0, first_indent.len)
11967                                ..Point::new(row.0, buffer.line_len(row)),
11968                        );
11969                        for row in start.row + 1..=end.row {
11970                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11971                            if row == end.row {
11972                                line_len = end.column;
11973                            }
11974                            if line_len == 0 {
11975                                trimmed_selections
11976                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11977                                continue;
11978                            }
11979                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11980                            if row_indent_size.len >= first_indent.len {
11981                                trimmed_selections.push(
11982                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11983                                );
11984                            } else {
11985                                trimmed_selections.clear();
11986                                trimmed_selections.push(start..end);
11987                                break;
11988                            }
11989                        }
11990                    }
11991                } else {
11992                    trimmed_selections.push(start..end);
11993                }
11994
11995                for trimmed_range in trimmed_selections {
11996                    if is_first {
11997                        is_first = false;
11998                    } else {
11999                        text += "\n";
12000                    }
12001                    let mut len = 0;
12002                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12003                        text.push_str(chunk);
12004                        len += chunk.len();
12005                    }
12006                    clipboard_selections.push(ClipboardSelection {
12007                        len,
12008                        is_entire_line,
12009                        first_line_indent: buffer
12010                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12011                            .len,
12012                    });
12013                }
12014            }
12015        }
12016
12017        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12018            text,
12019            clipboard_selections,
12020        ));
12021    }
12022
12023    pub fn do_paste(
12024        &mut self,
12025        text: &String,
12026        clipboard_selections: Option<Vec<ClipboardSelection>>,
12027        handle_entire_lines: bool,
12028        window: &mut Window,
12029        cx: &mut Context<Self>,
12030    ) {
12031        if self.read_only(cx) {
12032            return;
12033        }
12034
12035        let clipboard_text = Cow::Borrowed(text);
12036
12037        self.transact(window, cx, |this, window, cx| {
12038            if let Some(mut clipboard_selections) = clipboard_selections {
12039                let old_selections = this.selections.all::<usize>(cx);
12040                let all_selections_were_entire_line =
12041                    clipboard_selections.iter().all(|s| s.is_entire_line);
12042                let first_selection_indent_column =
12043                    clipboard_selections.first().map(|s| s.first_line_indent);
12044                if clipboard_selections.len() != old_selections.len() {
12045                    clipboard_selections.drain(..);
12046                }
12047                let cursor_offset = this.selections.last::<usize>(cx).head();
12048                let mut auto_indent_on_paste = true;
12049
12050                this.buffer.update(cx, |buffer, cx| {
12051                    let snapshot = buffer.read(cx);
12052                    auto_indent_on_paste = snapshot
12053                        .language_settings_at(cursor_offset, cx)
12054                        .auto_indent_on_paste;
12055
12056                    let mut start_offset = 0;
12057                    let mut edits = Vec::new();
12058                    let mut original_indent_columns = Vec::new();
12059                    for (ix, selection) in old_selections.iter().enumerate() {
12060                        let to_insert;
12061                        let entire_line;
12062                        let original_indent_column;
12063                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12064                            let end_offset = start_offset + clipboard_selection.len;
12065                            to_insert = &clipboard_text[start_offset..end_offset];
12066                            entire_line = clipboard_selection.is_entire_line;
12067                            start_offset = end_offset + 1;
12068                            original_indent_column = Some(clipboard_selection.first_line_indent);
12069                        } else {
12070                            to_insert = clipboard_text.as_str();
12071                            entire_line = all_selections_were_entire_line;
12072                            original_indent_column = first_selection_indent_column
12073                        }
12074
12075                        // If the corresponding selection was empty when this slice of the
12076                        // clipboard text was written, then the entire line containing the
12077                        // selection was copied. If this selection is also currently empty,
12078                        // then paste the line before the current line of the buffer.
12079                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12080                            let column = selection.start.to_point(&snapshot).column as usize;
12081                            let line_start = selection.start - column;
12082                            line_start..line_start
12083                        } else {
12084                            selection.range()
12085                        };
12086
12087                        edits.push((range, to_insert));
12088                        original_indent_columns.push(original_indent_column);
12089                    }
12090                    drop(snapshot);
12091
12092                    buffer.edit(
12093                        edits,
12094                        if auto_indent_on_paste {
12095                            Some(AutoindentMode::Block {
12096                                original_indent_columns,
12097                            })
12098                        } else {
12099                            None
12100                        },
12101                        cx,
12102                    );
12103                });
12104
12105                let selections = this.selections.all::<usize>(cx);
12106                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12107            } else {
12108                this.insert(&clipboard_text, window, cx);
12109            }
12110        });
12111    }
12112
12113    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12114        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12115        if let Some(item) = cx.read_from_clipboard() {
12116            let entries = item.entries();
12117
12118            match entries.first() {
12119                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12120                // of all the pasted entries.
12121                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12122                    .do_paste(
12123                        clipboard_string.text(),
12124                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12125                        true,
12126                        window,
12127                        cx,
12128                    ),
12129                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12130            }
12131        }
12132    }
12133
12134    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12135        if self.read_only(cx) {
12136            return;
12137        }
12138
12139        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12140
12141        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12142            if let Some((selections, _)) =
12143                self.selection_history.transaction(transaction_id).cloned()
12144            {
12145                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12146                    s.select_anchors(selections.to_vec());
12147                });
12148            } else {
12149                log::error!(
12150                    "No entry in selection_history found for undo. \
12151                     This may correspond to a bug where undo does not update the selection. \
12152                     If this is occurring, please add details to \
12153                     https://github.com/zed-industries/zed/issues/22692"
12154                );
12155            }
12156            self.request_autoscroll(Autoscroll::fit(), cx);
12157            self.unmark_text(window, cx);
12158            self.refresh_inline_completion(true, false, window, cx);
12159            cx.emit(EditorEvent::Edited { transaction_id });
12160            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12161        }
12162    }
12163
12164    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12165        if self.read_only(cx) {
12166            return;
12167        }
12168
12169        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12170
12171        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12172            if let Some((_, Some(selections))) =
12173                self.selection_history.transaction(transaction_id).cloned()
12174            {
12175                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12176                    s.select_anchors(selections.to_vec());
12177                });
12178            } else {
12179                log::error!(
12180                    "No entry in selection_history found for redo. \
12181                     This may correspond to a bug where undo does not update the selection. \
12182                     If this is occurring, please add details to \
12183                     https://github.com/zed-industries/zed/issues/22692"
12184                );
12185            }
12186            self.request_autoscroll(Autoscroll::fit(), cx);
12187            self.unmark_text(window, cx);
12188            self.refresh_inline_completion(true, false, window, cx);
12189            cx.emit(EditorEvent::Edited { transaction_id });
12190        }
12191    }
12192
12193    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12194        self.buffer
12195            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12196    }
12197
12198    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12199        self.buffer
12200            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12201    }
12202
12203    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12204        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12205        self.change_selections(Default::default(), window, cx, |s| {
12206            s.move_with(|map, selection| {
12207                let cursor = if selection.is_empty() {
12208                    movement::left(map, selection.start)
12209                } else {
12210                    selection.start
12211                };
12212                selection.collapse_to(cursor, SelectionGoal::None);
12213            });
12214        })
12215    }
12216
12217    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12219        self.change_selections(Default::default(), window, cx, |s| {
12220            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12221        })
12222    }
12223
12224    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12225        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12226        self.change_selections(Default::default(), window, cx, |s| {
12227            s.move_with(|map, selection| {
12228                let cursor = if selection.is_empty() {
12229                    movement::right(map, selection.end)
12230                } else {
12231                    selection.end
12232                };
12233                selection.collapse_to(cursor, SelectionGoal::None)
12234            });
12235        })
12236    }
12237
12238    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12239        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12240        self.change_selections(Default::default(), window, cx, |s| {
12241            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12242        })
12243    }
12244
12245    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12246        if self.take_rename(true, window, cx).is_some() {
12247            return;
12248        }
12249
12250        if self.mode.is_single_line() {
12251            cx.propagate();
12252            return;
12253        }
12254
12255        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12256
12257        let text_layout_details = &self.text_layout_details(window);
12258        let selection_count = self.selections.count();
12259        let first_selection = self.selections.first_anchor();
12260
12261        self.change_selections(Default::default(), window, cx, |s| {
12262            s.move_with(|map, selection| {
12263                if !selection.is_empty() {
12264                    selection.goal = SelectionGoal::None;
12265                }
12266                let (cursor, goal) = movement::up(
12267                    map,
12268                    selection.start,
12269                    selection.goal,
12270                    false,
12271                    text_layout_details,
12272                );
12273                selection.collapse_to(cursor, goal);
12274            });
12275        });
12276
12277        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12278        {
12279            cx.propagate();
12280        }
12281    }
12282
12283    pub fn move_up_by_lines(
12284        &mut self,
12285        action: &MoveUpByLines,
12286        window: &mut Window,
12287        cx: &mut Context<Self>,
12288    ) {
12289        if self.take_rename(true, window, cx).is_some() {
12290            return;
12291        }
12292
12293        if self.mode.is_single_line() {
12294            cx.propagate();
12295            return;
12296        }
12297
12298        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12299
12300        let text_layout_details = &self.text_layout_details(window);
12301
12302        self.change_selections(Default::default(), window, cx, |s| {
12303            s.move_with(|map, selection| {
12304                if !selection.is_empty() {
12305                    selection.goal = SelectionGoal::None;
12306                }
12307                let (cursor, goal) = movement::up_by_rows(
12308                    map,
12309                    selection.start,
12310                    action.lines,
12311                    selection.goal,
12312                    false,
12313                    text_layout_details,
12314                );
12315                selection.collapse_to(cursor, goal);
12316            });
12317        })
12318    }
12319
12320    pub fn move_down_by_lines(
12321        &mut self,
12322        action: &MoveDownByLines,
12323        window: &mut Window,
12324        cx: &mut Context<Self>,
12325    ) {
12326        if self.take_rename(true, window, cx).is_some() {
12327            return;
12328        }
12329
12330        if self.mode.is_single_line() {
12331            cx.propagate();
12332            return;
12333        }
12334
12335        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12336
12337        let text_layout_details = &self.text_layout_details(window);
12338
12339        self.change_selections(Default::default(), window, cx, |s| {
12340            s.move_with(|map, selection| {
12341                if !selection.is_empty() {
12342                    selection.goal = SelectionGoal::None;
12343                }
12344                let (cursor, goal) = movement::down_by_rows(
12345                    map,
12346                    selection.start,
12347                    action.lines,
12348                    selection.goal,
12349                    false,
12350                    text_layout_details,
12351                );
12352                selection.collapse_to(cursor, goal);
12353            });
12354        })
12355    }
12356
12357    pub fn select_down_by_lines(
12358        &mut self,
12359        action: &SelectDownByLines,
12360        window: &mut Window,
12361        cx: &mut Context<Self>,
12362    ) {
12363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12364        let text_layout_details = &self.text_layout_details(window);
12365        self.change_selections(Default::default(), window, cx, |s| {
12366            s.move_heads_with(|map, head, goal| {
12367                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12368            })
12369        })
12370    }
12371
12372    pub fn select_up_by_lines(
12373        &mut self,
12374        action: &SelectUpByLines,
12375        window: &mut Window,
12376        cx: &mut Context<Self>,
12377    ) {
12378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12379        let text_layout_details = &self.text_layout_details(window);
12380        self.change_selections(Default::default(), window, cx, |s| {
12381            s.move_heads_with(|map, head, goal| {
12382                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12383            })
12384        })
12385    }
12386
12387    pub fn select_page_up(
12388        &mut self,
12389        _: &SelectPageUp,
12390        window: &mut Window,
12391        cx: &mut Context<Self>,
12392    ) {
12393        let Some(row_count) = self.visible_row_count() else {
12394            return;
12395        };
12396
12397        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12398
12399        let text_layout_details = &self.text_layout_details(window);
12400
12401        self.change_selections(Default::default(), window, cx, |s| {
12402            s.move_heads_with(|map, head, goal| {
12403                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12404            })
12405        })
12406    }
12407
12408    pub fn move_page_up(
12409        &mut self,
12410        action: &MovePageUp,
12411        window: &mut Window,
12412        cx: &mut Context<Self>,
12413    ) {
12414        if self.take_rename(true, window, cx).is_some() {
12415            return;
12416        }
12417
12418        if self
12419            .context_menu
12420            .borrow_mut()
12421            .as_mut()
12422            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12423            .unwrap_or(false)
12424        {
12425            return;
12426        }
12427
12428        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12429            cx.propagate();
12430            return;
12431        }
12432
12433        let Some(row_count) = self.visible_row_count() else {
12434            return;
12435        };
12436
12437        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12438
12439        let effects = if action.center_cursor {
12440            SelectionEffects::scroll(Autoscroll::center())
12441        } else {
12442            SelectionEffects::default()
12443        };
12444
12445        let text_layout_details = &self.text_layout_details(window);
12446
12447        self.change_selections(effects, window, cx, |s| {
12448            s.move_with(|map, selection| {
12449                if !selection.is_empty() {
12450                    selection.goal = SelectionGoal::None;
12451                }
12452                let (cursor, goal) = movement::up_by_rows(
12453                    map,
12454                    selection.end,
12455                    row_count,
12456                    selection.goal,
12457                    false,
12458                    text_layout_details,
12459                );
12460                selection.collapse_to(cursor, goal);
12461            });
12462        });
12463    }
12464
12465    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12466        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12467        let text_layout_details = &self.text_layout_details(window);
12468        self.change_selections(Default::default(), window, cx, |s| {
12469            s.move_heads_with(|map, head, goal| {
12470                movement::up(map, head, goal, false, text_layout_details)
12471            })
12472        })
12473    }
12474
12475    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12476        self.take_rename(true, window, cx);
12477
12478        if self.mode.is_single_line() {
12479            cx.propagate();
12480            return;
12481        }
12482
12483        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12484
12485        let text_layout_details = &self.text_layout_details(window);
12486        let selection_count = self.selections.count();
12487        let first_selection = self.selections.first_anchor();
12488
12489        self.change_selections(Default::default(), window, cx, |s| {
12490            s.move_with(|map, selection| {
12491                if !selection.is_empty() {
12492                    selection.goal = SelectionGoal::None;
12493                }
12494                let (cursor, goal) = movement::down(
12495                    map,
12496                    selection.end,
12497                    selection.goal,
12498                    false,
12499                    text_layout_details,
12500                );
12501                selection.collapse_to(cursor, goal);
12502            });
12503        });
12504
12505        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12506        {
12507            cx.propagate();
12508        }
12509    }
12510
12511    pub fn select_page_down(
12512        &mut self,
12513        _: &SelectPageDown,
12514        window: &mut Window,
12515        cx: &mut Context<Self>,
12516    ) {
12517        let Some(row_count) = self.visible_row_count() else {
12518            return;
12519        };
12520
12521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12522
12523        let text_layout_details = &self.text_layout_details(window);
12524
12525        self.change_selections(Default::default(), window, cx, |s| {
12526            s.move_heads_with(|map, head, goal| {
12527                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12528            })
12529        })
12530    }
12531
12532    pub fn move_page_down(
12533        &mut self,
12534        action: &MovePageDown,
12535        window: &mut Window,
12536        cx: &mut Context<Self>,
12537    ) {
12538        if self.take_rename(true, window, cx).is_some() {
12539            return;
12540        }
12541
12542        if self
12543            .context_menu
12544            .borrow_mut()
12545            .as_mut()
12546            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12547            .unwrap_or(false)
12548        {
12549            return;
12550        }
12551
12552        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12553            cx.propagate();
12554            return;
12555        }
12556
12557        let Some(row_count) = self.visible_row_count() else {
12558            return;
12559        };
12560
12561        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12562
12563        let effects = if action.center_cursor {
12564            SelectionEffects::scroll(Autoscroll::center())
12565        } else {
12566            SelectionEffects::default()
12567        };
12568
12569        let text_layout_details = &self.text_layout_details(window);
12570        self.change_selections(effects, window, cx, |s| {
12571            s.move_with(|map, selection| {
12572                if !selection.is_empty() {
12573                    selection.goal = SelectionGoal::None;
12574                }
12575                let (cursor, goal) = movement::down_by_rows(
12576                    map,
12577                    selection.end,
12578                    row_count,
12579                    selection.goal,
12580                    false,
12581                    text_layout_details,
12582                );
12583                selection.collapse_to(cursor, goal);
12584            });
12585        });
12586    }
12587
12588    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12590        let text_layout_details = &self.text_layout_details(window);
12591        self.change_selections(Default::default(), window, cx, |s| {
12592            s.move_heads_with(|map, head, goal| {
12593                movement::down(map, head, goal, false, text_layout_details)
12594            })
12595        });
12596    }
12597
12598    pub fn context_menu_first(
12599        &mut self,
12600        _: &ContextMenuFirst,
12601        window: &mut Window,
12602        cx: &mut Context<Self>,
12603    ) {
12604        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12605            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12606        }
12607    }
12608
12609    pub fn context_menu_prev(
12610        &mut self,
12611        _: &ContextMenuPrevious,
12612        window: &mut Window,
12613        cx: &mut Context<Self>,
12614    ) {
12615        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12616            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12617        }
12618    }
12619
12620    pub fn context_menu_next(
12621        &mut self,
12622        _: &ContextMenuNext,
12623        window: &mut Window,
12624        cx: &mut Context<Self>,
12625    ) {
12626        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12627            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12628        }
12629    }
12630
12631    pub fn context_menu_last(
12632        &mut self,
12633        _: &ContextMenuLast,
12634        window: &mut Window,
12635        cx: &mut Context<Self>,
12636    ) {
12637        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12638            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12639        }
12640    }
12641
12642    pub fn signature_help_prev(
12643        &mut self,
12644        _: &SignatureHelpPrevious,
12645        _: &mut Window,
12646        cx: &mut Context<Self>,
12647    ) {
12648        if let Some(popover) = self.signature_help_state.popover_mut() {
12649            if popover.current_signature == 0 {
12650                popover.current_signature = popover.signatures.len() - 1;
12651            } else {
12652                popover.current_signature -= 1;
12653            }
12654            cx.notify();
12655        }
12656    }
12657
12658    pub fn signature_help_next(
12659        &mut self,
12660        _: &SignatureHelpNext,
12661        _: &mut Window,
12662        cx: &mut Context<Self>,
12663    ) {
12664        if let Some(popover) = self.signature_help_state.popover_mut() {
12665            if popover.current_signature + 1 == popover.signatures.len() {
12666                popover.current_signature = 0;
12667            } else {
12668                popover.current_signature += 1;
12669            }
12670            cx.notify();
12671        }
12672    }
12673
12674    pub fn move_to_previous_word_start(
12675        &mut self,
12676        _: &MoveToPreviousWordStart,
12677        window: &mut Window,
12678        cx: &mut Context<Self>,
12679    ) {
12680        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12681        self.change_selections(Default::default(), window, cx, |s| {
12682            s.move_cursors_with(|map, head, _| {
12683                (
12684                    movement::previous_word_start(map, head),
12685                    SelectionGoal::None,
12686                )
12687            });
12688        })
12689    }
12690
12691    pub fn move_to_previous_subword_start(
12692        &mut self,
12693        _: &MoveToPreviousSubwordStart,
12694        window: &mut Window,
12695        cx: &mut Context<Self>,
12696    ) {
12697        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12698        self.change_selections(Default::default(), window, cx, |s| {
12699            s.move_cursors_with(|map, head, _| {
12700                (
12701                    movement::previous_subword_start(map, head),
12702                    SelectionGoal::None,
12703                )
12704            });
12705        })
12706    }
12707
12708    pub fn select_to_previous_word_start(
12709        &mut self,
12710        _: &SelectToPreviousWordStart,
12711        window: &mut Window,
12712        cx: &mut Context<Self>,
12713    ) {
12714        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12715        self.change_selections(Default::default(), window, cx, |s| {
12716            s.move_heads_with(|map, head, _| {
12717                (
12718                    movement::previous_word_start(map, head),
12719                    SelectionGoal::None,
12720                )
12721            });
12722        })
12723    }
12724
12725    pub fn select_to_previous_subword_start(
12726        &mut self,
12727        _: &SelectToPreviousSubwordStart,
12728        window: &mut Window,
12729        cx: &mut Context<Self>,
12730    ) {
12731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12732        self.change_selections(Default::default(), window, cx, |s| {
12733            s.move_heads_with(|map, head, _| {
12734                (
12735                    movement::previous_subword_start(map, head),
12736                    SelectionGoal::None,
12737                )
12738            });
12739        })
12740    }
12741
12742    pub fn delete_to_previous_word_start(
12743        &mut self,
12744        action: &DeleteToPreviousWordStart,
12745        window: &mut Window,
12746        cx: &mut Context<Self>,
12747    ) {
12748        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12749        self.transact(window, cx, |this, window, cx| {
12750            this.select_autoclose_pair(window, cx);
12751            this.change_selections(Default::default(), window, cx, |s| {
12752                s.move_with(|map, selection| {
12753                    if selection.is_empty() {
12754                        let cursor = if action.ignore_newlines {
12755                            movement::previous_word_start(map, selection.head())
12756                        } else {
12757                            movement::previous_word_start_or_newline(map, selection.head())
12758                        };
12759                        selection.set_head(cursor, SelectionGoal::None);
12760                    }
12761                });
12762            });
12763            this.insert("", window, cx);
12764        });
12765    }
12766
12767    pub fn delete_to_previous_subword_start(
12768        &mut self,
12769        _: &DeleteToPreviousSubwordStart,
12770        window: &mut Window,
12771        cx: &mut Context<Self>,
12772    ) {
12773        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12774        self.transact(window, cx, |this, window, cx| {
12775            this.select_autoclose_pair(window, cx);
12776            this.change_selections(Default::default(), window, cx, |s| {
12777                s.move_with(|map, selection| {
12778                    if selection.is_empty() {
12779                        let cursor = movement::previous_subword_start(map, selection.head());
12780                        selection.set_head(cursor, SelectionGoal::None);
12781                    }
12782                });
12783            });
12784            this.insert("", window, cx);
12785        });
12786    }
12787
12788    pub fn move_to_next_word_end(
12789        &mut self,
12790        _: &MoveToNextWordEnd,
12791        window: &mut Window,
12792        cx: &mut Context<Self>,
12793    ) {
12794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12795        self.change_selections(Default::default(), window, cx, |s| {
12796            s.move_cursors_with(|map, head, _| {
12797                (movement::next_word_end(map, head), SelectionGoal::None)
12798            });
12799        })
12800    }
12801
12802    pub fn move_to_next_subword_end(
12803        &mut self,
12804        _: &MoveToNextSubwordEnd,
12805        window: &mut Window,
12806        cx: &mut Context<Self>,
12807    ) {
12808        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12809        self.change_selections(Default::default(), window, cx, |s| {
12810            s.move_cursors_with(|map, head, _| {
12811                (movement::next_subword_end(map, head), SelectionGoal::None)
12812            });
12813        })
12814    }
12815
12816    pub fn select_to_next_word_end(
12817        &mut self,
12818        _: &SelectToNextWordEnd,
12819        window: &mut Window,
12820        cx: &mut Context<Self>,
12821    ) {
12822        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12823        self.change_selections(Default::default(), window, cx, |s| {
12824            s.move_heads_with(|map, head, _| {
12825                (movement::next_word_end(map, head), SelectionGoal::None)
12826            });
12827        })
12828    }
12829
12830    pub fn select_to_next_subword_end(
12831        &mut self,
12832        _: &SelectToNextSubwordEnd,
12833        window: &mut Window,
12834        cx: &mut Context<Self>,
12835    ) {
12836        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12837        self.change_selections(Default::default(), window, cx, |s| {
12838            s.move_heads_with(|map, head, _| {
12839                (movement::next_subword_end(map, head), SelectionGoal::None)
12840            });
12841        })
12842    }
12843
12844    pub fn delete_to_next_word_end(
12845        &mut self,
12846        action: &DeleteToNextWordEnd,
12847        window: &mut Window,
12848        cx: &mut Context<Self>,
12849    ) {
12850        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12851        self.transact(window, cx, |this, window, cx| {
12852            this.change_selections(Default::default(), window, cx, |s| {
12853                s.move_with(|map, selection| {
12854                    if selection.is_empty() {
12855                        let cursor = if action.ignore_newlines {
12856                            movement::next_word_end(map, selection.head())
12857                        } else {
12858                            movement::next_word_end_or_newline(map, selection.head())
12859                        };
12860                        selection.set_head(cursor, SelectionGoal::None);
12861                    }
12862                });
12863            });
12864            this.insert("", window, cx);
12865        });
12866    }
12867
12868    pub fn delete_to_next_subword_end(
12869        &mut self,
12870        _: &DeleteToNextSubwordEnd,
12871        window: &mut Window,
12872        cx: &mut Context<Self>,
12873    ) {
12874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12875        self.transact(window, cx, |this, window, cx| {
12876            this.change_selections(Default::default(), window, cx, |s| {
12877                s.move_with(|map, selection| {
12878                    if selection.is_empty() {
12879                        let cursor = movement::next_subword_end(map, selection.head());
12880                        selection.set_head(cursor, SelectionGoal::None);
12881                    }
12882                });
12883            });
12884            this.insert("", window, cx);
12885        });
12886    }
12887
12888    pub fn move_to_beginning_of_line(
12889        &mut self,
12890        action: &MoveToBeginningOfLine,
12891        window: &mut Window,
12892        cx: &mut Context<Self>,
12893    ) {
12894        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12895        self.change_selections(Default::default(), window, cx, |s| {
12896            s.move_cursors_with(|map, head, _| {
12897                (
12898                    movement::indented_line_beginning(
12899                        map,
12900                        head,
12901                        action.stop_at_soft_wraps,
12902                        action.stop_at_indent,
12903                    ),
12904                    SelectionGoal::None,
12905                )
12906            });
12907        })
12908    }
12909
12910    pub fn select_to_beginning_of_line(
12911        &mut self,
12912        action: &SelectToBeginningOfLine,
12913        window: &mut Window,
12914        cx: &mut Context<Self>,
12915    ) {
12916        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12917        self.change_selections(Default::default(), window, cx, |s| {
12918            s.move_heads_with(|map, head, _| {
12919                (
12920                    movement::indented_line_beginning(
12921                        map,
12922                        head,
12923                        action.stop_at_soft_wraps,
12924                        action.stop_at_indent,
12925                    ),
12926                    SelectionGoal::None,
12927                )
12928            });
12929        });
12930    }
12931
12932    pub fn delete_to_beginning_of_line(
12933        &mut self,
12934        action: &DeleteToBeginningOfLine,
12935        window: &mut Window,
12936        cx: &mut Context<Self>,
12937    ) {
12938        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12939        self.transact(window, cx, |this, window, cx| {
12940            this.change_selections(Default::default(), window, cx, |s| {
12941                s.move_with(|_, selection| {
12942                    selection.reversed = true;
12943                });
12944            });
12945
12946            this.select_to_beginning_of_line(
12947                &SelectToBeginningOfLine {
12948                    stop_at_soft_wraps: false,
12949                    stop_at_indent: action.stop_at_indent,
12950                },
12951                window,
12952                cx,
12953            );
12954            this.backspace(&Backspace, window, cx);
12955        });
12956    }
12957
12958    pub fn move_to_end_of_line(
12959        &mut self,
12960        action: &MoveToEndOfLine,
12961        window: &mut Window,
12962        cx: &mut Context<Self>,
12963    ) {
12964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12965        self.change_selections(Default::default(), window, cx, |s| {
12966            s.move_cursors_with(|map, head, _| {
12967                (
12968                    movement::line_end(map, head, action.stop_at_soft_wraps),
12969                    SelectionGoal::None,
12970                )
12971            });
12972        })
12973    }
12974
12975    pub fn select_to_end_of_line(
12976        &mut self,
12977        action: &SelectToEndOfLine,
12978        window: &mut Window,
12979        cx: &mut Context<Self>,
12980    ) {
12981        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12982        self.change_selections(Default::default(), window, cx, |s| {
12983            s.move_heads_with(|map, head, _| {
12984                (
12985                    movement::line_end(map, head, action.stop_at_soft_wraps),
12986                    SelectionGoal::None,
12987                )
12988            });
12989        })
12990    }
12991
12992    pub fn delete_to_end_of_line(
12993        &mut self,
12994        _: &DeleteToEndOfLine,
12995        window: &mut Window,
12996        cx: &mut Context<Self>,
12997    ) {
12998        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12999        self.transact(window, cx, |this, window, cx| {
13000            this.select_to_end_of_line(
13001                &SelectToEndOfLine {
13002                    stop_at_soft_wraps: false,
13003                },
13004                window,
13005                cx,
13006            );
13007            this.delete(&Delete, window, cx);
13008        });
13009    }
13010
13011    pub fn cut_to_end_of_line(
13012        &mut self,
13013        _: &CutToEndOfLine,
13014        window: &mut Window,
13015        cx: &mut Context<Self>,
13016    ) {
13017        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13018        self.transact(window, cx, |this, window, cx| {
13019            this.select_to_end_of_line(
13020                &SelectToEndOfLine {
13021                    stop_at_soft_wraps: false,
13022                },
13023                window,
13024                cx,
13025            );
13026            this.cut(&Cut, window, cx);
13027        });
13028    }
13029
13030    pub fn move_to_start_of_paragraph(
13031        &mut self,
13032        _: &MoveToStartOfParagraph,
13033        window: &mut Window,
13034        cx: &mut Context<Self>,
13035    ) {
13036        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13037            cx.propagate();
13038            return;
13039        }
13040        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13041        self.change_selections(Default::default(), window, cx, |s| {
13042            s.move_with(|map, selection| {
13043                selection.collapse_to(
13044                    movement::start_of_paragraph(map, selection.head(), 1),
13045                    SelectionGoal::None,
13046                )
13047            });
13048        })
13049    }
13050
13051    pub fn move_to_end_of_paragraph(
13052        &mut self,
13053        _: &MoveToEndOfParagraph,
13054        window: &mut Window,
13055        cx: &mut Context<Self>,
13056    ) {
13057        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13058            cx.propagate();
13059            return;
13060        }
13061        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13062        self.change_selections(Default::default(), window, cx, |s| {
13063            s.move_with(|map, selection| {
13064                selection.collapse_to(
13065                    movement::end_of_paragraph(map, selection.head(), 1),
13066                    SelectionGoal::None,
13067                )
13068            });
13069        })
13070    }
13071
13072    pub fn select_to_start_of_paragraph(
13073        &mut self,
13074        _: &SelectToStartOfParagraph,
13075        window: &mut Window,
13076        cx: &mut Context<Self>,
13077    ) {
13078        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13079            cx.propagate();
13080            return;
13081        }
13082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13083        self.change_selections(Default::default(), window, cx, |s| {
13084            s.move_heads_with(|map, head, _| {
13085                (
13086                    movement::start_of_paragraph(map, head, 1),
13087                    SelectionGoal::None,
13088                )
13089            });
13090        })
13091    }
13092
13093    pub fn select_to_end_of_paragraph(
13094        &mut self,
13095        _: &SelectToEndOfParagraph,
13096        window: &mut Window,
13097        cx: &mut Context<Self>,
13098    ) {
13099        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13100            cx.propagate();
13101            return;
13102        }
13103        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13104        self.change_selections(Default::default(), window, cx, |s| {
13105            s.move_heads_with(|map, head, _| {
13106                (
13107                    movement::end_of_paragraph(map, head, 1),
13108                    SelectionGoal::None,
13109                )
13110            });
13111        })
13112    }
13113
13114    pub fn move_to_start_of_excerpt(
13115        &mut self,
13116        _: &MoveToStartOfExcerpt,
13117        window: &mut Window,
13118        cx: &mut Context<Self>,
13119    ) {
13120        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13121            cx.propagate();
13122            return;
13123        }
13124        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13125        self.change_selections(Default::default(), window, cx, |s| {
13126            s.move_with(|map, selection| {
13127                selection.collapse_to(
13128                    movement::start_of_excerpt(
13129                        map,
13130                        selection.head(),
13131                        workspace::searchable::Direction::Prev,
13132                    ),
13133                    SelectionGoal::None,
13134                )
13135            });
13136        })
13137    }
13138
13139    pub fn move_to_start_of_next_excerpt(
13140        &mut self,
13141        _: &MoveToStartOfNextExcerpt,
13142        window: &mut Window,
13143        cx: &mut Context<Self>,
13144    ) {
13145        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13146            cx.propagate();
13147            return;
13148        }
13149
13150        self.change_selections(Default::default(), window, cx, |s| {
13151            s.move_with(|map, selection| {
13152                selection.collapse_to(
13153                    movement::start_of_excerpt(
13154                        map,
13155                        selection.head(),
13156                        workspace::searchable::Direction::Next,
13157                    ),
13158                    SelectionGoal::None,
13159                )
13160            });
13161        })
13162    }
13163
13164    pub fn move_to_end_of_excerpt(
13165        &mut self,
13166        _: &MoveToEndOfExcerpt,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13171            cx.propagate();
13172            return;
13173        }
13174        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13175        self.change_selections(Default::default(), window, cx, |s| {
13176            s.move_with(|map, selection| {
13177                selection.collapse_to(
13178                    movement::end_of_excerpt(
13179                        map,
13180                        selection.head(),
13181                        workspace::searchable::Direction::Next,
13182                    ),
13183                    SelectionGoal::None,
13184                )
13185            });
13186        })
13187    }
13188
13189    pub fn move_to_end_of_previous_excerpt(
13190        &mut self,
13191        _: &MoveToEndOfPreviousExcerpt,
13192        window: &mut Window,
13193        cx: &mut Context<Self>,
13194    ) {
13195        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13196            cx.propagate();
13197            return;
13198        }
13199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13200        self.change_selections(Default::default(), window, cx, |s| {
13201            s.move_with(|map, selection| {
13202                selection.collapse_to(
13203                    movement::end_of_excerpt(
13204                        map,
13205                        selection.head(),
13206                        workspace::searchable::Direction::Prev,
13207                    ),
13208                    SelectionGoal::None,
13209                )
13210            });
13211        })
13212    }
13213
13214    pub fn select_to_start_of_excerpt(
13215        &mut self,
13216        _: &SelectToStartOfExcerpt,
13217        window: &mut Window,
13218        cx: &mut Context<Self>,
13219    ) {
13220        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13221            cx.propagate();
13222            return;
13223        }
13224        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13225        self.change_selections(Default::default(), window, cx, |s| {
13226            s.move_heads_with(|map, head, _| {
13227                (
13228                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13229                    SelectionGoal::None,
13230                )
13231            });
13232        })
13233    }
13234
13235    pub fn select_to_start_of_next_excerpt(
13236        &mut self,
13237        _: &SelectToStartOfNextExcerpt,
13238        window: &mut Window,
13239        cx: &mut Context<Self>,
13240    ) {
13241        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13242            cx.propagate();
13243            return;
13244        }
13245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13246        self.change_selections(Default::default(), window, cx, |s| {
13247            s.move_heads_with(|map, head, _| {
13248                (
13249                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13250                    SelectionGoal::None,
13251                )
13252            });
13253        })
13254    }
13255
13256    pub fn select_to_end_of_excerpt(
13257        &mut self,
13258        _: &SelectToEndOfExcerpt,
13259        window: &mut Window,
13260        cx: &mut Context<Self>,
13261    ) {
13262        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13263            cx.propagate();
13264            return;
13265        }
13266        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13267        self.change_selections(Default::default(), window, cx, |s| {
13268            s.move_heads_with(|map, head, _| {
13269                (
13270                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13271                    SelectionGoal::None,
13272                )
13273            });
13274        })
13275    }
13276
13277    pub fn select_to_end_of_previous_excerpt(
13278        &mut self,
13279        _: &SelectToEndOfPreviousExcerpt,
13280        window: &mut Window,
13281        cx: &mut Context<Self>,
13282    ) {
13283        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13284            cx.propagate();
13285            return;
13286        }
13287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13288        self.change_selections(Default::default(), window, cx, |s| {
13289            s.move_heads_with(|map, head, _| {
13290                (
13291                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13292                    SelectionGoal::None,
13293                )
13294            });
13295        })
13296    }
13297
13298    pub fn move_to_beginning(
13299        &mut self,
13300        _: &MoveToBeginning,
13301        window: &mut Window,
13302        cx: &mut Context<Self>,
13303    ) {
13304        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13305            cx.propagate();
13306            return;
13307        }
13308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13309        self.change_selections(Default::default(), window, cx, |s| {
13310            s.select_ranges(vec![0..0]);
13311        });
13312    }
13313
13314    pub fn select_to_beginning(
13315        &mut self,
13316        _: &SelectToBeginning,
13317        window: &mut Window,
13318        cx: &mut Context<Self>,
13319    ) {
13320        let mut selection = self.selections.last::<Point>(cx);
13321        selection.set_head(Point::zero(), SelectionGoal::None);
13322        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13323        self.change_selections(Default::default(), window, cx, |s| {
13324            s.select(vec![selection]);
13325        });
13326    }
13327
13328    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13329        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13330            cx.propagate();
13331            return;
13332        }
13333        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13334        let cursor = self.buffer.read(cx).read(cx).len();
13335        self.change_selections(Default::default(), window, cx, |s| {
13336            s.select_ranges(vec![cursor..cursor])
13337        });
13338    }
13339
13340    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13341        self.nav_history = nav_history;
13342    }
13343
13344    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13345        self.nav_history.as_ref()
13346    }
13347
13348    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13349        self.push_to_nav_history(
13350            self.selections.newest_anchor().head(),
13351            None,
13352            false,
13353            true,
13354            cx,
13355        );
13356    }
13357
13358    fn push_to_nav_history(
13359        &mut self,
13360        cursor_anchor: Anchor,
13361        new_position: Option<Point>,
13362        is_deactivate: bool,
13363        always: bool,
13364        cx: &mut Context<Self>,
13365    ) {
13366        if let Some(nav_history) = self.nav_history.as_mut() {
13367            let buffer = self.buffer.read(cx).read(cx);
13368            let cursor_position = cursor_anchor.to_point(&buffer);
13369            let scroll_state = self.scroll_manager.anchor();
13370            let scroll_top_row = scroll_state.top_row(&buffer);
13371            drop(buffer);
13372
13373            if let Some(new_position) = new_position {
13374                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13375                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13376                    return;
13377                }
13378            }
13379
13380            nav_history.push(
13381                Some(NavigationData {
13382                    cursor_anchor,
13383                    cursor_position,
13384                    scroll_anchor: scroll_state,
13385                    scroll_top_row,
13386                }),
13387                cx,
13388            );
13389            cx.emit(EditorEvent::PushedToNavHistory {
13390                anchor: cursor_anchor,
13391                is_deactivate,
13392            })
13393        }
13394    }
13395
13396    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13397        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13398        let buffer = self.buffer.read(cx).snapshot(cx);
13399        let mut selection = self.selections.first::<usize>(cx);
13400        selection.set_head(buffer.len(), SelectionGoal::None);
13401        self.change_selections(Default::default(), window, cx, |s| {
13402            s.select(vec![selection]);
13403        });
13404    }
13405
13406    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13408        let end = self.buffer.read(cx).read(cx).len();
13409        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13410            s.select_ranges(vec![0..end]);
13411        });
13412    }
13413
13414    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13415        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13416        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13417        let mut selections = self.selections.all::<Point>(cx);
13418        let max_point = display_map.buffer_snapshot.max_point();
13419        for selection in &mut selections {
13420            let rows = selection.spanned_rows(true, &display_map);
13421            selection.start = Point::new(rows.start.0, 0);
13422            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13423            selection.reversed = false;
13424        }
13425        self.change_selections(Default::default(), window, cx, |s| {
13426            s.select(selections);
13427        });
13428    }
13429
13430    pub fn split_selection_into_lines(
13431        &mut self,
13432        _: &SplitSelectionIntoLines,
13433        window: &mut Window,
13434        cx: &mut Context<Self>,
13435    ) {
13436        let selections = self
13437            .selections
13438            .all::<Point>(cx)
13439            .into_iter()
13440            .map(|selection| selection.start..selection.end)
13441            .collect::<Vec<_>>();
13442        self.unfold_ranges(&selections, true, true, cx);
13443
13444        let mut new_selection_ranges = Vec::new();
13445        {
13446            let buffer = self.buffer.read(cx).read(cx);
13447            for selection in selections {
13448                for row in selection.start.row..selection.end.row {
13449                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13450                    new_selection_ranges.push(cursor..cursor);
13451                }
13452
13453                let is_multiline_selection = selection.start.row != selection.end.row;
13454                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13455                // so this action feels more ergonomic when paired with other selection operations
13456                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13457                if !should_skip_last {
13458                    new_selection_ranges.push(selection.end..selection.end);
13459                }
13460            }
13461        }
13462        self.change_selections(Default::default(), window, cx, |s| {
13463            s.select_ranges(new_selection_ranges);
13464        });
13465    }
13466
13467    pub fn add_selection_above(
13468        &mut self,
13469        _: &AddSelectionAbove,
13470        window: &mut Window,
13471        cx: &mut Context<Self>,
13472    ) {
13473        self.add_selection(true, window, cx);
13474    }
13475
13476    pub fn add_selection_below(
13477        &mut self,
13478        _: &AddSelectionBelow,
13479        window: &mut Window,
13480        cx: &mut Context<Self>,
13481    ) {
13482        self.add_selection(false, window, cx);
13483    }
13484
13485    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13487
13488        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13489        let all_selections = self.selections.all::<Point>(cx);
13490        let text_layout_details = self.text_layout_details(window);
13491
13492        let (mut columnar_selections, new_selections_to_columnarize) = {
13493            if let Some(state) = self.add_selections_state.as_ref() {
13494                let columnar_selection_ids: HashSet<_> = state
13495                    .groups
13496                    .iter()
13497                    .flat_map(|group| group.stack.iter())
13498                    .copied()
13499                    .collect();
13500
13501                all_selections
13502                    .into_iter()
13503                    .partition(|s| columnar_selection_ids.contains(&s.id))
13504            } else {
13505                (Vec::new(), all_selections)
13506            }
13507        };
13508
13509        let mut state = self
13510            .add_selections_state
13511            .take()
13512            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13513
13514        for selection in new_selections_to_columnarize {
13515            let range = selection.display_range(&display_map).sorted();
13516            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13517            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13518            let positions = start_x.min(end_x)..start_x.max(end_x);
13519            let mut stack = Vec::new();
13520            for row in range.start.row().0..=range.end.row().0 {
13521                if let Some(selection) = self.selections.build_columnar_selection(
13522                    &display_map,
13523                    DisplayRow(row),
13524                    &positions,
13525                    selection.reversed,
13526                    &text_layout_details,
13527                ) {
13528                    stack.push(selection.id);
13529                    columnar_selections.push(selection);
13530                }
13531            }
13532            if !stack.is_empty() {
13533                if above {
13534                    stack.reverse();
13535                }
13536                state.groups.push(AddSelectionsGroup { above, stack });
13537            }
13538        }
13539
13540        let mut final_selections = Vec::new();
13541        let end_row = if above {
13542            DisplayRow(0)
13543        } else {
13544            display_map.max_point().row()
13545        };
13546
13547        let mut last_added_item_per_group = HashMap::default();
13548        for group in state.groups.iter_mut() {
13549            if let Some(last_id) = group.stack.last() {
13550                last_added_item_per_group.insert(*last_id, group);
13551            }
13552        }
13553
13554        for selection in columnar_selections {
13555            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13556                if above == group.above {
13557                    let range = selection.display_range(&display_map).sorted();
13558                    debug_assert_eq!(range.start.row(), range.end.row());
13559                    let mut row = range.start.row();
13560                    let positions =
13561                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13562                            px(start)..px(end)
13563                        } else {
13564                            let start_x =
13565                                display_map.x_for_display_point(range.start, &text_layout_details);
13566                            let end_x =
13567                                display_map.x_for_display_point(range.end, &text_layout_details);
13568                            start_x.min(end_x)..start_x.max(end_x)
13569                        };
13570
13571                    let mut maybe_new_selection = None;
13572                    while row != end_row {
13573                        if above {
13574                            row.0 -= 1;
13575                        } else {
13576                            row.0 += 1;
13577                        }
13578                        if let Some(new_selection) = self.selections.build_columnar_selection(
13579                            &display_map,
13580                            row,
13581                            &positions,
13582                            selection.reversed,
13583                            &text_layout_details,
13584                        ) {
13585                            maybe_new_selection = Some(new_selection);
13586                            break;
13587                        }
13588                    }
13589
13590                    if let Some(new_selection) = maybe_new_selection {
13591                        group.stack.push(new_selection.id);
13592                        if above {
13593                            final_selections.push(new_selection);
13594                            final_selections.push(selection);
13595                        } else {
13596                            final_selections.push(selection);
13597                            final_selections.push(new_selection);
13598                        }
13599                    } else {
13600                        final_selections.push(selection);
13601                    }
13602                } else {
13603                    group.stack.pop();
13604                }
13605            } else {
13606                final_selections.push(selection);
13607            }
13608        }
13609
13610        self.change_selections(Default::default(), window, cx, |s| {
13611            s.select(final_selections);
13612        });
13613
13614        let final_selection_ids: HashSet<_> = self
13615            .selections
13616            .all::<Point>(cx)
13617            .iter()
13618            .map(|s| s.id)
13619            .collect();
13620        state.groups.retain_mut(|group| {
13621            // selections might get merged above so we remove invalid items from stacks
13622            group.stack.retain(|id| final_selection_ids.contains(id));
13623
13624            // single selection in stack can be treated as initial state
13625            group.stack.len() > 1
13626        });
13627
13628        if !state.groups.is_empty() {
13629            self.add_selections_state = Some(state);
13630        }
13631    }
13632
13633    fn select_match_ranges(
13634        &mut self,
13635        range: Range<usize>,
13636        reversed: bool,
13637        replace_newest: bool,
13638        auto_scroll: Option<Autoscroll>,
13639        window: &mut Window,
13640        cx: &mut Context<Editor>,
13641    ) {
13642        self.unfold_ranges(
13643            std::slice::from_ref(&range),
13644            false,
13645            auto_scroll.is_some(),
13646            cx,
13647        );
13648        let effects = if let Some(scroll) = auto_scroll {
13649            SelectionEffects::scroll(scroll)
13650        } else {
13651            SelectionEffects::no_scroll()
13652        };
13653        self.change_selections(effects, window, cx, |s| {
13654            if replace_newest {
13655                s.delete(s.newest_anchor().id);
13656            }
13657            if reversed {
13658                s.insert_range(range.end..range.start);
13659            } else {
13660                s.insert_range(range);
13661            }
13662        });
13663    }
13664
13665    pub fn select_next_match_internal(
13666        &mut self,
13667        display_map: &DisplaySnapshot,
13668        replace_newest: bool,
13669        autoscroll: Option<Autoscroll>,
13670        window: &mut Window,
13671        cx: &mut Context<Self>,
13672    ) -> Result<()> {
13673        let buffer = &display_map.buffer_snapshot;
13674        let mut selections = self.selections.all::<usize>(cx);
13675        if let Some(mut select_next_state) = self.select_next_state.take() {
13676            let query = &select_next_state.query;
13677            if !select_next_state.done {
13678                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13679                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13680                let mut next_selected_range = None;
13681
13682                let bytes_after_last_selection =
13683                    buffer.bytes_in_range(last_selection.end..buffer.len());
13684                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13685                let query_matches = query
13686                    .stream_find_iter(bytes_after_last_selection)
13687                    .map(|result| (last_selection.end, result))
13688                    .chain(
13689                        query
13690                            .stream_find_iter(bytes_before_first_selection)
13691                            .map(|result| (0, result)),
13692                    );
13693
13694                for (start_offset, query_match) in query_matches {
13695                    let query_match = query_match.unwrap(); // can only fail due to I/O
13696                    let offset_range =
13697                        start_offset + query_match.start()..start_offset + query_match.end();
13698
13699                    if !select_next_state.wordwise
13700                        || (!buffer.is_inside_word(offset_range.start, false)
13701                            && !buffer.is_inside_word(offset_range.end, false))
13702                    {
13703                        // TODO: This is n^2, because we might check all the selections
13704                        if !selections
13705                            .iter()
13706                            .any(|selection| selection.range().overlaps(&offset_range))
13707                        {
13708                            next_selected_range = Some(offset_range);
13709                            break;
13710                        }
13711                    }
13712                }
13713
13714                if let Some(next_selected_range) = next_selected_range {
13715                    self.select_match_ranges(
13716                        next_selected_range,
13717                        last_selection.reversed,
13718                        replace_newest,
13719                        autoscroll,
13720                        window,
13721                        cx,
13722                    );
13723                } else {
13724                    select_next_state.done = true;
13725                }
13726            }
13727
13728            self.select_next_state = Some(select_next_state);
13729        } else {
13730            let mut only_carets = true;
13731            let mut same_text_selected = true;
13732            let mut selected_text = None;
13733
13734            let mut selections_iter = selections.iter().peekable();
13735            while let Some(selection) = selections_iter.next() {
13736                if selection.start != selection.end {
13737                    only_carets = false;
13738                }
13739
13740                if same_text_selected {
13741                    if selected_text.is_none() {
13742                        selected_text =
13743                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13744                    }
13745
13746                    if let Some(next_selection) = selections_iter.peek() {
13747                        if next_selection.range().len() == selection.range().len() {
13748                            let next_selected_text = buffer
13749                                .text_for_range(next_selection.range())
13750                                .collect::<String>();
13751                            if Some(next_selected_text) != selected_text {
13752                                same_text_selected = false;
13753                                selected_text = None;
13754                            }
13755                        } else {
13756                            same_text_selected = false;
13757                            selected_text = None;
13758                        }
13759                    }
13760                }
13761            }
13762
13763            if only_carets {
13764                for selection in &mut selections {
13765                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13766                    selection.start = word_range.start;
13767                    selection.end = word_range.end;
13768                    selection.goal = SelectionGoal::None;
13769                    selection.reversed = false;
13770                    self.select_match_ranges(
13771                        selection.start..selection.end,
13772                        selection.reversed,
13773                        replace_newest,
13774                        autoscroll,
13775                        window,
13776                        cx,
13777                    );
13778                }
13779
13780                if selections.len() == 1 {
13781                    let selection = selections
13782                        .last()
13783                        .expect("ensured that there's only one selection");
13784                    let query = buffer
13785                        .text_for_range(selection.start..selection.end)
13786                        .collect::<String>();
13787                    let is_empty = query.is_empty();
13788                    let select_state = SelectNextState {
13789                        query: AhoCorasick::new(&[query])?,
13790                        wordwise: true,
13791                        done: is_empty,
13792                    };
13793                    self.select_next_state = Some(select_state);
13794                } else {
13795                    self.select_next_state = None;
13796                }
13797            } else if let Some(selected_text) = selected_text {
13798                self.select_next_state = Some(SelectNextState {
13799                    query: AhoCorasick::new(&[selected_text])?,
13800                    wordwise: false,
13801                    done: false,
13802                });
13803                self.select_next_match_internal(
13804                    display_map,
13805                    replace_newest,
13806                    autoscroll,
13807                    window,
13808                    cx,
13809                )?;
13810            }
13811        }
13812        Ok(())
13813    }
13814
13815    pub fn select_all_matches(
13816        &mut self,
13817        _action: &SelectAllMatches,
13818        window: &mut Window,
13819        cx: &mut Context<Self>,
13820    ) -> Result<()> {
13821        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13822
13823        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13824
13825        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13826        let Some(select_next_state) = self.select_next_state.as_mut() else {
13827            return Ok(());
13828        };
13829        if select_next_state.done {
13830            return Ok(());
13831        }
13832
13833        let mut new_selections = Vec::new();
13834
13835        let reversed = self.selections.oldest::<usize>(cx).reversed;
13836        let buffer = &display_map.buffer_snapshot;
13837        let query_matches = select_next_state
13838            .query
13839            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13840
13841        for query_match in query_matches.into_iter() {
13842            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13843            let offset_range = if reversed {
13844                query_match.end()..query_match.start()
13845            } else {
13846                query_match.start()..query_match.end()
13847            };
13848
13849            if !select_next_state.wordwise
13850                || (!buffer.is_inside_word(offset_range.start, false)
13851                    && !buffer.is_inside_word(offset_range.end, false))
13852            {
13853                new_selections.push(offset_range.start..offset_range.end);
13854            }
13855        }
13856
13857        select_next_state.done = true;
13858
13859        if new_selections.is_empty() {
13860            log::error!("bug: new_selections is empty in select_all_matches");
13861            return Ok(());
13862        }
13863
13864        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13865        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13866            selections.select_ranges(new_selections)
13867        });
13868
13869        Ok(())
13870    }
13871
13872    pub fn select_next(
13873        &mut self,
13874        action: &SelectNext,
13875        window: &mut Window,
13876        cx: &mut Context<Self>,
13877    ) -> Result<()> {
13878        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13879        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13880        self.select_next_match_internal(
13881            &display_map,
13882            action.replace_newest,
13883            Some(Autoscroll::newest()),
13884            window,
13885            cx,
13886        )?;
13887        Ok(())
13888    }
13889
13890    pub fn select_previous(
13891        &mut self,
13892        action: &SelectPrevious,
13893        window: &mut Window,
13894        cx: &mut Context<Self>,
13895    ) -> Result<()> {
13896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13897        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13898        let buffer = &display_map.buffer_snapshot;
13899        let mut selections = self.selections.all::<usize>(cx);
13900        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13901            let query = &select_prev_state.query;
13902            if !select_prev_state.done {
13903                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13904                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13905                let mut next_selected_range = None;
13906                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13907                let bytes_before_last_selection =
13908                    buffer.reversed_bytes_in_range(0..last_selection.start);
13909                let bytes_after_first_selection =
13910                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13911                let query_matches = query
13912                    .stream_find_iter(bytes_before_last_selection)
13913                    .map(|result| (last_selection.start, result))
13914                    .chain(
13915                        query
13916                            .stream_find_iter(bytes_after_first_selection)
13917                            .map(|result| (buffer.len(), result)),
13918                    );
13919                for (end_offset, query_match) in query_matches {
13920                    let query_match = query_match.unwrap(); // can only fail due to I/O
13921                    let offset_range =
13922                        end_offset - query_match.end()..end_offset - query_match.start();
13923
13924                    if !select_prev_state.wordwise
13925                        || (!buffer.is_inside_word(offset_range.start, false)
13926                            && !buffer.is_inside_word(offset_range.end, false))
13927                    {
13928                        next_selected_range = Some(offset_range);
13929                        break;
13930                    }
13931                }
13932
13933                if let Some(next_selected_range) = next_selected_range {
13934                    self.select_match_ranges(
13935                        next_selected_range,
13936                        last_selection.reversed,
13937                        action.replace_newest,
13938                        Some(Autoscroll::newest()),
13939                        window,
13940                        cx,
13941                    );
13942                } else {
13943                    select_prev_state.done = true;
13944                }
13945            }
13946
13947            self.select_prev_state = Some(select_prev_state);
13948        } else {
13949            let mut only_carets = true;
13950            let mut same_text_selected = true;
13951            let mut selected_text = None;
13952
13953            let mut selections_iter = selections.iter().peekable();
13954            while let Some(selection) = selections_iter.next() {
13955                if selection.start != selection.end {
13956                    only_carets = false;
13957                }
13958
13959                if same_text_selected {
13960                    if selected_text.is_none() {
13961                        selected_text =
13962                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13963                    }
13964
13965                    if let Some(next_selection) = selections_iter.peek() {
13966                        if next_selection.range().len() == selection.range().len() {
13967                            let next_selected_text = buffer
13968                                .text_for_range(next_selection.range())
13969                                .collect::<String>();
13970                            if Some(next_selected_text) != selected_text {
13971                                same_text_selected = false;
13972                                selected_text = None;
13973                            }
13974                        } else {
13975                            same_text_selected = false;
13976                            selected_text = None;
13977                        }
13978                    }
13979                }
13980            }
13981
13982            if only_carets {
13983                for selection in &mut selections {
13984                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13985                    selection.start = word_range.start;
13986                    selection.end = word_range.end;
13987                    selection.goal = SelectionGoal::None;
13988                    selection.reversed = false;
13989                    self.select_match_ranges(
13990                        selection.start..selection.end,
13991                        selection.reversed,
13992                        action.replace_newest,
13993                        Some(Autoscroll::newest()),
13994                        window,
13995                        cx,
13996                    );
13997                }
13998                if selections.len() == 1 {
13999                    let selection = selections
14000                        .last()
14001                        .expect("ensured that there's only one selection");
14002                    let query = buffer
14003                        .text_for_range(selection.start..selection.end)
14004                        .collect::<String>();
14005                    let is_empty = query.is_empty();
14006                    let select_state = SelectNextState {
14007                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14008                        wordwise: true,
14009                        done: is_empty,
14010                    };
14011                    self.select_prev_state = Some(select_state);
14012                } else {
14013                    self.select_prev_state = None;
14014                }
14015            } else if let Some(selected_text) = selected_text {
14016                self.select_prev_state = Some(SelectNextState {
14017                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14018                    wordwise: false,
14019                    done: false,
14020                });
14021                self.select_previous(action, window, cx)?;
14022            }
14023        }
14024        Ok(())
14025    }
14026
14027    pub fn find_next_match(
14028        &mut self,
14029        _: &FindNextMatch,
14030        window: &mut Window,
14031        cx: &mut Context<Self>,
14032    ) -> Result<()> {
14033        let selections = self.selections.disjoint_anchors();
14034        match selections.first() {
14035            Some(first) if selections.len() >= 2 => {
14036                self.change_selections(Default::default(), window, cx, |s| {
14037                    s.select_ranges([first.range()]);
14038                });
14039            }
14040            _ => self.select_next(
14041                &SelectNext {
14042                    replace_newest: true,
14043                },
14044                window,
14045                cx,
14046            )?,
14047        }
14048        Ok(())
14049    }
14050
14051    pub fn find_previous_match(
14052        &mut self,
14053        _: &FindPreviousMatch,
14054        window: &mut Window,
14055        cx: &mut Context<Self>,
14056    ) -> Result<()> {
14057        let selections = self.selections.disjoint_anchors();
14058        match selections.last() {
14059            Some(last) if selections.len() >= 2 => {
14060                self.change_selections(Default::default(), window, cx, |s| {
14061                    s.select_ranges([last.range()]);
14062                });
14063            }
14064            _ => self.select_previous(
14065                &SelectPrevious {
14066                    replace_newest: true,
14067                },
14068                window,
14069                cx,
14070            )?,
14071        }
14072        Ok(())
14073    }
14074
14075    pub fn toggle_comments(
14076        &mut self,
14077        action: &ToggleComments,
14078        window: &mut Window,
14079        cx: &mut Context<Self>,
14080    ) {
14081        if self.read_only(cx) {
14082            return;
14083        }
14084        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14085        let text_layout_details = &self.text_layout_details(window);
14086        self.transact(window, cx, |this, window, cx| {
14087            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14088            let mut edits = Vec::new();
14089            let mut selection_edit_ranges = Vec::new();
14090            let mut last_toggled_row = None;
14091            let snapshot = this.buffer.read(cx).read(cx);
14092            let empty_str: Arc<str> = Arc::default();
14093            let mut suffixes_inserted = Vec::new();
14094            let ignore_indent = action.ignore_indent;
14095
14096            fn comment_prefix_range(
14097                snapshot: &MultiBufferSnapshot,
14098                row: MultiBufferRow,
14099                comment_prefix: &str,
14100                comment_prefix_whitespace: &str,
14101                ignore_indent: bool,
14102            ) -> Range<Point> {
14103                let indent_size = if ignore_indent {
14104                    0
14105                } else {
14106                    snapshot.indent_size_for_line(row).len
14107                };
14108
14109                let start = Point::new(row.0, indent_size);
14110
14111                let mut line_bytes = snapshot
14112                    .bytes_in_range(start..snapshot.max_point())
14113                    .flatten()
14114                    .copied();
14115
14116                // If this line currently begins with the line comment prefix, then record
14117                // the range containing the prefix.
14118                if line_bytes
14119                    .by_ref()
14120                    .take(comment_prefix.len())
14121                    .eq(comment_prefix.bytes())
14122                {
14123                    // Include any whitespace that matches the comment prefix.
14124                    let matching_whitespace_len = line_bytes
14125                        .zip(comment_prefix_whitespace.bytes())
14126                        .take_while(|(a, b)| a == b)
14127                        .count() as u32;
14128                    let end = Point::new(
14129                        start.row,
14130                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14131                    );
14132                    start..end
14133                } else {
14134                    start..start
14135                }
14136            }
14137
14138            fn comment_suffix_range(
14139                snapshot: &MultiBufferSnapshot,
14140                row: MultiBufferRow,
14141                comment_suffix: &str,
14142                comment_suffix_has_leading_space: bool,
14143            ) -> Range<Point> {
14144                let end = Point::new(row.0, snapshot.line_len(row));
14145                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14146
14147                let mut line_end_bytes = snapshot
14148                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14149                    .flatten()
14150                    .copied();
14151
14152                let leading_space_len = if suffix_start_column > 0
14153                    && line_end_bytes.next() == Some(b' ')
14154                    && comment_suffix_has_leading_space
14155                {
14156                    1
14157                } else {
14158                    0
14159                };
14160
14161                // If this line currently begins with the line comment prefix, then record
14162                // the range containing the prefix.
14163                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14164                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14165                    start..end
14166                } else {
14167                    end..end
14168                }
14169            }
14170
14171            // TODO: Handle selections that cross excerpts
14172            for selection in &mut selections {
14173                let start_column = snapshot
14174                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14175                    .len;
14176                let language = if let Some(language) =
14177                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14178                {
14179                    language
14180                } else {
14181                    continue;
14182                };
14183
14184                selection_edit_ranges.clear();
14185
14186                // If multiple selections contain a given row, avoid processing that
14187                // row more than once.
14188                let mut start_row = MultiBufferRow(selection.start.row);
14189                if last_toggled_row == Some(start_row) {
14190                    start_row = start_row.next_row();
14191                }
14192                let end_row =
14193                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14194                        MultiBufferRow(selection.end.row - 1)
14195                    } else {
14196                        MultiBufferRow(selection.end.row)
14197                    };
14198                last_toggled_row = Some(end_row);
14199
14200                if start_row > end_row {
14201                    continue;
14202                }
14203
14204                // If the language has line comments, toggle those.
14205                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14206
14207                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14208                if ignore_indent {
14209                    full_comment_prefixes = full_comment_prefixes
14210                        .into_iter()
14211                        .map(|s| Arc::from(s.trim_end()))
14212                        .collect();
14213                }
14214
14215                if !full_comment_prefixes.is_empty() {
14216                    let first_prefix = full_comment_prefixes
14217                        .first()
14218                        .expect("prefixes is non-empty");
14219                    let prefix_trimmed_lengths = full_comment_prefixes
14220                        .iter()
14221                        .map(|p| p.trim_end_matches(' ').len())
14222                        .collect::<SmallVec<[usize; 4]>>();
14223
14224                    let mut all_selection_lines_are_comments = true;
14225
14226                    for row in start_row.0..=end_row.0 {
14227                        let row = MultiBufferRow(row);
14228                        if start_row < end_row && snapshot.is_line_blank(row) {
14229                            continue;
14230                        }
14231
14232                        let prefix_range = full_comment_prefixes
14233                            .iter()
14234                            .zip(prefix_trimmed_lengths.iter().copied())
14235                            .map(|(prefix, trimmed_prefix_len)| {
14236                                comment_prefix_range(
14237                                    snapshot.deref(),
14238                                    row,
14239                                    &prefix[..trimmed_prefix_len],
14240                                    &prefix[trimmed_prefix_len..],
14241                                    ignore_indent,
14242                                )
14243                            })
14244                            .max_by_key(|range| range.end.column - range.start.column)
14245                            .expect("prefixes is non-empty");
14246
14247                        if prefix_range.is_empty() {
14248                            all_selection_lines_are_comments = false;
14249                        }
14250
14251                        selection_edit_ranges.push(prefix_range);
14252                    }
14253
14254                    if all_selection_lines_are_comments {
14255                        edits.extend(
14256                            selection_edit_ranges
14257                                .iter()
14258                                .cloned()
14259                                .map(|range| (range, empty_str.clone())),
14260                        );
14261                    } else {
14262                        let min_column = selection_edit_ranges
14263                            .iter()
14264                            .map(|range| range.start.column)
14265                            .min()
14266                            .unwrap_or(0);
14267                        edits.extend(selection_edit_ranges.iter().map(|range| {
14268                            let position = Point::new(range.start.row, min_column);
14269                            (position..position, first_prefix.clone())
14270                        }));
14271                    }
14272                } else if let Some((full_comment_prefix, comment_suffix)) =
14273                    language.block_comment_delimiters()
14274                {
14275                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14276                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14277                    let prefix_range = comment_prefix_range(
14278                        snapshot.deref(),
14279                        start_row,
14280                        comment_prefix,
14281                        comment_prefix_whitespace,
14282                        ignore_indent,
14283                    );
14284                    let suffix_range = comment_suffix_range(
14285                        snapshot.deref(),
14286                        end_row,
14287                        comment_suffix.trim_start_matches(' '),
14288                        comment_suffix.starts_with(' '),
14289                    );
14290
14291                    if prefix_range.is_empty() || suffix_range.is_empty() {
14292                        edits.push((
14293                            prefix_range.start..prefix_range.start,
14294                            full_comment_prefix.clone(),
14295                        ));
14296                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14297                        suffixes_inserted.push((end_row, comment_suffix.len()));
14298                    } else {
14299                        edits.push((prefix_range, empty_str.clone()));
14300                        edits.push((suffix_range, empty_str.clone()));
14301                    }
14302                } else {
14303                    continue;
14304                }
14305            }
14306
14307            drop(snapshot);
14308            this.buffer.update(cx, |buffer, cx| {
14309                buffer.edit(edits, None, cx);
14310            });
14311
14312            // Adjust selections so that they end before any comment suffixes that
14313            // were inserted.
14314            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14315            let mut selections = this.selections.all::<Point>(cx);
14316            let snapshot = this.buffer.read(cx).read(cx);
14317            for selection in &mut selections {
14318                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14319                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14320                        Ordering::Less => {
14321                            suffixes_inserted.next();
14322                            continue;
14323                        }
14324                        Ordering::Greater => break,
14325                        Ordering::Equal => {
14326                            if selection.end.column == snapshot.line_len(row) {
14327                                if selection.is_empty() {
14328                                    selection.start.column -= suffix_len as u32;
14329                                }
14330                                selection.end.column -= suffix_len as u32;
14331                            }
14332                            break;
14333                        }
14334                    }
14335                }
14336            }
14337
14338            drop(snapshot);
14339            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14340
14341            let selections = this.selections.all::<Point>(cx);
14342            let selections_on_single_row = selections.windows(2).all(|selections| {
14343                selections[0].start.row == selections[1].start.row
14344                    && selections[0].end.row == selections[1].end.row
14345                    && selections[0].start.row == selections[0].end.row
14346            });
14347            let selections_selecting = selections
14348                .iter()
14349                .any(|selection| selection.start != selection.end);
14350            let advance_downwards = action.advance_downwards
14351                && selections_on_single_row
14352                && !selections_selecting
14353                && !matches!(this.mode, EditorMode::SingleLine { .. });
14354
14355            if advance_downwards {
14356                let snapshot = this.buffer.read(cx).snapshot(cx);
14357
14358                this.change_selections(Default::default(), window, cx, |s| {
14359                    s.move_cursors_with(|display_snapshot, display_point, _| {
14360                        let mut point = display_point.to_point(display_snapshot);
14361                        point.row += 1;
14362                        point = snapshot.clip_point(point, Bias::Left);
14363                        let display_point = point.to_display_point(display_snapshot);
14364                        let goal = SelectionGoal::HorizontalPosition(
14365                            display_snapshot
14366                                .x_for_display_point(display_point, text_layout_details)
14367                                .into(),
14368                        );
14369                        (display_point, goal)
14370                    })
14371                });
14372            }
14373        });
14374    }
14375
14376    pub fn select_enclosing_symbol(
14377        &mut self,
14378        _: &SelectEnclosingSymbol,
14379        window: &mut Window,
14380        cx: &mut Context<Self>,
14381    ) {
14382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14383
14384        let buffer = self.buffer.read(cx).snapshot(cx);
14385        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14386
14387        fn update_selection(
14388            selection: &Selection<usize>,
14389            buffer_snap: &MultiBufferSnapshot,
14390        ) -> Option<Selection<usize>> {
14391            let cursor = selection.head();
14392            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14393            for symbol in symbols.iter().rev() {
14394                let start = symbol.range.start.to_offset(buffer_snap);
14395                let end = symbol.range.end.to_offset(buffer_snap);
14396                let new_range = start..end;
14397                if start < selection.start || end > selection.end {
14398                    return Some(Selection {
14399                        id: selection.id,
14400                        start: new_range.start,
14401                        end: new_range.end,
14402                        goal: SelectionGoal::None,
14403                        reversed: selection.reversed,
14404                    });
14405                }
14406            }
14407            None
14408        }
14409
14410        let mut selected_larger_symbol = false;
14411        let new_selections = old_selections
14412            .iter()
14413            .map(|selection| match update_selection(selection, &buffer) {
14414                Some(new_selection) => {
14415                    if new_selection.range() != selection.range() {
14416                        selected_larger_symbol = true;
14417                    }
14418                    new_selection
14419                }
14420                None => selection.clone(),
14421            })
14422            .collect::<Vec<_>>();
14423
14424        if selected_larger_symbol {
14425            self.change_selections(Default::default(), window, cx, |s| {
14426                s.select(new_selections);
14427            });
14428        }
14429    }
14430
14431    pub fn select_larger_syntax_node(
14432        &mut self,
14433        _: &SelectLargerSyntaxNode,
14434        window: &mut Window,
14435        cx: &mut Context<Self>,
14436    ) {
14437        let Some(visible_row_count) = self.visible_row_count() else {
14438            return;
14439        };
14440        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14441        if old_selections.is_empty() {
14442            return;
14443        }
14444
14445        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14446
14447        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14448        let buffer = self.buffer.read(cx).snapshot(cx);
14449
14450        let mut selected_larger_node = false;
14451        let mut new_selections = old_selections
14452            .iter()
14453            .map(|selection| {
14454                let old_range = selection.start..selection.end;
14455
14456                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14457                    // manually select word at selection
14458                    if ["string_content", "inline"].contains(&node.kind()) {
14459                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14460                        // ignore if word is already selected
14461                        if !word_range.is_empty() && old_range != word_range {
14462                            let (last_word_range, _) =
14463                                buffer.surrounding_word(old_range.end, false);
14464                            // only select word if start and end point belongs to same word
14465                            if word_range == last_word_range {
14466                                selected_larger_node = true;
14467                                return Selection {
14468                                    id: selection.id,
14469                                    start: word_range.start,
14470                                    end: word_range.end,
14471                                    goal: SelectionGoal::None,
14472                                    reversed: selection.reversed,
14473                                };
14474                            }
14475                        }
14476                    }
14477                }
14478
14479                let mut new_range = old_range.clone();
14480                while let Some((_node, containing_range)) =
14481                    buffer.syntax_ancestor(new_range.clone())
14482                {
14483                    new_range = match containing_range {
14484                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14485                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14486                    };
14487                    if !display_map.intersects_fold(new_range.start)
14488                        && !display_map.intersects_fold(new_range.end)
14489                    {
14490                        break;
14491                    }
14492                }
14493
14494                selected_larger_node |= new_range != old_range;
14495                Selection {
14496                    id: selection.id,
14497                    start: new_range.start,
14498                    end: new_range.end,
14499                    goal: SelectionGoal::None,
14500                    reversed: selection.reversed,
14501                }
14502            })
14503            .collect::<Vec<_>>();
14504
14505        if !selected_larger_node {
14506            return; // don't put this call in the history
14507        }
14508
14509        // scroll based on transformation done to the last selection created by the user
14510        let (last_old, last_new) = old_selections
14511            .last()
14512            .zip(new_selections.last().cloned())
14513            .expect("old_selections isn't empty");
14514
14515        // revert selection
14516        let is_selection_reversed = {
14517            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14518            new_selections.last_mut().expect("checked above").reversed =
14519                should_newest_selection_be_reversed;
14520            should_newest_selection_be_reversed
14521        };
14522
14523        if selected_larger_node {
14524            self.select_syntax_node_history.disable_clearing = true;
14525            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14526                s.select(new_selections.clone());
14527            });
14528            self.select_syntax_node_history.disable_clearing = false;
14529        }
14530
14531        let start_row = last_new.start.to_display_point(&display_map).row().0;
14532        let end_row = last_new.end.to_display_point(&display_map).row().0;
14533        let selection_height = end_row - start_row + 1;
14534        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14535
14536        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14537        let scroll_behavior = if fits_on_the_screen {
14538            self.request_autoscroll(Autoscroll::fit(), cx);
14539            SelectSyntaxNodeScrollBehavior::FitSelection
14540        } else if is_selection_reversed {
14541            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14542            SelectSyntaxNodeScrollBehavior::CursorTop
14543        } else {
14544            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14545            SelectSyntaxNodeScrollBehavior::CursorBottom
14546        };
14547
14548        self.select_syntax_node_history.push((
14549            old_selections,
14550            scroll_behavior,
14551            is_selection_reversed,
14552        ));
14553    }
14554
14555    pub fn select_smaller_syntax_node(
14556        &mut self,
14557        _: &SelectSmallerSyntaxNode,
14558        window: &mut Window,
14559        cx: &mut Context<Self>,
14560    ) {
14561        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14562
14563        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14564            self.select_syntax_node_history.pop()
14565        {
14566            if let Some(selection) = selections.last_mut() {
14567                selection.reversed = is_selection_reversed;
14568            }
14569
14570            self.select_syntax_node_history.disable_clearing = true;
14571            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14572                s.select(selections.to_vec());
14573            });
14574            self.select_syntax_node_history.disable_clearing = false;
14575
14576            match scroll_behavior {
14577                SelectSyntaxNodeScrollBehavior::CursorTop => {
14578                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14579                }
14580                SelectSyntaxNodeScrollBehavior::FitSelection => {
14581                    self.request_autoscroll(Autoscroll::fit(), cx);
14582                }
14583                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14584                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14585                }
14586            }
14587        }
14588    }
14589
14590    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14591        if !EditorSettings::get_global(cx).gutter.runnables {
14592            self.clear_tasks();
14593            return Task::ready(());
14594        }
14595        let project = self.project.as_ref().map(Entity::downgrade);
14596        let task_sources = self.lsp_task_sources(cx);
14597        let multi_buffer = self.buffer.downgrade();
14598        cx.spawn_in(window, async move |editor, cx| {
14599            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14600            let Some(project) = project.and_then(|p| p.upgrade()) else {
14601                return;
14602            };
14603            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14604                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14605            }) else {
14606                return;
14607            };
14608
14609            let hide_runnables = project
14610                .update(cx, |project, cx| {
14611                    // Do not display any test indicators in non-dev server remote projects.
14612                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14613                })
14614                .unwrap_or(true);
14615            if hide_runnables {
14616                return;
14617            }
14618            let new_rows =
14619                cx.background_spawn({
14620                    let snapshot = display_snapshot.clone();
14621                    async move {
14622                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14623                    }
14624                })
14625                    .await;
14626            let Ok(lsp_tasks) =
14627                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14628            else {
14629                return;
14630            };
14631            let lsp_tasks = lsp_tasks.await;
14632
14633            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14634                lsp_tasks
14635                    .into_iter()
14636                    .flat_map(|(kind, tasks)| {
14637                        tasks.into_iter().filter_map(move |(location, task)| {
14638                            Some((kind.clone(), location?, task))
14639                        })
14640                    })
14641                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14642                        let buffer = location.target.buffer;
14643                        let buffer_snapshot = buffer.read(cx).snapshot();
14644                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14645                            |(excerpt_id, snapshot, _)| {
14646                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14647                                    display_snapshot
14648                                        .buffer_snapshot
14649                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14650                                } else {
14651                                    None
14652                                }
14653                            },
14654                        );
14655                        if let Some(offset) = offset {
14656                            let task_buffer_range =
14657                                location.target.range.to_point(&buffer_snapshot);
14658                            let context_buffer_range =
14659                                task_buffer_range.to_offset(&buffer_snapshot);
14660                            let context_range = BufferOffset(context_buffer_range.start)
14661                                ..BufferOffset(context_buffer_range.end);
14662
14663                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14664                                .or_insert_with(|| RunnableTasks {
14665                                    templates: Vec::new(),
14666                                    offset,
14667                                    column: task_buffer_range.start.column,
14668                                    extra_variables: HashMap::default(),
14669                                    context_range,
14670                                })
14671                                .templates
14672                                .push((kind, task.original_task().clone()));
14673                        }
14674
14675                        acc
14676                    })
14677            }) else {
14678                return;
14679            };
14680
14681            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14682                buffer.language_settings(cx).tasks.prefer_lsp
14683            }) else {
14684                return;
14685            };
14686
14687            let rows = Self::runnable_rows(
14688                project,
14689                display_snapshot,
14690                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14691                new_rows,
14692                cx.clone(),
14693            )
14694            .await;
14695            editor
14696                .update(cx, |editor, _| {
14697                    editor.clear_tasks();
14698                    for (key, mut value) in rows {
14699                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14700                            value.templates.extend(lsp_tasks.templates);
14701                        }
14702
14703                        editor.insert_tasks(key, value);
14704                    }
14705                    for (key, value) in lsp_tasks_by_rows {
14706                        editor.insert_tasks(key, value);
14707                    }
14708                })
14709                .ok();
14710        })
14711    }
14712    fn fetch_runnable_ranges(
14713        snapshot: &DisplaySnapshot,
14714        range: Range<Anchor>,
14715    ) -> Vec<language::RunnableRange> {
14716        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14717    }
14718
14719    fn runnable_rows(
14720        project: Entity<Project>,
14721        snapshot: DisplaySnapshot,
14722        prefer_lsp: bool,
14723        runnable_ranges: Vec<RunnableRange>,
14724        cx: AsyncWindowContext,
14725    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14726        cx.spawn(async move |cx| {
14727            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14728            for mut runnable in runnable_ranges {
14729                let Some(tasks) = cx
14730                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14731                    .ok()
14732                else {
14733                    continue;
14734                };
14735                let mut tasks = tasks.await;
14736
14737                if prefer_lsp {
14738                    tasks.retain(|(task_kind, _)| {
14739                        !matches!(task_kind, TaskSourceKind::Language { .. })
14740                    });
14741                }
14742                if tasks.is_empty() {
14743                    continue;
14744                }
14745
14746                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14747                let Some(row) = snapshot
14748                    .buffer_snapshot
14749                    .buffer_line_for_row(MultiBufferRow(point.row))
14750                    .map(|(_, range)| range.start.row)
14751                else {
14752                    continue;
14753                };
14754
14755                let context_range =
14756                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14757                runnable_rows.push((
14758                    (runnable.buffer_id, row),
14759                    RunnableTasks {
14760                        templates: tasks,
14761                        offset: snapshot
14762                            .buffer_snapshot
14763                            .anchor_before(runnable.run_range.start),
14764                        context_range,
14765                        column: point.column,
14766                        extra_variables: runnable.extra_captures,
14767                    },
14768                ));
14769            }
14770            runnable_rows
14771        })
14772    }
14773
14774    fn templates_with_tags(
14775        project: &Entity<Project>,
14776        runnable: &mut Runnable,
14777        cx: &mut App,
14778    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14779        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14780            let (worktree_id, file) = project
14781                .buffer_for_id(runnable.buffer, cx)
14782                .and_then(|buffer| buffer.read(cx).file())
14783                .map(|file| (file.worktree_id(cx), file.clone()))
14784                .unzip();
14785
14786            (
14787                project.task_store().read(cx).task_inventory().cloned(),
14788                worktree_id,
14789                file,
14790            )
14791        });
14792
14793        let tags = mem::take(&mut runnable.tags);
14794        let language = runnable.language.clone();
14795        cx.spawn(async move |cx| {
14796            let mut templates_with_tags = Vec::new();
14797            if let Some(inventory) = inventory {
14798                for RunnableTag(tag) in tags {
14799                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14800                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14801                    }) else {
14802                        return templates_with_tags;
14803                    };
14804                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14805                        move |(_, template)| {
14806                            template.tags.iter().any(|source_tag| source_tag == &tag)
14807                        },
14808                    ));
14809                }
14810            }
14811            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14812
14813            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14814                // Strongest source wins; if we have worktree tag binding, prefer that to
14815                // global and language bindings;
14816                // if we have a global binding, prefer that to language binding.
14817                let first_mismatch = templates_with_tags
14818                    .iter()
14819                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14820                if let Some(index) = first_mismatch {
14821                    templates_with_tags.truncate(index);
14822                }
14823            }
14824
14825            templates_with_tags
14826        })
14827    }
14828
14829    pub fn move_to_enclosing_bracket(
14830        &mut self,
14831        _: &MoveToEnclosingBracket,
14832        window: &mut Window,
14833        cx: &mut Context<Self>,
14834    ) {
14835        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14836        self.change_selections(Default::default(), window, cx, |s| {
14837            s.move_offsets_with(|snapshot, selection| {
14838                let Some(enclosing_bracket_ranges) =
14839                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14840                else {
14841                    return;
14842                };
14843
14844                let mut best_length = usize::MAX;
14845                let mut best_inside = false;
14846                let mut best_in_bracket_range = false;
14847                let mut best_destination = None;
14848                for (open, close) in enclosing_bracket_ranges {
14849                    let close = close.to_inclusive();
14850                    let length = close.end() - open.start;
14851                    let inside = selection.start >= open.end && selection.end <= *close.start();
14852                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14853                        || close.contains(&selection.head());
14854
14855                    // If best is next to a bracket and current isn't, skip
14856                    if !in_bracket_range && best_in_bracket_range {
14857                        continue;
14858                    }
14859
14860                    // Prefer smaller lengths unless best is inside and current isn't
14861                    if length > best_length && (best_inside || !inside) {
14862                        continue;
14863                    }
14864
14865                    best_length = length;
14866                    best_inside = inside;
14867                    best_in_bracket_range = in_bracket_range;
14868                    best_destination = Some(
14869                        if close.contains(&selection.start) && close.contains(&selection.end) {
14870                            if inside { open.end } else { open.start }
14871                        } else if inside {
14872                            *close.start()
14873                        } else {
14874                            *close.end()
14875                        },
14876                    );
14877                }
14878
14879                if let Some(destination) = best_destination {
14880                    selection.collapse_to(destination, SelectionGoal::None);
14881                }
14882            })
14883        });
14884    }
14885
14886    pub fn undo_selection(
14887        &mut self,
14888        _: &UndoSelection,
14889        window: &mut Window,
14890        cx: &mut Context<Self>,
14891    ) {
14892        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14893        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14894            self.selection_history.mode = SelectionHistoryMode::Undoing;
14895            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14896                this.end_selection(window, cx);
14897                this.change_selections(
14898                    SelectionEffects::scroll(Autoscroll::newest()),
14899                    window,
14900                    cx,
14901                    |s| s.select_anchors(entry.selections.to_vec()),
14902                );
14903            });
14904            self.selection_history.mode = SelectionHistoryMode::Normal;
14905
14906            self.select_next_state = entry.select_next_state;
14907            self.select_prev_state = entry.select_prev_state;
14908            self.add_selections_state = entry.add_selections_state;
14909        }
14910    }
14911
14912    pub fn redo_selection(
14913        &mut self,
14914        _: &RedoSelection,
14915        window: &mut Window,
14916        cx: &mut Context<Self>,
14917    ) {
14918        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14919        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14920            self.selection_history.mode = SelectionHistoryMode::Redoing;
14921            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14922                this.end_selection(window, cx);
14923                this.change_selections(
14924                    SelectionEffects::scroll(Autoscroll::newest()),
14925                    window,
14926                    cx,
14927                    |s| s.select_anchors(entry.selections.to_vec()),
14928                );
14929            });
14930            self.selection_history.mode = SelectionHistoryMode::Normal;
14931
14932            self.select_next_state = entry.select_next_state;
14933            self.select_prev_state = entry.select_prev_state;
14934            self.add_selections_state = entry.add_selections_state;
14935        }
14936    }
14937
14938    pub fn expand_excerpts(
14939        &mut self,
14940        action: &ExpandExcerpts,
14941        _: &mut Window,
14942        cx: &mut Context<Self>,
14943    ) {
14944        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14945    }
14946
14947    pub fn expand_excerpts_down(
14948        &mut self,
14949        action: &ExpandExcerptsDown,
14950        _: &mut Window,
14951        cx: &mut Context<Self>,
14952    ) {
14953        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14954    }
14955
14956    pub fn expand_excerpts_up(
14957        &mut self,
14958        action: &ExpandExcerptsUp,
14959        _: &mut Window,
14960        cx: &mut Context<Self>,
14961    ) {
14962        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14963    }
14964
14965    pub fn expand_excerpts_for_direction(
14966        &mut self,
14967        lines: u32,
14968        direction: ExpandExcerptDirection,
14969
14970        cx: &mut Context<Self>,
14971    ) {
14972        let selections = self.selections.disjoint_anchors();
14973
14974        let lines = if lines == 0 {
14975            EditorSettings::get_global(cx).expand_excerpt_lines
14976        } else {
14977            lines
14978        };
14979
14980        self.buffer.update(cx, |buffer, cx| {
14981            let snapshot = buffer.snapshot(cx);
14982            let mut excerpt_ids = selections
14983                .iter()
14984                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14985                .collect::<Vec<_>>();
14986            excerpt_ids.sort();
14987            excerpt_ids.dedup();
14988            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14989        })
14990    }
14991
14992    pub fn expand_excerpt(
14993        &mut self,
14994        excerpt: ExcerptId,
14995        direction: ExpandExcerptDirection,
14996        window: &mut Window,
14997        cx: &mut Context<Self>,
14998    ) {
14999        let current_scroll_position = self.scroll_position(cx);
15000        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15001        let mut should_scroll_up = false;
15002
15003        if direction == ExpandExcerptDirection::Down {
15004            let multi_buffer = self.buffer.read(cx);
15005            let snapshot = multi_buffer.snapshot(cx);
15006            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15007                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15008                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15009                        let buffer_snapshot = buffer.read(cx).snapshot();
15010                        let excerpt_end_row =
15011                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15012                        let last_row = buffer_snapshot.max_point().row;
15013                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15014                        should_scroll_up = lines_below >= lines_to_expand;
15015                    }
15016                }
15017            }
15018        }
15019
15020        self.buffer.update(cx, |buffer, cx| {
15021            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15022        });
15023
15024        if should_scroll_up {
15025            let new_scroll_position =
15026                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15027            self.set_scroll_position(new_scroll_position, window, cx);
15028        }
15029    }
15030
15031    pub fn go_to_singleton_buffer_point(
15032        &mut self,
15033        point: Point,
15034        window: &mut Window,
15035        cx: &mut Context<Self>,
15036    ) {
15037        self.go_to_singleton_buffer_range(point..point, window, cx);
15038    }
15039
15040    pub fn go_to_singleton_buffer_range(
15041        &mut self,
15042        range: Range<Point>,
15043        window: &mut Window,
15044        cx: &mut Context<Self>,
15045    ) {
15046        let multibuffer = self.buffer().read(cx);
15047        let Some(buffer) = multibuffer.as_singleton() else {
15048            return;
15049        };
15050        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15051            return;
15052        };
15053        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15054            return;
15055        };
15056        self.change_selections(
15057            SelectionEffects::default().nav_history(true),
15058            window,
15059            cx,
15060            |s| s.select_anchor_ranges([start..end]),
15061        );
15062    }
15063
15064    pub fn go_to_diagnostic(
15065        &mut self,
15066        _: &GoToDiagnostic,
15067        window: &mut Window,
15068        cx: &mut Context<Self>,
15069    ) {
15070        if !self.diagnostics_enabled() {
15071            return;
15072        }
15073        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15074        self.go_to_diagnostic_impl(Direction::Next, window, cx)
15075    }
15076
15077    pub fn go_to_prev_diagnostic(
15078        &mut self,
15079        _: &GoToPreviousDiagnostic,
15080        window: &mut Window,
15081        cx: &mut Context<Self>,
15082    ) {
15083        if !self.diagnostics_enabled() {
15084            return;
15085        }
15086        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15087        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
15088    }
15089
15090    pub fn go_to_diagnostic_impl(
15091        &mut self,
15092        direction: Direction,
15093        window: &mut Window,
15094        cx: &mut Context<Self>,
15095    ) {
15096        let buffer = self.buffer.read(cx).snapshot(cx);
15097        let selection = self.selections.newest::<usize>(cx);
15098
15099        let mut active_group_id = None;
15100        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15101            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15102                active_group_id = Some(active_group.group_id);
15103            }
15104        }
15105
15106        fn filtered(
15107            snapshot: EditorSnapshot,
15108            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15109        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15110            diagnostics
15111                .filter(|entry| entry.range.start != entry.range.end)
15112                .filter(|entry| !entry.diagnostic.is_unnecessary)
15113                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15114        }
15115
15116        let snapshot = self.snapshot(window, cx);
15117        let before = filtered(
15118            snapshot.clone(),
15119            buffer
15120                .diagnostics_in_range(0..selection.start)
15121                .filter(|entry| entry.range.start <= selection.start),
15122        );
15123        let after = filtered(
15124            snapshot,
15125            buffer
15126                .diagnostics_in_range(selection.start..buffer.len())
15127                .filter(|entry| entry.range.start >= selection.start),
15128        );
15129
15130        let mut found: Option<DiagnosticEntry<usize>> = None;
15131        if direction == Direction::Prev {
15132            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15133            {
15134                for diagnostic in prev_diagnostics.into_iter().rev() {
15135                    if diagnostic.range.start != selection.start
15136                        || active_group_id
15137                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15138                    {
15139                        found = Some(diagnostic);
15140                        break 'outer;
15141                    }
15142                }
15143            }
15144        } else {
15145            for diagnostic in after.chain(before) {
15146                if diagnostic.range.start != selection.start
15147                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15148                {
15149                    found = Some(diagnostic);
15150                    break;
15151                }
15152            }
15153        }
15154        let Some(next_diagnostic) = found else {
15155            return;
15156        };
15157
15158        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15159            return;
15160        };
15161        self.change_selections(Default::default(), window, cx, |s| {
15162            s.select_ranges(vec![
15163                next_diagnostic.range.start..next_diagnostic.range.start,
15164            ])
15165        });
15166        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15167        self.refresh_inline_completion(false, true, window, cx);
15168    }
15169
15170    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15172        let snapshot = self.snapshot(window, cx);
15173        let selection = self.selections.newest::<Point>(cx);
15174        self.go_to_hunk_before_or_after_position(
15175            &snapshot,
15176            selection.head(),
15177            Direction::Next,
15178            window,
15179            cx,
15180        );
15181    }
15182
15183    pub fn go_to_hunk_before_or_after_position(
15184        &mut self,
15185        snapshot: &EditorSnapshot,
15186        position: Point,
15187        direction: Direction,
15188        window: &mut Window,
15189        cx: &mut Context<Editor>,
15190    ) {
15191        let row = if direction == Direction::Next {
15192            self.hunk_after_position(snapshot, position)
15193                .map(|hunk| hunk.row_range.start)
15194        } else {
15195            self.hunk_before_position(snapshot, position)
15196        };
15197
15198        if let Some(row) = row {
15199            let destination = Point::new(row.0, 0);
15200            let autoscroll = Autoscroll::center();
15201
15202            self.unfold_ranges(&[destination..destination], false, false, cx);
15203            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15204                s.select_ranges([destination..destination]);
15205            });
15206        }
15207    }
15208
15209    fn hunk_after_position(
15210        &mut self,
15211        snapshot: &EditorSnapshot,
15212        position: Point,
15213    ) -> Option<MultiBufferDiffHunk> {
15214        snapshot
15215            .buffer_snapshot
15216            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15217            .find(|hunk| hunk.row_range.start.0 > position.row)
15218            .or_else(|| {
15219                snapshot
15220                    .buffer_snapshot
15221                    .diff_hunks_in_range(Point::zero()..position)
15222                    .find(|hunk| hunk.row_range.end.0 < position.row)
15223            })
15224    }
15225
15226    fn go_to_prev_hunk(
15227        &mut self,
15228        _: &GoToPreviousHunk,
15229        window: &mut Window,
15230        cx: &mut Context<Self>,
15231    ) {
15232        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15233        let snapshot = self.snapshot(window, cx);
15234        let selection = self.selections.newest::<Point>(cx);
15235        self.go_to_hunk_before_or_after_position(
15236            &snapshot,
15237            selection.head(),
15238            Direction::Prev,
15239            window,
15240            cx,
15241        );
15242    }
15243
15244    fn hunk_before_position(
15245        &mut self,
15246        snapshot: &EditorSnapshot,
15247        position: Point,
15248    ) -> Option<MultiBufferRow> {
15249        snapshot
15250            .buffer_snapshot
15251            .diff_hunk_before(position)
15252            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15253    }
15254
15255    fn go_to_next_change(
15256        &mut self,
15257        _: &GoToNextChange,
15258        window: &mut Window,
15259        cx: &mut Context<Self>,
15260    ) {
15261        if let Some(selections) = self
15262            .change_list
15263            .next_change(1, Direction::Next)
15264            .map(|s| s.to_vec())
15265        {
15266            self.change_selections(Default::default(), window, cx, |s| {
15267                let map = s.display_map();
15268                s.select_display_ranges(selections.iter().map(|a| {
15269                    let point = a.to_display_point(&map);
15270                    point..point
15271                }))
15272            })
15273        }
15274    }
15275
15276    fn go_to_previous_change(
15277        &mut self,
15278        _: &GoToPreviousChange,
15279        window: &mut Window,
15280        cx: &mut Context<Self>,
15281    ) {
15282        if let Some(selections) = self
15283            .change_list
15284            .next_change(1, Direction::Prev)
15285            .map(|s| s.to_vec())
15286        {
15287            self.change_selections(Default::default(), window, cx, |s| {
15288                let map = s.display_map();
15289                s.select_display_ranges(selections.iter().map(|a| {
15290                    let point = a.to_display_point(&map);
15291                    point..point
15292                }))
15293            })
15294        }
15295    }
15296
15297    fn go_to_line<T: 'static>(
15298        &mut self,
15299        position: Anchor,
15300        highlight_color: Option<Hsla>,
15301        window: &mut Window,
15302        cx: &mut Context<Self>,
15303    ) {
15304        let snapshot = self.snapshot(window, cx).display_snapshot;
15305        let position = position.to_point(&snapshot.buffer_snapshot);
15306        let start = snapshot
15307            .buffer_snapshot
15308            .clip_point(Point::new(position.row, 0), Bias::Left);
15309        let end = start + Point::new(1, 0);
15310        let start = snapshot.buffer_snapshot.anchor_before(start);
15311        let end = snapshot.buffer_snapshot.anchor_before(end);
15312
15313        self.highlight_rows::<T>(
15314            start..end,
15315            highlight_color
15316                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15317            Default::default(),
15318            cx,
15319        );
15320
15321        if self.buffer.read(cx).is_singleton() {
15322            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15323        }
15324    }
15325
15326    pub fn go_to_definition(
15327        &mut self,
15328        _: &GoToDefinition,
15329        window: &mut Window,
15330        cx: &mut Context<Self>,
15331    ) -> Task<Result<Navigated>> {
15332        let definition =
15333            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15334        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15335        cx.spawn_in(window, async move |editor, cx| {
15336            if definition.await? == Navigated::Yes {
15337                return Ok(Navigated::Yes);
15338            }
15339            match fallback_strategy {
15340                GoToDefinitionFallback::None => Ok(Navigated::No),
15341                GoToDefinitionFallback::FindAllReferences => {
15342                    match editor.update_in(cx, |editor, window, cx| {
15343                        editor.find_all_references(&FindAllReferences, window, cx)
15344                    })? {
15345                        Some(references) => references.await,
15346                        None => Ok(Navigated::No),
15347                    }
15348                }
15349            }
15350        })
15351    }
15352
15353    pub fn go_to_declaration(
15354        &mut self,
15355        _: &GoToDeclaration,
15356        window: &mut Window,
15357        cx: &mut Context<Self>,
15358    ) -> Task<Result<Navigated>> {
15359        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15360    }
15361
15362    pub fn go_to_declaration_split(
15363        &mut self,
15364        _: &GoToDeclaration,
15365        window: &mut Window,
15366        cx: &mut Context<Self>,
15367    ) -> Task<Result<Navigated>> {
15368        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15369    }
15370
15371    pub fn go_to_implementation(
15372        &mut self,
15373        _: &GoToImplementation,
15374        window: &mut Window,
15375        cx: &mut Context<Self>,
15376    ) -> Task<Result<Navigated>> {
15377        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15378    }
15379
15380    pub fn go_to_implementation_split(
15381        &mut self,
15382        _: &GoToImplementationSplit,
15383        window: &mut Window,
15384        cx: &mut Context<Self>,
15385    ) -> Task<Result<Navigated>> {
15386        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15387    }
15388
15389    pub fn go_to_type_definition(
15390        &mut self,
15391        _: &GoToTypeDefinition,
15392        window: &mut Window,
15393        cx: &mut Context<Self>,
15394    ) -> Task<Result<Navigated>> {
15395        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15396    }
15397
15398    pub fn go_to_definition_split(
15399        &mut self,
15400        _: &GoToDefinitionSplit,
15401        window: &mut Window,
15402        cx: &mut Context<Self>,
15403    ) -> Task<Result<Navigated>> {
15404        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15405    }
15406
15407    pub fn go_to_type_definition_split(
15408        &mut self,
15409        _: &GoToTypeDefinitionSplit,
15410        window: &mut Window,
15411        cx: &mut Context<Self>,
15412    ) -> Task<Result<Navigated>> {
15413        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15414    }
15415
15416    fn go_to_definition_of_kind(
15417        &mut self,
15418        kind: GotoDefinitionKind,
15419        split: bool,
15420        window: &mut Window,
15421        cx: &mut Context<Self>,
15422    ) -> Task<Result<Navigated>> {
15423        let Some(provider) = self.semantics_provider.clone() else {
15424            return Task::ready(Ok(Navigated::No));
15425        };
15426        let head = self.selections.newest::<usize>(cx).head();
15427        let buffer = self.buffer.read(cx);
15428        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15429            text_anchor
15430        } else {
15431            return Task::ready(Ok(Navigated::No));
15432        };
15433
15434        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15435            return Task::ready(Ok(Navigated::No));
15436        };
15437
15438        cx.spawn_in(window, async move |editor, cx| {
15439            let definitions = definitions.await?;
15440            let navigated = editor
15441                .update_in(cx, |editor, window, cx| {
15442                    editor.navigate_to_hover_links(
15443                        Some(kind),
15444                        definitions
15445                            .into_iter()
15446                            .filter(|location| {
15447                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15448                            })
15449                            .map(HoverLink::Text)
15450                            .collect::<Vec<_>>(),
15451                        split,
15452                        window,
15453                        cx,
15454                    )
15455                })?
15456                .await?;
15457            anyhow::Ok(navigated)
15458        })
15459    }
15460
15461    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15462        let selection = self.selections.newest_anchor();
15463        let head = selection.head();
15464        let tail = selection.tail();
15465
15466        let Some((buffer, start_position)) =
15467            self.buffer.read(cx).text_anchor_for_position(head, cx)
15468        else {
15469            return;
15470        };
15471
15472        let end_position = if head != tail {
15473            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15474                return;
15475            };
15476            Some(pos)
15477        } else {
15478            None
15479        };
15480
15481        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15482            let url = if let Some(end_pos) = end_position {
15483                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15484            } else {
15485                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15486            };
15487
15488            if let Some(url) = url {
15489                editor.update(cx, |_, cx| {
15490                    cx.open_url(&url);
15491                })
15492            } else {
15493                Ok(())
15494            }
15495        });
15496
15497        url_finder.detach();
15498    }
15499
15500    pub fn open_selected_filename(
15501        &mut self,
15502        _: &OpenSelectedFilename,
15503        window: &mut Window,
15504        cx: &mut Context<Self>,
15505    ) {
15506        let Some(workspace) = self.workspace() else {
15507            return;
15508        };
15509
15510        let position = self.selections.newest_anchor().head();
15511
15512        let Some((buffer, buffer_position)) =
15513            self.buffer.read(cx).text_anchor_for_position(position, cx)
15514        else {
15515            return;
15516        };
15517
15518        let project = self.project.clone();
15519
15520        cx.spawn_in(window, async move |_, cx| {
15521            let result = find_file(&buffer, project, buffer_position, cx).await;
15522
15523            if let Some((_, path)) = result {
15524                workspace
15525                    .update_in(cx, |workspace, window, cx| {
15526                        workspace.open_resolved_path(path, window, cx)
15527                    })?
15528                    .await?;
15529            }
15530            anyhow::Ok(())
15531        })
15532        .detach();
15533    }
15534
15535    pub(crate) fn navigate_to_hover_links(
15536        &mut self,
15537        kind: Option<GotoDefinitionKind>,
15538        mut definitions: Vec<HoverLink>,
15539        split: bool,
15540        window: &mut Window,
15541        cx: &mut Context<Editor>,
15542    ) -> Task<Result<Navigated>> {
15543        // If there is one definition, just open it directly
15544        if definitions.len() == 1 {
15545            let definition = definitions.pop().unwrap();
15546
15547            enum TargetTaskResult {
15548                Location(Option<Location>),
15549                AlreadyNavigated,
15550            }
15551
15552            let target_task = match definition {
15553                HoverLink::Text(link) => {
15554                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15555                }
15556                HoverLink::InlayHint(lsp_location, server_id) => {
15557                    let computation =
15558                        self.compute_target_location(lsp_location, server_id, window, cx);
15559                    cx.background_spawn(async move {
15560                        let location = computation.await?;
15561                        Ok(TargetTaskResult::Location(location))
15562                    })
15563                }
15564                HoverLink::Url(url) => {
15565                    cx.open_url(&url);
15566                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15567                }
15568                HoverLink::File(path) => {
15569                    if let Some(workspace) = self.workspace() {
15570                        cx.spawn_in(window, async move |_, cx| {
15571                            workspace
15572                                .update_in(cx, |workspace, window, cx| {
15573                                    workspace.open_resolved_path(path, window, cx)
15574                                })?
15575                                .await
15576                                .map(|_| TargetTaskResult::AlreadyNavigated)
15577                        })
15578                    } else {
15579                        Task::ready(Ok(TargetTaskResult::Location(None)))
15580                    }
15581                }
15582            };
15583            cx.spawn_in(window, async move |editor, cx| {
15584                let target = match target_task.await.context("target resolution task")? {
15585                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15586                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15587                    TargetTaskResult::Location(Some(target)) => target,
15588                };
15589
15590                editor.update_in(cx, |editor, window, cx| {
15591                    let Some(workspace) = editor.workspace() else {
15592                        return Navigated::No;
15593                    };
15594                    let pane = workspace.read(cx).active_pane().clone();
15595
15596                    let range = target.range.to_point(target.buffer.read(cx));
15597                    let range = editor.range_for_match(&range);
15598                    let range = collapse_multiline_range(range);
15599
15600                    if !split
15601                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15602                    {
15603                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15604                    } else {
15605                        window.defer(cx, move |window, cx| {
15606                            let target_editor: Entity<Self> =
15607                                workspace.update(cx, |workspace, cx| {
15608                                    let pane = if split {
15609                                        workspace.adjacent_pane(window, cx)
15610                                    } else {
15611                                        workspace.active_pane().clone()
15612                                    };
15613
15614                                    workspace.open_project_item(
15615                                        pane,
15616                                        target.buffer.clone(),
15617                                        true,
15618                                        true,
15619                                        window,
15620                                        cx,
15621                                    )
15622                                });
15623                            target_editor.update(cx, |target_editor, cx| {
15624                                // When selecting a definition in a different buffer, disable the nav history
15625                                // to avoid creating a history entry at the previous cursor location.
15626                                pane.update(cx, |pane, _| pane.disable_history());
15627                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15628                                pane.update(cx, |pane, _| pane.enable_history());
15629                            });
15630                        });
15631                    }
15632                    Navigated::Yes
15633                })
15634            })
15635        } else if !definitions.is_empty() {
15636            cx.spawn_in(window, async move |editor, cx| {
15637                let (title, location_tasks, workspace) = editor
15638                    .update_in(cx, |editor, window, cx| {
15639                        let tab_kind = match kind {
15640                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15641                            _ => "Definitions",
15642                        };
15643                        let title = definitions
15644                            .iter()
15645                            .find_map(|definition| match definition {
15646                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15647                                    let buffer = origin.buffer.read(cx);
15648                                    format!(
15649                                        "{} for {}",
15650                                        tab_kind,
15651                                        buffer
15652                                            .text_for_range(origin.range.clone())
15653                                            .collect::<String>()
15654                                    )
15655                                }),
15656                                HoverLink::InlayHint(_, _) => None,
15657                                HoverLink::Url(_) => None,
15658                                HoverLink::File(_) => None,
15659                            })
15660                            .unwrap_or(tab_kind.to_string());
15661                        let location_tasks = definitions
15662                            .into_iter()
15663                            .map(|definition| match definition {
15664                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15665                                HoverLink::InlayHint(lsp_location, server_id) => editor
15666                                    .compute_target_location(lsp_location, server_id, window, cx),
15667                                HoverLink::Url(_) => Task::ready(Ok(None)),
15668                                HoverLink::File(_) => Task::ready(Ok(None)),
15669                            })
15670                            .collect::<Vec<_>>();
15671                        (title, location_tasks, editor.workspace().clone())
15672                    })
15673                    .context("location tasks preparation")?;
15674
15675                let locations: Vec<Location> = future::join_all(location_tasks)
15676                    .await
15677                    .into_iter()
15678                    .filter_map(|location| location.transpose())
15679                    .collect::<Result<_>>()
15680                    .context("location tasks")?;
15681
15682                if locations.is_empty() {
15683                    return Ok(Navigated::No);
15684                }
15685
15686                let Some(workspace) = workspace else {
15687                    return Ok(Navigated::No);
15688                };
15689
15690                let opened = workspace
15691                    .update_in(cx, |workspace, window, cx| {
15692                        Self::open_locations_in_multibuffer(
15693                            workspace,
15694                            locations,
15695                            title,
15696                            split,
15697                            MultibufferSelectionMode::First,
15698                            window,
15699                            cx,
15700                        )
15701                    })
15702                    .ok();
15703
15704                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15705            })
15706        } else {
15707            Task::ready(Ok(Navigated::No))
15708        }
15709    }
15710
15711    fn compute_target_location(
15712        &self,
15713        lsp_location: lsp::Location,
15714        server_id: LanguageServerId,
15715        window: &mut Window,
15716        cx: &mut Context<Self>,
15717    ) -> Task<anyhow::Result<Option<Location>>> {
15718        let Some(project) = self.project.clone() else {
15719            return Task::ready(Ok(None));
15720        };
15721
15722        cx.spawn_in(window, async move |editor, cx| {
15723            let location_task = editor.update(cx, |_, cx| {
15724                project.update(cx, |project, cx| {
15725                    let language_server_name = project
15726                        .language_server_statuses(cx)
15727                        .find(|(id, _)| server_id == *id)
15728                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15729                    language_server_name.map(|language_server_name| {
15730                        project.open_local_buffer_via_lsp(
15731                            lsp_location.uri.clone(),
15732                            server_id,
15733                            language_server_name,
15734                            cx,
15735                        )
15736                    })
15737                })
15738            })?;
15739            let location = match location_task {
15740                Some(task) => Some({
15741                    let target_buffer_handle = task.await.context("open local buffer")?;
15742                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15743                        let target_start = target_buffer
15744                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15745                        let target_end = target_buffer
15746                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15747                        target_buffer.anchor_after(target_start)
15748                            ..target_buffer.anchor_before(target_end)
15749                    })?;
15750                    Location {
15751                        buffer: target_buffer_handle,
15752                        range,
15753                    }
15754                }),
15755                None => None,
15756            };
15757            Ok(location)
15758        })
15759    }
15760
15761    pub fn find_all_references(
15762        &mut self,
15763        _: &FindAllReferences,
15764        window: &mut Window,
15765        cx: &mut Context<Self>,
15766    ) -> Option<Task<Result<Navigated>>> {
15767        let selection = self.selections.newest::<usize>(cx);
15768        let multi_buffer = self.buffer.read(cx);
15769        let head = selection.head();
15770
15771        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15772        let head_anchor = multi_buffer_snapshot.anchor_at(
15773            head,
15774            if head < selection.tail() {
15775                Bias::Right
15776            } else {
15777                Bias::Left
15778            },
15779        );
15780
15781        match self
15782            .find_all_references_task_sources
15783            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15784        {
15785            Ok(_) => {
15786                log::info!(
15787                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15788                );
15789                return None;
15790            }
15791            Err(i) => {
15792                self.find_all_references_task_sources.insert(i, head_anchor);
15793            }
15794        }
15795
15796        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15797        let workspace = self.workspace()?;
15798        let project = workspace.read(cx).project().clone();
15799        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15800        Some(cx.spawn_in(window, async move |editor, cx| {
15801            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15802                if let Ok(i) = editor
15803                    .find_all_references_task_sources
15804                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15805                {
15806                    editor.find_all_references_task_sources.remove(i);
15807                }
15808            });
15809
15810            let locations = references.await?;
15811            if locations.is_empty() {
15812                return anyhow::Ok(Navigated::No);
15813            }
15814
15815            workspace.update_in(cx, |workspace, window, cx| {
15816                let title = locations
15817                    .first()
15818                    .as_ref()
15819                    .map(|location| {
15820                        let buffer = location.buffer.read(cx);
15821                        format!(
15822                            "References to `{}`",
15823                            buffer
15824                                .text_for_range(location.range.clone())
15825                                .collect::<String>()
15826                        )
15827                    })
15828                    .unwrap();
15829                Self::open_locations_in_multibuffer(
15830                    workspace,
15831                    locations,
15832                    title,
15833                    false,
15834                    MultibufferSelectionMode::First,
15835                    window,
15836                    cx,
15837                );
15838                Navigated::Yes
15839            })
15840        }))
15841    }
15842
15843    /// Opens a multibuffer with the given project locations in it
15844    pub fn open_locations_in_multibuffer(
15845        workspace: &mut Workspace,
15846        mut locations: Vec<Location>,
15847        title: String,
15848        split: bool,
15849        multibuffer_selection_mode: MultibufferSelectionMode,
15850        window: &mut Window,
15851        cx: &mut Context<Workspace>,
15852    ) {
15853        if locations.is_empty() {
15854            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15855            return;
15856        }
15857
15858        // If there are multiple definitions, open them in a multibuffer
15859        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15860        let mut locations = locations.into_iter().peekable();
15861        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15862        let capability = workspace.project().read(cx).capability();
15863
15864        let excerpt_buffer = cx.new(|cx| {
15865            let mut multibuffer = MultiBuffer::new(capability);
15866            while let Some(location) = locations.next() {
15867                let buffer = location.buffer.read(cx);
15868                let mut ranges_for_buffer = Vec::new();
15869                let range = location.range.to_point(buffer);
15870                ranges_for_buffer.push(range.clone());
15871
15872                while let Some(next_location) = locations.peek() {
15873                    if next_location.buffer == location.buffer {
15874                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15875                        locations.next();
15876                    } else {
15877                        break;
15878                    }
15879                }
15880
15881                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15882                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15883                    PathKey::for_buffer(&location.buffer, cx),
15884                    location.buffer.clone(),
15885                    ranges_for_buffer,
15886                    DEFAULT_MULTIBUFFER_CONTEXT,
15887                    cx,
15888                );
15889                ranges.extend(new_ranges)
15890            }
15891
15892            multibuffer.with_title(title)
15893        });
15894
15895        let editor = cx.new(|cx| {
15896            Editor::for_multibuffer(
15897                excerpt_buffer,
15898                Some(workspace.project().clone()),
15899                window,
15900                cx,
15901            )
15902        });
15903        editor.update(cx, |editor, cx| {
15904            match multibuffer_selection_mode {
15905                MultibufferSelectionMode::First => {
15906                    if let Some(first_range) = ranges.first() {
15907                        editor.change_selections(
15908                            SelectionEffects::no_scroll(),
15909                            window,
15910                            cx,
15911                            |selections| {
15912                                selections.clear_disjoint();
15913                                selections
15914                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
15915                            },
15916                        );
15917                    }
15918                    editor.highlight_background::<Self>(
15919                        &ranges,
15920                        |theme| theme.colors().editor_highlighted_line_background,
15921                        cx,
15922                    );
15923                }
15924                MultibufferSelectionMode::All => {
15925                    editor.change_selections(
15926                        SelectionEffects::no_scroll(),
15927                        window,
15928                        cx,
15929                        |selections| {
15930                            selections.clear_disjoint();
15931                            selections.select_anchor_ranges(ranges);
15932                        },
15933                    );
15934                }
15935            }
15936            editor.register_buffers_with_language_servers(cx);
15937        });
15938
15939        let item = Box::new(editor);
15940        let item_id = item.item_id();
15941
15942        if split {
15943            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15944        } else {
15945            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15946                let (preview_item_id, preview_item_idx) =
15947                    workspace.active_pane().read_with(cx, |pane, _| {
15948                        (pane.preview_item_id(), pane.preview_item_idx())
15949                    });
15950
15951                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15952
15953                if let Some(preview_item_id) = preview_item_id {
15954                    workspace.active_pane().update(cx, |pane, cx| {
15955                        pane.remove_item(preview_item_id, false, false, window, cx);
15956                    });
15957                }
15958            } else {
15959                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15960            }
15961        }
15962        workspace.active_pane().update(cx, |pane, cx| {
15963            pane.set_preview_item_id(Some(item_id), cx);
15964        });
15965    }
15966
15967    pub fn rename(
15968        &mut self,
15969        _: &Rename,
15970        window: &mut Window,
15971        cx: &mut Context<Self>,
15972    ) -> Option<Task<Result<()>>> {
15973        use language::ToOffset as _;
15974
15975        let provider = self.semantics_provider.clone()?;
15976        let selection = self.selections.newest_anchor().clone();
15977        let (cursor_buffer, cursor_buffer_position) = self
15978            .buffer
15979            .read(cx)
15980            .text_anchor_for_position(selection.head(), cx)?;
15981        let (tail_buffer, cursor_buffer_position_end) = self
15982            .buffer
15983            .read(cx)
15984            .text_anchor_for_position(selection.tail(), cx)?;
15985        if tail_buffer != cursor_buffer {
15986            return None;
15987        }
15988
15989        let snapshot = cursor_buffer.read(cx).snapshot();
15990        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15991        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15992        let prepare_rename = provider
15993            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15994            .unwrap_or_else(|| Task::ready(Ok(None)));
15995        drop(snapshot);
15996
15997        Some(cx.spawn_in(window, async move |this, cx| {
15998            let rename_range = if let Some(range) = prepare_rename.await? {
15999                Some(range)
16000            } else {
16001                this.update(cx, |this, cx| {
16002                    let buffer = this.buffer.read(cx).snapshot(cx);
16003                    let mut buffer_highlights = this
16004                        .document_highlights_for_position(selection.head(), &buffer)
16005                        .filter(|highlight| {
16006                            highlight.start.excerpt_id == selection.head().excerpt_id
16007                                && highlight.end.excerpt_id == selection.head().excerpt_id
16008                        });
16009                    buffer_highlights
16010                        .next()
16011                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16012                })?
16013            };
16014            if let Some(rename_range) = rename_range {
16015                this.update_in(cx, |this, window, cx| {
16016                    let snapshot = cursor_buffer.read(cx).snapshot();
16017                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16018                    let cursor_offset_in_rename_range =
16019                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16020                    let cursor_offset_in_rename_range_end =
16021                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16022
16023                    this.take_rename(false, window, cx);
16024                    let buffer = this.buffer.read(cx).read(cx);
16025                    let cursor_offset = selection.head().to_offset(&buffer);
16026                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16027                    let rename_end = rename_start + rename_buffer_range.len();
16028                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16029                    let mut old_highlight_id = None;
16030                    let old_name: Arc<str> = buffer
16031                        .chunks(rename_start..rename_end, true)
16032                        .map(|chunk| {
16033                            if old_highlight_id.is_none() {
16034                                old_highlight_id = chunk.syntax_highlight_id;
16035                            }
16036                            chunk.text
16037                        })
16038                        .collect::<String>()
16039                        .into();
16040
16041                    drop(buffer);
16042
16043                    // Position the selection in the rename editor so that it matches the current selection.
16044                    this.show_local_selections = false;
16045                    let rename_editor = cx.new(|cx| {
16046                        let mut editor = Editor::single_line(window, cx);
16047                        editor.buffer.update(cx, |buffer, cx| {
16048                            buffer.edit([(0..0, old_name.clone())], None, cx)
16049                        });
16050                        let rename_selection_range = match cursor_offset_in_rename_range
16051                            .cmp(&cursor_offset_in_rename_range_end)
16052                        {
16053                            Ordering::Equal => {
16054                                editor.select_all(&SelectAll, window, cx);
16055                                return editor;
16056                            }
16057                            Ordering::Less => {
16058                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16059                            }
16060                            Ordering::Greater => {
16061                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16062                            }
16063                        };
16064                        if rename_selection_range.end > old_name.len() {
16065                            editor.select_all(&SelectAll, window, cx);
16066                        } else {
16067                            editor.change_selections(Default::default(), window, cx, |s| {
16068                                s.select_ranges([rename_selection_range]);
16069                            });
16070                        }
16071                        editor
16072                    });
16073                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16074                        if e == &EditorEvent::Focused {
16075                            cx.emit(EditorEvent::FocusedIn)
16076                        }
16077                    })
16078                    .detach();
16079
16080                    let write_highlights =
16081                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16082                    let read_highlights =
16083                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16084                    let ranges = write_highlights
16085                        .iter()
16086                        .flat_map(|(_, ranges)| ranges.iter())
16087                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16088                        .cloned()
16089                        .collect();
16090
16091                    this.highlight_text::<Rename>(
16092                        ranges,
16093                        HighlightStyle {
16094                            fade_out: Some(0.6),
16095                            ..Default::default()
16096                        },
16097                        cx,
16098                    );
16099                    let rename_focus_handle = rename_editor.focus_handle(cx);
16100                    window.focus(&rename_focus_handle);
16101                    let block_id = this.insert_blocks(
16102                        [BlockProperties {
16103                            style: BlockStyle::Flex,
16104                            placement: BlockPlacement::Below(range.start),
16105                            height: Some(1),
16106                            render: Arc::new({
16107                                let rename_editor = rename_editor.clone();
16108                                move |cx: &mut BlockContext| {
16109                                    let mut text_style = cx.editor_style.text.clone();
16110                                    if let Some(highlight_style) = old_highlight_id
16111                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16112                                    {
16113                                        text_style = text_style.highlight(highlight_style);
16114                                    }
16115                                    div()
16116                                        .block_mouse_except_scroll()
16117                                        .pl(cx.anchor_x)
16118                                        .child(EditorElement::new(
16119                                            &rename_editor,
16120                                            EditorStyle {
16121                                                background: cx.theme().system().transparent,
16122                                                local_player: cx.editor_style.local_player,
16123                                                text: text_style,
16124                                                scrollbar_width: cx.editor_style.scrollbar_width,
16125                                                syntax: cx.editor_style.syntax.clone(),
16126                                                status: cx.editor_style.status.clone(),
16127                                                inlay_hints_style: HighlightStyle {
16128                                                    font_weight: Some(FontWeight::BOLD),
16129                                                    ..make_inlay_hints_style(cx.app)
16130                                                },
16131                                                inline_completion_styles: make_suggestion_styles(
16132                                                    cx.app,
16133                                                ),
16134                                                ..EditorStyle::default()
16135                                            },
16136                                        ))
16137                                        .into_any_element()
16138                                }
16139                            }),
16140                            priority: 0,
16141                            render_in_minimap: true,
16142                        }],
16143                        Some(Autoscroll::fit()),
16144                        cx,
16145                    )[0];
16146                    this.pending_rename = Some(RenameState {
16147                        range,
16148                        old_name,
16149                        editor: rename_editor,
16150                        block_id,
16151                    });
16152                })?;
16153            }
16154
16155            Ok(())
16156        }))
16157    }
16158
16159    pub fn confirm_rename(
16160        &mut self,
16161        _: &ConfirmRename,
16162        window: &mut Window,
16163        cx: &mut Context<Self>,
16164    ) -> Option<Task<Result<()>>> {
16165        let rename = self.take_rename(false, window, cx)?;
16166        let workspace = self.workspace()?.downgrade();
16167        let (buffer, start) = self
16168            .buffer
16169            .read(cx)
16170            .text_anchor_for_position(rename.range.start, cx)?;
16171        let (end_buffer, _) = self
16172            .buffer
16173            .read(cx)
16174            .text_anchor_for_position(rename.range.end, cx)?;
16175        if buffer != end_buffer {
16176            return None;
16177        }
16178
16179        let old_name = rename.old_name;
16180        let new_name = rename.editor.read(cx).text(cx);
16181
16182        let rename = self.semantics_provider.as_ref()?.perform_rename(
16183            &buffer,
16184            start,
16185            new_name.clone(),
16186            cx,
16187        )?;
16188
16189        Some(cx.spawn_in(window, async move |editor, cx| {
16190            let project_transaction = rename.await?;
16191            Self::open_project_transaction(
16192                &editor,
16193                workspace,
16194                project_transaction,
16195                format!("Rename: {}{}", old_name, new_name),
16196                cx,
16197            )
16198            .await?;
16199
16200            editor.update(cx, |editor, cx| {
16201                editor.refresh_document_highlights(cx);
16202            })?;
16203            Ok(())
16204        }))
16205    }
16206
16207    fn take_rename(
16208        &mut self,
16209        moving_cursor: bool,
16210        window: &mut Window,
16211        cx: &mut Context<Self>,
16212    ) -> Option<RenameState> {
16213        let rename = self.pending_rename.take()?;
16214        if rename.editor.focus_handle(cx).is_focused(window) {
16215            window.focus(&self.focus_handle);
16216        }
16217
16218        self.remove_blocks(
16219            [rename.block_id].into_iter().collect(),
16220            Some(Autoscroll::fit()),
16221            cx,
16222        );
16223        self.clear_highlights::<Rename>(cx);
16224        self.show_local_selections = true;
16225
16226        if moving_cursor {
16227            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16228                editor.selections.newest::<usize>(cx).head()
16229            });
16230
16231            // Update the selection to match the position of the selection inside
16232            // the rename editor.
16233            let snapshot = self.buffer.read(cx).read(cx);
16234            let rename_range = rename.range.to_offset(&snapshot);
16235            let cursor_in_editor = snapshot
16236                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16237                .min(rename_range.end);
16238            drop(snapshot);
16239
16240            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16241                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16242            });
16243        } else {
16244            self.refresh_document_highlights(cx);
16245        }
16246
16247        Some(rename)
16248    }
16249
16250    pub fn pending_rename(&self) -> Option<&RenameState> {
16251        self.pending_rename.as_ref()
16252    }
16253
16254    fn format(
16255        &mut self,
16256        _: &Format,
16257        window: &mut Window,
16258        cx: &mut Context<Self>,
16259    ) -> Option<Task<Result<()>>> {
16260        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16261
16262        let project = match &self.project {
16263            Some(project) => project.clone(),
16264            None => return None,
16265        };
16266
16267        Some(self.perform_format(
16268            project,
16269            FormatTrigger::Manual,
16270            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16271            window,
16272            cx,
16273        ))
16274    }
16275
16276    fn format_selections(
16277        &mut self,
16278        _: &FormatSelections,
16279        window: &mut Window,
16280        cx: &mut Context<Self>,
16281    ) -> Option<Task<Result<()>>> {
16282        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16283
16284        let project = match &self.project {
16285            Some(project) => project.clone(),
16286            None => return None,
16287        };
16288
16289        let ranges = self
16290            .selections
16291            .all_adjusted(cx)
16292            .into_iter()
16293            .map(|selection| selection.range())
16294            .collect_vec();
16295
16296        Some(self.perform_format(
16297            project,
16298            FormatTrigger::Manual,
16299            FormatTarget::Ranges(ranges),
16300            window,
16301            cx,
16302        ))
16303    }
16304
16305    fn perform_format(
16306        &mut self,
16307        project: Entity<Project>,
16308        trigger: FormatTrigger,
16309        target: FormatTarget,
16310        window: &mut Window,
16311        cx: &mut Context<Self>,
16312    ) -> Task<Result<()>> {
16313        let buffer = self.buffer.clone();
16314        let (buffers, target) = match target {
16315            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16316            FormatTarget::Ranges(selection_ranges) => {
16317                let multi_buffer = buffer.read(cx);
16318                let snapshot = multi_buffer.read(cx);
16319                let mut buffers = HashSet::default();
16320                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16321                    BTreeMap::new();
16322                for selection_range in selection_ranges {
16323                    for (buffer, buffer_range, _) in
16324                        snapshot.range_to_buffer_ranges(selection_range)
16325                    {
16326                        let buffer_id = buffer.remote_id();
16327                        let start = buffer.anchor_before(buffer_range.start);
16328                        let end = buffer.anchor_after(buffer_range.end);
16329                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16330                        buffer_id_to_ranges
16331                            .entry(buffer_id)
16332                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16333                            .or_insert_with(|| vec![start..end]);
16334                    }
16335                }
16336                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16337            }
16338        };
16339
16340        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16341        let selections_prev = transaction_id_prev
16342            .and_then(|transaction_id_prev| {
16343                // default to selections as they were after the last edit, if we have them,
16344                // instead of how they are now.
16345                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16346                // will take you back to where you made the last edit, instead of staying where you scrolled
16347                self.selection_history
16348                    .transaction(transaction_id_prev)
16349                    .map(|t| t.0.clone())
16350            })
16351            .unwrap_or_else(|| {
16352                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16353                self.selections.disjoint_anchors()
16354            });
16355
16356        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16357        let format = project.update(cx, |project, cx| {
16358            project.format(buffers, target, true, trigger, cx)
16359        });
16360
16361        cx.spawn_in(window, async move |editor, cx| {
16362            let transaction = futures::select_biased! {
16363                transaction = format.log_err().fuse() => transaction,
16364                () = timeout => {
16365                    log::warn!("timed out waiting for formatting");
16366                    None
16367                }
16368            };
16369
16370            buffer
16371                .update(cx, |buffer, cx| {
16372                    if let Some(transaction) = transaction {
16373                        if !buffer.is_singleton() {
16374                            buffer.push_transaction(&transaction.0, cx);
16375                        }
16376                    }
16377                    cx.notify();
16378                })
16379                .ok();
16380
16381            if let Some(transaction_id_now) =
16382                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16383            {
16384                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16385                if has_new_transaction {
16386                    _ = editor.update(cx, |editor, _| {
16387                        editor
16388                            .selection_history
16389                            .insert_transaction(transaction_id_now, selections_prev);
16390                    });
16391                }
16392            }
16393
16394            Ok(())
16395        })
16396    }
16397
16398    fn organize_imports(
16399        &mut self,
16400        _: &OrganizeImports,
16401        window: &mut Window,
16402        cx: &mut Context<Self>,
16403    ) -> Option<Task<Result<()>>> {
16404        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16405        let project = match &self.project {
16406            Some(project) => project.clone(),
16407            None => return None,
16408        };
16409        Some(self.perform_code_action_kind(
16410            project,
16411            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16412            window,
16413            cx,
16414        ))
16415    }
16416
16417    fn perform_code_action_kind(
16418        &mut self,
16419        project: Entity<Project>,
16420        kind: CodeActionKind,
16421        window: &mut Window,
16422        cx: &mut Context<Self>,
16423    ) -> Task<Result<()>> {
16424        let buffer = self.buffer.clone();
16425        let buffers = buffer.read(cx).all_buffers();
16426        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16427        let apply_action = project.update(cx, |project, cx| {
16428            project.apply_code_action_kind(buffers, kind, true, cx)
16429        });
16430        cx.spawn_in(window, async move |_, cx| {
16431            let transaction = futures::select_biased! {
16432                () = timeout => {
16433                    log::warn!("timed out waiting for executing code action");
16434                    None
16435                }
16436                transaction = apply_action.log_err().fuse() => transaction,
16437            };
16438            buffer
16439                .update(cx, |buffer, cx| {
16440                    // check if we need this
16441                    if let Some(transaction) = transaction {
16442                        if !buffer.is_singleton() {
16443                            buffer.push_transaction(&transaction.0, cx);
16444                        }
16445                    }
16446                    cx.notify();
16447                })
16448                .ok();
16449            Ok(())
16450        })
16451    }
16452
16453    pub fn restart_language_server(
16454        &mut self,
16455        _: &RestartLanguageServer,
16456        _: &mut Window,
16457        cx: &mut Context<Self>,
16458    ) {
16459        if let Some(project) = self.project.clone() {
16460            self.buffer.update(cx, |multi_buffer, cx| {
16461                project.update(cx, |project, cx| {
16462                    project.restart_language_servers_for_buffers(
16463                        multi_buffer.all_buffers().into_iter().collect(),
16464                        HashSet::default(),
16465                        cx,
16466                    );
16467                });
16468            })
16469        }
16470    }
16471
16472    pub fn stop_language_server(
16473        &mut self,
16474        _: &StopLanguageServer,
16475        _: &mut Window,
16476        cx: &mut Context<Self>,
16477    ) {
16478        if let Some(project) = self.project.clone() {
16479            self.buffer.update(cx, |multi_buffer, cx| {
16480                project.update(cx, |project, cx| {
16481                    project.stop_language_servers_for_buffers(
16482                        multi_buffer.all_buffers().into_iter().collect(),
16483                        HashSet::default(),
16484                        cx,
16485                    );
16486                    cx.emit(project::Event::RefreshInlayHints);
16487                });
16488            });
16489        }
16490    }
16491
16492    fn cancel_language_server_work(
16493        workspace: &mut Workspace,
16494        _: &actions::CancelLanguageServerWork,
16495        _: &mut Window,
16496        cx: &mut Context<Workspace>,
16497    ) {
16498        let project = workspace.project();
16499        let buffers = workspace
16500            .active_item(cx)
16501            .and_then(|item| item.act_as::<Editor>(cx))
16502            .map_or(HashSet::default(), |editor| {
16503                editor.read(cx).buffer.read(cx).all_buffers()
16504            });
16505        project.update(cx, |project, cx| {
16506            project.cancel_language_server_work_for_buffers(buffers, cx);
16507        });
16508    }
16509
16510    fn show_character_palette(
16511        &mut self,
16512        _: &ShowCharacterPalette,
16513        window: &mut Window,
16514        _: &mut Context<Self>,
16515    ) {
16516        window.show_character_palette();
16517    }
16518
16519    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16520        if !self.diagnostics_enabled() {
16521            return;
16522        }
16523
16524        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16525            let buffer = self.buffer.read(cx).snapshot(cx);
16526            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16527            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16528            let is_valid = buffer
16529                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16530                .any(|entry| {
16531                    entry.diagnostic.is_primary
16532                        && !entry.range.is_empty()
16533                        && entry.range.start == primary_range_start
16534                        && entry.diagnostic.message == active_diagnostics.active_message
16535                });
16536
16537            if !is_valid {
16538                self.dismiss_diagnostics(cx);
16539            }
16540        }
16541    }
16542
16543    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16544        match &self.active_diagnostics {
16545            ActiveDiagnostic::Group(group) => Some(group),
16546            _ => None,
16547        }
16548    }
16549
16550    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16551        if !self.diagnostics_enabled() {
16552            return;
16553        }
16554        self.dismiss_diagnostics(cx);
16555        self.active_diagnostics = ActiveDiagnostic::All;
16556    }
16557
16558    fn activate_diagnostics(
16559        &mut self,
16560        buffer_id: BufferId,
16561        diagnostic: DiagnosticEntry<usize>,
16562        window: &mut Window,
16563        cx: &mut Context<Self>,
16564    ) {
16565        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16566            return;
16567        }
16568        self.dismiss_diagnostics(cx);
16569        let snapshot = self.snapshot(window, cx);
16570        let buffer = self.buffer.read(cx).snapshot(cx);
16571        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16572            return;
16573        };
16574
16575        let diagnostic_group = buffer
16576            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16577            .collect::<Vec<_>>();
16578
16579        let blocks =
16580            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16581
16582        let blocks = self.display_map.update(cx, |display_map, cx| {
16583            display_map.insert_blocks(blocks, cx).into_iter().collect()
16584        });
16585        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16586            active_range: buffer.anchor_before(diagnostic.range.start)
16587                ..buffer.anchor_after(diagnostic.range.end),
16588            active_message: diagnostic.diagnostic.message.clone(),
16589            group_id: diagnostic.diagnostic.group_id,
16590            blocks,
16591        });
16592        cx.notify();
16593    }
16594
16595    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16596        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16597            return;
16598        };
16599
16600        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16601        if let ActiveDiagnostic::Group(group) = prev {
16602            self.display_map.update(cx, |display_map, cx| {
16603                display_map.remove_blocks(group.blocks, cx);
16604            });
16605            cx.notify();
16606        }
16607    }
16608
16609    /// Disable inline diagnostics rendering for this editor.
16610    pub fn disable_inline_diagnostics(&mut self) {
16611        self.inline_diagnostics_enabled = false;
16612        self.inline_diagnostics_update = Task::ready(());
16613        self.inline_diagnostics.clear();
16614    }
16615
16616    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16617        self.diagnostics_enabled = false;
16618        self.dismiss_diagnostics(cx);
16619        self.inline_diagnostics_update = Task::ready(());
16620        self.inline_diagnostics.clear();
16621    }
16622
16623    pub fn diagnostics_enabled(&self) -> bool {
16624        self.diagnostics_enabled && self.mode.is_full()
16625    }
16626
16627    pub fn inline_diagnostics_enabled(&self) -> bool {
16628        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16629    }
16630
16631    pub fn show_inline_diagnostics(&self) -> bool {
16632        self.show_inline_diagnostics
16633    }
16634
16635    pub fn toggle_inline_diagnostics(
16636        &mut self,
16637        _: &ToggleInlineDiagnostics,
16638        window: &mut Window,
16639        cx: &mut Context<Editor>,
16640    ) {
16641        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16642        self.refresh_inline_diagnostics(false, window, cx);
16643    }
16644
16645    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16646        self.diagnostics_max_severity = severity;
16647        self.display_map.update(cx, |display_map, _| {
16648            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16649        });
16650    }
16651
16652    pub fn toggle_diagnostics(
16653        &mut self,
16654        _: &ToggleDiagnostics,
16655        window: &mut Window,
16656        cx: &mut Context<Editor>,
16657    ) {
16658        if !self.diagnostics_enabled() {
16659            return;
16660        }
16661
16662        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16663            EditorSettings::get_global(cx)
16664                .diagnostics_max_severity
16665                .filter(|severity| severity != &DiagnosticSeverity::Off)
16666                .unwrap_or(DiagnosticSeverity::Hint)
16667        } else {
16668            DiagnosticSeverity::Off
16669        };
16670        self.set_max_diagnostics_severity(new_severity, cx);
16671        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16672            self.active_diagnostics = ActiveDiagnostic::None;
16673            self.inline_diagnostics_update = Task::ready(());
16674            self.inline_diagnostics.clear();
16675        } else {
16676            self.refresh_inline_diagnostics(false, window, cx);
16677        }
16678
16679        cx.notify();
16680    }
16681
16682    pub fn toggle_minimap(
16683        &mut self,
16684        _: &ToggleMinimap,
16685        window: &mut Window,
16686        cx: &mut Context<Editor>,
16687    ) {
16688        if self.supports_minimap(cx) {
16689            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16690        }
16691    }
16692
16693    fn refresh_inline_diagnostics(
16694        &mut self,
16695        debounce: bool,
16696        window: &mut Window,
16697        cx: &mut Context<Self>,
16698    ) {
16699        let max_severity = ProjectSettings::get_global(cx)
16700            .diagnostics
16701            .inline
16702            .max_severity
16703            .unwrap_or(self.diagnostics_max_severity);
16704
16705        if !self.inline_diagnostics_enabled()
16706            || !self.show_inline_diagnostics
16707            || max_severity == DiagnosticSeverity::Off
16708        {
16709            self.inline_diagnostics_update = Task::ready(());
16710            self.inline_diagnostics.clear();
16711            return;
16712        }
16713
16714        let debounce_ms = ProjectSettings::get_global(cx)
16715            .diagnostics
16716            .inline
16717            .update_debounce_ms;
16718        let debounce = if debounce && debounce_ms > 0 {
16719            Some(Duration::from_millis(debounce_ms))
16720        } else {
16721            None
16722        };
16723        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16724            if let Some(debounce) = debounce {
16725                cx.background_executor().timer(debounce).await;
16726            }
16727            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16728                editor
16729                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16730                    .ok()
16731            }) else {
16732                return;
16733            };
16734
16735            let new_inline_diagnostics = cx
16736                .background_spawn(async move {
16737                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16738                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16739                        let message = diagnostic_entry
16740                            .diagnostic
16741                            .message
16742                            .split_once('\n')
16743                            .map(|(line, _)| line)
16744                            .map(SharedString::new)
16745                            .unwrap_or_else(|| {
16746                                SharedString::from(diagnostic_entry.diagnostic.message)
16747                            });
16748                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16749                        let (Ok(i) | Err(i)) = inline_diagnostics
16750                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16751                        inline_diagnostics.insert(
16752                            i,
16753                            (
16754                                start_anchor,
16755                                InlineDiagnostic {
16756                                    message,
16757                                    group_id: diagnostic_entry.diagnostic.group_id,
16758                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16759                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16760                                    severity: diagnostic_entry.diagnostic.severity,
16761                                },
16762                            ),
16763                        );
16764                    }
16765                    inline_diagnostics
16766                })
16767                .await;
16768
16769            editor
16770                .update(cx, |editor, cx| {
16771                    editor.inline_diagnostics = new_inline_diagnostics;
16772                    cx.notify();
16773                })
16774                .ok();
16775        });
16776    }
16777
16778    fn pull_diagnostics(
16779        &mut self,
16780        buffer_id: Option<BufferId>,
16781        window: &Window,
16782        cx: &mut Context<Self>,
16783    ) -> Option<()> {
16784        if !self.mode().is_full() {
16785            return None;
16786        }
16787        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16788            .diagnostics
16789            .lsp_pull_diagnostics;
16790        if !pull_diagnostics_settings.enabled {
16791            return None;
16792        }
16793        let project = self.project.as_ref()?.downgrade();
16794        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16795        let mut buffers = self.buffer.read(cx).all_buffers();
16796        if let Some(buffer_id) = buffer_id {
16797            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16798        }
16799
16800        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16801            cx.background_executor().timer(debounce).await;
16802
16803            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16804                buffers
16805                    .into_iter()
16806                    .filter_map(|buffer| {
16807                        project
16808                            .update(cx, |project, cx| {
16809                                project.lsp_store().update(cx, |lsp_store, cx| {
16810                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16811                                })
16812                            })
16813                            .ok()
16814                    })
16815                    .collect::<FuturesUnordered<_>>()
16816            }) else {
16817                return;
16818            };
16819
16820            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16821                match pull_task {
16822                    Ok(()) => {
16823                        if editor
16824                            .update_in(cx, |editor, window, cx| {
16825                                editor.update_diagnostics_state(window, cx);
16826                            })
16827                            .is_err()
16828                        {
16829                            return;
16830                        }
16831                    }
16832                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16833                }
16834            }
16835        });
16836
16837        Some(())
16838    }
16839
16840    pub fn set_selections_from_remote(
16841        &mut self,
16842        selections: Vec<Selection<Anchor>>,
16843        pending_selection: Option<Selection<Anchor>>,
16844        window: &mut Window,
16845        cx: &mut Context<Self>,
16846    ) {
16847        let old_cursor_position = self.selections.newest_anchor().head();
16848        self.selections.change_with(cx, |s| {
16849            s.select_anchors(selections);
16850            if let Some(pending_selection) = pending_selection {
16851                s.set_pending(pending_selection, SelectMode::Character);
16852            } else {
16853                s.clear_pending();
16854            }
16855        });
16856        self.selections_did_change(
16857            false,
16858            &old_cursor_position,
16859            SelectionEffects::default(),
16860            window,
16861            cx,
16862        );
16863    }
16864
16865    pub fn transact(
16866        &mut self,
16867        window: &mut Window,
16868        cx: &mut Context<Self>,
16869        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16870    ) -> Option<TransactionId> {
16871        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16872            this.start_transaction_at(Instant::now(), window, cx);
16873            update(this, window, cx);
16874            this.end_transaction_at(Instant::now(), cx)
16875        })
16876    }
16877
16878    pub fn start_transaction_at(
16879        &mut self,
16880        now: Instant,
16881        window: &mut Window,
16882        cx: &mut Context<Self>,
16883    ) {
16884        self.end_selection(window, cx);
16885        if let Some(tx_id) = self
16886            .buffer
16887            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16888        {
16889            self.selection_history
16890                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16891            cx.emit(EditorEvent::TransactionBegun {
16892                transaction_id: tx_id,
16893            })
16894        }
16895    }
16896
16897    pub fn end_transaction_at(
16898        &mut self,
16899        now: Instant,
16900        cx: &mut Context<Self>,
16901    ) -> Option<TransactionId> {
16902        if let Some(transaction_id) = self
16903            .buffer
16904            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16905        {
16906            if let Some((_, end_selections)) =
16907                self.selection_history.transaction_mut(transaction_id)
16908            {
16909                *end_selections = Some(self.selections.disjoint_anchors());
16910            } else {
16911                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16912            }
16913
16914            cx.emit(EditorEvent::Edited { transaction_id });
16915            Some(transaction_id)
16916        } else {
16917            None
16918        }
16919    }
16920
16921    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16922        if self.selection_mark_mode {
16923            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16924                s.move_with(|_, sel| {
16925                    sel.collapse_to(sel.head(), SelectionGoal::None);
16926                });
16927            })
16928        }
16929        self.selection_mark_mode = true;
16930        cx.notify();
16931    }
16932
16933    pub fn swap_selection_ends(
16934        &mut self,
16935        _: &actions::SwapSelectionEnds,
16936        window: &mut Window,
16937        cx: &mut Context<Self>,
16938    ) {
16939        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16940            s.move_with(|_, sel| {
16941                if sel.start != sel.end {
16942                    sel.reversed = !sel.reversed
16943                }
16944            });
16945        });
16946        self.request_autoscroll(Autoscroll::newest(), cx);
16947        cx.notify();
16948    }
16949
16950    pub fn toggle_fold(
16951        &mut self,
16952        _: &actions::ToggleFold,
16953        window: &mut Window,
16954        cx: &mut Context<Self>,
16955    ) {
16956        if self.is_singleton(cx) {
16957            let selection = self.selections.newest::<Point>(cx);
16958
16959            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16960            let range = if selection.is_empty() {
16961                let point = selection.head().to_display_point(&display_map);
16962                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16963                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16964                    .to_point(&display_map);
16965                start..end
16966            } else {
16967                selection.range()
16968            };
16969            if display_map.folds_in_range(range).next().is_some() {
16970                self.unfold_lines(&Default::default(), window, cx)
16971            } else {
16972                self.fold(&Default::default(), window, cx)
16973            }
16974        } else {
16975            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16976            let buffer_ids: HashSet<_> = self
16977                .selections
16978                .disjoint_anchor_ranges()
16979                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16980                .collect();
16981
16982            let should_unfold = buffer_ids
16983                .iter()
16984                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16985
16986            for buffer_id in buffer_ids {
16987                if should_unfold {
16988                    self.unfold_buffer(buffer_id, cx);
16989                } else {
16990                    self.fold_buffer(buffer_id, cx);
16991                }
16992            }
16993        }
16994    }
16995
16996    pub fn toggle_fold_recursive(
16997        &mut self,
16998        _: &actions::ToggleFoldRecursive,
16999        window: &mut Window,
17000        cx: &mut Context<Self>,
17001    ) {
17002        let selection = self.selections.newest::<Point>(cx);
17003
17004        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17005        let range = if selection.is_empty() {
17006            let point = selection.head().to_display_point(&display_map);
17007            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17008            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17009                .to_point(&display_map);
17010            start..end
17011        } else {
17012            selection.range()
17013        };
17014        if display_map.folds_in_range(range).next().is_some() {
17015            self.unfold_recursive(&Default::default(), window, cx)
17016        } else {
17017            self.fold_recursive(&Default::default(), window, cx)
17018        }
17019    }
17020
17021    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17022        if self.is_singleton(cx) {
17023            let mut to_fold = Vec::new();
17024            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17025            let selections = self.selections.all_adjusted(cx);
17026
17027            for selection in selections {
17028                let range = selection.range().sorted();
17029                let buffer_start_row = range.start.row;
17030
17031                if range.start.row != range.end.row {
17032                    let mut found = false;
17033                    let mut row = range.start.row;
17034                    while row <= range.end.row {
17035                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17036                        {
17037                            found = true;
17038                            row = crease.range().end.row + 1;
17039                            to_fold.push(crease);
17040                        } else {
17041                            row += 1
17042                        }
17043                    }
17044                    if found {
17045                        continue;
17046                    }
17047                }
17048
17049                for row in (0..=range.start.row).rev() {
17050                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17051                        if crease.range().end.row >= buffer_start_row {
17052                            to_fold.push(crease);
17053                            if row <= range.start.row {
17054                                break;
17055                            }
17056                        }
17057                    }
17058                }
17059            }
17060
17061            self.fold_creases(to_fold, true, window, cx);
17062        } else {
17063            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17064            let buffer_ids = self
17065                .selections
17066                .disjoint_anchor_ranges()
17067                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17068                .collect::<HashSet<_>>();
17069            for buffer_id in buffer_ids {
17070                self.fold_buffer(buffer_id, cx);
17071            }
17072        }
17073    }
17074
17075    fn fold_at_level(
17076        &mut self,
17077        fold_at: &FoldAtLevel,
17078        window: &mut Window,
17079        cx: &mut Context<Self>,
17080    ) {
17081        if !self.buffer.read(cx).is_singleton() {
17082            return;
17083        }
17084
17085        let fold_at_level = fold_at.0;
17086        let snapshot = self.buffer.read(cx).snapshot(cx);
17087        let mut to_fold = Vec::new();
17088        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17089
17090        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17091            while start_row < end_row {
17092                match self
17093                    .snapshot(window, cx)
17094                    .crease_for_buffer_row(MultiBufferRow(start_row))
17095                {
17096                    Some(crease) => {
17097                        let nested_start_row = crease.range().start.row + 1;
17098                        let nested_end_row = crease.range().end.row;
17099
17100                        if current_level < fold_at_level {
17101                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17102                        } else if current_level == fold_at_level {
17103                            to_fold.push(crease);
17104                        }
17105
17106                        start_row = nested_end_row + 1;
17107                    }
17108                    None => start_row += 1,
17109                }
17110            }
17111        }
17112
17113        self.fold_creases(to_fold, true, window, cx);
17114    }
17115
17116    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17117        if self.buffer.read(cx).is_singleton() {
17118            let mut fold_ranges = Vec::new();
17119            let snapshot = self.buffer.read(cx).snapshot(cx);
17120
17121            for row in 0..snapshot.max_row().0 {
17122                if let Some(foldable_range) = self
17123                    .snapshot(window, cx)
17124                    .crease_for_buffer_row(MultiBufferRow(row))
17125                {
17126                    fold_ranges.push(foldable_range);
17127                }
17128            }
17129
17130            self.fold_creases(fold_ranges, true, window, cx);
17131        } else {
17132            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17133                editor
17134                    .update_in(cx, |editor, _, cx| {
17135                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17136                            editor.fold_buffer(buffer_id, cx);
17137                        }
17138                    })
17139                    .ok();
17140            });
17141        }
17142    }
17143
17144    pub fn fold_function_bodies(
17145        &mut self,
17146        _: &actions::FoldFunctionBodies,
17147        window: &mut Window,
17148        cx: &mut Context<Self>,
17149    ) {
17150        let snapshot = self.buffer.read(cx).snapshot(cx);
17151
17152        let ranges = snapshot
17153            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17154            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17155            .collect::<Vec<_>>();
17156
17157        let creases = ranges
17158            .into_iter()
17159            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17160            .collect();
17161
17162        self.fold_creases(creases, true, window, cx);
17163    }
17164
17165    pub fn fold_recursive(
17166        &mut self,
17167        _: &actions::FoldRecursive,
17168        window: &mut Window,
17169        cx: &mut Context<Self>,
17170    ) {
17171        let mut to_fold = Vec::new();
17172        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17173        let selections = self.selections.all_adjusted(cx);
17174
17175        for selection in selections {
17176            let range = selection.range().sorted();
17177            let buffer_start_row = range.start.row;
17178
17179            if range.start.row != range.end.row {
17180                let mut found = false;
17181                for row in range.start.row..=range.end.row {
17182                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17183                        found = true;
17184                        to_fold.push(crease);
17185                    }
17186                }
17187                if found {
17188                    continue;
17189                }
17190            }
17191
17192            for row in (0..=range.start.row).rev() {
17193                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17194                    if crease.range().end.row >= buffer_start_row {
17195                        to_fold.push(crease);
17196                    } else {
17197                        break;
17198                    }
17199                }
17200            }
17201        }
17202
17203        self.fold_creases(to_fold, true, window, cx);
17204    }
17205
17206    pub fn fold_at(
17207        &mut self,
17208        buffer_row: MultiBufferRow,
17209        window: &mut Window,
17210        cx: &mut Context<Self>,
17211    ) {
17212        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17213
17214        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17215            let autoscroll = self
17216                .selections
17217                .all::<Point>(cx)
17218                .iter()
17219                .any(|selection| crease.range().overlaps(&selection.range()));
17220
17221            self.fold_creases(vec![crease], autoscroll, window, cx);
17222        }
17223    }
17224
17225    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17226        if self.is_singleton(cx) {
17227            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17228            let buffer = &display_map.buffer_snapshot;
17229            let selections = self.selections.all::<Point>(cx);
17230            let ranges = selections
17231                .iter()
17232                .map(|s| {
17233                    let range = s.display_range(&display_map).sorted();
17234                    let mut start = range.start.to_point(&display_map);
17235                    let mut end = range.end.to_point(&display_map);
17236                    start.column = 0;
17237                    end.column = buffer.line_len(MultiBufferRow(end.row));
17238                    start..end
17239                })
17240                .collect::<Vec<_>>();
17241
17242            self.unfold_ranges(&ranges, true, true, cx);
17243        } else {
17244            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17245            let buffer_ids = self
17246                .selections
17247                .disjoint_anchor_ranges()
17248                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17249                .collect::<HashSet<_>>();
17250            for buffer_id in buffer_ids {
17251                self.unfold_buffer(buffer_id, cx);
17252            }
17253        }
17254    }
17255
17256    pub fn unfold_recursive(
17257        &mut self,
17258        _: &UnfoldRecursive,
17259        _window: &mut Window,
17260        cx: &mut Context<Self>,
17261    ) {
17262        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17263        let selections = self.selections.all::<Point>(cx);
17264        let ranges = selections
17265            .iter()
17266            .map(|s| {
17267                let mut range = s.display_range(&display_map).sorted();
17268                *range.start.column_mut() = 0;
17269                *range.end.column_mut() = display_map.line_len(range.end.row());
17270                let start = range.start.to_point(&display_map);
17271                let end = range.end.to_point(&display_map);
17272                start..end
17273            })
17274            .collect::<Vec<_>>();
17275
17276        self.unfold_ranges(&ranges, true, true, cx);
17277    }
17278
17279    pub fn unfold_at(
17280        &mut self,
17281        buffer_row: MultiBufferRow,
17282        _window: &mut Window,
17283        cx: &mut Context<Self>,
17284    ) {
17285        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17286
17287        let intersection_range = Point::new(buffer_row.0, 0)
17288            ..Point::new(
17289                buffer_row.0,
17290                display_map.buffer_snapshot.line_len(buffer_row),
17291            );
17292
17293        let autoscroll = self
17294            .selections
17295            .all::<Point>(cx)
17296            .iter()
17297            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17298
17299        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17300    }
17301
17302    pub fn unfold_all(
17303        &mut self,
17304        _: &actions::UnfoldAll,
17305        _window: &mut Window,
17306        cx: &mut Context<Self>,
17307    ) {
17308        if self.buffer.read(cx).is_singleton() {
17309            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17310            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17311        } else {
17312            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17313                editor
17314                    .update(cx, |editor, cx| {
17315                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17316                            editor.unfold_buffer(buffer_id, cx);
17317                        }
17318                    })
17319                    .ok();
17320            });
17321        }
17322    }
17323
17324    pub fn fold_selected_ranges(
17325        &mut self,
17326        _: &FoldSelectedRanges,
17327        window: &mut Window,
17328        cx: &mut Context<Self>,
17329    ) {
17330        let selections = self.selections.all_adjusted(cx);
17331        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17332        let ranges = selections
17333            .into_iter()
17334            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17335            .collect::<Vec<_>>();
17336        self.fold_creases(ranges, true, window, cx);
17337    }
17338
17339    pub fn fold_ranges<T: ToOffset + Clone>(
17340        &mut self,
17341        ranges: Vec<Range<T>>,
17342        auto_scroll: bool,
17343        window: &mut Window,
17344        cx: &mut Context<Self>,
17345    ) {
17346        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17347        let ranges = ranges
17348            .into_iter()
17349            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17350            .collect::<Vec<_>>();
17351        self.fold_creases(ranges, auto_scroll, window, cx);
17352    }
17353
17354    pub fn fold_creases<T: ToOffset + Clone>(
17355        &mut self,
17356        creases: Vec<Crease<T>>,
17357        auto_scroll: bool,
17358        _window: &mut Window,
17359        cx: &mut Context<Self>,
17360    ) {
17361        if creases.is_empty() {
17362            return;
17363        }
17364
17365        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17366
17367        if auto_scroll {
17368            self.request_autoscroll(Autoscroll::fit(), cx);
17369        }
17370
17371        cx.notify();
17372
17373        self.scrollbar_marker_state.dirty = true;
17374        self.folds_did_change(cx);
17375    }
17376
17377    /// Removes any folds whose ranges intersect any of the given ranges.
17378    pub fn unfold_ranges<T: ToOffset + Clone>(
17379        &mut self,
17380        ranges: &[Range<T>],
17381        inclusive: bool,
17382        auto_scroll: bool,
17383        cx: &mut Context<Self>,
17384    ) {
17385        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17386            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17387        });
17388        self.folds_did_change(cx);
17389    }
17390
17391    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17392        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17393            return;
17394        }
17395        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17396        self.display_map.update(cx, |display_map, cx| {
17397            display_map.fold_buffers([buffer_id], cx)
17398        });
17399        cx.emit(EditorEvent::BufferFoldToggled {
17400            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17401            folded: true,
17402        });
17403        cx.notify();
17404    }
17405
17406    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17407        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17408            return;
17409        }
17410        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17411        self.display_map.update(cx, |display_map, cx| {
17412            display_map.unfold_buffers([buffer_id], cx);
17413        });
17414        cx.emit(EditorEvent::BufferFoldToggled {
17415            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17416            folded: false,
17417        });
17418        cx.notify();
17419    }
17420
17421    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17422        self.display_map.read(cx).is_buffer_folded(buffer)
17423    }
17424
17425    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17426        self.display_map.read(cx).folded_buffers()
17427    }
17428
17429    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17430        self.display_map.update(cx, |display_map, cx| {
17431            display_map.disable_header_for_buffer(buffer_id, cx);
17432        });
17433        cx.notify();
17434    }
17435
17436    /// Removes any folds with the given ranges.
17437    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17438        &mut self,
17439        ranges: &[Range<T>],
17440        type_id: TypeId,
17441        auto_scroll: bool,
17442        cx: &mut Context<Self>,
17443    ) {
17444        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17445            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17446        });
17447        self.folds_did_change(cx);
17448    }
17449
17450    fn remove_folds_with<T: ToOffset + Clone>(
17451        &mut self,
17452        ranges: &[Range<T>],
17453        auto_scroll: bool,
17454        cx: &mut Context<Self>,
17455        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17456    ) {
17457        if ranges.is_empty() {
17458            return;
17459        }
17460
17461        let mut buffers_affected = HashSet::default();
17462        let multi_buffer = self.buffer().read(cx);
17463        for range in ranges {
17464            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17465                buffers_affected.insert(buffer.read(cx).remote_id());
17466            };
17467        }
17468
17469        self.display_map.update(cx, update);
17470
17471        if auto_scroll {
17472            self.request_autoscroll(Autoscroll::fit(), cx);
17473        }
17474
17475        cx.notify();
17476        self.scrollbar_marker_state.dirty = true;
17477        self.active_indent_guides_state.dirty = true;
17478    }
17479
17480    pub fn update_renderer_widths(
17481        &mut self,
17482        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17483        cx: &mut Context<Self>,
17484    ) -> bool {
17485        self.display_map
17486            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17487    }
17488
17489    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17490        self.display_map.read(cx).fold_placeholder.clone()
17491    }
17492
17493    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17494        self.buffer.update(cx, |buffer, cx| {
17495            buffer.set_all_diff_hunks_expanded(cx);
17496        });
17497    }
17498
17499    pub fn expand_all_diff_hunks(
17500        &mut self,
17501        _: &ExpandAllDiffHunks,
17502        _window: &mut Window,
17503        cx: &mut Context<Self>,
17504    ) {
17505        self.buffer.update(cx, |buffer, cx| {
17506            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17507        });
17508    }
17509
17510    pub fn toggle_selected_diff_hunks(
17511        &mut self,
17512        _: &ToggleSelectedDiffHunks,
17513        _window: &mut Window,
17514        cx: &mut Context<Self>,
17515    ) {
17516        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17517        self.toggle_diff_hunks_in_ranges(ranges, cx);
17518    }
17519
17520    pub fn diff_hunks_in_ranges<'a>(
17521        &'a self,
17522        ranges: &'a [Range<Anchor>],
17523        buffer: &'a MultiBufferSnapshot,
17524    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17525        ranges.iter().flat_map(move |range| {
17526            let end_excerpt_id = range.end.excerpt_id;
17527            let range = range.to_point(buffer);
17528            let mut peek_end = range.end;
17529            if range.end.row < buffer.max_row().0 {
17530                peek_end = Point::new(range.end.row + 1, 0);
17531            }
17532            buffer
17533                .diff_hunks_in_range(range.start..peek_end)
17534                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17535        })
17536    }
17537
17538    pub fn has_stageable_diff_hunks_in_ranges(
17539        &self,
17540        ranges: &[Range<Anchor>],
17541        snapshot: &MultiBufferSnapshot,
17542    ) -> bool {
17543        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17544        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17545    }
17546
17547    pub fn toggle_staged_selected_diff_hunks(
17548        &mut self,
17549        _: &::git::ToggleStaged,
17550        _: &mut Window,
17551        cx: &mut Context<Self>,
17552    ) {
17553        let snapshot = self.buffer.read(cx).snapshot(cx);
17554        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17555        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17556        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17557    }
17558
17559    pub fn set_render_diff_hunk_controls(
17560        &mut self,
17561        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17562        cx: &mut Context<Self>,
17563    ) {
17564        self.render_diff_hunk_controls = render_diff_hunk_controls;
17565        cx.notify();
17566    }
17567
17568    pub fn stage_and_next(
17569        &mut self,
17570        _: &::git::StageAndNext,
17571        window: &mut Window,
17572        cx: &mut Context<Self>,
17573    ) {
17574        self.do_stage_or_unstage_and_next(true, window, cx);
17575    }
17576
17577    pub fn unstage_and_next(
17578        &mut self,
17579        _: &::git::UnstageAndNext,
17580        window: &mut Window,
17581        cx: &mut Context<Self>,
17582    ) {
17583        self.do_stage_or_unstage_and_next(false, window, cx);
17584    }
17585
17586    pub fn stage_or_unstage_diff_hunks(
17587        &mut self,
17588        stage: bool,
17589        ranges: Vec<Range<Anchor>>,
17590        cx: &mut Context<Self>,
17591    ) {
17592        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17593        cx.spawn(async move |this, cx| {
17594            task.await?;
17595            this.update(cx, |this, cx| {
17596                let snapshot = this.buffer.read(cx).snapshot(cx);
17597                let chunk_by = this
17598                    .diff_hunks_in_ranges(&ranges, &snapshot)
17599                    .chunk_by(|hunk| hunk.buffer_id);
17600                for (buffer_id, hunks) in &chunk_by {
17601                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17602                }
17603            })
17604        })
17605        .detach_and_log_err(cx);
17606    }
17607
17608    fn save_buffers_for_ranges_if_needed(
17609        &mut self,
17610        ranges: &[Range<Anchor>],
17611        cx: &mut Context<Editor>,
17612    ) -> Task<Result<()>> {
17613        let multibuffer = self.buffer.read(cx);
17614        let snapshot = multibuffer.read(cx);
17615        let buffer_ids: HashSet<_> = ranges
17616            .iter()
17617            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17618            .collect();
17619        drop(snapshot);
17620
17621        let mut buffers = HashSet::default();
17622        for buffer_id in buffer_ids {
17623            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17624                let buffer = buffer_entity.read(cx);
17625                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17626                {
17627                    buffers.insert(buffer_entity);
17628                }
17629            }
17630        }
17631
17632        if let Some(project) = &self.project {
17633            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17634        } else {
17635            Task::ready(Ok(()))
17636        }
17637    }
17638
17639    fn do_stage_or_unstage_and_next(
17640        &mut self,
17641        stage: bool,
17642        window: &mut Window,
17643        cx: &mut Context<Self>,
17644    ) {
17645        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17646
17647        if ranges.iter().any(|range| range.start != range.end) {
17648            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17649            return;
17650        }
17651
17652        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17653        let snapshot = self.snapshot(window, cx);
17654        let position = self.selections.newest::<Point>(cx).head();
17655        let mut row = snapshot
17656            .buffer_snapshot
17657            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17658            .find(|hunk| hunk.row_range.start.0 > position.row)
17659            .map(|hunk| hunk.row_range.start);
17660
17661        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17662        // Outside of the project diff editor, wrap around to the beginning.
17663        if !all_diff_hunks_expanded {
17664            row = row.or_else(|| {
17665                snapshot
17666                    .buffer_snapshot
17667                    .diff_hunks_in_range(Point::zero()..position)
17668                    .find(|hunk| hunk.row_range.end.0 < position.row)
17669                    .map(|hunk| hunk.row_range.start)
17670            });
17671        }
17672
17673        if let Some(row) = row {
17674            let destination = Point::new(row.0, 0);
17675            let autoscroll = Autoscroll::center();
17676
17677            self.unfold_ranges(&[destination..destination], false, false, cx);
17678            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17679                s.select_ranges([destination..destination]);
17680            });
17681        }
17682    }
17683
17684    fn do_stage_or_unstage(
17685        &self,
17686        stage: bool,
17687        buffer_id: BufferId,
17688        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17689        cx: &mut App,
17690    ) -> Option<()> {
17691        let project = self.project.as_ref()?;
17692        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17693        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17694        let buffer_snapshot = buffer.read(cx).snapshot();
17695        let file_exists = buffer_snapshot
17696            .file()
17697            .is_some_and(|file| file.disk_state().exists());
17698        diff.update(cx, |diff, cx| {
17699            diff.stage_or_unstage_hunks(
17700                stage,
17701                &hunks
17702                    .map(|hunk| buffer_diff::DiffHunk {
17703                        buffer_range: hunk.buffer_range,
17704                        diff_base_byte_range: hunk.diff_base_byte_range,
17705                        secondary_status: hunk.secondary_status,
17706                        range: Point::zero()..Point::zero(), // unused
17707                    })
17708                    .collect::<Vec<_>>(),
17709                &buffer_snapshot,
17710                file_exists,
17711                cx,
17712            )
17713        });
17714        None
17715    }
17716
17717    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17718        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17719        self.buffer
17720            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17721    }
17722
17723    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17724        self.buffer.update(cx, |buffer, cx| {
17725            let ranges = vec![Anchor::min()..Anchor::max()];
17726            if !buffer.all_diff_hunks_expanded()
17727                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17728            {
17729                buffer.collapse_diff_hunks(ranges, cx);
17730                true
17731            } else {
17732                false
17733            }
17734        })
17735    }
17736
17737    fn toggle_diff_hunks_in_ranges(
17738        &mut self,
17739        ranges: Vec<Range<Anchor>>,
17740        cx: &mut Context<Editor>,
17741    ) {
17742        self.buffer.update(cx, |buffer, cx| {
17743            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17744            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17745        })
17746    }
17747
17748    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17749        self.buffer.update(cx, |buffer, cx| {
17750            let snapshot = buffer.snapshot(cx);
17751            let excerpt_id = range.end.excerpt_id;
17752            let point_range = range.to_point(&snapshot);
17753            let expand = !buffer.single_hunk_is_expanded(range, cx);
17754            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17755        })
17756    }
17757
17758    pub(crate) fn apply_all_diff_hunks(
17759        &mut self,
17760        _: &ApplyAllDiffHunks,
17761        window: &mut Window,
17762        cx: &mut Context<Self>,
17763    ) {
17764        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17765
17766        let buffers = self.buffer.read(cx).all_buffers();
17767        for branch_buffer in buffers {
17768            branch_buffer.update(cx, |branch_buffer, cx| {
17769                branch_buffer.merge_into_base(Vec::new(), cx);
17770            });
17771        }
17772
17773        if let Some(project) = self.project.clone() {
17774            self.save(
17775                SaveOptions {
17776                    format: true,
17777                    autosave: false,
17778                },
17779                project,
17780                window,
17781                cx,
17782            )
17783            .detach_and_log_err(cx);
17784        }
17785    }
17786
17787    pub(crate) fn apply_selected_diff_hunks(
17788        &mut self,
17789        _: &ApplyDiffHunk,
17790        window: &mut Window,
17791        cx: &mut Context<Self>,
17792    ) {
17793        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17794        let snapshot = self.snapshot(window, cx);
17795        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17796        let mut ranges_by_buffer = HashMap::default();
17797        self.transact(window, cx, |editor, _window, cx| {
17798            for hunk in hunks {
17799                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17800                    ranges_by_buffer
17801                        .entry(buffer.clone())
17802                        .or_insert_with(Vec::new)
17803                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17804                }
17805            }
17806
17807            for (buffer, ranges) in ranges_by_buffer {
17808                buffer.update(cx, |buffer, cx| {
17809                    buffer.merge_into_base(ranges, cx);
17810                });
17811            }
17812        });
17813
17814        if let Some(project) = self.project.clone() {
17815            self.save(
17816                SaveOptions {
17817                    format: true,
17818                    autosave: false,
17819                },
17820                project,
17821                window,
17822                cx,
17823            )
17824            .detach_and_log_err(cx);
17825        }
17826    }
17827
17828    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17829        if hovered != self.gutter_hovered {
17830            self.gutter_hovered = hovered;
17831            cx.notify();
17832        }
17833    }
17834
17835    pub fn insert_blocks(
17836        &mut self,
17837        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17838        autoscroll: Option<Autoscroll>,
17839        cx: &mut Context<Self>,
17840    ) -> Vec<CustomBlockId> {
17841        let blocks = self
17842            .display_map
17843            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17844        if let Some(autoscroll) = autoscroll {
17845            self.request_autoscroll(autoscroll, cx);
17846        }
17847        cx.notify();
17848        blocks
17849    }
17850
17851    pub fn resize_blocks(
17852        &mut self,
17853        heights: HashMap<CustomBlockId, u32>,
17854        autoscroll: Option<Autoscroll>,
17855        cx: &mut Context<Self>,
17856    ) {
17857        self.display_map
17858            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17859        if let Some(autoscroll) = autoscroll {
17860            self.request_autoscroll(autoscroll, cx);
17861        }
17862        cx.notify();
17863    }
17864
17865    pub fn replace_blocks(
17866        &mut self,
17867        renderers: HashMap<CustomBlockId, RenderBlock>,
17868        autoscroll: Option<Autoscroll>,
17869        cx: &mut Context<Self>,
17870    ) {
17871        self.display_map
17872            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17873        if let Some(autoscroll) = autoscroll {
17874            self.request_autoscroll(autoscroll, cx);
17875        }
17876        cx.notify();
17877    }
17878
17879    pub fn remove_blocks(
17880        &mut self,
17881        block_ids: HashSet<CustomBlockId>,
17882        autoscroll: Option<Autoscroll>,
17883        cx: &mut Context<Self>,
17884    ) {
17885        self.display_map.update(cx, |display_map, cx| {
17886            display_map.remove_blocks(block_ids, cx)
17887        });
17888        if let Some(autoscroll) = autoscroll {
17889            self.request_autoscroll(autoscroll, cx);
17890        }
17891        cx.notify();
17892    }
17893
17894    pub fn row_for_block(
17895        &self,
17896        block_id: CustomBlockId,
17897        cx: &mut Context<Self>,
17898    ) -> Option<DisplayRow> {
17899        self.display_map
17900            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17901    }
17902
17903    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17904        self.focused_block = Some(focused_block);
17905    }
17906
17907    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17908        self.focused_block.take()
17909    }
17910
17911    pub fn insert_creases(
17912        &mut self,
17913        creases: impl IntoIterator<Item = Crease<Anchor>>,
17914        cx: &mut Context<Self>,
17915    ) -> Vec<CreaseId> {
17916        self.display_map
17917            .update(cx, |map, cx| map.insert_creases(creases, cx))
17918    }
17919
17920    pub fn remove_creases(
17921        &mut self,
17922        ids: impl IntoIterator<Item = CreaseId>,
17923        cx: &mut Context<Self>,
17924    ) -> Vec<(CreaseId, Range<Anchor>)> {
17925        self.display_map
17926            .update(cx, |map, cx| map.remove_creases(ids, cx))
17927    }
17928
17929    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17930        self.display_map
17931            .update(cx, |map, cx| map.snapshot(cx))
17932            .longest_row()
17933    }
17934
17935    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17936        self.display_map
17937            .update(cx, |map, cx| map.snapshot(cx))
17938            .max_point()
17939    }
17940
17941    pub fn text(&self, cx: &App) -> String {
17942        self.buffer.read(cx).read(cx).text()
17943    }
17944
17945    pub fn is_empty(&self, cx: &App) -> bool {
17946        self.buffer.read(cx).read(cx).is_empty()
17947    }
17948
17949    pub fn text_option(&self, cx: &App) -> Option<String> {
17950        let text = self.text(cx);
17951        let text = text.trim();
17952
17953        if text.is_empty() {
17954            return None;
17955        }
17956
17957        Some(text.to_string())
17958    }
17959
17960    pub fn set_text(
17961        &mut self,
17962        text: impl Into<Arc<str>>,
17963        window: &mut Window,
17964        cx: &mut Context<Self>,
17965    ) {
17966        self.transact(window, cx, |this, _, cx| {
17967            this.buffer
17968                .read(cx)
17969                .as_singleton()
17970                .expect("you can only call set_text on editors for singleton buffers")
17971                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17972        });
17973    }
17974
17975    pub fn display_text(&self, cx: &mut App) -> String {
17976        self.display_map
17977            .update(cx, |map, cx| map.snapshot(cx))
17978            .text()
17979    }
17980
17981    fn create_minimap(
17982        &self,
17983        minimap_settings: MinimapSettings,
17984        window: &mut Window,
17985        cx: &mut Context<Self>,
17986    ) -> Option<Entity<Self>> {
17987        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17988            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17989    }
17990
17991    fn initialize_new_minimap(
17992        &self,
17993        minimap_settings: MinimapSettings,
17994        window: &mut Window,
17995        cx: &mut Context<Self>,
17996    ) -> Entity<Self> {
17997        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17998
17999        let mut minimap = Editor::new_internal(
18000            EditorMode::Minimap {
18001                parent: cx.weak_entity(),
18002            },
18003            self.buffer.clone(),
18004            self.project.clone(),
18005            Some(self.display_map.clone()),
18006            window,
18007            cx,
18008        );
18009        minimap.scroll_manager.clone_state(&self.scroll_manager);
18010        minimap.set_text_style_refinement(TextStyleRefinement {
18011            font_size: Some(MINIMAP_FONT_SIZE),
18012            font_weight: Some(MINIMAP_FONT_WEIGHT),
18013            ..Default::default()
18014        });
18015        minimap.update_minimap_configuration(minimap_settings, cx);
18016        cx.new(|_| minimap)
18017    }
18018
18019    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18020        let current_line_highlight = minimap_settings
18021            .current_line_highlight
18022            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18023        self.set_current_line_highlight(Some(current_line_highlight));
18024    }
18025
18026    pub fn minimap(&self) -> Option<&Entity<Self>> {
18027        self.minimap
18028            .as_ref()
18029            .filter(|_| self.minimap_visibility.visible())
18030    }
18031
18032    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18033        let mut wrap_guides = smallvec![];
18034
18035        if self.show_wrap_guides == Some(false) {
18036            return wrap_guides;
18037        }
18038
18039        let settings = self.buffer.read(cx).language_settings(cx);
18040        if settings.show_wrap_guides {
18041            match self.soft_wrap_mode(cx) {
18042                SoftWrap::Column(soft_wrap) => {
18043                    wrap_guides.push((soft_wrap as usize, true));
18044                }
18045                SoftWrap::Bounded(soft_wrap) => {
18046                    wrap_guides.push((soft_wrap as usize, true));
18047                }
18048                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18049            }
18050            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18051        }
18052
18053        wrap_guides
18054    }
18055
18056    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18057        let settings = self.buffer.read(cx).language_settings(cx);
18058        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18059        match mode {
18060            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18061                SoftWrap::None
18062            }
18063            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18064            language_settings::SoftWrap::PreferredLineLength => {
18065                SoftWrap::Column(settings.preferred_line_length)
18066            }
18067            language_settings::SoftWrap::Bounded => {
18068                SoftWrap::Bounded(settings.preferred_line_length)
18069            }
18070        }
18071    }
18072
18073    pub fn set_soft_wrap_mode(
18074        &mut self,
18075        mode: language_settings::SoftWrap,
18076
18077        cx: &mut Context<Self>,
18078    ) {
18079        self.soft_wrap_mode_override = Some(mode);
18080        cx.notify();
18081    }
18082
18083    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18084        self.hard_wrap = hard_wrap;
18085        cx.notify();
18086    }
18087
18088    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18089        self.text_style_refinement = Some(style);
18090    }
18091
18092    /// called by the Element so we know what style we were most recently rendered with.
18093    pub(crate) fn set_style(
18094        &mut self,
18095        style: EditorStyle,
18096        window: &mut Window,
18097        cx: &mut Context<Self>,
18098    ) {
18099        // We intentionally do not inform the display map about the minimap style
18100        // so that wrapping is not recalculated and stays consistent for the editor
18101        // and its linked minimap.
18102        if !self.mode.is_minimap() {
18103            let rem_size = window.rem_size();
18104            self.display_map.update(cx, |map, cx| {
18105                map.set_font(
18106                    style.text.font(),
18107                    style.text.font_size.to_pixels(rem_size),
18108                    cx,
18109                )
18110            });
18111        }
18112        self.style = Some(style);
18113    }
18114
18115    pub fn style(&self) -> Option<&EditorStyle> {
18116        self.style.as_ref()
18117    }
18118
18119    // Called by the element. This method is not designed to be called outside of the editor
18120    // element's layout code because it does not notify when rewrapping is computed synchronously.
18121    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18122        self.display_map
18123            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18124    }
18125
18126    pub fn set_soft_wrap(&mut self) {
18127        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18128    }
18129
18130    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18131        if self.soft_wrap_mode_override.is_some() {
18132            self.soft_wrap_mode_override.take();
18133        } else {
18134            let soft_wrap = match self.soft_wrap_mode(cx) {
18135                SoftWrap::GitDiff => return,
18136                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18137                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18138                    language_settings::SoftWrap::None
18139                }
18140            };
18141            self.soft_wrap_mode_override = Some(soft_wrap);
18142        }
18143        cx.notify();
18144    }
18145
18146    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18147        let Some(workspace) = self.workspace() else {
18148            return;
18149        };
18150        let fs = workspace.read(cx).app_state().fs.clone();
18151        let current_show = TabBarSettings::get_global(cx).show;
18152        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18153            setting.show = Some(!current_show);
18154        });
18155    }
18156
18157    pub fn toggle_indent_guides(
18158        &mut self,
18159        _: &ToggleIndentGuides,
18160        _: &mut Window,
18161        cx: &mut Context<Self>,
18162    ) {
18163        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18164            self.buffer
18165                .read(cx)
18166                .language_settings(cx)
18167                .indent_guides
18168                .enabled
18169        });
18170        self.show_indent_guides = Some(!currently_enabled);
18171        cx.notify();
18172    }
18173
18174    fn should_show_indent_guides(&self) -> Option<bool> {
18175        self.show_indent_guides
18176    }
18177
18178    pub fn toggle_line_numbers(
18179        &mut self,
18180        _: &ToggleLineNumbers,
18181        _: &mut Window,
18182        cx: &mut Context<Self>,
18183    ) {
18184        let mut editor_settings = EditorSettings::get_global(cx).clone();
18185        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18186        EditorSettings::override_global(editor_settings, cx);
18187    }
18188
18189    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18190        if let Some(show_line_numbers) = self.show_line_numbers {
18191            return show_line_numbers;
18192        }
18193        EditorSettings::get_global(cx).gutter.line_numbers
18194    }
18195
18196    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18197        self.use_relative_line_numbers
18198            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18199    }
18200
18201    pub fn toggle_relative_line_numbers(
18202        &mut self,
18203        _: &ToggleRelativeLineNumbers,
18204        _: &mut Window,
18205        cx: &mut Context<Self>,
18206    ) {
18207        let is_relative = self.should_use_relative_line_numbers(cx);
18208        self.set_relative_line_number(Some(!is_relative), cx)
18209    }
18210
18211    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18212        self.use_relative_line_numbers = is_relative;
18213        cx.notify();
18214    }
18215
18216    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18217        self.show_gutter = show_gutter;
18218        cx.notify();
18219    }
18220
18221    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18222        self.show_scrollbars = ScrollbarAxes {
18223            horizontal: show,
18224            vertical: show,
18225        };
18226        cx.notify();
18227    }
18228
18229    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18230        self.show_scrollbars.vertical = show;
18231        cx.notify();
18232    }
18233
18234    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18235        self.show_scrollbars.horizontal = show;
18236        cx.notify();
18237    }
18238
18239    pub fn set_minimap_visibility(
18240        &mut self,
18241        minimap_visibility: MinimapVisibility,
18242        window: &mut Window,
18243        cx: &mut Context<Self>,
18244    ) {
18245        if self.minimap_visibility != minimap_visibility {
18246            if minimap_visibility.visible() && self.minimap.is_none() {
18247                let minimap_settings = EditorSettings::get_global(cx).minimap;
18248                self.minimap =
18249                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18250            }
18251            self.minimap_visibility = minimap_visibility;
18252            cx.notify();
18253        }
18254    }
18255
18256    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18257        self.set_show_scrollbars(false, cx);
18258        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18259    }
18260
18261    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18262        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18263    }
18264
18265    /// Normally the text in full mode and auto height editors is padded on the
18266    /// left side by roughly half a character width for improved hit testing.
18267    ///
18268    /// Use this method to disable this for cases where this is not wanted (e.g.
18269    /// if you want to align the editor text with some other text above or below)
18270    /// or if you want to add this padding to single-line editors.
18271    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18272        self.offset_content = offset_content;
18273        cx.notify();
18274    }
18275
18276    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18277        self.show_line_numbers = Some(show_line_numbers);
18278        cx.notify();
18279    }
18280
18281    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18282        self.disable_expand_excerpt_buttons = true;
18283        cx.notify();
18284    }
18285
18286    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18287        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18288        cx.notify();
18289    }
18290
18291    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18292        self.show_code_actions = Some(show_code_actions);
18293        cx.notify();
18294    }
18295
18296    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18297        self.show_runnables = Some(show_runnables);
18298        cx.notify();
18299    }
18300
18301    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18302        self.show_breakpoints = Some(show_breakpoints);
18303        cx.notify();
18304    }
18305
18306    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18307        if self.display_map.read(cx).masked != masked {
18308            self.display_map.update(cx, |map, _| map.masked = masked);
18309        }
18310        cx.notify()
18311    }
18312
18313    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18314        self.show_wrap_guides = Some(show_wrap_guides);
18315        cx.notify();
18316    }
18317
18318    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18319        self.show_indent_guides = Some(show_indent_guides);
18320        cx.notify();
18321    }
18322
18323    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18324        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18325            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18326                if let Some(dir) = file.abs_path(cx).parent() {
18327                    return Some(dir.to_owned());
18328                }
18329            }
18330
18331            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18332                return Some(project_path.path.to_path_buf());
18333            }
18334        }
18335
18336        None
18337    }
18338
18339    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18340        self.active_excerpt(cx)?
18341            .1
18342            .read(cx)
18343            .file()
18344            .and_then(|f| f.as_local())
18345    }
18346
18347    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18348        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18349            let buffer = buffer.read(cx);
18350            if let Some(project_path) = buffer.project_path(cx) {
18351                let project = self.project.as_ref()?.read(cx);
18352                project.absolute_path(&project_path, cx)
18353            } else {
18354                buffer
18355                    .file()
18356                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18357            }
18358        })
18359    }
18360
18361    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18362        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18363            let project_path = buffer.read(cx).project_path(cx)?;
18364            let project = self.project.as_ref()?.read(cx);
18365            let entry = project.entry_for_path(&project_path, cx)?;
18366            let path = entry.path.to_path_buf();
18367            Some(path)
18368        })
18369    }
18370
18371    pub fn reveal_in_finder(
18372        &mut self,
18373        _: &RevealInFileManager,
18374        _window: &mut Window,
18375        cx: &mut Context<Self>,
18376    ) {
18377        if let Some(target) = self.target_file(cx) {
18378            cx.reveal_path(&target.abs_path(cx));
18379        }
18380    }
18381
18382    pub fn copy_path(
18383        &mut self,
18384        _: &zed_actions::workspace::CopyPath,
18385        _window: &mut Window,
18386        cx: &mut Context<Self>,
18387    ) {
18388        if let Some(path) = self.target_file_abs_path(cx) {
18389            if let Some(path) = path.to_str() {
18390                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18391            }
18392        }
18393    }
18394
18395    pub fn copy_relative_path(
18396        &mut self,
18397        _: &zed_actions::workspace::CopyRelativePath,
18398        _window: &mut Window,
18399        cx: &mut Context<Self>,
18400    ) {
18401        if let Some(path) = self.target_file_path(cx) {
18402            if let Some(path) = path.to_str() {
18403                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18404            }
18405        }
18406    }
18407
18408    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18409        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18410            buffer.read(cx).project_path(cx)
18411        } else {
18412            None
18413        }
18414    }
18415
18416    // Returns true if the editor handled a go-to-line request
18417    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18418        maybe!({
18419            let breakpoint_store = self.breakpoint_store.as_ref()?;
18420
18421            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18422            else {
18423                self.clear_row_highlights::<ActiveDebugLine>();
18424                return None;
18425            };
18426
18427            let position = active_stack_frame.position;
18428            let buffer_id = position.buffer_id?;
18429            let snapshot = self
18430                .project
18431                .as_ref()?
18432                .read(cx)
18433                .buffer_for_id(buffer_id, cx)?
18434                .read(cx)
18435                .snapshot();
18436
18437            let mut handled = false;
18438            for (id, ExcerptRange { context, .. }) in
18439                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18440            {
18441                if context.start.cmp(&position, &snapshot).is_ge()
18442                    || context.end.cmp(&position, &snapshot).is_lt()
18443                {
18444                    continue;
18445                }
18446                let snapshot = self.buffer.read(cx).snapshot(cx);
18447                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18448
18449                handled = true;
18450                self.clear_row_highlights::<ActiveDebugLine>();
18451
18452                self.go_to_line::<ActiveDebugLine>(
18453                    multibuffer_anchor,
18454                    Some(cx.theme().colors().editor_debugger_active_line_background),
18455                    window,
18456                    cx,
18457                );
18458
18459                cx.notify();
18460            }
18461
18462            handled.then_some(())
18463        })
18464        .is_some()
18465    }
18466
18467    pub fn copy_file_name_without_extension(
18468        &mut self,
18469        _: &CopyFileNameWithoutExtension,
18470        _: &mut Window,
18471        cx: &mut Context<Self>,
18472    ) {
18473        if let Some(file) = self.target_file(cx) {
18474            if let Some(file_stem) = file.path().file_stem() {
18475                if let Some(name) = file_stem.to_str() {
18476                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18477                }
18478            }
18479        }
18480    }
18481
18482    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18483        if let Some(file) = self.target_file(cx) {
18484            if let Some(file_name) = file.path().file_name() {
18485                if let Some(name) = file_name.to_str() {
18486                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18487                }
18488            }
18489        }
18490    }
18491
18492    pub fn toggle_git_blame(
18493        &mut self,
18494        _: &::git::Blame,
18495        window: &mut Window,
18496        cx: &mut Context<Self>,
18497    ) {
18498        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18499
18500        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18501            self.start_git_blame(true, window, cx);
18502        }
18503
18504        cx.notify();
18505    }
18506
18507    pub fn toggle_git_blame_inline(
18508        &mut self,
18509        _: &ToggleGitBlameInline,
18510        window: &mut Window,
18511        cx: &mut Context<Self>,
18512    ) {
18513        self.toggle_git_blame_inline_internal(true, window, cx);
18514        cx.notify();
18515    }
18516
18517    pub fn open_git_blame_commit(
18518        &mut self,
18519        _: &OpenGitBlameCommit,
18520        window: &mut Window,
18521        cx: &mut Context<Self>,
18522    ) {
18523        self.open_git_blame_commit_internal(window, cx);
18524    }
18525
18526    fn open_git_blame_commit_internal(
18527        &mut self,
18528        window: &mut Window,
18529        cx: &mut Context<Self>,
18530    ) -> Option<()> {
18531        let blame = self.blame.as_ref()?;
18532        let snapshot = self.snapshot(window, cx);
18533        let cursor = self.selections.newest::<Point>(cx).head();
18534        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18535        let blame_entry = blame
18536            .update(cx, |blame, cx| {
18537                blame
18538                    .blame_for_rows(
18539                        &[RowInfo {
18540                            buffer_id: Some(buffer.remote_id()),
18541                            buffer_row: Some(point.row),
18542                            ..Default::default()
18543                        }],
18544                        cx,
18545                    )
18546                    .next()
18547            })
18548            .flatten()?;
18549        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18550        let repo = blame.read(cx).repository(cx)?;
18551        let workspace = self.workspace()?.downgrade();
18552        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18553        None
18554    }
18555
18556    pub fn git_blame_inline_enabled(&self) -> bool {
18557        self.git_blame_inline_enabled
18558    }
18559
18560    pub fn toggle_selection_menu(
18561        &mut self,
18562        _: &ToggleSelectionMenu,
18563        _: &mut Window,
18564        cx: &mut Context<Self>,
18565    ) {
18566        self.show_selection_menu = self
18567            .show_selection_menu
18568            .map(|show_selections_menu| !show_selections_menu)
18569            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18570
18571        cx.notify();
18572    }
18573
18574    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18575        self.show_selection_menu
18576            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18577    }
18578
18579    fn start_git_blame(
18580        &mut self,
18581        user_triggered: bool,
18582        window: &mut Window,
18583        cx: &mut Context<Self>,
18584    ) {
18585        if let Some(project) = self.project.as_ref() {
18586            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18587                return;
18588            };
18589
18590            if buffer.read(cx).file().is_none() {
18591                return;
18592            }
18593
18594            let focused = self.focus_handle(cx).contains_focused(window, cx);
18595
18596            let project = project.clone();
18597            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18598            self.blame_subscription =
18599                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18600            self.blame = Some(blame);
18601        }
18602    }
18603
18604    fn toggle_git_blame_inline_internal(
18605        &mut self,
18606        user_triggered: bool,
18607        window: &mut Window,
18608        cx: &mut Context<Self>,
18609    ) {
18610        if self.git_blame_inline_enabled {
18611            self.git_blame_inline_enabled = false;
18612            self.show_git_blame_inline = false;
18613            self.show_git_blame_inline_delay_task.take();
18614        } else {
18615            self.git_blame_inline_enabled = true;
18616            self.start_git_blame_inline(user_triggered, window, cx);
18617        }
18618
18619        cx.notify();
18620    }
18621
18622    fn start_git_blame_inline(
18623        &mut self,
18624        user_triggered: bool,
18625        window: &mut Window,
18626        cx: &mut Context<Self>,
18627    ) {
18628        self.start_git_blame(user_triggered, window, cx);
18629
18630        if ProjectSettings::get_global(cx)
18631            .git
18632            .inline_blame_delay()
18633            .is_some()
18634        {
18635            self.start_inline_blame_timer(window, cx);
18636        } else {
18637            self.show_git_blame_inline = true
18638        }
18639    }
18640
18641    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18642        self.blame.as_ref()
18643    }
18644
18645    pub fn show_git_blame_gutter(&self) -> bool {
18646        self.show_git_blame_gutter
18647    }
18648
18649    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18650        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18651    }
18652
18653    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18654        self.show_git_blame_inline
18655            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18656            && !self.newest_selection_head_on_empty_line(cx)
18657            && self.has_blame_entries(cx)
18658    }
18659
18660    fn has_blame_entries(&self, cx: &App) -> bool {
18661        self.blame()
18662            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18663    }
18664
18665    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18666        let cursor_anchor = self.selections.newest_anchor().head();
18667
18668        let snapshot = self.buffer.read(cx).snapshot(cx);
18669        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18670
18671        snapshot.line_len(buffer_row) == 0
18672    }
18673
18674    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18675        let buffer_and_selection = maybe!({
18676            let selection = self.selections.newest::<Point>(cx);
18677            let selection_range = selection.range();
18678
18679            let multi_buffer = self.buffer().read(cx);
18680            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18681            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18682
18683            let (buffer, range, _) = if selection.reversed {
18684                buffer_ranges.first()
18685            } else {
18686                buffer_ranges.last()
18687            }?;
18688
18689            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18690                ..text::ToPoint::to_point(&range.end, &buffer).row;
18691            Some((
18692                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18693                selection,
18694            ))
18695        });
18696
18697        let Some((buffer, selection)) = buffer_and_selection else {
18698            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18699        };
18700
18701        let Some(project) = self.project.as_ref() else {
18702            return Task::ready(Err(anyhow!("editor does not have project")));
18703        };
18704
18705        project.update(cx, |project, cx| {
18706            project.get_permalink_to_line(&buffer, selection, cx)
18707        })
18708    }
18709
18710    pub fn copy_permalink_to_line(
18711        &mut self,
18712        _: &CopyPermalinkToLine,
18713        window: &mut Window,
18714        cx: &mut Context<Self>,
18715    ) {
18716        let permalink_task = self.get_permalink_to_line(cx);
18717        let workspace = self.workspace();
18718
18719        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18720            Ok(permalink) => {
18721                cx.update(|_, cx| {
18722                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18723                })
18724                .ok();
18725            }
18726            Err(err) => {
18727                let message = format!("Failed to copy permalink: {err}");
18728
18729                anyhow::Result::<()>::Err(err).log_err();
18730
18731                if let Some(workspace) = workspace {
18732                    workspace
18733                        .update_in(cx, |workspace, _, cx| {
18734                            struct CopyPermalinkToLine;
18735
18736                            workspace.show_toast(
18737                                Toast::new(
18738                                    NotificationId::unique::<CopyPermalinkToLine>(),
18739                                    message,
18740                                ),
18741                                cx,
18742                            )
18743                        })
18744                        .ok();
18745                }
18746            }
18747        })
18748        .detach();
18749    }
18750
18751    pub fn copy_file_location(
18752        &mut self,
18753        _: &CopyFileLocation,
18754        _: &mut Window,
18755        cx: &mut Context<Self>,
18756    ) {
18757        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18758        if let Some(file) = self.target_file(cx) {
18759            if let Some(path) = file.path().to_str() {
18760                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18761            }
18762        }
18763    }
18764
18765    pub fn open_permalink_to_line(
18766        &mut self,
18767        _: &OpenPermalinkToLine,
18768        window: &mut Window,
18769        cx: &mut Context<Self>,
18770    ) {
18771        let permalink_task = self.get_permalink_to_line(cx);
18772        let workspace = self.workspace();
18773
18774        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18775            Ok(permalink) => {
18776                cx.update(|_, cx| {
18777                    cx.open_url(permalink.as_ref());
18778                })
18779                .ok();
18780            }
18781            Err(err) => {
18782                let message = format!("Failed to open permalink: {err}");
18783
18784                anyhow::Result::<()>::Err(err).log_err();
18785
18786                if let Some(workspace) = workspace {
18787                    workspace
18788                        .update(cx, |workspace, cx| {
18789                            struct OpenPermalinkToLine;
18790
18791                            workspace.show_toast(
18792                                Toast::new(
18793                                    NotificationId::unique::<OpenPermalinkToLine>(),
18794                                    message,
18795                                ),
18796                                cx,
18797                            )
18798                        })
18799                        .ok();
18800                }
18801            }
18802        })
18803        .detach();
18804    }
18805
18806    pub fn insert_uuid_v4(
18807        &mut self,
18808        _: &InsertUuidV4,
18809        window: &mut Window,
18810        cx: &mut Context<Self>,
18811    ) {
18812        self.insert_uuid(UuidVersion::V4, window, cx);
18813    }
18814
18815    pub fn insert_uuid_v7(
18816        &mut self,
18817        _: &InsertUuidV7,
18818        window: &mut Window,
18819        cx: &mut Context<Self>,
18820    ) {
18821        self.insert_uuid(UuidVersion::V7, window, cx);
18822    }
18823
18824    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18825        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18826        self.transact(window, cx, |this, window, cx| {
18827            let edits = this
18828                .selections
18829                .all::<Point>(cx)
18830                .into_iter()
18831                .map(|selection| {
18832                    let uuid = match version {
18833                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18834                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18835                    };
18836
18837                    (selection.range(), uuid.to_string())
18838                });
18839            this.edit(edits, cx);
18840            this.refresh_inline_completion(true, false, window, cx);
18841        });
18842    }
18843
18844    pub fn open_selections_in_multibuffer(
18845        &mut self,
18846        _: &OpenSelectionsInMultibuffer,
18847        window: &mut Window,
18848        cx: &mut Context<Self>,
18849    ) {
18850        let multibuffer = self.buffer.read(cx);
18851
18852        let Some(buffer) = multibuffer.as_singleton() else {
18853            return;
18854        };
18855
18856        let Some(workspace) = self.workspace() else {
18857            return;
18858        };
18859
18860        let title = multibuffer.title(cx).to_string();
18861
18862        let locations = self
18863            .selections
18864            .all_anchors(cx)
18865            .into_iter()
18866            .map(|selection| Location {
18867                buffer: buffer.clone(),
18868                range: selection.start.text_anchor..selection.end.text_anchor,
18869            })
18870            .collect::<Vec<_>>();
18871
18872        cx.spawn_in(window, async move |_, cx| {
18873            workspace.update_in(cx, |workspace, window, cx| {
18874                Self::open_locations_in_multibuffer(
18875                    workspace,
18876                    locations,
18877                    format!("Selections for '{title}'"),
18878                    false,
18879                    MultibufferSelectionMode::All,
18880                    window,
18881                    cx,
18882                );
18883            })
18884        })
18885        .detach();
18886    }
18887
18888    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18889    /// last highlight added will be used.
18890    ///
18891    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18892    pub fn highlight_rows<T: 'static>(
18893        &mut self,
18894        range: Range<Anchor>,
18895        color: Hsla,
18896        options: RowHighlightOptions,
18897        cx: &mut Context<Self>,
18898    ) {
18899        let snapshot = self.buffer().read(cx).snapshot(cx);
18900        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18901        let ix = row_highlights.binary_search_by(|highlight| {
18902            Ordering::Equal
18903                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18904                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18905        });
18906
18907        if let Err(mut ix) = ix {
18908            let index = post_inc(&mut self.highlight_order);
18909
18910            // If this range intersects with the preceding highlight, then merge it with
18911            // the preceding highlight. Otherwise insert a new highlight.
18912            let mut merged = false;
18913            if ix > 0 {
18914                let prev_highlight = &mut row_highlights[ix - 1];
18915                if prev_highlight
18916                    .range
18917                    .end
18918                    .cmp(&range.start, &snapshot)
18919                    .is_ge()
18920                {
18921                    ix -= 1;
18922                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18923                        prev_highlight.range.end = range.end;
18924                    }
18925                    merged = true;
18926                    prev_highlight.index = index;
18927                    prev_highlight.color = color;
18928                    prev_highlight.options = options;
18929                }
18930            }
18931
18932            if !merged {
18933                row_highlights.insert(
18934                    ix,
18935                    RowHighlight {
18936                        range: range.clone(),
18937                        index,
18938                        color,
18939                        options,
18940                        type_id: TypeId::of::<T>(),
18941                    },
18942                );
18943            }
18944
18945            // If any of the following highlights intersect with this one, merge them.
18946            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18947                let highlight = &row_highlights[ix];
18948                if next_highlight
18949                    .range
18950                    .start
18951                    .cmp(&highlight.range.end, &snapshot)
18952                    .is_le()
18953                {
18954                    if next_highlight
18955                        .range
18956                        .end
18957                        .cmp(&highlight.range.end, &snapshot)
18958                        .is_gt()
18959                    {
18960                        row_highlights[ix].range.end = next_highlight.range.end;
18961                    }
18962                    row_highlights.remove(ix + 1);
18963                } else {
18964                    break;
18965                }
18966            }
18967        }
18968    }
18969
18970    /// Remove any highlighted row ranges of the given type that intersect the
18971    /// given ranges.
18972    pub fn remove_highlighted_rows<T: 'static>(
18973        &mut self,
18974        ranges_to_remove: Vec<Range<Anchor>>,
18975        cx: &mut Context<Self>,
18976    ) {
18977        let snapshot = self.buffer().read(cx).snapshot(cx);
18978        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18979        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18980        row_highlights.retain(|highlight| {
18981            while let Some(range_to_remove) = ranges_to_remove.peek() {
18982                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18983                    Ordering::Less | Ordering::Equal => {
18984                        ranges_to_remove.next();
18985                    }
18986                    Ordering::Greater => {
18987                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18988                            Ordering::Less | Ordering::Equal => {
18989                                return false;
18990                            }
18991                            Ordering::Greater => break,
18992                        }
18993                    }
18994                }
18995            }
18996
18997            true
18998        })
18999    }
19000
19001    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19002    pub fn clear_row_highlights<T: 'static>(&mut self) {
19003        self.highlighted_rows.remove(&TypeId::of::<T>());
19004    }
19005
19006    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19007    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19008        self.highlighted_rows
19009            .get(&TypeId::of::<T>())
19010            .map_or(&[] as &[_], |vec| vec.as_slice())
19011            .iter()
19012            .map(|highlight| (highlight.range.clone(), highlight.color))
19013    }
19014
19015    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19016    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19017    /// Allows to ignore certain kinds of highlights.
19018    pub fn highlighted_display_rows(
19019        &self,
19020        window: &mut Window,
19021        cx: &mut App,
19022    ) -> BTreeMap<DisplayRow, LineHighlight> {
19023        let snapshot = self.snapshot(window, cx);
19024        let mut used_highlight_orders = HashMap::default();
19025        self.highlighted_rows
19026            .iter()
19027            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19028            .fold(
19029                BTreeMap::<DisplayRow, LineHighlight>::new(),
19030                |mut unique_rows, highlight| {
19031                    let start = highlight.range.start.to_display_point(&snapshot);
19032                    let end = highlight.range.end.to_display_point(&snapshot);
19033                    let start_row = start.row().0;
19034                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19035                        && end.column() == 0
19036                    {
19037                        end.row().0.saturating_sub(1)
19038                    } else {
19039                        end.row().0
19040                    };
19041                    for row in start_row..=end_row {
19042                        let used_index =
19043                            used_highlight_orders.entry(row).or_insert(highlight.index);
19044                        if highlight.index >= *used_index {
19045                            *used_index = highlight.index;
19046                            unique_rows.insert(
19047                                DisplayRow(row),
19048                                LineHighlight {
19049                                    include_gutter: highlight.options.include_gutter,
19050                                    border: None,
19051                                    background: highlight.color.into(),
19052                                    type_id: Some(highlight.type_id),
19053                                },
19054                            );
19055                        }
19056                    }
19057                    unique_rows
19058                },
19059            )
19060    }
19061
19062    pub fn highlighted_display_row_for_autoscroll(
19063        &self,
19064        snapshot: &DisplaySnapshot,
19065    ) -> Option<DisplayRow> {
19066        self.highlighted_rows
19067            .values()
19068            .flat_map(|highlighted_rows| highlighted_rows.iter())
19069            .filter_map(|highlight| {
19070                if highlight.options.autoscroll {
19071                    Some(highlight.range.start.to_display_point(snapshot).row())
19072                } else {
19073                    None
19074                }
19075            })
19076            .min()
19077    }
19078
19079    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19080        self.highlight_background::<SearchWithinRange>(
19081            ranges,
19082            |colors| colors.colors().editor_document_highlight_read_background,
19083            cx,
19084        )
19085    }
19086
19087    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19088        self.breadcrumb_header = Some(new_header);
19089    }
19090
19091    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19092        self.clear_background_highlights::<SearchWithinRange>(cx);
19093    }
19094
19095    pub fn highlight_background<T: 'static>(
19096        &mut self,
19097        ranges: &[Range<Anchor>],
19098        color_fetcher: fn(&Theme) -> Hsla,
19099        cx: &mut Context<Self>,
19100    ) {
19101        self.background_highlights.insert(
19102            HighlightKey::Type(TypeId::of::<T>()),
19103            (color_fetcher, Arc::from(ranges)),
19104        );
19105        self.scrollbar_marker_state.dirty = true;
19106        cx.notify();
19107    }
19108
19109    pub fn highlight_background_key<T: 'static>(
19110        &mut self,
19111        key: usize,
19112        ranges: &[Range<Anchor>],
19113        color_fetcher: fn(&Theme) -> Hsla,
19114        cx: &mut Context<Self>,
19115    ) {
19116        self.background_highlights.insert(
19117            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19118            (color_fetcher, Arc::from(ranges)),
19119        );
19120        self.scrollbar_marker_state.dirty = true;
19121        cx.notify();
19122    }
19123
19124    pub fn clear_background_highlights<T: 'static>(
19125        &mut self,
19126        cx: &mut Context<Self>,
19127    ) -> Option<BackgroundHighlight> {
19128        let text_highlights = self
19129            .background_highlights
19130            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19131        if !text_highlights.1.is_empty() {
19132            self.scrollbar_marker_state.dirty = true;
19133            cx.notify();
19134        }
19135        Some(text_highlights)
19136    }
19137
19138    pub fn highlight_gutter<T: 'static>(
19139        &mut self,
19140        ranges: impl Into<Vec<Range<Anchor>>>,
19141        color_fetcher: fn(&App) -> Hsla,
19142        cx: &mut Context<Self>,
19143    ) {
19144        self.gutter_highlights
19145            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19146        cx.notify();
19147    }
19148
19149    pub fn clear_gutter_highlights<T: 'static>(
19150        &mut self,
19151        cx: &mut Context<Self>,
19152    ) -> Option<GutterHighlight> {
19153        cx.notify();
19154        self.gutter_highlights.remove(&TypeId::of::<T>())
19155    }
19156
19157    pub fn insert_gutter_highlight<T: 'static>(
19158        &mut self,
19159        range: Range<Anchor>,
19160        color_fetcher: fn(&App) -> Hsla,
19161        cx: &mut Context<Self>,
19162    ) {
19163        let snapshot = self.buffer().read(cx).snapshot(cx);
19164        let mut highlights = self
19165            .gutter_highlights
19166            .remove(&TypeId::of::<T>())
19167            .map(|(_, highlights)| highlights)
19168            .unwrap_or_default();
19169        let ix = highlights.binary_search_by(|highlight| {
19170            Ordering::Equal
19171                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19172                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19173        });
19174        if let Err(ix) = ix {
19175            highlights.insert(ix, range);
19176        }
19177        self.gutter_highlights
19178            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19179    }
19180
19181    pub fn remove_gutter_highlights<T: 'static>(
19182        &mut self,
19183        ranges_to_remove: Vec<Range<Anchor>>,
19184        cx: &mut Context<Self>,
19185    ) {
19186        let snapshot = self.buffer().read(cx).snapshot(cx);
19187        let Some((color_fetcher, mut gutter_highlights)) =
19188            self.gutter_highlights.remove(&TypeId::of::<T>())
19189        else {
19190            return;
19191        };
19192        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19193        gutter_highlights.retain(|highlight| {
19194            while let Some(range_to_remove) = ranges_to_remove.peek() {
19195                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19196                    Ordering::Less | Ordering::Equal => {
19197                        ranges_to_remove.next();
19198                    }
19199                    Ordering::Greater => {
19200                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19201                            Ordering::Less | Ordering::Equal => {
19202                                return false;
19203                            }
19204                            Ordering::Greater => break,
19205                        }
19206                    }
19207                }
19208            }
19209
19210            true
19211        });
19212        self.gutter_highlights
19213            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19214    }
19215
19216    #[cfg(feature = "test-support")]
19217    pub fn all_text_highlights(
19218        &self,
19219        window: &mut Window,
19220        cx: &mut Context<Self>,
19221    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19222        let snapshot = self.snapshot(window, cx);
19223        self.display_map.update(cx, |display_map, _| {
19224            display_map
19225                .all_text_highlights()
19226                .map(|highlight| {
19227                    let (style, ranges) = highlight.as_ref();
19228                    (
19229                        *style,
19230                        ranges
19231                            .iter()
19232                            .map(|range| range.clone().to_display_points(&snapshot))
19233                            .collect(),
19234                    )
19235                })
19236                .collect()
19237        })
19238    }
19239
19240    #[cfg(feature = "test-support")]
19241    pub fn all_text_background_highlights(
19242        &self,
19243        window: &mut Window,
19244        cx: &mut Context<Self>,
19245    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19246        let snapshot = self.snapshot(window, cx);
19247        let buffer = &snapshot.buffer_snapshot;
19248        let start = buffer.anchor_before(0);
19249        let end = buffer.anchor_after(buffer.len());
19250        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19251    }
19252
19253    #[cfg(feature = "test-support")]
19254    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19255        let snapshot = self.buffer().read(cx).snapshot(cx);
19256
19257        let highlights = self
19258            .background_highlights
19259            .get(&HighlightKey::Type(TypeId::of::<
19260                items::BufferSearchHighlights,
19261            >()));
19262
19263        if let Some((_color, ranges)) = highlights {
19264            ranges
19265                .iter()
19266                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19267                .collect_vec()
19268        } else {
19269            vec![]
19270        }
19271    }
19272
19273    fn document_highlights_for_position<'a>(
19274        &'a self,
19275        position: Anchor,
19276        buffer: &'a MultiBufferSnapshot,
19277    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19278        let read_highlights = self
19279            .background_highlights
19280            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19281            .map(|h| &h.1);
19282        let write_highlights = self
19283            .background_highlights
19284            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19285            .map(|h| &h.1);
19286        let left_position = position.bias_left(buffer);
19287        let right_position = position.bias_right(buffer);
19288        read_highlights
19289            .into_iter()
19290            .chain(write_highlights)
19291            .flat_map(move |ranges| {
19292                let start_ix = match ranges.binary_search_by(|probe| {
19293                    let cmp = probe.end.cmp(&left_position, buffer);
19294                    if cmp.is_ge() {
19295                        Ordering::Greater
19296                    } else {
19297                        Ordering::Less
19298                    }
19299                }) {
19300                    Ok(i) | Err(i) => i,
19301                };
19302
19303                ranges[start_ix..]
19304                    .iter()
19305                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19306            })
19307    }
19308
19309    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19310        self.background_highlights
19311            .get(&HighlightKey::Type(TypeId::of::<T>()))
19312            .map_or(false, |(_, highlights)| !highlights.is_empty())
19313    }
19314
19315    pub fn background_highlights_in_range(
19316        &self,
19317        search_range: Range<Anchor>,
19318        display_snapshot: &DisplaySnapshot,
19319        theme: &Theme,
19320    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19321        let mut results = Vec::new();
19322        for (color_fetcher, ranges) in self.background_highlights.values() {
19323            let color = color_fetcher(theme);
19324            let start_ix = match ranges.binary_search_by(|probe| {
19325                let cmp = probe
19326                    .end
19327                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19328                if cmp.is_gt() {
19329                    Ordering::Greater
19330                } else {
19331                    Ordering::Less
19332                }
19333            }) {
19334                Ok(i) | Err(i) => i,
19335            };
19336            for range in &ranges[start_ix..] {
19337                if range
19338                    .start
19339                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19340                    .is_ge()
19341                {
19342                    break;
19343                }
19344
19345                let start = range.start.to_display_point(display_snapshot);
19346                let end = range.end.to_display_point(display_snapshot);
19347                results.push((start..end, color))
19348            }
19349        }
19350        results
19351    }
19352
19353    pub fn background_highlight_row_ranges<T: 'static>(
19354        &self,
19355        search_range: Range<Anchor>,
19356        display_snapshot: &DisplaySnapshot,
19357        count: usize,
19358    ) -> Vec<RangeInclusive<DisplayPoint>> {
19359        let mut results = Vec::new();
19360        let Some((_, ranges)) = self
19361            .background_highlights
19362            .get(&HighlightKey::Type(TypeId::of::<T>()))
19363        else {
19364            return vec![];
19365        };
19366
19367        let start_ix = match ranges.binary_search_by(|probe| {
19368            let cmp = probe
19369                .end
19370                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19371            if cmp.is_gt() {
19372                Ordering::Greater
19373            } else {
19374                Ordering::Less
19375            }
19376        }) {
19377            Ok(i) | Err(i) => i,
19378        };
19379        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19380            if let (Some(start_display), Some(end_display)) = (start, end) {
19381                results.push(
19382                    start_display.to_display_point(display_snapshot)
19383                        ..=end_display.to_display_point(display_snapshot),
19384                );
19385            }
19386        };
19387        let mut start_row: Option<Point> = None;
19388        let mut end_row: Option<Point> = None;
19389        if ranges.len() > count {
19390            return Vec::new();
19391        }
19392        for range in &ranges[start_ix..] {
19393            if range
19394                .start
19395                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19396                .is_ge()
19397            {
19398                break;
19399            }
19400            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19401            if let Some(current_row) = &end_row {
19402                if end.row == current_row.row {
19403                    continue;
19404                }
19405            }
19406            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19407            if start_row.is_none() {
19408                assert_eq!(end_row, None);
19409                start_row = Some(start);
19410                end_row = Some(end);
19411                continue;
19412            }
19413            if let Some(current_end) = end_row.as_mut() {
19414                if start.row > current_end.row + 1 {
19415                    push_region(start_row, end_row);
19416                    start_row = Some(start);
19417                    end_row = Some(end);
19418                } else {
19419                    // Merge two hunks.
19420                    *current_end = end;
19421                }
19422            } else {
19423                unreachable!();
19424            }
19425        }
19426        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19427        push_region(start_row, end_row);
19428        results
19429    }
19430
19431    pub fn gutter_highlights_in_range(
19432        &self,
19433        search_range: Range<Anchor>,
19434        display_snapshot: &DisplaySnapshot,
19435        cx: &App,
19436    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19437        let mut results = Vec::new();
19438        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19439            let color = color_fetcher(cx);
19440            let start_ix = match ranges.binary_search_by(|probe| {
19441                let cmp = probe
19442                    .end
19443                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19444                if cmp.is_gt() {
19445                    Ordering::Greater
19446                } else {
19447                    Ordering::Less
19448                }
19449            }) {
19450                Ok(i) | Err(i) => i,
19451            };
19452            for range in &ranges[start_ix..] {
19453                if range
19454                    .start
19455                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19456                    .is_ge()
19457                {
19458                    break;
19459                }
19460
19461                let start = range.start.to_display_point(display_snapshot);
19462                let end = range.end.to_display_point(display_snapshot);
19463                results.push((start..end, color))
19464            }
19465        }
19466        results
19467    }
19468
19469    /// Get the text ranges corresponding to the redaction query
19470    pub fn redacted_ranges(
19471        &self,
19472        search_range: Range<Anchor>,
19473        display_snapshot: &DisplaySnapshot,
19474        cx: &App,
19475    ) -> Vec<Range<DisplayPoint>> {
19476        display_snapshot
19477            .buffer_snapshot
19478            .redacted_ranges(search_range, |file| {
19479                if let Some(file) = file {
19480                    file.is_private()
19481                        && EditorSettings::get(
19482                            Some(SettingsLocation {
19483                                worktree_id: file.worktree_id(cx),
19484                                path: file.path().as_ref(),
19485                            }),
19486                            cx,
19487                        )
19488                        .redact_private_values
19489                } else {
19490                    false
19491                }
19492            })
19493            .map(|range| {
19494                range.start.to_display_point(display_snapshot)
19495                    ..range.end.to_display_point(display_snapshot)
19496            })
19497            .collect()
19498    }
19499
19500    pub fn highlight_text_key<T: 'static>(
19501        &mut self,
19502        key: usize,
19503        ranges: Vec<Range<Anchor>>,
19504        style: HighlightStyle,
19505        cx: &mut Context<Self>,
19506    ) {
19507        self.display_map.update(cx, |map, _| {
19508            map.highlight_text(
19509                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19510                ranges,
19511                style,
19512            );
19513        });
19514        cx.notify();
19515    }
19516
19517    pub fn highlight_text<T: 'static>(
19518        &mut self,
19519        ranges: Vec<Range<Anchor>>,
19520        style: HighlightStyle,
19521        cx: &mut Context<Self>,
19522    ) {
19523        self.display_map.update(cx, |map, _| {
19524            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19525        });
19526        cx.notify();
19527    }
19528
19529    pub(crate) fn highlight_inlays<T: 'static>(
19530        &mut self,
19531        highlights: Vec<InlayHighlight>,
19532        style: HighlightStyle,
19533        cx: &mut Context<Self>,
19534    ) {
19535        self.display_map.update(cx, |map, _| {
19536            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19537        });
19538        cx.notify();
19539    }
19540
19541    pub fn text_highlights<'a, T: 'static>(
19542        &'a self,
19543        cx: &'a App,
19544    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19545        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19546    }
19547
19548    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19549        let cleared = self
19550            .display_map
19551            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19552        if cleared {
19553            cx.notify();
19554        }
19555    }
19556
19557    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19558        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19559            && self.focus_handle.is_focused(window)
19560    }
19561
19562    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19563        self.show_cursor_when_unfocused = is_enabled;
19564        cx.notify();
19565    }
19566
19567    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19568        cx.notify();
19569    }
19570
19571    fn on_debug_session_event(
19572        &mut self,
19573        _session: Entity<Session>,
19574        event: &SessionEvent,
19575        cx: &mut Context<Self>,
19576    ) {
19577        match event {
19578            SessionEvent::InvalidateInlineValue => {
19579                self.refresh_inline_values(cx);
19580            }
19581            _ => {}
19582        }
19583    }
19584
19585    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19586        let Some(project) = self.project.clone() else {
19587            return;
19588        };
19589
19590        if !self.inline_value_cache.enabled {
19591            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19592            self.splice_inlays(&inlays, Vec::new(), cx);
19593            return;
19594        }
19595
19596        let current_execution_position = self
19597            .highlighted_rows
19598            .get(&TypeId::of::<ActiveDebugLine>())
19599            .and_then(|lines| lines.last().map(|line| line.range.end));
19600
19601        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19602            let inline_values = editor
19603                .update(cx, |editor, cx| {
19604                    let Some(current_execution_position) = current_execution_position else {
19605                        return Some(Task::ready(Ok(Vec::new())));
19606                    };
19607
19608                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19609                        let snapshot = buffer.snapshot(cx);
19610
19611                        let excerpt = snapshot.excerpt_containing(
19612                            current_execution_position..current_execution_position,
19613                        )?;
19614
19615                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19616                    })?;
19617
19618                    let range =
19619                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19620
19621                    project.inline_values(buffer, range, cx)
19622                })
19623                .ok()
19624                .flatten()?
19625                .await
19626                .context("refreshing debugger inlays")
19627                .log_err()?;
19628
19629            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19630
19631            for (buffer_id, inline_value) in inline_values
19632                .into_iter()
19633                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19634            {
19635                buffer_inline_values
19636                    .entry(buffer_id)
19637                    .or_default()
19638                    .push(inline_value);
19639            }
19640
19641            editor
19642                .update(cx, |editor, cx| {
19643                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19644                    let mut new_inlays = Vec::default();
19645
19646                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19647                        let buffer_id = buffer_snapshot.remote_id();
19648                        buffer_inline_values
19649                            .get(&buffer_id)
19650                            .into_iter()
19651                            .flatten()
19652                            .for_each(|hint| {
19653                                let inlay = Inlay::debugger(
19654                                    post_inc(&mut editor.next_inlay_id),
19655                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19656                                    hint.text(),
19657                                );
19658
19659                                new_inlays.push(inlay);
19660                            });
19661                    }
19662
19663                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19664                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19665
19666                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19667                })
19668                .ok()?;
19669            Some(())
19670        });
19671    }
19672
19673    fn on_buffer_event(
19674        &mut self,
19675        multibuffer: &Entity<MultiBuffer>,
19676        event: &multi_buffer::Event,
19677        window: &mut Window,
19678        cx: &mut Context<Self>,
19679    ) {
19680        match event {
19681            multi_buffer::Event::Edited {
19682                singleton_buffer_edited,
19683                edited_buffer,
19684            } => {
19685                self.scrollbar_marker_state.dirty = true;
19686                self.active_indent_guides_state.dirty = true;
19687                self.refresh_active_diagnostics(cx);
19688                self.refresh_code_actions(window, cx);
19689                self.refresh_selected_text_highlights(true, window, cx);
19690                self.refresh_single_line_folds(window, cx);
19691                refresh_matching_bracket_highlights(self, window, cx);
19692                if self.has_active_inline_completion() {
19693                    self.update_visible_inline_completion(window, cx);
19694                }
19695                if let Some(project) = self.project.as_ref() {
19696                    if let Some(edited_buffer) = edited_buffer {
19697                        project.update(cx, |project, cx| {
19698                            self.registered_buffers
19699                                .entry(edited_buffer.read(cx).remote_id())
19700                                .or_insert_with(|| {
19701                                    project
19702                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19703                                });
19704                        });
19705                    }
19706                }
19707                cx.emit(EditorEvent::BufferEdited);
19708                cx.emit(SearchEvent::MatchesInvalidated);
19709
19710                if let Some(buffer) = edited_buffer {
19711                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19712                }
19713
19714                if *singleton_buffer_edited {
19715                    if let Some(buffer) = edited_buffer {
19716                        if buffer.read(cx).file().is_none() {
19717                            cx.emit(EditorEvent::TitleChanged);
19718                        }
19719                    }
19720                    if let Some(project) = &self.project {
19721                        #[allow(clippy::mutable_key_type)]
19722                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19723                            multibuffer
19724                                .all_buffers()
19725                                .into_iter()
19726                                .filter_map(|buffer| {
19727                                    buffer.update(cx, |buffer, cx| {
19728                                        let language = buffer.language()?;
19729                                        let should_discard = project.update(cx, |project, cx| {
19730                                            project.is_local()
19731                                                && !project.has_language_servers_for(buffer, cx)
19732                                        });
19733                                        should_discard.not().then_some(language.clone())
19734                                    })
19735                                })
19736                                .collect::<HashSet<_>>()
19737                        });
19738                        if !languages_affected.is_empty() {
19739                            self.refresh_inlay_hints(
19740                                InlayHintRefreshReason::BufferEdited(languages_affected),
19741                                cx,
19742                            );
19743                        }
19744                    }
19745                }
19746
19747                let Some(project) = &self.project else { return };
19748                let (telemetry, is_via_ssh) = {
19749                    let project = project.read(cx);
19750                    let telemetry = project.client().telemetry().clone();
19751                    let is_via_ssh = project.is_via_ssh();
19752                    (telemetry, is_via_ssh)
19753                };
19754                refresh_linked_ranges(self, window, cx);
19755                telemetry.log_edit_event("editor", is_via_ssh);
19756            }
19757            multi_buffer::Event::ExcerptsAdded {
19758                buffer,
19759                predecessor,
19760                excerpts,
19761            } => {
19762                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19763                let buffer_id = buffer.read(cx).remote_id();
19764                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19765                    if let Some(project) = &self.project {
19766                        update_uncommitted_diff_for_buffer(
19767                            cx.entity(),
19768                            project,
19769                            [buffer.clone()],
19770                            self.buffer.clone(),
19771                            cx,
19772                        )
19773                        .detach();
19774                    }
19775                }
19776                self.update_lsp_data(false, Some(buffer_id), window, cx);
19777                cx.emit(EditorEvent::ExcerptsAdded {
19778                    buffer: buffer.clone(),
19779                    predecessor: *predecessor,
19780                    excerpts: excerpts.clone(),
19781                });
19782                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19783            }
19784            multi_buffer::Event::ExcerptsRemoved {
19785                ids,
19786                removed_buffer_ids,
19787            } => {
19788                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19789                let buffer = self.buffer.read(cx);
19790                self.registered_buffers
19791                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19792                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19793                cx.emit(EditorEvent::ExcerptsRemoved {
19794                    ids: ids.clone(),
19795                    removed_buffer_ids: removed_buffer_ids.clone(),
19796                });
19797            }
19798            multi_buffer::Event::ExcerptsEdited {
19799                excerpt_ids,
19800                buffer_ids,
19801            } => {
19802                self.display_map.update(cx, |map, cx| {
19803                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19804                });
19805                cx.emit(EditorEvent::ExcerptsEdited {
19806                    ids: excerpt_ids.clone(),
19807                });
19808            }
19809            multi_buffer::Event::ExcerptsExpanded { ids } => {
19810                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19811                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19812            }
19813            multi_buffer::Event::Reparsed(buffer_id) => {
19814                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19815                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19816
19817                cx.emit(EditorEvent::Reparsed(*buffer_id));
19818            }
19819            multi_buffer::Event::DiffHunksToggled => {
19820                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19821            }
19822            multi_buffer::Event::LanguageChanged(buffer_id) => {
19823                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19824                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19825                cx.emit(EditorEvent::Reparsed(*buffer_id));
19826                cx.notify();
19827            }
19828            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19829            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19830            multi_buffer::Event::FileHandleChanged
19831            | multi_buffer::Event::Reloaded
19832            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19833            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19834            multi_buffer::Event::DiagnosticsUpdated => {
19835                self.update_diagnostics_state(window, cx);
19836            }
19837            _ => {}
19838        };
19839    }
19840
19841    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19842        if !self.diagnostics_enabled() {
19843            return;
19844        }
19845        self.refresh_active_diagnostics(cx);
19846        self.refresh_inline_diagnostics(true, window, cx);
19847        self.scrollbar_marker_state.dirty = true;
19848        cx.notify();
19849    }
19850
19851    pub fn start_temporary_diff_override(&mut self) {
19852        self.load_diff_task.take();
19853        self.temporary_diff_override = true;
19854    }
19855
19856    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19857        self.temporary_diff_override = false;
19858        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19859        self.buffer.update(cx, |buffer, cx| {
19860            buffer.set_all_diff_hunks_collapsed(cx);
19861        });
19862
19863        if let Some(project) = self.project.clone() {
19864            self.load_diff_task = Some(
19865                update_uncommitted_diff_for_buffer(
19866                    cx.entity(),
19867                    &project,
19868                    self.buffer.read(cx).all_buffers(),
19869                    self.buffer.clone(),
19870                    cx,
19871                )
19872                .shared(),
19873            );
19874        }
19875    }
19876
19877    fn on_display_map_changed(
19878        &mut self,
19879        _: Entity<DisplayMap>,
19880        _: &mut Window,
19881        cx: &mut Context<Self>,
19882    ) {
19883        cx.notify();
19884    }
19885
19886    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19887        let new_severity = if self.diagnostics_enabled() {
19888            EditorSettings::get_global(cx)
19889                .diagnostics_max_severity
19890                .unwrap_or(DiagnosticSeverity::Hint)
19891        } else {
19892            DiagnosticSeverity::Off
19893        };
19894        self.set_max_diagnostics_severity(new_severity, cx);
19895        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19896        self.update_edit_prediction_settings(cx);
19897        self.refresh_inline_completion(true, false, window, cx);
19898        self.refresh_inline_values(cx);
19899        self.refresh_inlay_hints(
19900            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19901                self.selections.newest_anchor().head(),
19902                &self.buffer.read(cx).snapshot(cx),
19903                cx,
19904            )),
19905            cx,
19906        );
19907
19908        let old_cursor_shape = self.cursor_shape;
19909
19910        {
19911            let editor_settings = EditorSettings::get_global(cx);
19912            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19913            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19914            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19915            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19916        }
19917
19918        if old_cursor_shape != self.cursor_shape {
19919            cx.emit(EditorEvent::CursorShapeChanged);
19920        }
19921
19922        let project_settings = ProjectSettings::get_global(cx);
19923        self.serialize_dirty_buffers =
19924            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19925
19926        if self.mode.is_full() {
19927            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19928            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19929            if self.show_inline_diagnostics != show_inline_diagnostics {
19930                self.show_inline_diagnostics = show_inline_diagnostics;
19931                self.refresh_inline_diagnostics(false, window, cx);
19932            }
19933
19934            if self.git_blame_inline_enabled != inline_blame_enabled {
19935                self.toggle_git_blame_inline_internal(false, window, cx);
19936            }
19937
19938            let minimap_settings = EditorSettings::get_global(cx).minimap;
19939            if self.minimap_visibility != MinimapVisibility::Disabled {
19940                if self.minimap_visibility.settings_visibility()
19941                    != minimap_settings.minimap_enabled()
19942                {
19943                    self.set_minimap_visibility(
19944                        MinimapVisibility::for_mode(self.mode(), cx),
19945                        window,
19946                        cx,
19947                    );
19948                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19949                    minimap_entity.update(cx, |minimap_editor, cx| {
19950                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19951                    })
19952                }
19953            }
19954        }
19955
19956        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19957            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19958        }) {
19959            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19960                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19961            }
19962            self.refresh_colors(false, None, window, cx);
19963        }
19964
19965        cx.notify();
19966    }
19967
19968    pub fn set_searchable(&mut self, searchable: bool) {
19969        self.searchable = searchable;
19970    }
19971
19972    pub fn searchable(&self) -> bool {
19973        self.searchable
19974    }
19975
19976    fn open_proposed_changes_editor(
19977        &mut self,
19978        _: &OpenProposedChangesEditor,
19979        window: &mut Window,
19980        cx: &mut Context<Self>,
19981    ) {
19982        let Some(workspace) = self.workspace() else {
19983            cx.propagate();
19984            return;
19985        };
19986
19987        let selections = self.selections.all::<usize>(cx);
19988        let multi_buffer = self.buffer.read(cx);
19989        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19990        let mut new_selections_by_buffer = HashMap::default();
19991        for selection in selections {
19992            for (buffer, range, _) in
19993                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19994            {
19995                let mut range = range.to_point(buffer);
19996                range.start.column = 0;
19997                range.end.column = buffer.line_len(range.end.row);
19998                new_selections_by_buffer
19999                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20000                    .or_insert(Vec::new())
20001                    .push(range)
20002            }
20003        }
20004
20005        let proposed_changes_buffers = new_selections_by_buffer
20006            .into_iter()
20007            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20008            .collect::<Vec<_>>();
20009        let proposed_changes_editor = cx.new(|cx| {
20010            ProposedChangesEditor::new(
20011                "Proposed changes",
20012                proposed_changes_buffers,
20013                self.project.clone(),
20014                window,
20015                cx,
20016            )
20017        });
20018
20019        window.defer(cx, move |window, cx| {
20020            workspace.update(cx, |workspace, cx| {
20021                workspace.active_pane().update(cx, |pane, cx| {
20022                    pane.add_item(
20023                        Box::new(proposed_changes_editor),
20024                        true,
20025                        true,
20026                        None,
20027                        window,
20028                        cx,
20029                    );
20030                });
20031            });
20032        });
20033    }
20034
20035    pub fn open_excerpts_in_split(
20036        &mut self,
20037        _: &OpenExcerptsSplit,
20038        window: &mut Window,
20039        cx: &mut Context<Self>,
20040    ) {
20041        self.open_excerpts_common(None, true, window, cx)
20042    }
20043
20044    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20045        self.open_excerpts_common(None, false, window, cx)
20046    }
20047
20048    fn open_excerpts_common(
20049        &mut self,
20050        jump_data: Option<JumpData>,
20051        split: bool,
20052        window: &mut Window,
20053        cx: &mut Context<Self>,
20054    ) {
20055        let Some(workspace) = self.workspace() else {
20056            cx.propagate();
20057            return;
20058        };
20059
20060        if self.buffer.read(cx).is_singleton() {
20061            cx.propagate();
20062            return;
20063        }
20064
20065        let mut new_selections_by_buffer = HashMap::default();
20066        match &jump_data {
20067            Some(JumpData::MultiBufferPoint {
20068                excerpt_id,
20069                position,
20070                anchor,
20071                line_offset_from_top,
20072            }) => {
20073                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20074                if let Some(buffer) = multi_buffer_snapshot
20075                    .buffer_id_for_excerpt(*excerpt_id)
20076                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20077                {
20078                    let buffer_snapshot = buffer.read(cx).snapshot();
20079                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20080                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20081                    } else {
20082                        buffer_snapshot.clip_point(*position, Bias::Left)
20083                    };
20084                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20085                    new_selections_by_buffer.insert(
20086                        buffer,
20087                        (
20088                            vec![jump_to_offset..jump_to_offset],
20089                            Some(*line_offset_from_top),
20090                        ),
20091                    );
20092                }
20093            }
20094            Some(JumpData::MultiBufferRow {
20095                row,
20096                line_offset_from_top,
20097            }) => {
20098                let point = MultiBufferPoint::new(row.0, 0);
20099                if let Some((buffer, buffer_point, _)) =
20100                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20101                {
20102                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20103                    new_selections_by_buffer
20104                        .entry(buffer)
20105                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20106                        .0
20107                        .push(buffer_offset..buffer_offset)
20108                }
20109            }
20110            None => {
20111                let selections = self.selections.all::<usize>(cx);
20112                let multi_buffer = self.buffer.read(cx);
20113                for selection in selections {
20114                    for (snapshot, range, _, anchor) in multi_buffer
20115                        .snapshot(cx)
20116                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20117                    {
20118                        if let Some(anchor) = anchor {
20119                            // selection is in a deleted hunk
20120                            let Some(buffer_id) = anchor.buffer_id else {
20121                                continue;
20122                            };
20123                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20124                                continue;
20125                            };
20126                            let offset = text::ToOffset::to_offset(
20127                                &anchor.text_anchor,
20128                                &buffer_handle.read(cx).snapshot(),
20129                            );
20130                            let range = offset..offset;
20131                            new_selections_by_buffer
20132                                .entry(buffer_handle)
20133                                .or_insert((Vec::new(), None))
20134                                .0
20135                                .push(range)
20136                        } else {
20137                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20138                            else {
20139                                continue;
20140                            };
20141                            new_selections_by_buffer
20142                                .entry(buffer_handle)
20143                                .or_insert((Vec::new(), None))
20144                                .0
20145                                .push(range)
20146                        }
20147                    }
20148                }
20149            }
20150        }
20151
20152        new_selections_by_buffer
20153            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20154
20155        if new_selections_by_buffer.is_empty() {
20156            return;
20157        }
20158
20159        // We defer the pane interaction because we ourselves are a workspace item
20160        // and activating a new item causes the pane to call a method on us reentrantly,
20161        // which panics if we're on the stack.
20162        window.defer(cx, move |window, cx| {
20163            workspace.update(cx, |workspace, cx| {
20164                let pane = if split {
20165                    workspace.adjacent_pane(window, cx)
20166                } else {
20167                    workspace.active_pane().clone()
20168                };
20169
20170                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20171                    let editor = buffer
20172                        .read(cx)
20173                        .file()
20174                        .is_none()
20175                        .then(|| {
20176                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20177                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20178                            // Instead, we try to activate the existing editor in the pane first.
20179                            let (editor, pane_item_index) =
20180                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20181                                    let editor = item.downcast::<Editor>()?;
20182                                    let singleton_buffer =
20183                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20184                                    if singleton_buffer == buffer {
20185                                        Some((editor, i))
20186                                    } else {
20187                                        None
20188                                    }
20189                                })?;
20190                            pane.update(cx, |pane, cx| {
20191                                pane.activate_item(pane_item_index, true, true, window, cx)
20192                            });
20193                            Some(editor)
20194                        })
20195                        .flatten()
20196                        .unwrap_or_else(|| {
20197                            workspace.open_project_item::<Self>(
20198                                pane.clone(),
20199                                buffer,
20200                                true,
20201                                true,
20202                                window,
20203                                cx,
20204                            )
20205                        });
20206
20207                    editor.update(cx, |editor, cx| {
20208                        let autoscroll = match scroll_offset {
20209                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20210                            None => Autoscroll::newest(),
20211                        };
20212                        let nav_history = editor.nav_history.take();
20213                        editor.change_selections(
20214                            SelectionEffects::scroll(autoscroll),
20215                            window,
20216                            cx,
20217                            |s| {
20218                                s.select_ranges(ranges);
20219                            },
20220                        );
20221                        editor.nav_history = nav_history;
20222                    });
20223                }
20224            })
20225        });
20226    }
20227
20228    // For now, don't allow opening excerpts in buffers that aren't backed by
20229    // regular project files.
20230    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20231        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20232    }
20233
20234    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20235        let snapshot = self.buffer.read(cx).read(cx);
20236        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20237        Some(
20238            ranges
20239                .iter()
20240                .map(move |range| {
20241                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20242                })
20243                .collect(),
20244        )
20245    }
20246
20247    fn selection_replacement_ranges(
20248        &self,
20249        range: Range<OffsetUtf16>,
20250        cx: &mut App,
20251    ) -> Vec<Range<OffsetUtf16>> {
20252        let selections = self.selections.all::<OffsetUtf16>(cx);
20253        let newest_selection = selections
20254            .iter()
20255            .max_by_key(|selection| selection.id)
20256            .unwrap();
20257        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20258        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20259        let snapshot = self.buffer.read(cx).read(cx);
20260        selections
20261            .into_iter()
20262            .map(|mut selection| {
20263                selection.start.0 =
20264                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20265                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20266                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20267                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20268            })
20269            .collect()
20270    }
20271
20272    fn report_editor_event(
20273        &self,
20274        event_type: &'static str,
20275        file_extension: Option<String>,
20276        cx: &App,
20277    ) {
20278        if cfg!(any(test, feature = "test-support")) {
20279            return;
20280        }
20281
20282        let Some(project) = &self.project else { return };
20283
20284        // If None, we are in a file without an extension
20285        let file = self
20286            .buffer
20287            .read(cx)
20288            .as_singleton()
20289            .and_then(|b| b.read(cx).file());
20290        let file_extension = file_extension.or(file
20291            .as_ref()
20292            .and_then(|file| Path::new(file.file_name(cx)).extension())
20293            .and_then(|e| e.to_str())
20294            .map(|a| a.to_string()));
20295
20296        let vim_mode = vim_enabled(cx);
20297
20298        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20299        let copilot_enabled = edit_predictions_provider
20300            == language::language_settings::EditPredictionProvider::Copilot;
20301        let copilot_enabled_for_language = self
20302            .buffer
20303            .read(cx)
20304            .language_settings(cx)
20305            .show_edit_predictions;
20306
20307        let project = project.read(cx);
20308        telemetry::event!(
20309            event_type,
20310            file_extension,
20311            vim_mode,
20312            copilot_enabled,
20313            copilot_enabled_for_language,
20314            edit_predictions_provider,
20315            is_via_ssh = project.is_via_ssh(),
20316        );
20317    }
20318
20319    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20320    /// with each line being an array of {text, highlight} objects.
20321    fn copy_highlight_json(
20322        &mut self,
20323        _: &CopyHighlightJson,
20324        window: &mut Window,
20325        cx: &mut Context<Self>,
20326    ) {
20327        #[derive(Serialize)]
20328        struct Chunk<'a> {
20329            text: String,
20330            highlight: Option<&'a str>,
20331        }
20332
20333        let snapshot = self.buffer.read(cx).snapshot(cx);
20334        let range = self
20335            .selected_text_range(false, window, cx)
20336            .and_then(|selection| {
20337                if selection.range.is_empty() {
20338                    None
20339                } else {
20340                    Some(selection.range)
20341                }
20342            })
20343            .unwrap_or_else(|| 0..snapshot.len());
20344
20345        let chunks = snapshot.chunks(range, true);
20346        let mut lines = Vec::new();
20347        let mut line: VecDeque<Chunk> = VecDeque::new();
20348
20349        let Some(style) = self.style.as_ref() else {
20350            return;
20351        };
20352
20353        for chunk in chunks {
20354            let highlight = chunk
20355                .syntax_highlight_id
20356                .and_then(|id| id.name(&style.syntax));
20357            let mut chunk_lines = chunk.text.split('\n').peekable();
20358            while let Some(text) = chunk_lines.next() {
20359                let mut merged_with_last_token = false;
20360                if let Some(last_token) = line.back_mut() {
20361                    if last_token.highlight == highlight {
20362                        last_token.text.push_str(text);
20363                        merged_with_last_token = true;
20364                    }
20365                }
20366
20367                if !merged_with_last_token {
20368                    line.push_back(Chunk {
20369                        text: text.into(),
20370                        highlight,
20371                    });
20372                }
20373
20374                if chunk_lines.peek().is_some() {
20375                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20376                        line.pop_front();
20377                    }
20378                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20379                        line.pop_back();
20380                    }
20381
20382                    lines.push(mem::take(&mut line));
20383                }
20384            }
20385        }
20386
20387        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20388            return;
20389        };
20390        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20391    }
20392
20393    pub fn open_context_menu(
20394        &mut self,
20395        _: &OpenContextMenu,
20396        window: &mut Window,
20397        cx: &mut Context<Self>,
20398    ) {
20399        self.request_autoscroll(Autoscroll::newest(), cx);
20400        let position = self.selections.newest_display(cx).start;
20401        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20402    }
20403
20404    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20405        &self.inlay_hint_cache
20406    }
20407
20408    pub fn replay_insert_event(
20409        &mut self,
20410        text: &str,
20411        relative_utf16_range: Option<Range<isize>>,
20412        window: &mut Window,
20413        cx: &mut Context<Self>,
20414    ) {
20415        if !self.input_enabled {
20416            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20417            return;
20418        }
20419        if let Some(relative_utf16_range) = relative_utf16_range {
20420            let selections = self.selections.all::<OffsetUtf16>(cx);
20421            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20422                let new_ranges = selections.into_iter().map(|range| {
20423                    let start = OffsetUtf16(
20424                        range
20425                            .head()
20426                            .0
20427                            .saturating_add_signed(relative_utf16_range.start),
20428                    );
20429                    let end = OffsetUtf16(
20430                        range
20431                            .head()
20432                            .0
20433                            .saturating_add_signed(relative_utf16_range.end),
20434                    );
20435                    start..end
20436                });
20437                s.select_ranges(new_ranges);
20438            });
20439        }
20440
20441        self.handle_input(text, window, cx);
20442    }
20443
20444    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20445        let Some(provider) = self.semantics_provider.as_ref() else {
20446            return false;
20447        };
20448
20449        let mut supports = false;
20450        self.buffer().update(cx, |this, cx| {
20451            this.for_each_buffer(|buffer| {
20452                supports |= provider.supports_inlay_hints(buffer, cx);
20453            });
20454        });
20455
20456        supports
20457    }
20458
20459    pub fn is_focused(&self, window: &Window) -> bool {
20460        self.focus_handle.is_focused(window)
20461    }
20462
20463    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20464        cx.emit(EditorEvent::Focused);
20465
20466        if let Some(descendant) = self
20467            .last_focused_descendant
20468            .take()
20469            .and_then(|descendant| descendant.upgrade())
20470        {
20471            window.focus(&descendant);
20472        } else {
20473            if let Some(blame) = self.blame.as_ref() {
20474                blame.update(cx, GitBlame::focus)
20475            }
20476
20477            self.blink_manager.update(cx, BlinkManager::enable);
20478            self.show_cursor_names(window, cx);
20479            self.buffer.update(cx, |buffer, cx| {
20480                buffer.finalize_last_transaction(cx);
20481                if self.leader_id.is_none() {
20482                    buffer.set_active_selections(
20483                        &self.selections.disjoint_anchors(),
20484                        self.selections.line_mode,
20485                        self.cursor_shape,
20486                        cx,
20487                    );
20488                }
20489            });
20490        }
20491    }
20492
20493    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20494        cx.emit(EditorEvent::FocusedIn)
20495    }
20496
20497    fn handle_focus_out(
20498        &mut self,
20499        event: FocusOutEvent,
20500        _window: &mut Window,
20501        cx: &mut Context<Self>,
20502    ) {
20503        if event.blurred != self.focus_handle {
20504            self.last_focused_descendant = Some(event.blurred);
20505        }
20506        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20507    }
20508
20509    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20510        self.blink_manager.update(cx, BlinkManager::disable);
20511        self.buffer
20512            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20513
20514        if let Some(blame) = self.blame.as_ref() {
20515            blame.update(cx, GitBlame::blur)
20516        }
20517        if !self.hover_state.focused(window, cx) {
20518            hide_hover(self, cx);
20519        }
20520        if !self
20521            .context_menu
20522            .borrow()
20523            .as_ref()
20524            .is_some_and(|context_menu| context_menu.focused(window, cx))
20525        {
20526            self.hide_context_menu(window, cx);
20527        }
20528        self.discard_inline_completion(false, cx);
20529        cx.emit(EditorEvent::Blurred);
20530        cx.notify();
20531    }
20532
20533    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20534        let mut pending: String = window
20535            .pending_input_keystrokes()
20536            .into_iter()
20537            .flatten()
20538            .filter_map(|keystroke| {
20539                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20540                    keystroke.key_char.clone()
20541                } else {
20542                    None
20543                }
20544            })
20545            .collect();
20546
20547        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20548            pending = "".to_string();
20549        }
20550
20551        let existing_pending = self
20552            .text_highlights::<PendingInput>(cx)
20553            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20554        if existing_pending.is_none() && pending.is_empty() {
20555            return;
20556        }
20557        let transaction =
20558            self.transact(window, cx, |this, window, cx| {
20559                let selections = this.selections.all::<usize>(cx);
20560                let edits = selections
20561                    .iter()
20562                    .map(|selection| (selection.end..selection.end, pending.clone()));
20563                this.edit(edits, cx);
20564                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20565                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20566                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20567                    }));
20568                });
20569                if let Some(existing_ranges) = existing_pending {
20570                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20571                    this.edit(edits, cx);
20572                }
20573            });
20574
20575        let snapshot = self.snapshot(window, cx);
20576        let ranges = self
20577            .selections
20578            .all::<usize>(cx)
20579            .into_iter()
20580            .map(|selection| {
20581                snapshot.buffer_snapshot.anchor_after(selection.end)
20582                    ..snapshot
20583                        .buffer_snapshot
20584                        .anchor_before(selection.end + pending.len())
20585            })
20586            .collect();
20587
20588        if pending.is_empty() {
20589            self.clear_highlights::<PendingInput>(cx);
20590        } else {
20591            self.highlight_text::<PendingInput>(
20592                ranges,
20593                HighlightStyle {
20594                    underline: Some(UnderlineStyle {
20595                        thickness: px(1.),
20596                        color: None,
20597                        wavy: false,
20598                    }),
20599                    ..Default::default()
20600                },
20601                cx,
20602            );
20603        }
20604
20605        self.ime_transaction = self.ime_transaction.or(transaction);
20606        if let Some(transaction) = self.ime_transaction {
20607            self.buffer.update(cx, |buffer, cx| {
20608                buffer.group_until_transaction(transaction, cx);
20609            });
20610        }
20611
20612        if self.text_highlights::<PendingInput>(cx).is_none() {
20613            self.ime_transaction.take();
20614        }
20615    }
20616
20617    pub fn register_action_renderer(
20618        &mut self,
20619        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20620    ) -> Subscription {
20621        let id = self.next_editor_action_id.post_inc();
20622        self.editor_actions
20623            .borrow_mut()
20624            .insert(id, Box::new(listener));
20625
20626        let editor_actions = self.editor_actions.clone();
20627        Subscription::new(move || {
20628            editor_actions.borrow_mut().remove(&id);
20629        })
20630    }
20631
20632    pub fn register_action<A: Action>(
20633        &mut self,
20634        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20635    ) -> Subscription {
20636        let id = self.next_editor_action_id.post_inc();
20637        let listener = Arc::new(listener);
20638        self.editor_actions.borrow_mut().insert(
20639            id,
20640            Box::new(move |_, window, _| {
20641                let listener = listener.clone();
20642                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20643                    let action = action.downcast_ref().unwrap();
20644                    if phase == DispatchPhase::Bubble {
20645                        listener(action, window, cx)
20646                    }
20647                })
20648            }),
20649        );
20650
20651        let editor_actions = self.editor_actions.clone();
20652        Subscription::new(move || {
20653            editor_actions.borrow_mut().remove(&id);
20654        })
20655    }
20656
20657    pub fn file_header_size(&self) -> u32 {
20658        FILE_HEADER_HEIGHT
20659    }
20660
20661    pub fn restore(
20662        &mut self,
20663        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20664        window: &mut Window,
20665        cx: &mut Context<Self>,
20666    ) {
20667        let workspace = self.workspace();
20668        let project = self.project.as_ref();
20669        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20670            let mut tasks = Vec::new();
20671            for (buffer_id, changes) in revert_changes {
20672                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20673                    buffer.update(cx, |buffer, cx| {
20674                        buffer.edit(
20675                            changes
20676                                .into_iter()
20677                                .map(|(range, text)| (range, text.to_string())),
20678                            None,
20679                            cx,
20680                        );
20681                    });
20682
20683                    if let Some(project) =
20684                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20685                    {
20686                        project.update(cx, |project, cx| {
20687                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20688                        })
20689                    }
20690                }
20691            }
20692            tasks
20693        });
20694        cx.spawn_in(window, async move |_, cx| {
20695            for (buffer, task) in save_tasks {
20696                let result = task.await;
20697                if result.is_err() {
20698                    let Some(path) = buffer
20699                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20700                        .ok()
20701                    else {
20702                        continue;
20703                    };
20704                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20705                        let Some(task) = cx
20706                            .update_window_entity(&workspace, |workspace, window, cx| {
20707                                workspace
20708                                    .open_path_preview(path, None, false, false, false, window, cx)
20709                            })
20710                            .ok()
20711                        else {
20712                            continue;
20713                        };
20714                        task.await.log_err();
20715                    }
20716                }
20717            }
20718        })
20719        .detach();
20720        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20721            selections.refresh()
20722        });
20723    }
20724
20725    pub fn to_pixel_point(
20726        &self,
20727        source: multi_buffer::Anchor,
20728        editor_snapshot: &EditorSnapshot,
20729        window: &mut Window,
20730    ) -> Option<gpui::Point<Pixels>> {
20731        let source_point = source.to_display_point(editor_snapshot);
20732        self.display_to_pixel_point(source_point, editor_snapshot, window)
20733    }
20734
20735    pub fn display_to_pixel_point(
20736        &self,
20737        source: DisplayPoint,
20738        editor_snapshot: &EditorSnapshot,
20739        window: &mut Window,
20740    ) -> Option<gpui::Point<Pixels>> {
20741        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20742        let text_layout_details = self.text_layout_details(window);
20743        let scroll_top = text_layout_details
20744            .scroll_anchor
20745            .scroll_position(editor_snapshot)
20746            .y;
20747
20748        if source.row().as_f32() < scroll_top.floor() {
20749            return None;
20750        }
20751        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20752        let source_y = line_height * (source.row().as_f32() - scroll_top);
20753        Some(gpui::Point::new(source_x, source_y))
20754    }
20755
20756    pub fn has_visible_completions_menu(&self) -> bool {
20757        !self.edit_prediction_preview_is_active()
20758            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20759                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20760            })
20761    }
20762
20763    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20764        if self.mode.is_minimap() {
20765            return;
20766        }
20767        self.addons
20768            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20769    }
20770
20771    pub fn unregister_addon<T: Addon>(&mut self) {
20772        self.addons.remove(&std::any::TypeId::of::<T>());
20773    }
20774
20775    pub fn addon<T: Addon>(&self) -> Option<&T> {
20776        let type_id = std::any::TypeId::of::<T>();
20777        self.addons
20778            .get(&type_id)
20779            .and_then(|item| item.to_any().downcast_ref::<T>())
20780    }
20781
20782    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20783        let type_id = std::any::TypeId::of::<T>();
20784        self.addons
20785            .get_mut(&type_id)
20786            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20787    }
20788
20789    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20790        let text_layout_details = self.text_layout_details(window);
20791        let style = &text_layout_details.editor_style;
20792        let font_id = window.text_system().resolve_font(&style.text.font());
20793        let font_size = style.text.font_size.to_pixels(window.rem_size());
20794        let line_height = style.text.line_height_in_pixels(window.rem_size());
20795        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20796        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20797
20798        CharacterDimensions {
20799            em_width,
20800            em_advance,
20801            line_height,
20802        }
20803    }
20804
20805    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20806        self.load_diff_task.clone()
20807    }
20808
20809    fn read_metadata_from_db(
20810        &mut self,
20811        item_id: u64,
20812        workspace_id: WorkspaceId,
20813        window: &mut Window,
20814        cx: &mut Context<Editor>,
20815    ) {
20816        if self.is_singleton(cx)
20817            && !self.mode.is_minimap()
20818            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20819        {
20820            let buffer_snapshot = OnceCell::new();
20821
20822            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20823                if !folds.is_empty() {
20824                    let snapshot =
20825                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20826                    self.fold_ranges(
20827                        folds
20828                            .into_iter()
20829                            .map(|(start, end)| {
20830                                snapshot.clip_offset(start, Bias::Left)
20831                                    ..snapshot.clip_offset(end, Bias::Right)
20832                            })
20833                            .collect(),
20834                        false,
20835                        window,
20836                        cx,
20837                    );
20838                }
20839            }
20840
20841            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20842                if !selections.is_empty() {
20843                    let snapshot =
20844                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20845                    // skip adding the initial selection to selection history
20846                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20847                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20848                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20849                            snapshot.clip_offset(start, Bias::Left)
20850                                ..snapshot.clip_offset(end, Bias::Right)
20851                        }));
20852                    });
20853                    self.selection_history.mode = SelectionHistoryMode::Normal;
20854                }
20855            };
20856        }
20857
20858        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20859    }
20860
20861    fn update_lsp_data(
20862        &mut self,
20863        ignore_cache: bool,
20864        for_buffer: Option<BufferId>,
20865        window: &mut Window,
20866        cx: &mut Context<'_, Self>,
20867    ) {
20868        self.pull_diagnostics(for_buffer, window, cx);
20869        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20870    }
20871}
20872
20873fn vim_enabled(cx: &App) -> bool {
20874    cx.global::<SettingsStore>()
20875        .raw_user_settings()
20876        .get("vim_mode")
20877        == Some(&serde_json::Value::Bool(true))
20878}
20879
20880fn process_completion_for_edit(
20881    completion: &Completion,
20882    intent: CompletionIntent,
20883    buffer: &Entity<Buffer>,
20884    cursor_position: &text::Anchor,
20885    cx: &mut Context<Editor>,
20886) -> CompletionEdit {
20887    let buffer = buffer.read(cx);
20888    let buffer_snapshot = buffer.snapshot();
20889    let (snippet, new_text) = if completion.is_snippet() {
20890        // Workaround for typescript language server issues so that methods don't expand within
20891        // strings and functions with type expressions. The previous point is used because the query
20892        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20893        let mut snippet_source = completion.new_text.clone();
20894        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20895        previous_point.column = previous_point.column.saturating_sub(1);
20896        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20897            if scope.prefers_label_for_snippet_in_completion() {
20898                if let Some(label) = completion.label() {
20899                    if matches!(
20900                        completion.kind(),
20901                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20902                    ) {
20903                        snippet_source = label;
20904                    }
20905                }
20906            }
20907        }
20908        match Snippet::parse(&snippet_source).log_err() {
20909            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20910            None => (None, completion.new_text.clone()),
20911        }
20912    } else {
20913        (None, completion.new_text.clone())
20914    };
20915
20916    let mut range_to_replace = {
20917        let replace_range = &completion.replace_range;
20918        if let CompletionSource::Lsp {
20919            insert_range: Some(insert_range),
20920            ..
20921        } = &completion.source
20922        {
20923            debug_assert_eq!(
20924                insert_range.start, replace_range.start,
20925                "insert_range and replace_range should start at the same position"
20926            );
20927            debug_assert!(
20928                insert_range
20929                    .start
20930                    .cmp(&cursor_position, &buffer_snapshot)
20931                    .is_le(),
20932                "insert_range should start before or at cursor position"
20933            );
20934            debug_assert!(
20935                replace_range
20936                    .start
20937                    .cmp(&cursor_position, &buffer_snapshot)
20938                    .is_le(),
20939                "replace_range should start before or at cursor position"
20940            );
20941            debug_assert!(
20942                insert_range
20943                    .end
20944                    .cmp(&cursor_position, &buffer_snapshot)
20945                    .is_le(),
20946                "insert_range should end before or at cursor position"
20947            );
20948
20949            let should_replace = match intent {
20950                CompletionIntent::CompleteWithInsert => false,
20951                CompletionIntent::CompleteWithReplace => true,
20952                CompletionIntent::Complete | CompletionIntent::Compose => {
20953                    let insert_mode =
20954                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20955                            .completions
20956                            .lsp_insert_mode;
20957                    match insert_mode {
20958                        LspInsertMode::Insert => false,
20959                        LspInsertMode::Replace => true,
20960                        LspInsertMode::ReplaceSubsequence => {
20961                            let mut text_to_replace = buffer.chars_for_range(
20962                                buffer.anchor_before(replace_range.start)
20963                                    ..buffer.anchor_after(replace_range.end),
20964                            );
20965                            let mut current_needle = text_to_replace.next();
20966                            for haystack_ch in completion.label.text.chars() {
20967                                if let Some(needle_ch) = current_needle {
20968                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20969                                        current_needle = text_to_replace.next();
20970                                    }
20971                                }
20972                            }
20973                            current_needle.is_none()
20974                        }
20975                        LspInsertMode::ReplaceSuffix => {
20976                            if replace_range
20977                                .end
20978                                .cmp(&cursor_position, &buffer_snapshot)
20979                                .is_gt()
20980                            {
20981                                let range_after_cursor = *cursor_position..replace_range.end;
20982                                let text_after_cursor = buffer
20983                                    .text_for_range(
20984                                        buffer.anchor_before(range_after_cursor.start)
20985                                            ..buffer.anchor_after(range_after_cursor.end),
20986                                    )
20987                                    .collect::<String>()
20988                                    .to_ascii_lowercase();
20989                                completion
20990                                    .label
20991                                    .text
20992                                    .to_ascii_lowercase()
20993                                    .ends_with(&text_after_cursor)
20994                            } else {
20995                                true
20996                            }
20997                        }
20998                    }
20999                }
21000            };
21001
21002            if should_replace {
21003                replace_range.clone()
21004            } else {
21005                insert_range.clone()
21006            }
21007        } else {
21008            replace_range.clone()
21009        }
21010    };
21011
21012    if range_to_replace
21013        .end
21014        .cmp(&cursor_position, &buffer_snapshot)
21015        .is_lt()
21016    {
21017        range_to_replace.end = *cursor_position;
21018    }
21019
21020    CompletionEdit {
21021        new_text,
21022        replace_range: range_to_replace.to_offset(&buffer),
21023        snippet,
21024    }
21025}
21026
21027struct CompletionEdit {
21028    new_text: String,
21029    replace_range: Range<usize>,
21030    snippet: Option<Snippet>,
21031}
21032
21033fn insert_extra_newline_brackets(
21034    buffer: &MultiBufferSnapshot,
21035    range: Range<usize>,
21036    language: &language::LanguageScope,
21037) -> bool {
21038    let leading_whitespace_len = buffer
21039        .reversed_chars_at(range.start)
21040        .take_while(|c| c.is_whitespace() && *c != '\n')
21041        .map(|c| c.len_utf8())
21042        .sum::<usize>();
21043    let trailing_whitespace_len = buffer
21044        .chars_at(range.end)
21045        .take_while(|c| c.is_whitespace() && *c != '\n')
21046        .map(|c| c.len_utf8())
21047        .sum::<usize>();
21048    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21049
21050    language.brackets().any(|(pair, enabled)| {
21051        let pair_start = pair.start.trim_end();
21052        let pair_end = pair.end.trim_start();
21053
21054        enabled
21055            && pair.newline
21056            && buffer.contains_str_at(range.end, pair_end)
21057            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21058    })
21059}
21060
21061fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21062    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21063        [(buffer, range, _)] => (*buffer, range.clone()),
21064        _ => return false,
21065    };
21066    let pair = {
21067        let mut result: Option<BracketMatch> = None;
21068
21069        for pair in buffer
21070            .all_bracket_ranges(range.clone())
21071            .filter(move |pair| {
21072                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21073            })
21074        {
21075            let len = pair.close_range.end - pair.open_range.start;
21076
21077            if let Some(existing) = &result {
21078                let existing_len = existing.close_range.end - existing.open_range.start;
21079                if len > existing_len {
21080                    continue;
21081                }
21082            }
21083
21084            result = Some(pair);
21085        }
21086
21087        result
21088    };
21089    let Some(pair) = pair else {
21090        return false;
21091    };
21092    pair.newline_only
21093        && buffer
21094            .chars_for_range(pair.open_range.end..range.start)
21095            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21096            .all(|c| c.is_whitespace() && c != '\n')
21097}
21098
21099fn update_uncommitted_diff_for_buffer(
21100    editor: Entity<Editor>,
21101    project: &Entity<Project>,
21102    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21103    buffer: Entity<MultiBuffer>,
21104    cx: &mut App,
21105) -> Task<()> {
21106    let mut tasks = Vec::new();
21107    project.update(cx, |project, cx| {
21108        for buffer in buffers {
21109            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21110                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21111            }
21112        }
21113    });
21114    cx.spawn(async move |cx| {
21115        let diffs = future::join_all(tasks).await;
21116        if editor
21117            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21118            .unwrap_or(false)
21119        {
21120            return;
21121        }
21122
21123        buffer
21124            .update(cx, |buffer, cx| {
21125                for diff in diffs.into_iter().flatten() {
21126                    buffer.add_diff(diff, cx);
21127                }
21128            })
21129            .ok();
21130    })
21131}
21132
21133fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21134    let tab_size = tab_size.get() as usize;
21135    let mut width = offset;
21136
21137    for ch in text.chars() {
21138        width += if ch == '\t' {
21139            tab_size - (width % tab_size)
21140        } else {
21141            1
21142        };
21143    }
21144
21145    width - offset
21146}
21147
21148#[cfg(test)]
21149mod tests {
21150    use super::*;
21151
21152    #[test]
21153    fn test_string_size_with_expanded_tabs() {
21154        let nz = |val| NonZeroU32::new(val).unwrap();
21155        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21156        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21157        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21158        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21159        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21160        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21161        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21162        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21163    }
21164}
21165
21166/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21167struct WordBreakingTokenizer<'a> {
21168    input: &'a str,
21169}
21170
21171impl<'a> WordBreakingTokenizer<'a> {
21172    fn new(input: &'a str) -> Self {
21173        Self { input }
21174    }
21175}
21176
21177fn is_char_ideographic(ch: char) -> bool {
21178    use unicode_script::Script::*;
21179    use unicode_script::UnicodeScript;
21180    matches!(ch.script(), Han | Tangut | Yi)
21181}
21182
21183fn is_grapheme_ideographic(text: &str) -> bool {
21184    text.chars().any(is_char_ideographic)
21185}
21186
21187fn is_grapheme_whitespace(text: &str) -> bool {
21188    text.chars().any(|x| x.is_whitespace())
21189}
21190
21191fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21192    text.chars().next().map_or(false, |ch| {
21193        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21194    })
21195}
21196
21197#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21198enum WordBreakToken<'a> {
21199    Word { token: &'a str, grapheme_len: usize },
21200    InlineWhitespace { token: &'a str, grapheme_len: usize },
21201    Newline,
21202}
21203
21204impl<'a> Iterator for WordBreakingTokenizer<'a> {
21205    /// Yields a span, the count of graphemes in the token, and whether it was
21206    /// whitespace. Note that it also breaks at word boundaries.
21207    type Item = WordBreakToken<'a>;
21208
21209    fn next(&mut self) -> Option<Self::Item> {
21210        use unicode_segmentation::UnicodeSegmentation;
21211        if self.input.is_empty() {
21212            return None;
21213        }
21214
21215        let mut iter = self.input.graphemes(true).peekable();
21216        let mut offset = 0;
21217        let mut grapheme_len = 0;
21218        if let Some(first_grapheme) = iter.next() {
21219            let is_newline = first_grapheme == "\n";
21220            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21221            offset += first_grapheme.len();
21222            grapheme_len += 1;
21223            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21224                if let Some(grapheme) = iter.peek().copied() {
21225                    if should_stay_with_preceding_ideograph(grapheme) {
21226                        offset += grapheme.len();
21227                        grapheme_len += 1;
21228                    }
21229                }
21230            } else {
21231                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21232                let mut next_word_bound = words.peek().copied();
21233                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21234                    next_word_bound = words.next();
21235                }
21236                while let Some(grapheme) = iter.peek().copied() {
21237                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21238                        break;
21239                    };
21240                    if is_grapheme_whitespace(grapheme) != is_whitespace
21241                        || (grapheme == "\n") != is_newline
21242                    {
21243                        break;
21244                    };
21245                    offset += grapheme.len();
21246                    grapheme_len += 1;
21247                    iter.next();
21248                }
21249            }
21250            let token = &self.input[..offset];
21251            self.input = &self.input[offset..];
21252            if token == "\n" {
21253                Some(WordBreakToken::Newline)
21254            } else if is_whitespace {
21255                Some(WordBreakToken::InlineWhitespace {
21256                    token,
21257                    grapheme_len,
21258                })
21259            } else {
21260                Some(WordBreakToken::Word {
21261                    token,
21262                    grapheme_len,
21263                })
21264            }
21265        } else {
21266            None
21267        }
21268    }
21269}
21270
21271#[test]
21272fn test_word_breaking_tokenizer() {
21273    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21274        ("", &[]),
21275        ("  ", &[whitespace("  ", 2)]),
21276        ("Ʒ", &[word("Ʒ", 1)]),
21277        ("Ǽ", &[word("Ǽ", 1)]),
21278        ("", &[word("", 1)]),
21279        ("⋑⋑", &[word("⋑⋑", 2)]),
21280        (
21281            "原理,进而",
21282            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21283        ),
21284        (
21285            "hello world",
21286            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21287        ),
21288        (
21289            "hello, world",
21290            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21291        ),
21292        (
21293            "  hello world",
21294            &[
21295                whitespace("  ", 2),
21296                word("hello", 5),
21297                whitespace(" ", 1),
21298                word("world", 5),
21299            ],
21300        ),
21301        (
21302            "这是什么 \n 钢笔",
21303            &[
21304                word("", 1),
21305                word("", 1),
21306                word("", 1),
21307                word("", 1),
21308                whitespace(" ", 1),
21309                newline(),
21310                whitespace(" ", 1),
21311                word("", 1),
21312                word("", 1),
21313            ],
21314        ),
21315        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21316    ];
21317
21318    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21319        WordBreakToken::Word {
21320            token,
21321            grapheme_len,
21322        }
21323    }
21324
21325    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21326        WordBreakToken::InlineWhitespace {
21327            token,
21328            grapheme_len,
21329        }
21330    }
21331
21332    fn newline() -> WordBreakToken<'static> {
21333        WordBreakToken::Newline
21334    }
21335
21336    for (input, result) in tests {
21337        assert_eq!(
21338            WordBreakingTokenizer::new(input)
21339                .collect::<Vec<_>>()
21340                .as_slice(),
21341            *result,
21342        );
21343    }
21344}
21345
21346fn wrap_with_prefix(
21347    first_line_prefix: String,
21348    subsequent_lines_prefix: String,
21349    unwrapped_text: String,
21350    wrap_column: usize,
21351    tab_size: NonZeroU32,
21352    preserve_existing_whitespace: bool,
21353) -> String {
21354    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21355    let subsequent_lines_prefix_len =
21356        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21357    let mut wrapped_text = String::new();
21358    let mut current_line = first_line_prefix.clone();
21359    let mut is_first_line = true;
21360
21361    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21362    let mut current_line_len = first_line_prefix_len;
21363    let mut in_whitespace = false;
21364    for token in tokenizer {
21365        let have_preceding_whitespace = in_whitespace;
21366        match token {
21367            WordBreakToken::Word {
21368                token,
21369                grapheme_len,
21370            } => {
21371                in_whitespace = false;
21372                let current_prefix_len = if is_first_line {
21373                    first_line_prefix_len
21374                } else {
21375                    subsequent_lines_prefix_len
21376                };
21377                if current_line_len + grapheme_len > wrap_column
21378                    && current_line_len != current_prefix_len
21379                {
21380                    wrapped_text.push_str(current_line.trim_end());
21381                    wrapped_text.push('\n');
21382                    is_first_line = false;
21383                    current_line = subsequent_lines_prefix.clone();
21384                    current_line_len = subsequent_lines_prefix_len;
21385                }
21386                current_line.push_str(token);
21387                current_line_len += grapheme_len;
21388            }
21389            WordBreakToken::InlineWhitespace {
21390                mut token,
21391                mut grapheme_len,
21392            } => {
21393                in_whitespace = true;
21394                if have_preceding_whitespace && !preserve_existing_whitespace {
21395                    continue;
21396                }
21397                if !preserve_existing_whitespace {
21398                    token = " ";
21399                    grapheme_len = 1;
21400                }
21401                let current_prefix_len = if is_first_line {
21402                    first_line_prefix_len
21403                } else {
21404                    subsequent_lines_prefix_len
21405                };
21406                if current_line_len + grapheme_len > wrap_column {
21407                    wrapped_text.push_str(current_line.trim_end());
21408                    wrapped_text.push('\n');
21409                    is_first_line = false;
21410                    current_line = subsequent_lines_prefix.clone();
21411                    current_line_len = subsequent_lines_prefix_len;
21412                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21413                    current_line.push_str(token);
21414                    current_line_len += grapheme_len;
21415                }
21416            }
21417            WordBreakToken::Newline => {
21418                in_whitespace = true;
21419                let current_prefix_len = if is_first_line {
21420                    first_line_prefix_len
21421                } else {
21422                    subsequent_lines_prefix_len
21423                };
21424                if preserve_existing_whitespace {
21425                    wrapped_text.push_str(current_line.trim_end());
21426                    wrapped_text.push('\n');
21427                    is_first_line = false;
21428                    current_line = subsequent_lines_prefix.clone();
21429                    current_line_len = subsequent_lines_prefix_len;
21430                } else if have_preceding_whitespace {
21431                    continue;
21432                } else if current_line_len + 1 > wrap_column
21433                    && current_line_len != current_prefix_len
21434                {
21435                    wrapped_text.push_str(current_line.trim_end());
21436                    wrapped_text.push('\n');
21437                    is_first_line = false;
21438                    current_line = subsequent_lines_prefix.clone();
21439                    current_line_len = subsequent_lines_prefix_len;
21440                } else if current_line_len != current_prefix_len {
21441                    current_line.push(' ');
21442                    current_line_len += 1;
21443                }
21444            }
21445        }
21446    }
21447
21448    if !current_line.is_empty() {
21449        wrapped_text.push_str(&current_line);
21450    }
21451    wrapped_text
21452}
21453
21454#[test]
21455fn test_wrap_with_prefix() {
21456    assert_eq!(
21457        wrap_with_prefix(
21458            "# ".to_string(),
21459            "# ".to_string(),
21460            "abcdefg".to_string(),
21461            4,
21462            NonZeroU32::new(4).unwrap(),
21463            false,
21464        ),
21465        "# abcdefg"
21466    );
21467    assert_eq!(
21468        wrap_with_prefix(
21469            "".to_string(),
21470            "".to_string(),
21471            "\thello world".to_string(),
21472            8,
21473            NonZeroU32::new(4).unwrap(),
21474            false,
21475        ),
21476        "hello\nworld"
21477    );
21478    assert_eq!(
21479        wrap_with_prefix(
21480            "// ".to_string(),
21481            "// ".to_string(),
21482            "xx \nyy zz aa bb cc".to_string(),
21483            12,
21484            NonZeroU32::new(4).unwrap(),
21485            false,
21486        ),
21487        "// xx yy zz\n// aa bb cc"
21488    );
21489    assert_eq!(
21490        wrap_with_prefix(
21491            String::new(),
21492            String::new(),
21493            "这是什么 \n 钢笔".to_string(),
21494            3,
21495            NonZeroU32::new(4).unwrap(),
21496            false,
21497        ),
21498        "这是什\n么 钢\n"
21499    );
21500}
21501
21502pub trait CollaborationHub {
21503    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21504    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21505    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21506}
21507
21508impl CollaborationHub for Entity<Project> {
21509    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21510        self.read(cx).collaborators()
21511    }
21512
21513    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21514        self.read(cx).user_store().read(cx).participant_indices()
21515    }
21516
21517    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21518        let this = self.read(cx);
21519        let user_ids = this.collaborators().values().map(|c| c.user_id);
21520        this.user_store().read(cx).participant_names(user_ids, cx)
21521    }
21522}
21523
21524pub trait SemanticsProvider {
21525    fn hover(
21526        &self,
21527        buffer: &Entity<Buffer>,
21528        position: text::Anchor,
21529        cx: &mut App,
21530    ) -> Option<Task<Vec<project::Hover>>>;
21531
21532    fn inline_values(
21533        &self,
21534        buffer_handle: Entity<Buffer>,
21535        range: Range<text::Anchor>,
21536        cx: &mut App,
21537    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21538
21539    fn inlay_hints(
21540        &self,
21541        buffer_handle: Entity<Buffer>,
21542        range: Range<text::Anchor>,
21543        cx: &mut App,
21544    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21545
21546    fn resolve_inlay_hint(
21547        &self,
21548        hint: InlayHint,
21549        buffer_handle: Entity<Buffer>,
21550        server_id: LanguageServerId,
21551        cx: &mut App,
21552    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21553
21554    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21555
21556    fn document_highlights(
21557        &self,
21558        buffer: &Entity<Buffer>,
21559        position: text::Anchor,
21560        cx: &mut App,
21561    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21562
21563    fn definitions(
21564        &self,
21565        buffer: &Entity<Buffer>,
21566        position: text::Anchor,
21567        kind: GotoDefinitionKind,
21568        cx: &mut App,
21569    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21570
21571    fn range_for_rename(
21572        &self,
21573        buffer: &Entity<Buffer>,
21574        position: text::Anchor,
21575        cx: &mut App,
21576    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21577
21578    fn perform_rename(
21579        &self,
21580        buffer: &Entity<Buffer>,
21581        position: text::Anchor,
21582        new_name: String,
21583        cx: &mut App,
21584    ) -> Option<Task<Result<ProjectTransaction>>>;
21585}
21586
21587pub trait CompletionProvider {
21588    fn completions(
21589        &self,
21590        excerpt_id: ExcerptId,
21591        buffer: &Entity<Buffer>,
21592        buffer_position: text::Anchor,
21593        trigger: CompletionContext,
21594        window: &mut Window,
21595        cx: &mut Context<Editor>,
21596    ) -> Task<Result<Vec<CompletionResponse>>>;
21597
21598    fn resolve_completions(
21599        &self,
21600        _buffer: Entity<Buffer>,
21601        _completion_indices: Vec<usize>,
21602        _completions: Rc<RefCell<Box<[Completion]>>>,
21603        _cx: &mut Context<Editor>,
21604    ) -> Task<Result<bool>> {
21605        Task::ready(Ok(false))
21606    }
21607
21608    fn apply_additional_edits_for_completion(
21609        &self,
21610        _buffer: Entity<Buffer>,
21611        _completions: Rc<RefCell<Box<[Completion]>>>,
21612        _completion_index: usize,
21613        _push_to_history: bool,
21614        _cx: &mut Context<Editor>,
21615    ) -> Task<Result<Option<language::Transaction>>> {
21616        Task::ready(Ok(None))
21617    }
21618
21619    fn is_completion_trigger(
21620        &self,
21621        buffer: &Entity<Buffer>,
21622        position: language::Anchor,
21623        text: &str,
21624        trigger_in_words: bool,
21625        menu_is_open: bool,
21626        cx: &mut Context<Editor>,
21627    ) -> bool;
21628
21629    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21630
21631    fn sort_completions(&self) -> bool {
21632        true
21633    }
21634
21635    fn filter_completions(&self) -> bool {
21636        true
21637    }
21638}
21639
21640pub trait CodeActionProvider {
21641    fn id(&self) -> Arc<str>;
21642
21643    fn code_actions(
21644        &self,
21645        buffer: &Entity<Buffer>,
21646        range: Range<text::Anchor>,
21647        window: &mut Window,
21648        cx: &mut App,
21649    ) -> Task<Result<Vec<CodeAction>>>;
21650
21651    fn apply_code_action(
21652        &self,
21653        buffer_handle: Entity<Buffer>,
21654        action: CodeAction,
21655        excerpt_id: ExcerptId,
21656        push_to_history: bool,
21657        window: &mut Window,
21658        cx: &mut App,
21659    ) -> Task<Result<ProjectTransaction>>;
21660}
21661
21662impl CodeActionProvider for Entity<Project> {
21663    fn id(&self) -> Arc<str> {
21664        "project".into()
21665    }
21666
21667    fn code_actions(
21668        &self,
21669        buffer: &Entity<Buffer>,
21670        range: Range<text::Anchor>,
21671        _window: &mut Window,
21672        cx: &mut App,
21673    ) -> Task<Result<Vec<CodeAction>>> {
21674        self.update(cx, |project, cx| {
21675            let code_lens = project.code_lens(buffer, range.clone(), cx);
21676            let code_actions = project.code_actions(buffer, range, None, cx);
21677            cx.background_spawn(async move {
21678                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21679                Ok(code_lens
21680                    .context("code lens fetch")?
21681                    .into_iter()
21682                    .chain(code_actions.context("code action fetch")?)
21683                    .collect())
21684            })
21685        })
21686    }
21687
21688    fn apply_code_action(
21689        &self,
21690        buffer_handle: Entity<Buffer>,
21691        action: CodeAction,
21692        _excerpt_id: ExcerptId,
21693        push_to_history: bool,
21694        _window: &mut Window,
21695        cx: &mut App,
21696    ) -> Task<Result<ProjectTransaction>> {
21697        self.update(cx, |project, cx| {
21698            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21699        })
21700    }
21701}
21702
21703fn snippet_completions(
21704    project: &Project,
21705    buffer: &Entity<Buffer>,
21706    buffer_position: text::Anchor,
21707    cx: &mut App,
21708) -> Task<Result<CompletionResponse>> {
21709    let languages = buffer.read(cx).languages_at(buffer_position);
21710    let snippet_store = project.snippets().read(cx);
21711
21712    let scopes: Vec<_> = languages
21713        .iter()
21714        .filter_map(|language| {
21715            let language_name = language.lsp_id();
21716            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21717
21718            if snippets.is_empty() {
21719                None
21720            } else {
21721                Some((language.default_scope(), snippets))
21722            }
21723        })
21724        .collect();
21725
21726    if scopes.is_empty() {
21727        return Task::ready(Ok(CompletionResponse {
21728            completions: vec![],
21729            is_incomplete: false,
21730        }));
21731    }
21732
21733    let snapshot = buffer.read(cx).text_snapshot();
21734    let chars: String = snapshot
21735        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21736        .collect();
21737    let executor = cx.background_executor().clone();
21738
21739    cx.background_spawn(async move {
21740        let mut is_incomplete = false;
21741        let mut completions: Vec<Completion> = Vec::new();
21742        for (scope, snippets) in scopes.into_iter() {
21743            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21744            let mut last_word = chars
21745                .chars()
21746                .take_while(|c| classifier.is_word(*c))
21747                .collect::<String>();
21748            last_word = last_word.chars().rev().collect();
21749
21750            if last_word.is_empty() {
21751                return Ok(CompletionResponse {
21752                    completions: vec![],
21753                    is_incomplete: true,
21754                });
21755            }
21756
21757            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21758            let to_lsp = |point: &text::Anchor| {
21759                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21760                point_to_lsp(end)
21761            };
21762            let lsp_end = to_lsp(&buffer_position);
21763
21764            let candidates = snippets
21765                .iter()
21766                .enumerate()
21767                .flat_map(|(ix, snippet)| {
21768                    snippet
21769                        .prefix
21770                        .iter()
21771                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21772                })
21773                .collect::<Vec<StringMatchCandidate>>();
21774
21775            const MAX_RESULTS: usize = 100;
21776            let mut matches = fuzzy::match_strings(
21777                &candidates,
21778                &last_word,
21779                last_word.chars().any(|c| c.is_uppercase()),
21780                true,
21781                MAX_RESULTS,
21782                &Default::default(),
21783                executor.clone(),
21784            )
21785            .await;
21786
21787            if matches.len() >= MAX_RESULTS {
21788                is_incomplete = true;
21789            }
21790
21791            // Remove all candidates where the query's start does not match the start of any word in the candidate
21792            if let Some(query_start) = last_word.chars().next() {
21793                matches.retain(|string_match| {
21794                    split_words(&string_match.string).any(|word| {
21795                        // Check that the first codepoint of the word as lowercase matches the first
21796                        // codepoint of the query as lowercase
21797                        word.chars()
21798                            .flat_map(|codepoint| codepoint.to_lowercase())
21799                            .zip(query_start.to_lowercase())
21800                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21801                    })
21802                });
21803            }
21804
21805            let matched_strings = matches
21806                .into_iter()
21807                .map(|m| m.string)
21808                .collect::<HashSet<_>>();
21809
21810            completions.extend(snippets.iter().filter_map(|snippet| {
21811                let matching_prefix = snippet
21812                    .prefix
21813                    .iter()
21814                    .find(|prefix| matched_strings.contains(*prefix))?;
21815                let start = as_offset - last_word.len();
21816                let start = snapshot.anchor_before(start);
21817                let range = start..buffer_position;
21818                let lsp_start = to_lsp(&start);
21819                let lsp_range = lsp::Range {
21820                    start: lsp_start,
21821                    end: lsp_end,
21822                };
21823                Some(Completion {
21824                    replace_range: range,
21825                    new_text: snippet.body.clone(),
21826                    source: CompletionSource::Lsp {
21827                        insert_range: None,
21828                        server_id: LanguageServerId(usize::MAX),
21829                        resolved: true,
21830                        lsp_completion: Box::new(lsp::CompletionItem {
21831                            label: snippet.prefix.first().unwrap().clone(),
21832                            kind: Some(CompletionItemKind::SNIPPET),
21833                            label_details: snippet.description.as_ref().map(|description| {
21834                                lsp::CompletionItemLabelDetails {
21835                                    detail: Some(description.clone()),
21836                                    description: None,
21837                                }
21838                            }),
21839                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21840                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21841                                lsp::InsertReplaceEdit {
21842                                    new_text: snippet.body.clone(),
21843                                    insert: lsp_range,
21844                                    replace: lsp_range,
21845                                },
21846                            )),
21847                            filter_text: Some(snippet.body.clone()),
21848                            sort_text: Some(char::MAX.to_string()),
21849                            ..lsp::CompletionItem::default()
21850                        }),
21851                        lsp_defaults: None,
21852                    },
21853                    label: CodeLabel {
21854                        text: matching_prefix.clone(),
21855                        runs: Vec::new(),
21856                        filter_range: 0..matching_prefix.len(),
21857                    },
21858                    icon_path: None,
21859                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21860                        single_line: snippet.name.clone().into(),
21861                        plain_text: snippet
21862                            .description
21863                            .clone()
21864                            .map(|description| description.into()),
21865                    }),
21866                    insert_text_mode: None,
21867                    confirm: None,
21868                })
21869            }))
21870        }
21871
21872        Ok(CompletionResponse {
21873            completions,
21874            is_incomplete,
21875        })
21876    })
21877}
21878
21879impl CompletionProvider for Entity<Project> {
21880    fn completions(
21881        &self,
21882        _excerpt_id: ExcerptId,
21883        buffer: &Entity<Buffer>,
21884        buffer_position: text::Anchor,
21885        options: CompletionContext,
21886        _window: &mut Window,
21887        cx: &mut Context<Editor>,
21888    ) -> Task<Result<Vec<CompletionResponse>>> {
21889        self.update(cx, |project, cx| {
21890            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21891            let project_completions = project.completions(buffer, buffer_position, options, cx);
21892            cx.background_spawn(async move {
21893                let mut responses = project_completions.await?;
21894                let snippets = snippets.await?;
21895                if !snippets.completions.is_empty() {
21896                    responses.push(snippets);
21897                }
21898                Ok(responses)
21899            })
21900        })
21901    }
21902
21903    fn resolve_completions(
21904        &self,
21905        buffer: Entity<Buffer>,
21906        completion_indices: Vec<usize>,
21907        completions: Rc<RefCell<Box<[Completion]>>>,
21908        cx: &mut Context<Editor>,
21909    ) -> Task<Result<bool>> {
21910        self.update(cx, |project, cx| {
21911            project.lsp_store().update(cx, |lsp_store, cx| {
21912                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21913            })
21914        })
21915    }
21916
21917    fn apply_additional_edits_for_completion(
21918        &self,
21919        buffer: Entity<Buffer>,
21920        completions: Rc<RefCell<Box<[Completion]>>>,
21921        completion_index: usize,
21922        push_to_history: bool,
21923        cx: &mut Context<Editor>,
21924    ) -> Task<Result<Option<language::Transaction>>> {
21925        self.update(cx, |project, cx| {
21926            project.lsp_store().update(cx, |lsp_store, cx| {
21927                lsp_store.apply_additional_edits_for_completion(
21928                    buffer,
21929                    completions,
21930                    completion_index,
21931                    push_to_history,
21932                    cx,
21933                )
21934            })
21935        })
21936    }
21937
21938    fn is_completion_trigger(
21939        &self,
21940        buffer: &Entity<Buffer>,
21941        position: language::Anchor,
21942        text: &str,
21943        trigger_in_words: bool,
21944        menu_is_open: bool,
21945        cx: &mut Context<Editor>,
21946    ) -> bool {
21947        let mut chars = text.chars();
21948        let char = if let Some(char) = chars.next() {
21949            char
21950        } else {
21951            return false;
21952        };
21953        if chars.next().is_some() {
21954            return false;
21955        }
21956
21957        let buffer = buffer.read(cx);
21958        let snapshot = buffer.snapshot();
21959        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21960            return false;
21961        }
21962        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21963        if trigger_in_words && classifier.is_word(char) {
21964            return true;
21965        }
21966
21967        buffer.completion_triggers().contains(text)
21968    }
21969}
21970
21971impl SemanticsProvider for Entity<Project> {
21972    fn hover(
21973        &self,
21974        buffer: &Entity<Buffer>,
21975        position: text::Anchor,
21976        cx: &mut App,
21977    ) -> Option<Task<Vec<project::Hover>>> {
21978        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21979    }
21980
21981    fn document_highlights(
21982        &self,
21983        buffer: &Entity<Buffer>,
21984        position: text::Anchor,
21985        cx: &mut App,
21986    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21987        Some(self.update(cx, |project, cx| {
21988            project.document_highlights(buffer, position, cx)
21989        }))
21990    }
21991
21992    fn definitions(
21993        &self,
21994        buffer: &Entity<Buffer>,
21995        position: text::Anchor,
21996        kind: GotoDefinitionKind,
21997        cx: &mut App,
21998    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21999        Some(self.update(cx, |project, cx| match kind {
22000            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22001            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22002            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22003            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22004        }))
22005    }
22006
22007    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22008        // TODO: make this work for remote projects
22009        self.update(cx, |project, cx| {
22010            if project
22011                .active_debug_session(cx)
22012                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22013            {
22014                return true;
22015            }
22016
22017            buffer.update(cx, |buffer, cx| {
22018                project.any_language_server_supports_inlay_hints(buffer, cx)
22019            })
22020        })
22021    }
22022
22023    fn inline_values(
22024        &self,
22025        buffer_handle: Entity<Buffer>,
22026        range: Range<text::Anchor>,
22027        cx: &mut App,
22028    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22029        self.update(cx, |project, cx| {
22030            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22031
22032            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22033        })
22034    }
22035
22036    fn inlay_hints(
22037        &self,
22038        buffer_handle: Entity<Buffer>,
22039        range: Range<text::Anchor>,
22040        cx: &mut App,
22041    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22042        Some(self.update(cx, |project, cx| {
22043            project.inlay_hints(buffer_handle, range, cx)
22044        }))
22045    }
22046
22047    fn resolve_inlay_hint(
22048        &self,
22049        hint: InlayHint,
22050        buffer_handle: Entity<Buffer>,
22051        server_id: LanguageServerId,
22052        cx: &mut App,
22053    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22054        Some(self.update(cx, |project, cx| {
22055            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22056        }))
22057    }
22058
22059    fn range_for_rename(
22060        &self,
22061        buffer: &Entity<Buffer>,
22062        position: text::Anchor,
22063        cx: &mut App,
22064    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22065        Some(self.update(cx, |project, cx| {
22066            let buffer = buffer.clone();
22067            let task = project.prepare_rename(buffer.clone(), position, cx);
22068            cx.spawn(async move |_, cx| {
22069                Ok(match task.await? {
22070                    PrepareRenameResponse::Success(range) => Some(range),
22071                    PrepareRenameResponse::InvalidPosition => None,
22072                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22073                        // Fallback on using TreeSitter info to determine identifier range
22074                        buffer.read_with(cx, |buffer, _| {
22075                            let snapshot = buffer.snapshot();
22076                            let (range, kind) = snapshot.surrounding_word(position);
22077                            if kind != Some(CharKind::Word) {
22078                                return None;
22079                            }
22080                            Some(
22081                                snapshot.anchor_before(range.start)
22082                                    ..snapshot.anchor_after(range.end),
22083                            )
22084                        })?
22085                    }
22086                })
22087            })
22088        }))
22089    }
22090
22091    fn perform_rename(
22092        &self,
22093        buffer: &Entity<Buffer>,
22094        position: text::Anchor,
22095        new_name: String,
22096        cx: &mut App,
22097    ) -> Option<Task<Result<ProjectTransaction>>> {
22098        Some(self.update(cx, |project, cx| {
22099            project.perform_rename(buffer.clone(), position, new_name, cx)
22100        }))
22101    }
22102}
22103
22104fn inlay_hint_settings(
22105    location: Anchor,
22106    snapshot: &MultiBufferSnapshot,
22107    cx: &mut Context<Editor>,
22108) -> InlayHintSettings {
22109    let file = snapshot.file_at(location);
22110    let language = snapshot.language_at(location).map(|l| l.name());
22111    language_settings(language, file, cx).inlay_hints
22112}
22113
22114fn consume_contiguous_rows(
22115    contiguous_row_selections: &mut Vec<Selection<Point>>,
22116    selection: &Selection<Point>,
22117    display_map: &DisplaySnapshot,
22118    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22119) -> (MultiBufferRow, MultiBufferRow) {
22120    contiguous_row_selections.push(selection.clone());
22121    let start_row = MultiBufferRow(selection.start.row);
22122    let mut end_row = ending_row(selection, display_map);
22123
22124    while let Some(next_selection) = selections.peek() {
22125        if next_selection.start.row <= end_row.0 {
22126            end_row = ending_row(next_selection, display_map);
22127            contiguous_row_selections.push(selections.next().unwrap().clone());
22128        } else {
22129            break;
22130        }
22131    }
22132    (start_row, end_row)
22133}
22134
22135fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22136    if next_selection.end.column > 0 || next_selection.is_empty() {
22137        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22138    } else {
22139        MultiBufferRow(next_selection.end.row)
22140    }
22141}
22142
22143impl EditorSnapshot {
22144    pub fn remote_selections_in_range<'a>(
22145        &'a self,
22146        range: &'a Range<Anchor>,
22147        collaboration_hub: &dyn CollaborationHub,
22148        cx: &'a App,
22149    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22150        let participant_names = collaboration_hub.user_names(cx);
22151        let participant_indices = collaboration_hub.user_participant_indices(cx);
22152        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22153        let collaborators_by_replica_id = collaborators_by_peer_id
22154            .values()
22155            .map(|collaborator| (collaborator.replica_id, collaborator))
22156            .collect::<HashMap<_, _>>();
22157        self.buffer_snapshot
22158            .selections_in_range(range, false)
22159            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22160                if replica_id == AGENT_REPLICA_ID {
22161                    Some(RemoteSelection {
22162                        replica_id,
22163                        selection,
22164                        cursor_shape,
22165                        line_mode,
22166                        collaborator_id: CollaboratorId::Agent,
22167                        user_name: Some("Agent".into()),
22168                        color: cx.theme().players().agent(),
22169                    })
22170                } else {
22171                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22172                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22173                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22174                    Some(RemoteSelection {
22175                        replica_id,
22176                        selection,
22177                        cursor_shape,
22178                        line_mode,
22179                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22180                        user_name,
22181                        color: if let Some(index) = participant_index {
22182                            cx.theme().players().color_for_participant(index.0)
22183                        } else {
22184                            cx.theme().players().absent()
22185                        },
22186                    })
22187                }
22188            })
22189    }
22190
22191    pub fn hunks_for_ranges(
22192        &self,
22193        ranges: impl IntoIterator<Item = Range<Point>>,
22194    ) -> Vec<MultiBufferDiffHunk> {
22195        let mut hunks = Vec::new();
22196        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22197            HashMap::default();
22198        for query_range in ranges {
22199            let query_rows =
22200                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22201            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22202                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22203            ) {
22204                // Include deleted hunks that are adjacent to the query range, because
22205                // otherwise they would be missed.
22206                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22207                if hunk.status().is_deleted() {
22208                    intersects_range |= hunk.row_range.start == query_rows.end;
22209                    intersects_range |= hunk.row_range.end == query_rows.start;
22210                }
22211                if intersects_range {
22212                    if !processed_buffer_rows
22213                        .entry(hunk.buffer_id)
22214                        .or_default()
22215                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22216                    {
22217                        continue;
22218                    }
22219                    hunks.push(hunk);
22220                }
22221            }
22222        }
22223
22224        hunks
22225    }
22226
22227    fn display_diff_hunks_for_rows<'a>(
22228        &'a self,
22229        display_rows: Range<DisplayRow>,
22230        folded_buffers: &'a HashSet<BufferId>,
22231    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22232        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22233        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22234
22235        self.buffer_snapshot
22236            .diff_hunks_in_range(buffer_start..buffer_end)
22237            .filter_map(|hunk| {
22238                if folded_buffers.contains(&hunk.buffer_id) {
22239                    return None;
22240                }
22241
22242                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22243                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22244
22245                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22246                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22247
22248                let display_hunk = if hunk_display_start.column() != 0 {
22249                    DisplayDiffHunk::Folded {
22250                        display_row: hunk_display_start.row(),
22251                    }
22252                } else {
22253                    let mut end_row = hunk_display_end.row();
22254                    if hunk_display_end.column() > 0 {
22255                        end_row.0 += 1;
22256                    }
22257                    let is_created_file = hunk.is_created_file();
22258                    DisplayDiffHunk::Unfolded {
22259                        status: hunk.status(),
22260                        diff_base_byte_range: hunk.diff_base_byte_range,
22261                        display_row_range: hunk_display_start.row()..end_row,
22262                        multi_buffer_range: Anchor::range_in_buffer(
22263                            hunk.excerpt_id,
22264                            hunk.buffer_id,
22265                            hunk.buffer_range,
22266                        ),
22267                        is_created_file,
22268                    }
22269                };
22270
22271                Some(display_hunk)
22272            })
22273    }
22274
22275    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22276        self.display_snapshot.buffer_snapshot.language_at(position)
22277    }
22278
22279    pub fn is_focused(&self) -> bool {
22280        self.is_focused
22281    }
22282
22283    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22284        self.placeholder_text.as_ref()
22285    }
22286
22287    pub fn scroll_position(&self) -> gpui::Point<f32> {
22288        self.scroll_anchor.scroll_position(&self.display_snapshot)
22289    }
22290
22291    fn gutter_dimensions(
22292        &self,
22293        font_id: FontId,
22294        font_size: Pixels,
22295        max_line_number_width: Pixels,
22296        cx: &App,
22297    ) -> Option<GutterDimensions> {
22298        if !self.show_gutter {
22299            return None;
22300        }
22301
22302        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22303        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22304
22305        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22306            matches!(
22307                ProjectSettings::get_global(cx).git.git_gutter,
22308                Some(GitGutterSetting::TrackedFiles)
22309            )
22310        });
22311        let gutter_settings = EditorSettings::get_global(cx).gutter;
22312        let show_line_numbers = self
22313            .show_line_numbers
22314            .unwrap_or(gutter_settings.line_numbers);
22315        let line_gutter_width = if show_line_numbers {
22316            // Avoid flicker-like gutter resizes when the line number gains another digit by
22317            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22318            let min_width_for_number_on_gutter =
22319                ch_advance * gutter_settings.min_line_number_digits as f32;
22320            max_line_number_width.max(min_width_for_number_on_gutter)
22321        } else {
22322            0.0.into()
22323        };
22324
22325        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22326        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22327
22328        let git_blame_entries_width =
22329            self.git_blame_gutter_max_author_length
22330                .map(|max_author_length| {
22331                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22332                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22333
22334                    /// The number of characters to dedicate to gaps and margins.
22335                    const SPACING_WIDTH: usize = 4;
22336
22337                    let max_char_count = max_author_length.min(renderer.max_author_length())
22338                        + ::git::SHORT_SHA_LENGTH
22339                        + MAX_RELATIVE_TIMESTAMP.len()
22340                        + SPACING_WIDTH;
22341
22342                    ch_advance * max_char_count
22343                });
22344
22345        let is_singleton = self.buffer_snapshot.is_singleton();
22346
22347        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22348        left_padding += if !is_singleton {
22349            ch_width * 4.0
22350        } else if show_runnables || show_breakpoints {
22351            ch_width * 3.0
22352        } else if show_git_gutter && show_line_numbers {
22353            ch_width * 2.0
22354        } else if show_git_gutter || show_line_numbers {
22355            ch_width
22356        } else {
22357            px(0.)
22358        };
22359
22360        let shows_folds = is_singleton && gutter_settings.folds;
22361
22362        let right_padding = if shows_folds && show_line_numbers {
22363            ch_width * 4.0
22364        } else if shows_folds || (!is_singleton && show_line_numbers) {
22365            ch_width * 3.0
22366        } else if show_line_numbers {
22367            ch_width
22368        } else {
22369            px(0.)
22370        };
22371
22372        Some(GutterDimensions {
22373            left_padding,
22374            right_padding,
22375            width: line_gutter_width + left_padding + right_padding,
22376            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22377            git_blame_entries_width,
22378        })
22379    }
22380
22381    pub fn render_crease_toggle(
22382        &self,
22383        buffer_row: MultiBufferRow,
22384        row_contains_cursor: bool,
22385        editor: Entity<Editor>,
22386        window: &mut Window,
22387        cx: &mut App,
22388    ) -> Option<AnyElement> {
22389        let folded = self.is_line_folded(buffer_row);
22390        let mut is_foldable = false;
22391
22392        if let Some(crease) = self
22393            .crease_snapshot
22394            .query_row(buffer_row, &self.buffer_snapshot)
22395        {
22396            is_foldable = true;
22397            match crease {
22398                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22399                    if let Some(render_toggle) = render_toggle {
22400                        let toggle_callback =
22401                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22402                                if folded {
22403                                    editor.update(cx, |editor, cx| {
22404                                        editor.fold_at(buffer_row, window, cx)
22405                                    });
22406                                } else {
22407                                    editor.update(cx, |editor, cx| {
22408                                        editor.unfold_at(buffer_row, window, cx)
22409                                    });
22410                                }
22411                            });
22412                        return Some((render_toggle)(
22413                            buffer_row,
22414                            folded,
22415                            toggle_callback,
22416                            window,
22417                            cx,
22418                        ));
22419                    }
22420                }
22421            }
22422        }
22423
22424        is_foldable |= self.starts_indent(buffer_row);
22425
22426        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22427            Some(
22428                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22429                    .toggle_state(folded)
22430                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22431                        if folded {
22432                            this.unfold_at(buffer_row, window, cx);
22433                        } else {
22434                            this.fold_at(buffer_row, window, cx);
22435                        }
22436                    }))
22437                    .into_any_element(),
22438            )
22439        } else {
22440            None
22441        }
22442    }
22443
22444    pub fn render_crease_trailer(
22445        &self,
22446        buffer_row: MultiBufferRow,
22447        window: &mut Window,
22448        cx: &mut App,
22449    ) -> Option<AnyElement> {
22450        let folded = self.is_line_folded(buffer_row);
22451        if let Crease::Inline { render_trailer, .. } = self
22452            .crease_snapshot
22453            .query_row(buffer_row, &self.buffer_snapshot)?
22454        {
22455            let render_trailer = render_trailer.as_ref()?;
22456            Some(render_trailer(buffer_row, folded, window, cx))
22457        } else {
22458            None
22459        }
22460    }
22461}
22462
22463impl Deref for EditorSnapshot {
22464    type Target = DisplaySnapshot;
22465
22466    fn deref(&self) -> &Self::Target {
22467        &self.display_snapshot
22468    }
22469}
22470
22471#[derive(Clone, Debug, PartialEq, Eq)]
22472pub enum EditorEvent {
22473    InputIgnored {
22474        text: Arc<str>,
22475    },
22476    InputHandled {
22477        utf16_range_to_replace: Option<Range<isize>>,
22478        text: Arc<str>,
22479    },
22480    ExcerptsAdded {
22481        buffer: Entity<Buffer>,
22482        predecessor: ExcerptId,
22483        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22484    },
22485    ExcerptsRemoved {
22486        ids: Vec<ExcerptId>,
22487        removed_buffer_ids: Vec<BufferId>,
22488    },
22489    BufferFoldToggled {
22490        ids: Vec<ExcerptId>,
22491        folded: bool,
22492    },
22493    ExcerptsEdited {
22494        ids: Vec<ExcerptId>,
22495    },
22496    ExcerptsExpanded {
22497        ids: Vec<ExcerptId>,
22498    },
22499    BufferEdited,
22500    Edited {
22501        transaction_id: clock::Lamport,
22502    },
22503    Reparsed(BufferId),
22504    Focused,
22505    FocusedIn,
22506    Blurred,
22507    DirtyChanged,
22508    Saved,
22509    TitleChanged,
22510    DiffBaseChanged,
22511    SelectionsChanged {
22512        local: bool,
22513    },
22514    ScrollPositionChanged {
22515        local: bool,
22516        autoscroll: bool,
22517    },
22518    Closed,
22519    TransactionUndone {
22520        transaction_id: clock::Lamport,
22521    },
22522    TransactionBegun {
22523        transaction_id: clock::Lamport,
22524    },
22525    Reloaded,
22526    CursorShapeChanged,
22527    PushedToNavHistory {
22528        anchor: Anchor,
22529        is_deactivate: bool,
22530    },
22531}
22532
22533impl EventEmitter<EditorEvent> for Editor {}
22534
22535impl Focusable for Editor {
22536    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22537        self.focus_handle.clone()
22538    }
22539}
22540
22541impl Render for Editor {
22542    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22543        let settings = ThemeSettings::get_global(cx);
22544
22545        let mut text_style = match self.mode {
22546            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22547                color: cx.theme().colors().editor_foreground,
22548                font_family: settings.ui_font.family.clone(),
22549                font_features: settings.ui_font.features.clone(),
22550                font_fallbacks: settings.ui_font.fallbacks.clone(),
22551                font_size: rems(0.875).into(),
22552                font_weight: settings.ui_font.weight,
22553                line_height: relative(settings.buffer_line_height.value()),
22554                ..Default::default()
22555            },
22556            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22557                color: cx.theme().colors().editor_foreground,
22558                font_family: settings.buffer_font.family.clone(),
22559                font_features: settings.buffer_font.features.clone(),
22560                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22561                font_size: settings.buffer_font_size(cx).into(),
22562                font_weight: settings.buffer_font.weight,
22563                line_height: relative(settings.buffer_line_height.value()),
22564                ..Default::default()
22565            },
22566        };
22567        if let Some(text_style_refinement) = &self.text_style_refinement {
22568            text_style.refine(text_style_refinement)
22569        }
22570
22571        let background = match self.mode {
22572            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22573            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22574            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22575            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22576        };
22577
22578        EditorElement::new(
22579            &cx.entity(),
22580            EditorStyle {
22581                background,
22582                border: cx.theme().colors().border,
22583                local_player: cx.theme().players().local(),
22584                text: text_style,
22585                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22586                syntax: cx.theme().syntax().clone(),
22587                status: cx.theme().status().clone(),
22588                inlay_hints_style: make_inlay_hints_style(cx),
22589                inline_completion_styles: make_suggestion_styles(cx),
22590                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22591                show_underlines: self.diagnostics_enabled(),
22592            },
22593        )
22594    }
22595}
22596
22597impl EntityInputHandler for Editor {
22598    fn text_for_range(
22599        &mut self,
22600        range_utf16: Range<usize>,
22601        adjusted_range: &mut Option<Range<usize>>,
22602        _: &mut Window,
22603        cx: &mut Context<Self>,
22604    ) -> Option<String> {
22605        let snapshot = self.buffer.read(cx).read(cx);
22606        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22607        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22608        if (start.0..end.0) != range_utf16 {
22609            adjusted_range.replace(start.0..end.0);
22610        }
22611        Some(snapshot.text_for_range(start..end).collect())
22612    }
22613
22614    fn selected_text_range(
22615        &mut self,
22616        ignore_disabled_input: bool,
22617        _: &mut Window,
22618        cx: &mut Context<Self>,
22619    ) -> Option<UTF16Selection> {
22620        // Prevent the IME menu from appearing when holding down an alphabetic key
22621        // while input is disabled.
22622        if !ignore_disabled_input && !self.input_enabled {
22623            return None;
22624        }
22625
22626        let selection = self.selections.newest::<OffsetUtf16>(cx);
22627        let range = selection.range();
22628
22629        Some(UTF16Selection {
22630            range: range.start.0..range.end.0,
22631            reversed: selection.reversed,
22632        })
22633    }
22634
22635    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22636        let snapshot = self.buffer.read(cx).read(cx);
22637        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22638        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22639    }
22640
22641    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22642        self.clear_highlights::<InputComposition>(cx);
22643        self.ime_transaction.take();
22644    }
22645
22646    fn replace_text_in_range(
22647        &mut self,
22648        range_utf16: Option<Range<usize>>,
22649        text: &str,
22650        window: &mut Window,
22651        cx: &mut Context<Self>,
22652    ) {
22653        if !self.input_enabled {
22654            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22655            return;
22656        }
22657
22658        self.transact(window, cx, |this, window, cx| {
22659            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22660                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22661                Some(this.selection_replacement_ranges(range_utf16, cx))
22662            } else {
22663                this.marked_text_ranges(cx)
22664            };
22665
22666            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22667                let newest_selection_id = this.selections.newest_anchor().id;
22668                this.selections
22669                    .all::<OffsetUtf16>(cx)
22670                    .iter()
22671                    .zip(ranges_to_replace.iter())
22672                    .find_map(|(selection, range)| {
22673                        if selection.id == newest_selection_id {
22674                            Some(
22675                                (range.start.0 as isize - selection.head().0 as isize)
22676                                    ..(range.end.0 as isize - selection.head().0 as isize),
22677                            )
22678                        } else {
22679                            None
22680                        }
22681                    })
22682            });
22683
22684            cx.emit(EditorEvent::InputHandled {
22685                utf16_range_to_replace: range_to_replace,
22686                text: text.into(),
22687            });
22688
22689            if let Some(new_selected_ranges) = new_selected_ranges {
22690                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22691                    selections.select_ranges(new_selected_ranges)
22692                });
22693                this.backspace(&Default::default(), window, cx);
22694            }
22695
22696            this.handle_input(text, window, cx);
22697        });
22698
22699        if let Some(transaction) = self.ime_transaction {
22700            self.buffer.update(cx, |buffer, cx| {
22701                buffer.group_until_transaction(transaction, cx);
22702            });
22703        }
22704
22705        self.unmark_text(window, cx);
22706    }
22707
22708    fn replace_and_mark_text_in_range(
22709        &mut self,
22710        range_utf16: Option<Range<usize>>,
22711        text: &str,
22712        new_selected_range_utf16: Option<Range<usize>>,
22713        window: &mut Window,
22714        cx: &mut Context<Self>,
22715    ) {
22716        if !self.input_enabled {
22717            return;
22718        }
22719
22720        let transaction = self.transact(window, cx, |this, window, cx| {
22721            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22722                let snapshot = this.buffer.read(cx).read(cx);
22723                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22724                    for marked_range in &mut marked_ranges {
22725                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22726                        marked_range.start.0 += relative_range_utf16.start;
22727                        marked_range.start =
22728                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22729                        marked_range.end =
22730                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22731                    }
22732                }
22733                Some(marked_ranges)
22734            } else if let Some(range_utf16) = range_utf16 {
22735                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22736                Some(this.selection_replacement_ranges(range_utf16, cx))
22737            } else {
22738                None
22739            };
22740
22741            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22742                let newest_selection_id = this.selections.newest_anchor().id;
22743                this.selections
22744                    .all::<OffsetUtf16>(cx)
22745                    .iter()
22746                    .zip(ranges_to_replace.iter())
22747                    .find_map(|(selection, range)| {
22748                        if selection.id == newest_selection_id {
22749                            Some(
22750                                (range.start.0 as isize - selection.head().0 as isize)
22751                                    ..(range.end.0 as isize - selection.head().0 as isize),
22752                            )
22753                        } else {
22754                            None
22755                        }
22756                    })
22757            });
22758
22759            cx.emit(EditorEvent::InputHandled {
22760                utf16_range_to_replace: range_to_replace,
22761                text: text.into(),
22762            });
22763
22764            if let Some(ranges) = ranges_to_replace {
22765                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22766                    s.select_ranges(ranges)
22767                });
22768            }
22769
22770            let marked_ranges = {
22771                let snapshot = this.buffer.read(cx).read(cx);
22772                this.selections
22773                    .disjoint_anchors()
22774                    .iter()
22775                    .map(|selection| {
22776                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22777                    })
22778                    .collect::<Vec<_>>()
22779            };
22780
22781            if text.is_empty() {
22782                this.unmark_text(window, cx);
22783            } else {
22784                this.highlight_text::<InputComposition>(
22785                    marked_ranges.clone(),
22786                    HighlightStyle {
22787                        underline: Some(UnderlineStyle {
22788                            thickness: px(1.),
22789                            color: None,
22790                            wavy: false,
22791                        }),
22792                        ..Default::default()
22793                    },
22794                    cx,
22795                );
22796            }
22797
22798            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22799            let use_autoclose = this.use_autoclose;
22800            let use_auto_surround = this.use_auto_surround;
22801            this.set_use_autoclose(false);
22802            this.set_use_auto_surround(false);
22803            this.handle_input(text, window, cx);
22804            this.set_use_autoclose(use_autoclose);
22805            this.set_use_auto_surround(use_auto_surround);
22806
22807            if let Some(new_selected_range) = new_selected_range_utf16 {
22808                let snapshot = this.buffer.read(cx).read(cx);
22809                let new_selected_ranges = marked_ranges
22810                    .into_iter()
22811                    .map(|marked_range| {
22812                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22813                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22814                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22815                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22816                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22817                    })
22818                    .collect::<Vec<_>>();
22819
22820                drop(snapshot);
22821                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22822                    selections.select_ranges(new_selected_ranges)
22823                });
22824            }
22825        });
22826
22827        self.ime_transaction = self.ime_transaction.or(transaction);
22828        if let Some(transaction) = self.ime_transaction {
22829            self.buffer.update(cx, |buffer, cx| {
22830                buffer.group_until_transaction(transaction, cx);
22831            });
22832        }
22833
22834        if self.text_highlights::<InputComposition>(cx).is_none() {
22835            self.ime_transaction.take();
22836        }
22837    }
22838
22839    fn bounds_for_range(
22840        &mut self,
22841        range_utf16: Range<usize>,
22842        element_bounds: gpui::Bounds<Pixels>,
22843        window: &mut Window,
22844        cx: &mut Context<Self>,
22845    ) -> Option<gpui::Bounds<Pixels>> {
22846        let text_layout_details = self.text_layout_details(window);
22847        let CharacterDimensions {
22848            em_width,
22849            em_advance,
22850            line_height,
22851        } = self.character_dimensions(window);
22852
22853        let snapshot = self.snapshot(window, cx);
22854        let scroll_position = snapshot.scroll_position();
22855        let scroll_left = scroll_position.x * em_advance;
22856
22857        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22858        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22859            + self.gutter_dimensions.full_width();
22860        let y = line_height * (start.row().as_f32() - scroll_position.y);
22861
22862        Some(Bounds {
22863            origin: element_bounds.origin + point(x, y),
22864            size: size(em_width, line_height),
22865        })
22866    }
22867
22868    fn character_index_for_point(
22869        &mut self,
22870        point: gpui::Point<Pixels>,
22871        _window: &mut Window,
22872        _cx: &mut Context<Self>,
22873    ) -> Option<usize> {
22874        let position_map = self.last_position_map.as_ref()?;
22875        if !position_map.text_hitbox.contains(&point) {
22876            return None;
22877        }
22878        let display_point = position_map.point_for_position(point).previous_valid;
22879        let anchor = position_map
22880            .snapshot
22881            .display_point_to_anchor(display_point, Bias::Left);
22882        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22883        Some(utf16_offset.0)
22884    }
22885}
22886
22887trait SelectionExt {
22888    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22889    fn spanned_rows(
22890        &self,
22891        include_end_if_at_line_start: bool,
22892        map: &DisplaySnapshot,
22893    ) -> Range<MultiBufferRow>;
22894}
22895
22896impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22897    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22898        let start = self
22899            .start
22900            .to_point(&map.buffer_snapshot)
22901            .to_display_point(map);
22902        let end = self
22903            .end
22904            .to_point(&map.buffer_snapshot)
22905            .to_display_point(map);
22906        if self.reversed {
22907            end..start
22908        } else {
22909            start..end
22910        }
22911    }
22912
22913    fn spanned_rows(
22914        &self,
22915        include_end_if_at_line_start: bool,
22916        map: &DisplaySnapshot,
22917    ) -> Range<MultiBufferRow> {
22918        let start = self.start.to_point(&map.buffer_snapshot);
22919        let mut end = self.end.to_point(&map.buffer_snapshot);
22920        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22921            end.row -= 1;
22922        }
22923
22924        let buffer_start = map.prev_line_boundary(start).0;
22925        let buffer_end = map.next_line_boundary(end).0;
22926        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22927    }
22928}
22929
22930impl<T: InvalidationRegion> InvalidationStack<T> {
22931    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22932    where
22933        S: Clone + ToOffset,
22934    {
22935        while let Some(region) = self.last() {
22936            let all_selections_inside_invalidation_ranges =
22937                if selections.len() == region.ranges().len() {
22938                    selections
22939                        .iter()
22940                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22941                        .all(|(selection, invalidation_range)| {
22942                            let head = selection.head().to_offset(buffer);
22943                            invalidation_range.start <= head && invalidation_range.end >= head
22944                        })
22945                } else {
22946                    false
22947                };
22948
22949            if all_selections_inside_invalidation_ranges {
22950                break;
22951            } else {
22952                self.pop();
22953            }
22954        }
22955    }
22956}
22957
22958impl<T> Default for InvalidationStack<T> {
22959    fn default() -> Self {
22960        Self(Default::default())
22961    }
22962}
22963
22964impl<T> Deref for InvalidationStack<T> {
22965    type Target = Vec<T>;
22966
22967    fn deref(&self) -> &Self::Target {
22968        &self.0
22969    }
22970}
22971
22972impl<T> DerefMut for InvalidationStack<T> {
22973    fn deref_mut(&mut self) -> &mut Self::Target {
22974        &mut self.0
22975    }
22976}
22977
22978impl InvalidationRegion for SnippetState {
22979    fn ranges(&self) -> &[Range<Anchor>] {
22980        &self.ranges[self.active_index]
22981    }
22982}
22983
22984fn inline_completion_edit_text(
22985    current_snapshot: &BufferSnapshot,
22986    edits: &[(Range<Anchor>, String)],
22987    edit_preview: &EditPreview,
22988    include_deletions: bool,
22989    cx: &App,
22990) -> HighlightedText {
22991    let edits = edits
22992        .iter()
22993        .map(|(anchor, text)| {
22994            (
22995                anchor.start.text_anchor..anchor.end.text_anchor,
22996                text.clone(),
22997            )
22998        })
22999        .collect::<Vec<_>>();
23000
23001    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23002}
23003
23004pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23005    match severity {
23006        lsp::DiagnosticSeverity::ERROR => colors.error,
23007        lsp::DiagnosticSeverity::WARNING => colors.warning,
23008        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23009        lsp::DiagnosticSeverity::HINT => colors.info,
23010        _ => colors.ignored,
23011    }
23012}
23013
23014pub fn styled_runs_for_code_label<'a>(
23015    label: &'a CodeLabel,
23016    syntax_theme: &'a theme::SyntaxTheme,
23017) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23018    let fade_out = HighlightStyle {
23019        fade_out: Some(0.35),
23020        ..Default::default()
23021    };
23022
23023    let mut prev_end = label.filter_range.end;
23024    label
23025        .runs
23026        .iter()
23027        .enumerate()
23028        .flat_map(move |(ix, (range, highlight_id))| {
23029            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23030                style
23031            } else {
23032                return Default::default();
23033            };
23034            let mut muted_style = style;
23035            muted_style.highlight(fade_out);
23036
23037            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23038            if range.start >= label.filter_range.end {
23039                if range.start > prev_end {
23040                    runs.push((prev_end..range.start, fade_out));
23041                }
23042                runs.push((range.clone(), muted_style));
23043            } else if range.end <= label.filter_range.end {
23044                runs.push((range.clone(), style));
23045            } else {
23046                runs.push((range.start..label.filter_range.end, style));
23047                runs.push((label.filter_range.end..range.end, muted_style));
23048            }
23049            prev_end = cmp::max(prev_end, range.end);
23050
23051            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23052                runs.push((prev_end..label.text.len(), fade_out));
23053            }
23054
23055            runs
23056        })
23057}
23058
23059pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23060    let mut prev_index = 0;
23061    let mut prev_codepoint: Option<char> = None;
23062    text.char_indices()
23063        .chain([(text.len(), '\0')])
23064        .filter_map(move |(index, codepoint)| {
23065            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23066            let is_boundary = index == text.len()
23067                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23068                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23069            if is_boundary {
23070                let chunk = &text[prev_index..index];
23071                prev_index = index;
23072                Some(chunk)
23073            } else {
23074                None
23075            }
23076        })
23077}
23078
23079pub trait RangeToAnchorExt: Sized {
23080    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23081
23082    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23083        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23084        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23085    }
23086}
23087
23088impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23089    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23090        let start_offset = self.start.to_offset(snapshot);
23091        let end_offset = self.end.to_offset(snapshot);
23092        if start_offset == end_offset {
23093            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23094        } else {
23095            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23096        }
23097    }
23098}
23099
23100pub trait RowExt {
23101    fn as_f32(&self) -> f32;
23102
23103    fn next_row(&self) -> Self;
23104
23105    fn previous_row(&self) -> Self;
23106
23107    fn minus(&self, other: Self) -> u32;
23108}
23109
23110impl RowExt for DisplayRow {
23111    fn as_f32(&self) -> f32 {
23112        self.0 as f32
23113    }
23114
23115    fn next_row(&self) -> Self {
23116        Self(self.0 + 1)
23117    }
23118
23119    fn previous_row(&self) -> Self {
23120        Self(self.0.saturating_sub(1))
23121    }
23122
23123    fn minus(&self, other: Self) -> u32 {
23124        self.0 - other.0
23125    }
23126}
23127
23128impl RowExt for MultiBufferRow {
23129    fn as_f32(&self) -> f32 {
23130        self.0 as f32
23131    }
23132
23133    fn next_row(&self) -> Self {
23134        Self(self.0 + 1)
23135    }
23136
23137    fn previous_row(&self) -> Self {
23138        Self(self.0.saturating_sub(1))
23139    }
23140
23141    fn minus(&self, other: Self) -> u32 {
23142        self.0 - other.0
23143    }
23144}
23145
23146trait RowRangeExt {
23147    type Row;
23148
23149    fn len(&self) -> usize;
23150
23151    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23152}
23153
23154impl RowRangeExt for Range<MultiBufferRow> {
23155    type Row = MultiBufferRow;
23156
23157    fn len(&self) -> usize {
23158        (self.end.0 - self.start.0) as usize
23159    }
23160
23161    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23162        (self.start.0..self.end.0).map(MultiBufferRow)
23163    }
23164}
23165
23166impl RowRangeExt for Range<DisplayRow> {
23167    type Row = DisplayRow;
23168
23169    fn len(&self) -> usize {
23170        (self.end.0 - self.start.0) as usize
23171    }
23172
23173    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23174        (self.start.0..self.end.0).map(DisplayRow)
23175    }
23176}
23177
23178/// If select range has more than one line, we
23179/// just point the cursor to range.start.
23180fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23181    if range.start.row == range.end.row {
23182        range
23183    } else {
23184        range.start..range.start
23185    }
23186}
23187pub struct KillRing(ClipboardItem);
23188impl Global for KillRing {}
23189
23190const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23191
23192enum BreakpointPromptEditAction {
23193    Log,
23194    Condition,
23195    HitCondition,
23196}
23197
23198struct BreakpointPromptEditor {
23199    pub(crate) prompt: Entity<Editor>,
23200    editor: WeakEntity<Editor>,
23201    breakpoint_anchor: Anchor,
23202    breakpoint: Breakpoint,
23203    edit_action: BreakpointPromptEditAction,
23204    block_ids: HashSet<CustomBlockId>,
23205    editor_margins: Arc<Mutex<EditorMargins>>,
23206    _subscriptions: Vec<Subscription>,
23207}
23208
23209impl BreakpointPromptEditor {
23210    const MAX_LINES: u8 = 4;
23211
23212    fn new(
23213        editor: WeakEntity<Editor>,
23214        breakpoint_anchor: Anchor,
23215        breakpoint: Breakpoint,
23216        edit_action: BreakpointPromptEditAction,
23217        window: &mut Window,
23218        cx: &mut Context<Self>,
23219    ) -> Self {
23220        let base_text = match edit_action {
23221            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23222            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23223            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23224        }
23225        .map(|msg| msg.to_string())
23226        .unwrap_or_default();
23227
23228        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23229        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23230
23231        let prompt = cx.new(|cx| {
23232            let mut prompt = Editor::new(
23233                EditorMode::AutoHeight {
23234                    min_lines: 1,
23235                    max_lines: Some(Self::MAX_LINES as usize),
23236                },
23237                buffer,
23238                None,
23239                window,
23240                cx,
23241            );
23242            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23243            prompt.set_show_cursor_when_unfocused(false, cx);
23244            prompt.set_placeholder_text(
23245                match edit_action {
23246                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23247                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23248                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23249                },
23250                cx,
23251            );
23252
23253            prompt
23254        });
23255
23256        Self {
23257            prompt,
23258            editor,
23259            breakpoint_anchor,
23260            breakpoint,
23261            edit_action,
23262            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23263            block_ids: Default::default(),
23264            _subscriptions: vec![],
23265        }
23266    }
23267
23268    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23269        self.block_ids.extend(block_ids)
23270    }
23271
23272    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23273        if let Some(editor) = self.editor.upgrade() {
23274            let message = self
23275                .prompt
23276                .read(cx)
23277                .buffer
23278                .read(cx)
23279                .as_singleton()
23280                .expect("A multi buffer in breakpoint prompt isn't possible")
23281                .read(cx)
23282                .as_rope()
23283                .to_string();
23284
23285            editor.update(cx, |editor, cx| {
23286                editor.edit_breakpoint_at_anchor(
23287                    self.breakpoint_anchor,
23288                    self.breakpoint.clone(),
23289                    match self.edit_action {
23290                        BreakpointPromptEditAction::Log => {
23291                            BreakpointEditAction::EditLogMessage(message.into())
23292                        }
23293                        BreakpointPromptEditAction::Condition => {
23294                            BreakpointEditAction::EditCondition(message.into())
23295                        }
23296                        BreakpointPromptEditAction::HitCondition => {
23297                            BreakpointEditAction::EditHitCondition(message.into())
23298                        }
23299                    },
23300                    cx,
23301                );
23302
23303                editor.remove_blocks(self.block_ids.clone(), None, cx);
23304                cx.focus_self(window);
23305            });
23306        }
23307    }
23308
23309    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23310        self.editor
23311            .update(cx, |editor, cx| {
23312                editor.remove_blocks(self.block_ids.clone(), None, cx);
23313                window.focus(&editor.focus_handle);
23314            })
23315            .log_err();
23316    }
23317
23318    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23319        let settings = ThemeSettings::get_global(cx);
23320        let text_style = TextStyle {
23321            color: if self.prompt.read(cx).read_only(cx) {
23322                cx.theme().colors().text_disabled
23323            } else {
23324                cx.theme().colors().text
23325            },
23326            font_family: settings.buffer_font.family.clone(),
23327            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23328            font_size: settings.buffer_font_size(cx).into(),
23329            font_weight: settings.buffer_font.weight,
23330            line_height: relative(settings.buffer_line_height.value()),
23331            ..Default::default()
23332        };
23333        EditorElement::new(
23334            &self.prompt,
23335            EditorStyle {
23336                background: cx.theme().colors().editor_background,
23337                local_player: cx.theme().players().local(),
23338                text: text_style,
23339                ..Default::default()
23340            },
23341        )
23342    }
23343}
23344
23345impl Render for BreakpointPromptEditor {
23346    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23347        let editor_margins = *self.editor_margins.lock();
23348        let gutter_dimensions = editor_margins.gutter;
23349        h_flex()
23350            .key_context("Editor")
23351            .bg(cx.theme().colors().editor_background)
23352            .border_y_1()
23353            .border_color(cx.theme().status().info_border)
23354            .size_full()
23355            .py(window.line_height() / 2.5)
23356            .on_action(cx.listener(Self::confirm))
23357            .on_action(cx.listener(Self::cancel))
23358            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23359            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23360    }
23361}
23362
23363impl Focusable for BreakpointPromptEditor {
23364    fn focus_handle(&self, cx: &App) -> FocusHandle {
23365        self.prompt.focus_handle(cx)
23366    }
23367}
23368
23369fn all_edits_insertions_or_deletions(
23370    edits: &Vec<(Range<Anchor>, String)>,
23371    snapshot: &MultiBufferSnapshot,
23372) -> bool {
23373    let mut all_insertions = true;
23374    let mut all_deletions = true;
23375
23376    for (range, new_text) in edits.iter() {
23377        let range_is_empty = range.to_offset(&snapshot).is_empty();
23378        let text_is_empty = new_text.is_empty();
23379
23380        if range_is_empty != text_is_empty {
23381            if range_is_empty {
23382                all_deletions = false;
23383            } else {
23384                all_insertions = false;
23385            }
23386        } else {
23387            return false;
23388        }
23389
23390        if !all_insertions && !all_deletions {
23391            return false;
23392        }
23393    }
23394    all_insertions || all_deletions
23395}
23396
23397struct MissingEditPredictionKeybindingTooltip;
23398
23399impl Render for MissingEditPredictionKeybindingTooltip {
23400    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23401        ui::tooltip_container(window, cx, |container, _, cx| {
23402            container
23403                .flex_shrink_0()
23404                .max_w_80()
23405                .min_h(rems_from_px(124.))
23406                .justify_between()
23407                .child(
23408                    v_flex()
23409                        .flex_1()
23410                        .text_ui_sm(cx)
23411                        .child(Label::new("Conflict with Accept Keybinding"))
23412                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23413                )
23414                .child(
23415                    h_flex()
23416                        .pb_1()
23417                        .gap_1()
23418                        .items_end()
23419                        .w_full()
23420                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23421                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23422                        }))
23423                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23424                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23425                        })),
23426                )
23427        })
23428    }
23429}
23430
23431#[derive(Debug, Clone, Copy, PartialEq)]
23432pub struct LineHighlight {
23433    pub background: Background,
23434    pub border: Option<gpui::Hsla>,
23435    pub include_gutter: bool,
23436    pub type_id: Option<TypeId>,
23437}
23438
23439struct LineManipulationResult {
23440    pub new_text: String,
23441    pub line_count_before: usize,
23442    pub line_count_after: usize,
23443}
23444
23445fn render_diff_hunk_controls(
23446    row: u32,
23447    status: &DiffHunkStatus,
23448    hunk_range: Range<Anchor>,
23449    is_created_file: bool,
23450    line_height: Pixels,
23451    editor: &Entity<Editor>,
23452    _window: &mut Window,
23453    cx: &mut App,
23454) -> AnyElement {
23455    h_flex()
23456        .h(line_height)
23457        .mr_1()
23458        .gap_1()
23459        .px_0p5()
23460        .pb_1()
23461        .border_x_1()
23462        .border_b_1()
23463        .border_color(cx.theme().colors().border_variant)
23464        .rounded_b_lg()
23465        .bg(cx.theme().colors().editor_background)
23466        .gap_1()
23467        .block_mouse_except_scroll()
23468        .shadow_md()
23469        .child(if status.has_secondary_hunk() {
23470            Button::new(("stage", row as u64), "Stage")
23471                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23472                .tooltip({
23473                    let focus_handle = editor.focus_handle(cx);
23474                    move |window, cx| {
23475                        Tooltip::for_action_in(
23476                            "Stage Hunk",
23477                            &::git::ToggleStaged,
23478                            &focus_handle,
23479                            window,
23480                            cx,
23481                        )
23482                    }
23483                })
23484                .on_click({
23485                    let editor = editor.clone();
23486                    move |_event, _window, cx| {
23487                        editor.update(cx, |editor, cx| {
23488                            editor.stage_or_unstage_diff_hunks(
23489                                true,
23490                                vec![hunk_range.start..hunk_range.start],
23491                                cx,
23492                            );
23493                        });
23494                    }
23495                })
23496        } else {
23497            Button::new(("unstage", row as u64), "Unstage")
23498                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23499                .tooltip({
23500                    let focus_handle = editor.focus_handle(cx);
23501                    move |window, cx| {
23502                        Tooltip::for_action_in(
23503                            "Unstage Hunk",
23504                            &::git::ToggleStaged,
23505                            &focus_handle,
23506                            window,
23507                            cx,
23508                        )
23509                    }
23510                })
23511                .on_click({
23512                    let editor = editor.clone();
23513                    move |_event, _window, cx| {
23514                        editor.update(cx, |editor, cx| {
23515                            editor.stage_or_unstage_diff_hunks(
23516                                false,
23517                                vec![hunk_range.start..hunk_range.start],
23518                                cx,
23519                            );
23520                        });
23521                    }
23522                })
23523        })
23524        .child(
23525            Button::new(("restore", row as u64), "Restore")
23526                .tooltip({
23527                    let focus_handle = editor.focus_handle(cx);
23528                    move |window, cx| {
23529                        Tooltip::for_action_in(
23530                            "Restore Hunk",
23531                            &::git::Restore,
23532                            &focus_handle,
23533                            window,
23534                            cx,
23535                        )
23536                    }
23537                })
23538                .on_click({
23539                    let editor = editor.clone();
23540                    move |_event, window, cx| {
23541                        editor.update(cx, |editor, cx| {
23542                            let snapshot = editor.snapshot(window, cx);
23543                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23544                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23545                        });
23546                    }
23547                })
23548                .disabled(is_created_file),
23549        )
23550        .when(
23551            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23552            |el| {
23553                el.child(
23554                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23555                        .shape(IconButtonShape::Square)
23556                        .icon_size(IconSize::Small)
23557                        // .disabled(!has_multiple_hunks)
23558                        .tooltip({
23559                            let focus_handle = editor.focus_handle(cx);
23560                            move |window, cx| {
23561                                Tooltip::for_action_in(
23562                                    "Next Hunk",
23563                                    &GoToHunk,
23564                                    &focus_handle,
23565                                    window,
23566                                    cx,
23567                                )
23568                            }
23569                        })
23570                        .on_click({
23571                            let editor = editor.clone();
23572                            move |_event, window, cx| {
23573                                editor.update(cx, |editor, cx| {
23574                                    let snapshot = editor.snapshot(window, cx);
23575                                    let position =
23576                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23577                                    editor.go_to_hunk_before_or_after_position(
23578                                        &snapshot,
23579                                        position,
23580                                        Direction::Next,
23581                                        window,
23582                                        cx,
23583                                    );
23584                                    editor.expand_selected_diff_hunks(cx);
23585                                });
23586                            }
23587                        }),
23588                )
23589                .child(
23590                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23591                        .shape(IconButtonShape::Square)
23592                        .icon_size(IconSize::Small)
23593                        // .disabled(!has_multiple_hunks)
23594                        .tooltip({
23595                            let focus_handle = editor.focus_handle(cx);
23596                            move |window, cx| {
23597                                Tooltip::for_action_in(
23598                                    "Previous Hunk",
23599                                    &GoToPreviousHunk,
23600                                    &focus_handle,
23601                                    window,
23602                                    cx,
23603                                )
23604                            }
23605                        })
23606                        .on_click({
23607                            let editor = editor.clone();
23608                            move |_event, window, cx| {
23609                                editor.update(cx, |editor, cx| {
23610                                    let snapshot = editor.snapshot(window, cx);
23611                                    let point =
23612                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23613                                    editor.go_to_hunk_before_or_after_position(
23614                                        &snapshot,
23615                                        point,
23616                                        Direction::Prev,
23617                                        window,
23618                                        cx,
23619                                    );
23620                                    editor.expand_selected_diff_hunks(cx);
23621                                });
23622                            }
23623                        }),
23624                )
23625            },
23626        )
23627        .into_any_element()
23628}